1 in 1 chance to return true always results in true.
// Copyright 2010-2014 The Rust Project Developers.
```
+# Coordination and communication
+
+Get feedback from other developers on
+[discuss.rust-lang.org][discuss], and
+[#rust-internals][pound-rust-internals].
+
+[pound-rust-internals]: http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust-internals
+[discuss]: http://discuss.rust-lang.org
+
For more details, please refer to
[Note-development-policy](https://github.com/rust-lang/rust/wiki/Note-development-policy).
\fB\-\-emit\fR [asm|llvm-bc|llvm-ir|obj|link|dep-info]
Configure the output that rustc will produce
.TP
-\fB\-\-print\fR [crate-name|output-file-names|sysroot]
+\fB\-\-print\fR [crate-name|file-names|sysroot]
Comma separated list of compiler information to print on stdout
.TP
\fB\-g\fR
RUSTDOC_HTML_OPTS = $(RUSTDOC_HTML_OPTS_NO_CSS) --markdown-css rust.css
PANDOC_BASE_OPTS := --standalone --toc --number-sections
-PANDOC_TEX_OPTS = $(PANDOC_BASE_OPTS) --include-before-body=doc/version.tex \
- --from=markdown --include-before-body=doc/footer.tex --to=latex
+PANDOC_TEX_OPTS = $(PANDOC_BASE_OPTS) --from=markdown --to=latex \
+ --include-before-body=doc/version.tex \
+ --include-before-body=doc/footer.tex \
+ --include-in-header=doc/uptack.tex
PANDOC_EPUB_OPTS = $(PANDOC_BASE_OPTS) --to=epub
# The rustdoc executable...
@$(call E, pandoc: $@)
$(CFG_PANDOC) --from=html --to=latex $< --output=$@
+doc/uptack.tex: $(D)/uptack.tex | doc/
+ $(Q)cp $< $@
+
# HTML (rustdoc)
DOC_TARGETS += doc/not_found.html
doc/not_found.html: $(D)/not_found.md $(HTML_DEPS) | doc/
# PDF (md =(pandoc)=> tex =(pdflatex)=> pdf)
DOC_TARGETS += doc/$(1).tex
-doc/$(1).tex: $$(D)/$(1).md doc/footer.tex doc/version.tex | doc/
+doc/$(1).tex: $$(D)/$(1).md doc/uptack.tex doc/footer.tex doc/version.tex | doc/
@$$(call E, pandoc: $$@)
$$(CFG_PANDOC) $$(PANDOC_TEX_OPTS) $$< --output=$$@
# Remove tmp files because it's a decent amount of disk space
$(Q)rm -R tmp/dist
-ifeq ($(CFG_DISABLE_DOCS),)
-prepare_install: dist/$(PKG_NAME)-$(CFG_BUILD).tar.gz dist/$(DOC_PKG_NAME)-$(CFG_BUILD).tar.gz | tmp/empty_dir
-else
-prepare_install: dist/$(PKG_NAME)-$(CFG_BUILD).tar.gz | tmp/empty_dir
-endif
+prepare_install: dist-tar-bins | tmp/empty_dir
uninstall:
ifeq (root user, $(USER) $(patsubst %,user,$(SUDO_USER)))
# Remove tmp files because it's a decent amount of disk space
$(Q)rm -R tmp/dist
-prepare_uninstall: dist/$(PKG_NAME)-$(CFG_BUILD).tar.gz | tmp/empty_dir
+prepare_uninstall: dist-tar-bins | tmp/empty_dir
.PHONY: install prepare_install uninstall prepare_uninstall
return valid;
}
-pub fn make_test(config: &Config, testfile: &Path, f: || -> test::TestFn)
- -> test::TestDescAndFn {
+pub fn make_test<F>(config: &Config, testfile: &Path, f: F) -> test::TestDescAndFn where
+ F: FnOnce() -> test::TestFn,
+{
test::TestDescAndFn {
desc: test::TestDesc {
name: make_test_name(config, testfile),
!val
}
-fn iter_header(testfile: &Path, it: |&str| -> bool) -> bool {
+fn iter_header<F>(testfile: &Path, mut it: F) -> bool where
+ F: FnMut(&str) -> bool,
+{
use std::io::{BufferedReader, File};
let mut rdr = BufferedReader::new(File::open(testfile).unwrap());
ThisDirectory(Path),
}
-fn make_compile_args(config: &Config,
- props: &TestProps,
- extras: Vec<String> ,
- xform: |&Config, &Path| -> TargetLocation,
- testfile: &Path)
- -> ProcArgs {
+fn make_compile_args<F>(config: &Config,
+ props: &TestProps,
+ extras: Vec<String> ,
+ xform: F,
+ testfile: &Path)
+ -> ProcArgs where
+ F: FnOnce(&Config, &Path) -> TargetLocation,
+{
let xform_file = xform(config, testfile);
let target = if props.force_host {
config.host.as_slice()
* [sprocketnes], an NES emulator with no GC, using modern Rust conventions
* The language's general-purpose [hash] function, SipHash-2-4. Bit twiddling, OO, macros
* The standard library's [HashMap], a sendable hash map in an OO style
-* The extra library's [json] module. Enums and pattern matching
+* The standard library's [json] module. Enums and pattern matching
[sprocketnes]: https://github.com/pcwalton/sprocketnes
[hash]: https://github.com/rust-lang/rust/blob/master/src/libstd/hash/mod.rs
~~~no_run
extern crate libc;
-use std::c_str::ToCStr;
+use std::ffi::CString;
use std::ptr;
#[link(name = "readline")]
}
fn main() {
- "[my-awesome-shell] $".with_c_str(|buf| {
- unsafe { rl_prompt = buf; }
- // get a line, process it
- unsafe { rl_prompt = ptr::null(); }
- });
+ let prompt = CString::from_slice(b"[my-awesome-shell] $");
+ unsafe { rl_prompt = prompt.as_ptr(); }
+ // get a line, process it
+ unsafe { rl_prompt = ptr::null(); }
}
~~~
# Interoperability with foreign code
-Rust guarantees that the layout of a `struct` is compatible with the platform's representation in C
-only if the `#[repr(C)]` attribute is applied to it. `#[repr(C, packed)]` can be used to lay out
-struct members without padding. `#[repr(C)]` can also be applied to an enum.
-
-Rust's owned boxes (`Box<T>`) use non-nullable pointers as handles which point to the contained
-object. However, they should not be manually created because they are managed by internal
-allocators. References can safely be assumed to be non-nullable pointers directly to the type.
-However, breaking the borrow checking or mutability rules is not guaranteed to be safe, so prefer
-using raw pointers (`*`) if that's needed because the compiler can't make as many assumptions about
-them.
-
-Vectors and strings share the same basic memory layout, and utilities are available in the `vec` and
-`str` modules for working with C APIs. However, strings are not terminated with `\0`. If you need a
-NUL-terminated string for interoperability with C, you should use the `c_str::to_c_str` function.
-
-The standard library includes type aliases and function definitions for the C standard library in
-the `libc` module, and Rust links against `libc` and `libm` by default.
+Rust guarantees that the layout of a `struct` is compatible with the platform's
+representation in C only if the `#[repr(C)]` attribute is applied to it.
+`#[repr(C, packed)]` can be used to lay out struct members without padding.
+`#[repr(C)]` can also be applied to an enum.
+
+Rust's owned boxes (`Box<T>`) use non-nullable pointers as handles which point
+to the contained object. However, they should not be manually created because
+they are managed by internal allocators. References can safely be assumed to be
+non-nullable pointers directly to the type. However, breaking the borrow
+checking or mutability rules is not guaranteed to be safe, so prefer using raw
+pointers (`*`) if that's needed because the compiler can't make as many
+assumptions about them.
+
+Vectors and strings share the same basic memory layout, and utilities are
+available in the `vec` and `str` modules for working with C APIs. However,
+strings are not terminated with `\0`. If you need a NUL-terminated string for
+interoperability with C, you should use the `CString` type in the `std::ffi`
+module.
+
+The standard library includes type aliases and function definitions for the C
+standard library in the `libc` module, and Rust links against `libc` and `libm`
+by default.
# The "nullable pointer optimization"
```
Rust has a feature called 'lifetime elision,' which allows you to not write
-lifetime annotations in certain circumstances. This is one of them. Without
-eliding the lifetimes, `add_one` looks like this:
+lifetime annotations in certain circumstances. This is one of them. We will
+cover the others later. Without eliding the lifetimes, `add_one` looks like
+this:
```rust
fn add_one<'a>(num: &'a int) -> int {
also `Arc<T>`, which uses more expensive atomic instructions to be the
thread-safe counterpart of `Rc<T>`.
+## Lifetime Elision
+
+Earlier, we mentioned 'lifetime elision,' a feature of Rust which allows you to
+not write lifetime annotations in certain circumstances. All references have a
+lifetime, and so if you elide a lifetime (like `&T` instead of `&'a T`), Rust
+will do three things to determine what those lifetimes should be.
+
+When talking about lifetime elision, we use the term 'input lifetime' and
+'output lifetime'. An 'input liftime' is a lifetime associated with a parameter
+of a function, and an 'output lifetime' is a lifetime associated with the return
+value of a function. For example, this function has an input lifetime:
+
+```{rust,ignore}
+fn foo<'a>(bar: &'a str)
+```
+
+This one has an output lifetime:
+
+```{rust,ignore}
+fn foo<'a>() -> &'a str
+```
+
+This one has a lifetime in both positions:
+
+```{rust,ignore}
+fn foo<'a>(bar: &'a str) -> &'a str
+```
+
+Here are the three rules:
+
+* Each elided lifetime in a function's arguments becomes a distinct lifetime
+ parameter.
+
+* If there is exactly one input lifetime, elided or not, that lifetime is
+ assigned to all elided lifetimes in the return values of that function..
+
+* If there are multiple input lifetimes, but one of them is `&self` or `&mut
+ self`, the lifetime of `self` is assigned to all elided output lifetimes.
+
+Otherwise, it is an error to elide an output lifetime.
+
+### Examples
+
+Here are some examples of functions with elided lifetimes, and the version of
+what the elided lifetimes are expand to:
+
+```{rust,ignore}
+fn print(s: &str); // elided
+fn print<'a>(s: &'a str); // expanded
+
+fn debug(lvl: uint, s: &str); // elided
+fn debug<'a>(lvl: uint, s: &'a str); // expanded
+
+// In the preceeding example, `lvl` doesn't need a lifetime because it's not a
+// reference (`&`). Only things relating to references (such as a `struct`
+// which contains a reference) need lifetimes.
+
+fn substr(s: &str, until: uint) -> &str; // elided
+fn substr<'a>(s: &'a str, until: uint) -> &'a str; // expanded
+
+fn get_str() -> &str; // ILLEGAL, no inputs
+
+fn frob(s: &str, t: &str) -> &str; // ILLEGAL, two inputs
+
+fn get_mut(&mut self) -> &mut T; // elided
+fn get_mut<'a>(&'a mut self) -> &'a mut T; // expanded
+
+fn args<T:ToCStr>(&mut self, args: &[T]) -> &mut Command // elided
+fn args<'a, 'b, T:ToCStr>(&'a mut self, args: &'b [T]) -> &'a mut Command // expanded
+
+fn new(buf: &mut [u8]) -> BufWriter; // elided
+fn new<'a>(buf: &'a mut [u8]) -> BufWriter<'a> // expanded
+```
+
# Related Resources
Coming Soon.
* Make the code in the `iter` loop do something simple, to assist in pinpointing
performance improvements (or regressions)
+## Gotcha: optimizations
+
There's another tricky part to writing benchmarks: benchmarks compiled with
optimizations activated can be dramatically changed by the optimizer so that
the benchmark is no longer benchmarking what one expects. For example, the
`b.iter` call to
```rust
-# struct X; impl X { fn iter<T>(&self, _: || -> T) {} } let b = X;
+# struct X;
+# impl X { fn iter<T, F>(&self, _: F) where F: FnMut() -> T {} } let b = X;
b.iter(|| {
// note lack of `;` (could also use an explicit `return`).
range(0u, 1000).fold(0, |old, new| old ^ new)
extern crate test;
# fn main() {
-# struct X; impl X { fn iter<T>(&self, _: || -> T) {} } let b = X;
+# struct X;
+# impl X { fn iter<T, F>(&self, _: F) where F: FnMut() -> T {} } let b = X;
b.iter(|| {
- test::black_box(range(0u, 1000).fold(0, |old, new| old ^ new));
-});
+ let mut n = 1000_u32;
+
+ test::black_box(&mut n); // pretend to modify `n`
+
+ range(0, n).fold(0, |a, b| a ^ b)
+})
# }
```
test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured
```
+
+However, the optimizer can still modify a testcase in an undesirable manner
+even when using either of the above.
in the `$`s, they just indicate the start of each command):
```bash
-curl -L https://static.rust-lang.org/rustup.sh | sudo sh
+$ curl -L https://static.rust-lang.org/rustup.sh | sudo sh
```
If you're concerned about the [potential insecurity](http://curlpipesh.tumblr.com/) of using `curl | sudo sh`,
please keep reading and see our disclaimer below. And feel free to use a two-step version of the installation and examine our installation script:
```bash
-curl -L https://static.rust-lang.org/rustup.sh -O
-sudo sh rustup.sh
+$ curl -L https://static.rust-lang.org/rustup.sh -O
+$ sudo sh rustup.sh
```
If you're on Windows, please download either the [32-bit
[Mibbit](http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust). Click
that link, and you'll be chatting with other Rustaceans (a silly nickname we
call ourselves), and we can help you out. Other great resources include [our
-mailing list](https://mail.mozilla.org/listinfo/rust-dev), [the /r/rust
+forum](http://discuss.rust-lang.org/), [the /r/rust
subreddit](http://www.reddit.com/r/rust), and [Stack
Overflow](http://stackoverflow.com/questions/tagged/rust).
its functionality. Eventually, we'll add more. Since we started off by using
Cargo, it'll be easy to add later.
-Let's convert Hello World to Cargo. The first thing we need to do to begin
-using Cargo is to install Cargo. Luckily for us, the script we ran to install
-Rust includes Cargo by default. If you installed Rust some other way, you may
-want to [check the Cargo
+If you installed Rust via the official installers you will also have
+Cargo. If you installed Rust some other way, you may want to [check
+the Cargo
README](https://github.com/rust-lang/cargo#installing-cargo-from-nightlies)
for specific instructions about installing it.
+Let's convert Hello World to Cargo.
+
To Cargo-ify our project, we need to do two things: Make a `Cargo.toml`
configuration file, and put our source file in the right place. Let's
do that part first:
Bam! We build our project with `cargo build`, and run it with
`./target/hello_world`. This hasn't bought us a whole lot over our simple use
of `rustc`, but think about the future: when our project has more than one
-file, we would need to call `rustc` twice, and pass it a bunch of options to
+file, we would need to call `rustc` more than once, and pass it a bunch of options to
tell it to build everything together. With Cargo, as our project grows, we can
just `cargo build` and it'll work the right way.
```{rust}
fn main() {
- let x = 5i;
+ let x = 5;
}
```
This means we can do things like:
```{rust}
-let (x, y) = (1i, 2i);
+let (x, y) = (1, 2);
```
After this expression is evaluated, `x` will be one, and `y` will be two.
Patterns are really powerful, but this is about all we can do with them so far.
So let's just keep this in the back of our minds as we go forward.
-By the way, in these examples, `i` indicates that the number is an integer.
-
Rust is a statically typed language, which means that we specify our types up
front. So why does our first example compile? Well, Rust has this thing called
"type inference." If it can figure out what the type of something is, Rust
We can add the type if we want to, though. Types come after a colon (`:`):
```{rust}
-let x: int = 5;
+let x: i32 = 5;
```
If I asked you to read this out loud to the rest of the class, you'd say "`x`
-is a binding with the type `int` and the value `five`."
+is a binding with the type `i32` and the value `five`."
In future examples, we may annotate the type in a comment. The examples will
look like this:
```{rust}
fn main() {
- let x = 5i; // x: int
+ let x = 5; // x: i32
}
```
By default, bindings are **immutable**. This code will not compile:
```{ignore}
-let x = 5i;
-x = 10i;
+let x = 5;
+x = 10;
```
It will give you this error:
```text
error: re-assignment of immutable variable `x`
- x = 10i;
+ x = 10;
^~~~~~~
```
If you want a binding to be mutable, you can use `mut`:
```{rust}
-let mut x = 5i; // mut x: int
-x = 10i;
+let mut x = 5; // mut x: i32
+x = 10;
```
There is no single reason that bindings are immutable by default, but we can
Giving it a type will compile, though:
```{rust}
-let x: int;
+let x: i32;
```
Let's try it out. Change your `src/main.rs` file to look like this:
```{rust}
fn main() {
- let x: int;
+ let x: i32;
println!("Hello world!");
}
```text
Compiling hello_world v0.0.1 (file:///home/you/projects/hello_world)
src/main.rs:2:9: 2:10 warning: unused variable: `x`, #[warn(unused_variable)] on by default
-src/main.rs:2 let x: int;
+src/main.rs:2 let x: i32;
^
```
```{rust,ignore}
fn main() {
- let x: int;
+ let x: i32;
println!("The value of x is: {}", x);
}
In the case of `if`, there is one choice that leads down two paths:
```rust
-let x = 5i;
+let x = 5;
-if x == 5i {
+if x == 5 {
println!("x is five!");
}
```
If you want something to happen in the `false` case, use an `else`:
```{rust}
-let x = 5i;
+let x = 5;
-if x == 5i {
+if x == 5 {
println!("x is five!");
} else {
println!("x is not five :(");
```{rust}
-let x = 5i;
+let x = 5;
-let y = if x == 5i {
- 10i
+let y = if x == 5 {
+ 10
} else {
- 15i
-}; // y: int
+ 15
+}; // y: i32
```
Which we can (and probably should) write like this:
```{rust}
-let x = 5i;
+let x = 5;
-let y = if x == 5i { 10i } else { 15i }; // y: int
+let y = if x == 5 { 10 } else { 15 }; // y: i32
```
This reveals two interesting things about Rust: it is an expression-based
following will produce a compile-time error:
```{ignore}
-let x = (let y = 5i); // expected identifier, found keyword `let`
+let x = (let y = 5); // expected identifier, found keyword `let`
```
The compiler is telling us here that it was expecting to see the beginning of
an expression, and a `let` can only begin a statement, not an expression.
-Note that assigning to an already-bound variable (e.g. `y = 5i`) is still an
+Note that assigning to an already-bound variable (e.g. `y = 5`) is still an
expression, although its value is not particularly useful. Unlike C, where an
-assignment evaluates to the assigned value (e.g. `5i` in the previous example),
+assignment evaluates to the assigned value (e.g. `5` in the previous example),
in Rust the value of an assignment is the unit type `()` (which we'll cover later).
The second kind of statement in Rust is the **expression statement**. Its
code:
```{rust}
-let x = 5i;
+let x = 5;
-let y: int = if x == 5i { 10i } else { 15i };
+let y: i32 = if x == 5 { 10 } else { 15 };
```
Note that I've added the type annotation to `y`, to specify explicitly that I
This is not the same as this, which won't compile:
```{ignore}
-let x = 5i;
+let x = 5;
-let y: int = if x == 5i { 10i; } else { 15i; };
+let y: i32 = if x == 5 { 10; } else { 15; };
```
Note the semicolons after the 10 and 15. Rust will give us the following error:
```text
-error: mismatched types: expected `int` but found `()` (expected int but found ())
+error: mismatched types: expected `i32` but found `()` (expected i32 but found ())
```
We expected an integer, but we got `()`. `()` is pronounced 'unit', and is a
special type in Rust's type system. In Rust, `()` is _not_ a valid value for a
-variable of type `int`. It's only a valid value for variables of the type `()`,
+variable of type `i32`. It's only a valid value for variables of the type `()`,
which aren't very useful. Remember how we said statements don't return a value?
Well, that's the purpose of unit in this case. The semicolon turns any
expression into a statement by throwing away its value and returning unit
So, what about taking arguments? Here's a function that prints a number:
```{rust}
-fn print_number(x: int) {
+fn print_number(x: i32) {
println!("x is: {}", x);
}
```
print_number(5);
}
-fn print_number(x: int) {
+fn print_number(x: i32) {
println!("x is: {}", x);
}
```
print_sum(5, 6);
}
-fn print_sum(x: int, y: int) {
+fn print_sum(x: i32, y: i32) {
println!("sum is: {}", x + y);
}
```
What about returning a value? Here's a function that adds one to an integer:
```{rust}
-fn add_one(x: int) -> int {
+fn add_one(x: i32) -> i32 {
x + 1
}
```
You'll note the lack of a semicolon here. If we added it in:
```{ignore}
-fn add_one(x: int) -> int {
+fn add_one(x: i32) -> i32 {
x + 1;
}
```
```text
error: not all control paths return a value
-fn add_one(x: int) -> int {
+fn add_one(x: i32) -> i32 {
x + 1;
}
```
Remember our earlier discussions about semicolons and `()`? Our function claims
-to return an `int`, but with a semicolon, it would return `()` instead. Rust
+to return an `i32`, but with a semicolon, it would return `()` instead. Rust
realizes this probably isn't what we want, and suggests removing the semicolon.
This is very much like our `if` statement before: the result of the block
But what about early returns? Rust does have a keyword for that, `return`:
```{rust}
-fn foo(x: int) -> int {
+fn foo(x: i32) -> i32 {
if x < 5 { return x; }
x + 1
style:
```{rust}
-fn foo(x: int) -> int {
+fn foo(x: i32) -> i32 {
if x < 5 { return x; }
return x + 1;
```{rust}
// Line comments are anything after '//' and extend to the end of the line.
-let x = 5i; // this is also a line comment.
+let x = 5; // this is also a line comment.
// If you have a long explanation for something, you can put line comments next
// to each other. Put a space between the // and your comment so that it's
Tuples are an ordered list of a fixed size. Like this:
```rust
-let x = (1i, "hello");
+let x = (1, "hello");
```
The parentheses and commas form this two-length tuple. Here's the same code, but
with the type annotated:
```rust
-let x: (int, &str) = (1, "hello");
+let x: (i32, &str) = (1, "hello");
```
As you can see, the type of a tuple looks just like the tuple, but with each
position having a type name rather than the value. Careful readers will also
-note that tuples are heterogeneous: we have an `int` and a `&str` in this tuple.
+note that tuples are heterogeneous: we have an `i32` and a `&str` in this tuple.
You haven't seen `&str` as a type before, and we'll discuss the details of
strings later. In systems programming languages, strings are a bit more complex
than in other languages. For now, just read `&str` as "a string slice," and
an example:
```rust
-let (x, y, z) = (1i, 2i, 3i);
+let (x, y, z) = (1, 2, 3);
println!("x is {}", x);
```
arity and contained types.
```rust
-let mut x = (1i, 2i); // x: (int, int)
-let y = (2i, 3i); // y: (int, int)
+let mut x = (1, 2); // x: (i32, i32)
+let y = (2, 3); // y: (i32, i32)
x = y;
```
tuples have the same type.
```rust
-let x = (1i, 2i, 3i);
-let y = (2i, 2i, 4i);
+let x = (1, 2, 3);
+let y = (2, 2, 4);
if x == y {
println!("yes");
One other use of tuples is to return multiple values from a function:
```rust
-fn next_two(x: int) -> (int, int) { (x + 1i, x + 2i) }
+fn next_two(x: i32) -> (i32, i32) { (x + 1, x + 2) }
fn main() {
- let (x, y) = next_two(5i);
+ let (x, y) = next_two(5);
println!("x, y = {}, {}", x, y);
}
```
Even though Rust functions can only return one value, a tuple _is_ one value,
-that happens to be made up of two. You can also see in this example how you
+that happens to be made up of more than one value. You can also see in this example how you
can destructure a pattern returned by a function, as well.
Tuples are a very simple data structure, and so are not often what you want.
```rust
struct Point {
- x: int,
- y: int,
+ x: i32,
+ y: i32,
}
fn main() {
- let origin = Point { x: 0i, y: 0i }; // origin: Point
+ let origin = Point { x: 0, y: 0 }; // origin: Point
println!("The origin is at ({}, {})", origin.x, origin.y);
}
```{rust}
struct Point {
- x: int,
- y: int,
+ x: i32,
+ y: i32,
}
fn main() {
- let mut point = Point { x: 0i, y: 0i };
+ let mut point = Point { x: 0, y: 0 };
point.x = 5;
```{rust}
-struct Color(int, int, int);
-struct Point(int, int, int);
+struct Color(i32, i32, i32);
+struct Point(i32, i32, i32);
```
These two will not be equal, even if they have the same values:
```{rust}
-# struct Color(int, int, int);
-# struct Point(int, int, int);
+# struct Color(i32, i32, i32);
+# struct Point(i32, i32, i32);
let black = Color(0, 0, 0);
let origin = Point(0, 0, 0);
```
```{rust}
struct Color {
- red: int,
- blue: int,
- green: int,
+ red: i32,
+ blue: i32,
+ green: i32,
}
struct Point {
- x: int,
- y: int,
- z: int,
+ x: i32,
+ y: i32,
+ z: i32,
}
```
you create a new type that's a synonym for another one:
```{rust}
-struct Inches(int);
+struct Inches(i32);
let length = Inches(10);
```{rust}
use std::cmp::Ordering;
-fn cmp(a: int, b: int) -> Ordering {
+fn cmp(a: i32, b: i32) -> Ordering {
if a < b { Ordering::Less }
else if a > b { Ordering::Greater }
else { Ordering::Equal }
}
fn main() {
- let x = 5i;
- let y = 10i;
+ let x = 5;
+ let y = 10;
let ordering = cmp(x, y); // ordering: Ordering
```
There's a symbol here we haven't seen before: the double colon (`::`).
-This is used to indicate a namesapce. In this case, `Ordering` lives in
+This is used to indicate a namespace. In this case, `Ordering` lives in
the `cmp` submodule of the `std` module. We'll talk more about modules
later in the guide. For now, all you need to know is that you can `use`
things from the standard library if you need them.
```{rust}
enum OptionalInt {
- Value(int),
+ Value(i32),
Missing,
}
```
-This enum represents an `int` that we may or may not have. In the `Missing`
+This enum represents an `i32` that we may or may not have. In the `Missing`
case, we have no value, but in the `Value` case, we do. This enum is specific
-to `int`s, though. We can make it usable by any type, but we haven't quite
+to `i32`s, though. We can make it usable by any type, but we haven't quite
gotten there yet!
You can also have any number of values in an enum:
```{rust}
enum OptionalColor {
- Color(int, int, int),
+ Color(i32, i32, i32),
Missing,
}
```
groupings with something more powerful. Check it out:
```{rust}
-let x = 5i;
+let x = 5;
match x {
1 => println!("one"),
In other words, Rust is trying to tell us we forgot a value. Because `x` is an
integer, Rust knows that it can have a number of different values – for example,
-`6i`. Without the `_`, however, there is no arm that could match, and so Rust refuses
+`6`. Without the `_`, however, there is no arm that could match, and so Rust refuses
to compile. `_` acts like a 'catch-all arm'. If none of the other arms match,
the arm with `_` will, and since we have this catch-all arm, we now have an arm
for every possible value of `x`, and so our program will compile successfully.
```{rust}
use std::cmp::Ordering;
-fn cmp(a: int, b: int) -> Ordering {
+fn cmp(a: i32, b: i32) -> Ordering {
if a < b { Ordering::Less }
else if a > b { Ordering::Greater }
else { Ordering::Equal }
}
fn main() {
- let x = 5i;
- let y = 10i;
+ let x = 5;
+ let y = 10;
let ordering = cmp(x, y);
```{rust}
use std::cmp::Ordering;
-fn cmp(a: int, b: int) -> Ordering {
+fn cmp(a: i32, b: i32) -> Ordering {
if a < b { Ordering::Less }
else if a > b { Ordering::Greater }
else { Ordering::Equal }
}
fn main() {
- let x = 5i;
- let y = 10i;
+ let x = 5;
+ let y = 10;
match cmp(x, y) {
Ordering::Less => println!("less"),
```{rust}
enum OptionalInt {
- Value(int),
+ Value(i32),
Missing,
}
That is how you can get and use the values contained in `enum`s.
It can also allow us to handle errors or unexpected computations; for example, a
-function that is not guaranteed to be able to compute a result (an `int` here)
+function that is not guaranteed to be able to compute a result (an `i32` here)
could return an `OptionalInt`, and we would handle that value with a `match`.
As you can see, `enum` and `match` used together are quite useful!
```{rust}
use std::cmp::Ordering;
-fn cmp(a: int, b: int) -> Ordering {
+fn cmp(a: i32, b: i32) -> Ordering {
if a < b { Ordering::Less }
else if a > b { Ordering::Greater }
else { Ordering::Equal }
}
fn main() {
- let x = 5i;
- let y = 10i;
+ let x = 5;
+ let y = 10;
println!("{}", match cmp(x, y) {
Ordering::Less => "less",
Instead, it looks like this:
```{rust}
-for x in range(0i, 10i) {
- println!("{}", x); // x: int
+for x in range(0, 10) {
+ println!("{}", x); // x: i32
}
```
iteration. This will only print the odd numbers:
```{rust}
-for x in range(0i, 10i) {
+for x in range(0, 10) {
if x % 2 == 0 { continue; }
println!("{}", x);
same type. By default, arrays are immutable.
```{rust}
-let a = [1i, 2i, 3i]; // a: [int; 3]
-let mut m = [1i, 2i, 3i]; // mut m: [int; 3]
+let a = [1, 2, 3]; // a: [i32; 3]
+let mut m = [1, 2, 3]; // mut m: [i32; 3]
```
There's a shorthand for initializing each element of an array to the same
-value. In this example, each element of `a` will be initialized to `0i`:
+value. In this example, each element of `a` will be initialized to `0`:
```{rust}
-let a = [0i; 20]; // a: [int; 20]
+let a = [0; 20]; // a: [i32; 20]
```
Arrays have type `[T; N]`. We'll talk about this `T` notation later, when we
number in order:
```{rust}
-let a = [1i, 2, 3]; // Only the first item needs a type suffix
+let a = [1, 2, 3];
println!("a has {} elements", a.len());
for e in a.iter() {
with the `vec!` macro:
```{rust}
-let v = vec![1i, 2, 3]; // v: Vec<int>
+let v = vec![1, 2, 3]; // v: Vec<i32>
```
(Notice that unlike the `println!` macro we've used in the past, we use square
arrays. In addition, (mutable) vectors can grow automatically:
```{rust}
-let mut nums = vec![1i, 2, 3]; // mut nums: Vec<int>
+let mut nums = vec![1, 2, 3]; // mut nums: Vec<i32>
nums.push(4);
arrays:
```{rust}
-let a = [0i, 1, 2, 3, 4];
+let a = [0, 1, 2, 3, 4];
let middle = a.slice(1, 4); // A slice of a: just the elements [1,2,3]
for e in middle.iter() {
```{rust}
enum OptionalInt {
- Value(int),
+ Value(i32),
Missing,
}
very similar to our `OptionalInt`: an `IoResult<T>`. We haven't talked about
`IoResult<T>` yet because it is the **generic** form of our `OptionalInt`.
Until then, you can think of it as being the same thing, just for any type –
-not just `int`s.
+not just `i32`s.
Rust provides a method on these `IoResult<T>`s called `ok()`, which does the
same thing as our `match` statement but assumes that we have a valid value.
fn main() {
println!("Guess the number!");
- let secret_number = (rand::random() % 100i) + 1i; // secret_number: int
+ let secret_number = (rand::random() % 100) + 1; // secret_number: i32
println!("The secret number is: {}", secret_number);
$ cargo build
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
src/main.rs:7:26: 7:34 error: the type of this value must be known in this context
-src/main.rs:7 let secret_number = (rand::random() % 100i) + 1i;
+src/main.rs:7 let secret_number = (rand::random() % 100) + 1;
^~~~~~~~
error: aborting due to previous error
```
context." What's up with that? Well, as it turns out, `rand::random()` can
generate many kinds of random values, not just integers. And in this case, Rust
isn't sure what kind of value `random()` should generate. So we have to help
-it. With number literals, we just add an `i` onto the end to tell Rust they're
+it. With number literals, we can just add an `i32` onto the end to tell Rust they're
integers, but that does not work with functions. There's a different syntax,
and it looks like this:
```{rust,ignore}
-rand::random::<int>();
+rand::random::<i32>();
```
-This says "please give me a random `int` value." We can change our code to use
+This says "please give me a random `i32` value." We can change our code to use
this hint:
```{rust,no_run}
fn main() {
println!("Guess the number!");
- let secret_number = (rand::random::<int>() % 100i) + 1i;
+ let secret_number = (rand::random::<i32>() % 100) + 1;
println!("The secret number is: {}", secret_number);
}
}
-fn cmp(a: int, b: int) -> Ordering {
+fn cmp(a: i32, b: i32) -> Ordering {
if a < b { Ordering::Less }
else if a > b { Ordering::Greater }
else { Ordering::Equal }
```bash
$ cargo build
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
-src/main.rs:20:15: 20:20 error: mismatched types: expected `int` but found `collections::string::String` (expected int but found struct collections::string::String)
+src/main.rs:20:15: 20:20 error: mismatched types: expected `i32` but found `collections::string::String` (expected i32 but found struct collections::string::String)
src/main.rs:20 match cmp(input, secret_number) {
^~~~~
-src/main.rs:20:22: 20:35 error: mismatched types: expected `int` but found `uint` (expected int but found uint)
+src/main.rs:20:22: 20:35 error: mismatched types: expected `i32` but found `uint` (expected i32 but found uint)
src/main.rs:20 match cmp(input, secret_number) {
^~~~~~~~~~~~~
error: aborting due to 2 previous errors
```{rust}
#[test]
fn is_one_equal_to_one() {
- assert_eq!(1i, 1i);
+ assert_eq!(1, 1);
}
```
```{rust,ignore}
#[test]
fn math_checks_out() {
- let result = add_three_times_four(5i);
+ let result = add_three_times_four(5);
- assert_eq!(32i, result);
+ assert_eq!(32, result);
}
```
$ cargo test
Compiling testing v0.0.1 (file:///home/you/projects/testing)
/home/you/projects/testing/tests/lib.rs:3:18: 3:38 error: unresolved name `add_three_times_four`.
-/home/you/projects/testing/tests/lib.rs:3 let result = add_three_times_four(5i);
+/home/you/projects/testing/tests/lib.rs:3 let result = add_three_times_four(5);
^~~~~~~~~~~~~~~~~~~~
error: aborting due to previous error
Build failed, waiting for other jobs to finish...
```{rust}
# fn main() {}
-pub fn add_three_times_four(x: int) -> int {
+pub fn add_three_times_four(x: i32) -> i32 {
(x + 3) * 4
}
```
#[test]
fn math_checks_out() {
- let result = add_three_times_four(5i);
+ let result = add_three_times_four(5);
- assert_eq!(32i, result);
+ assert_eq!(32, result);
}
```
Change your `src/lib.rs` to look like this:
```{rust,ignore}
-pub fn add_three_times_four(x: int) -> int {
+pub fn add_three_times_four(x: i32) -> i32 {
times_four(add_three(x))
}
-fn add_three(x: int) -> int { x + 3 }
+fn add_three(x: i32) -> i32 { x + 3 }
-fn times_four(x: int) -> int { x * 4 }
+fn times_four(x: i32) -> i32 { x * 4 }
```
If you run `cargo test`, you should get the same output:
#[test]
fn math_checks_out() {
- let result = add_three_times_four(5i);
+ let result = add_three_times_four(5);
- assert_eq!(32i, result);
+ assert_eq!(32, result);
}
#[test]
fn test_add_three() {
- let result = add_three(5i);
+ let result = add_three(5);
- assert_eq!(8i, result);
+ assert_eq!(8, result);
}
```
unit test. Open up your `src/lib.rs` and add this:
```{rust,ignore}
-pub fn add_three_times_four(x: int) -> int {
+pub fn add_three_times_four(x: i32) -> i32 {
times_four(add_three(x))
}
-fn add_three(x: int) -> int { x + 3 }
+fn add_three(x: i32) -> i32 { x + 3 }
-fn times_four(x: int) -> int { x * 4 }
+fn times_four(x: i32) -> i32 { x * 4 }
#[cfg(test)]
mod test {
#[test]
fn test_add_three() {
- let result = add_three(5i);
+ let result = add_three(5);
- assert_eq!(8i, result);
+ assert_eq!(8, result);
}
#[test]
fn test_times_four() {
- let result = times_four(5i);
+ let result = times_four(5);
- assert_eq!(20i, result);
+ assert_eq!(20, result);
}
}
```
reference:
```{rust}
-let x = 5i;
+let x = 5;
let y = &x;
```
rather than the reference itself) `y`, we use the asterisk (`*`):
```{rust}
-let x = 5i;
+let x = 5;
let y = &x;
-assert_eq!(5i, *y);
+assert_eq!(5, *y);
```
Like any `let` binding, references are immutable by default.
You can declare that functions take a reference:
```{rust}
-fn add_one(x: &int) -> int { *x + 1 }
+fn add_one(x: &i32) -> i32 { *x + 1 }
fn main() {
assert_eq!(6, add_one(&5));
**alias** (point to the same place):
```{rust}
-let x = 5i;
+let x = 5;
let y = &x;
let z = &x;
```
We can make a mutable reference by using `&mut` instead of `&`:
```{rust}
-let mut x = 5i;
+let mut x = 5;
let y = &mut x;
```
Note that `x` must also be mutable. If it isn't, like this:
```{rust,ignore}
-let x = 5i;
+let x = 5;
let y = &mut x;
```
This won't work:
```{rust,ignore}
-let mut x = 5i;
+let mut x = 5;
let y = &mut x;
let z = &mut x;
```
^
note: previous borrow ends here
fn main() {
- let mut x = 5i;
+ let mut x = 5;
let y = &mut x;
let z = &mut x;
}
```{rust}
{
- let x = 5i; // x is the owner of this integer, which is memory on the stack.
+ let x = 5; // x is the owner of this integer, which is memory on the stack.
// other code here...
/// this function borrows an integer. It's given back automatically when the
/// function returns.
-fn foo(x: &int) -> &int { x }
+fn foo(x: &i32) -> &i32 { x }
{
// x is the owner of the integer, which is memory on the stack.
- let x = 5i;
+ let x = 5;
// privilege 2: you may lend that resource to as many borrowers as you like
let y = &x;
{
// x is the owner of this integer, which is memory on the stack.
- let mut x = 5i;
+ let mut x = 5;
// privilege 3: you may lend that resource to a single borrower, mutably
let y = &mut x;
The code:
```{rust,ignore}
-let mut x = 5i;
+let mut x = 5;
let y = &mut x;
let z = &mut x;
```
^
note: previous borrow ends here
fn main() {
- let mut x = 5i;
+ let mut x = 5;
let y = &mut x;
let z = &mut x;
}
```text
note: previous borrow ends here
fn main() {
- let mut x = 5i;
+ let mut x = 5;
let y = &mut x;
let z = &mut x;
}
```{rust}
{
- let x = box 5i;
+ let x = box 5;
println!("{}", *x); // Prints 5
}
```
```{c,ignore}
{
- int *x = (int *)malloc(sizeof(int));
+ i32 *x = (i32 *)malloc(sizeof(i32));
if (!x) abort();
*x = 5;
printf("%d\n", *x);
reference to them and then use the original box:
```{rust,ignore}
-let mut x = box 5i;
+let mut x = box 5;
let y = &mut x;
*x; // you might expect 5, but this is actually an error
done borrowing the value, we can use it again. This works fine:
```{rust}
-let mut x = box 5i;
+let mut x = box 5;
{
let y = &mut x;
```{rust}
use std::rc::Rc;
-let x = Rc::new(5i);
+let x = Rc::new(5);
let y = x.clone();
println!("{} {}", *x, *y); // Prints 5 5
'any' case:
```{rust}
-let x = 1i;
+let x = 1;
match x {
1 => println!("one"),
You can match multiple patterns with `|`:
```{rust}
-let x = 1i;
+let x = 1;
match x {
1 | 2 => println!("one or two"),
You can match a range of values with `...`:
```{rust}
-let x = 1i;
+let x = 1;
match x {
1 ... 5 => println!("one through five"),
the value to a name with `@`:
```{rust}
-let x = 1i;
+let x = 1;
match x {
e @ 1 ... 5 => println!("got a range element {}", e),
```{rust}
enum OptionalInt {
- Value(int),
+ Value(i32),
Missing,
}
-let x = OptionalInt::Value(5i);
+let x = OptionalInt::Value(5);
match x {
- OptionalInt::Value(..) => println!("Got an int!"),
+ OptionalInt::Value(..) => println!("Got an i32!"),
OptionalInt::Missing => println!("No such luck."),
}
```
```{rust}
enum OptionalInt {
- Value(int),
+ Value(i32),
Missing,
}
-let x = OptionalInt::Value(5i);
+let x = OptionalInt::Value(5);
match x {
- OptionalInt::Value(i) if i > 5 => println!("Got an int bigger than five!"),
- OptionalInt::Value(..) => println!("Got an int!"),
+ OptionalInt::Value(i) if i > 5 => println!("Got an i32 bigger than five!"),
+ OptionalInt::Value(..) => println!("Got an i32!"),
OptionalInt::Missing => println!("No such luck."),
}
```
with. First, `&`:
```{rust}
-let x = &5i;
+let x = &5;
match x {
&val => println!("Got a value: {}", val),
}
```
-Here, the `val` inside the `match` has type `int`. In other words, the left-hand
-side of the pattern destructures the value. If we have `&5i`, then in `&val`, `val`
-would be `5i`.
+Here, the `val` inside the `match` has type `i32`. In other words, the left-hand
+side of the pattern destructures the value. If we have `&5`, then in `&val`, `val`
+would be `5`.
If you want to get a reference, use the `ref` keyword:
```{rust}
-let x = 5i;
+let x = 5;
match x {
ref r => println!("Got a reference to {}", r),
}
```
-Here, the `r` inside the `match` has the type `&int`. In other words, the `ref`
+Here, the `r` inside the `match` has the type `&i32`. In other words, the `ref`
keyword _creates_ a reference, for use in the pattern. If you need a mutable
reference, `ref mut` will work in the same way:
```{rust}
-let mut x = 5i;
+let mut x = 5;
match x {
ref mut mr => println!("Got a mutable reference to {}", mr),
```{rust}
# #![allow(non_shorthand_field_patterns)]
struct Point {
- x: int,
- y: int,
+ x: i32,
+ y: i32,
}
-let origin = Point { x: 0i, y: 0i };
+let origin = Point { x: 0, y: 0 };
match origin {
Point { x: x, y: y } => println!("({},{})", x, y),
```{rust}
# #![allow(non_shorthand_field_patterns)]
struct Point {
- x: int,
- y: int,
+ x: i32,
+ y: i32,
}
-let origin = Point { x: 0i, y: 0i };
+let origin = Point { x: 0, y: 0 };
match origin {
Point { x: x, .. } => println!("x is {}", x),
```{rust}
# #![allow(non_shorthand_field_patterns)]
struct Point {
- x: int,
- y: int,
+ x: i32,
+ y: i32,
}
-let origin = Point { x: 0i, y: 0i };
+let origin = Point { x: 0, y: 0 };
match origin {
Point { y: y, .. } => println!("y is {}", y),
Let's make a closure:
```{rust}
-let add_one = |x| { 1i + x };
+let add_one = |&: x| { 1 + x };
-println!("The sum of 5 plus 1 is {}.", add_one(5i));
+println!("The sum of 5 plus 1 is {}.", add_one(5));
```
We create a closure using the `|...| { ... }` syntax, and then we create a
Let's compare syntax. The two are pretty close:
```{rust}
-let add_one = |x: int| -> int { 1i + x };
-fn add_one (x: int) -> int { 1i + x }
+let add_one = |&: x: i32| -> i32 { 1 + x };
+fn add_one (x: i32) -> i32 { 1 + x }
```
As you may have noticed, closures infer their argument and return types, so you
```{rust}
fn main() {
- let x = 5i;
+ let x: i32 = 5;
- let printer = || { println!("x is: {}", x); };
+ let printer = |&:| { println!("x is: {}", x); };
printer(); // prints "x is: 5"
}
```{rust,ignore}
fn main() {
- let mut x = 5i;
+ let mut x = 5;
- let printer = || { println!("x is: {}", x); };
+ let printer = |&:| { println!("x is: {}", x); };
- x = 6i; // error: cannot assign to `x` because it is borrowed
+ x = 6; // error: cannot assign to `x` because it is borrowed
}
```
Closures are most useful as an argument to another function. Here's an example:
```{rust}
-fn twice(x: int, f: |int| -> int) -> int {
+fn twice<F: Fn(i32) -> i32>(x: i32, f: F) -> i32 {
f(x) + f(x)
}
fn main() {
- let square = |x: int| { x * x };
+ let square = |&: x: i32| { x * x };
- twice(5i, square); // evaluates to 50
+ twice(5, square); // evaluates to 50
}
```
Let's break the example down, starting with `main`:
```{rust}
-let square = |x: int| { x * x };
+let square = |&: x: i32| { x * x };
```
We've seen this before. We make a closure that takes an integer, and returns
its square.
```{rust}
-# fn twice(x: int, f: |int| -> int) -> int { f(x) + f(x) }
-# let square = |x: int| { x * x };
-twice(5i, square); // evaluates to 50
+# fn twice<F: Fn(i32) -> i32>(x: i32, f: F) -> i32 { f(x) + f(x) }
+# let square = |&: x: i32| { x * x };
+twice(5, square); // evaluates to 50
```
This line is more interesting. Here, we call our function, `twice`, and we pass
it two arguments: an integer, `5`, and our closure, `square`. This is just like
passing any other two variable bindings to a function, but if you've never
worked with closures before, it can seem a little complex. Just think: "I'm
-passing two variables: one is an int, and one is a function."
+passing two variables: one is an i32, and one is a function."
Next, let's look at how `twice` is defined:
```{rust,ignore}
-fn twice(x: int, f: |int| -> int) -> int {
+fn twice(x: i32, f: |i32| -> i32) -> i32 {
```
`twice` takes two arguments, `x` and `f`. That's why we called it with two
-arguments. `x` is an `int`, we've done that a ton of times. `f` is a function,
-though, and that function takes an `int` and returns an `int`. Notice
-how the `|int| -> int` syntax looks a lot like our definition of `square`
+arguments. `x` is an `i32`, we've done that a ton of times. `f` is a function,
+though, and that function takes an `i32` and returns an `i32`. Notice
+how the `|i32| -> i32` syntax looks a lot like our definition of `square`
above, if we added the return type in:
```{rust}
-let square = |x: int| -> int { x * x };
-// |int| -> int
+let square = |&: x: i32| -> i32 { x * x };
+// |i32| -> i32
```
-This function takes an `int` and returns an `int`.
+This function takes an `i32` and returns an `i32`.
This is the most complicated function signature we've seen yet! Give it a read
a few times until you can see how it works. It takes a teeny bit of practice, and
then it's easy.
-Finally, `twice` returns an `int` as well.
+Finally, `twice` returns an `i32` as well.
Okay, let's look at the body of `twice`:
```{rust}
-fn twice(x: int, f: |int| -> int) -> int {
+fn twice<F: Fn(i32) -> i32>(x: i32, f: F) -> i32 {
f(x) + f(x)
}
```
This example is the same as the previous one:
```{rust}
-fn twice(x: int, f: |int| -> int) -> int {
+fn twice<F: Fn(i32) -> i32>(x: i32, f: F) -> i32 {
f(x) + f(x)
}
fn main() {
- twice(5i, |x: int| { x * x }); // evaluates to 50
+ twice(5, |x: i32| { x * x }); // evaluates to 50
}
```
way of writing the previous example:
```{rust}
-fn twice(x: int, f: |int| -> int) -> int {
+fn twice<F: Fn(i32) -> i32>(x: i32, f: F) -> i32 {
f(x) + f(x)
}
-fn square(x: int) -> int { x * x }
+fn square(x: i32) -> i32 { x * x }
fn main() {
- twice(5i, square); // evaluates to 50
+ twice(5, square); // evaluates to 50
}
```
Remember Rust's `for` loop? Here's an example:
```{rust}
-for x in range(0i, 10i) {
+for x in range(0, 10) {
println!("{}", x);
}
```
Like this:
```{rust}
-let mut range = range(0i, 10i);
+let mut range = range(0, 10);
loop {
match range.next() {
We make a mutable binding to the return value of `range`, which is our iterator.
We then `loop`, with an inner `match`. This `match` is used on the result of
`range.next()`, which gives us a reference to the next value of the iterator.
-`next` returns an `Option<int>`, in this case, which will be `Some(int)` when
-we have a value and `None` once we run out. If we get `Some(int)`, we print it
+`next` returns an `Option<i32>`, in this case, which will be `Some(i32)` when
+we have a value and `None` once we run out. If we get `Some(i32)`, we print it
out, and if we get `None`, we `break` out of the loop.
This code sample is basically the same as our `for` loop version. The `for`
a vector, you may be tempted to write this:
```{rust}
-let nums = vec![1i, 2i, 3i];
+let nums = vec![1, 2, 3];
for i in range(0u, nums.len()) {
println!("{}", nums[i]);
of the vector in turn. So write this:
```{rust}
-let nums = vec![1i, 2i, 3i];
+let nums = vec![1, 2, 3];
for num in nums.iter() {
println!("{}", num);
know that we're safe.
There's another detail here that's not 100% clear because of how `println!`
-works. `num` is actually of type `&int`. That is, it's a reference to an `int`,
-not an `int` itself. `println!` handles the dereferencing for us, so we don't
+works. `num` is actually of type `&i32`. That is, it's a reference to an `i32`,
+not an `i32` itself. `println!` handles the dereferencing for us, so we don't
see it. This code works fine too:
```{rust}
-let nums = vec![1i, 2i, 3i];
+let nums = vec![1, 2, 3];
for num in nums.iter() {
println!("{}", *num);
but it shows the intention:
```{rust,ignore}
-let one_to_one_hundred = range(1i, 101i).collect();
+let one_to_one_hundred = range(1, 101).collect();
```
As you can see, we call `collect()` on our iterator. `collect()` takes
Here's the version that does compile:
```{rust}
-let one_to_one_hundred = range(1i, 101i).collect::<Vec<int>>();
+let one_to_one_hundred = range(1, 101).collect::<Vec<i32>>();
```
If you remember, the `::<>` syntax allows us to give a type hint,
is one:
```{rust}
-let greater_than_forty_two = range(0i, 100i)
+let greater_than_forty_two = range(0, 100)
.find(|x| *x > 42);
match greater_than_forty_two {
Another important consumer is `fold`. Here's what it looks like:
```{rust}
-let sum = range(1i, 4i)
- .fold(0i, |sum, x| sum + x);
+let sum = range(1, 4)
+ .fold(0, |sum, x| sum + x);
```
`fold()` is a consumer that looks like this:
| base | accumulator | element | closure result |
|------|-------------|---------|----------------|
-| 0i | 0i | 1i | 1i |
-| 0i | 1i | 2i | 3i |
-| 0i | 3i | 3i | 6i |
+| 0 | 0 | 1 | 1 |
+| 0 | 1 | 2 | 3 |
+| 0 | 3 | 3 | 6 |
We called `fold()` with these arguments:
```{rust}
-# range(1i, 4i)
-.fold(0i, |sum, x| sum + x);
+# range(1, 4)
+.fold(0, |sum, x| sum + x);
```
-So, `0i` is our base, `sum` is our accumulator, and `x` is our element. On the
-first iteration, we set `sum` to `0i`, and `x` is the first element of `nums`,
-`1i`. We then add `sum` and `x`, which gives us `0i + 1i = 1i`. On the second
+So, `0` is our base, `sum` is our accumulator, and `x` is our element. On the
+first iteration, we set `sum` to `0`, and `x` is the first element of `nums`,
+`1`. We then add `sum` and `x`, which gives us `0 + 1 = 1`. On the second
iteration, that value becomes our accumulator, `sum`, and the element is
-the second element of the array, `2i`. `1i + 2i = 3i`, and so that becomes
+the second element of the array, `2`. `1 + 2 = 3`, and so that becomes
the value of the accumulator for the last iteration. On that iteration,
-`x` is the last element, `3i`, and `3i + 3i = 6i`, which is our final
+`x` is the last element, `3`, and `3 + 3 = 6`, which is our final
result for our sum. `1 + 2 + 3 = 6`, and that's the result we got.
Whew. `fold` can be a bit strange the first few times you see it, but once it
`1-100`, and just creates a value that represents the sequence:
```{rust}
-let nums = range(1i, 100i);
+let nums = range(1, 100);
```
Since we didn't do anything with the range, it didn't generate the sequence.
Let's add the consumer:
```{rust}
-let nums = range(1i, 100i).collect::<Vec<int>>();
+let nums = range(1, 100).collect::<Vec<i32>>();
```
Now, `collect()` will require that `range()` give it some numbers, and so
that gives you each element in turn:
```{rust}
-let nums = [1i, 2i, 3i];
+let nums = [1, 2, 3];
for num in nums.iter() {
println!("{}", num);
advanced iterators, including ones that are infinite. Like `count`:
```{rust}
-std::iter::count(1i, 5i);
+std::iter::count(1, 5);
```
This iterator counts up from one, adding five each time. It will give
you a new integer every time, forever (well, technically, until it reaches the
-maximum number representable by an `int`). But since iterators are lazy,
+maximum number representable by an `i32`). But since iterators are lazy,
that's okay! You probably don't want to use `collect()` on it, though...
That's enough about iterators. Iterator adapters are the last concept
a new iterator. The simplest one is called `map`:
```{rust,ignore}
-range(1i, 100i).map(|x| x + 1i);
+range(1, 100).map(|x| x + 1);
```
`map` is called upon another iterator, and produces a new iterator where each
```text
warning: unused result which must be used: iterator adaptors are lazy and
do nothing unless consumed, #[warn(unused_must_use)] on by default
- range(1i, 100i).map(|x| x + 1i);
+ range(1, 100).map(|x| x + 1);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
```
doesn't print any numbers:
```{rust,ignore}
-range(1i, 100i).map(|x| println!("{}", x));
+range(1, 100).map(|x| println!("{}", x));
```
If you are trying to execute a closure on an iterator for its side effects,
iterator from before, `count()`:
```{rust}
-for i in std::iter::count(1i, 5i).take(5) {
+for i in std::iter::count(1, 5).take(5) {
println!("{}", i);
}
```
only the elements that that closure returns `true` for:
```{rust}
-for i in range(1i, 100i).filter(|&x| x % 2 == 0) {
+for i in range(1, 100).filter(|&x| x % 2 == 0) {
println!("{}", i);
}
```
a few times, and then consume the result. Check it out:
```{rust}
-range(1i, 1000i)
+range(1, 1000)
.filter(|&x| x % 2 == 0)
.filter(|&x| x % 3 == 0)
.take(5)
- .collect::<Vec<int>>();
+ .collect::<Vec<i32>>();
```
This will give you a vector containing `6`, `12`, `18`, `24`, and `30`.
```{rust}
enum OptionalInt {
- Value(int),
+ Value(i32),
Missing,
}
```
generic data type. `T` is called a **type parameter**. When we create instances
of `Option`, we need to provide a concrete type in place of the type
parameter. For example, if we wanted something like our `OptionalInt`, we would
-need to instantiate an `Option<int>`. Inside the declaration of our enum,
+need to instantiate an `Option<i32>`. Inside the declaration of our enum,
wherever we see a `T`, we replace it with the type specified (or inferred by the
the compiler).
```{rust}
-let x: Option<int> = Some(5i);
+let x: Option<i32> = Some(5);
```
-In this particular `Option`, `T` has the value of `int`. On the right-hand side
-of the binding, we do make a `Some(T)`, where `T` is `5i`. Since that's an
-`int`, the two sides match, and Rust is happy. If they didn't match, we'd get an
+In this particular `Option`, `T` has the value of `i32`. On the right-hand side
+of the binding, we do make a `Some(T)`, where `T` is `5`. Since that's an
+`i32`, the two sides match, and Rust is happy. If they didn't match, we'd get an
error:
```{rust,ignore}
-let x: Option<f64> = Some(5i);
+let x: Option<f64> = Some(5);
// error: mismatched types: expected `core::option::Option<f64>`,
-// found `core::option::Option<int>` (expected f64, found int)
+// found `core::option::Option<i32>` (expected f64, found i32)
```
That doesn't mean we can't make `Option<T>`s that hold an `f64`! They just have to
match up:
```{rust}
-let x: Option<int> = Some(5i);
+let x: Option<i32> = Some(5);
let y: Option<f64> = Some(5.0f64);
```
have passed in the correct types. If we pass in an incorrect type:
```{rust,ignore}
-print_area(5i);
+print_area(5);
```
We get a compile-time error:
```text
-error: failed to find an implementation of trait main::HasArea for int
+error: failed to find an implementation of trait main::HasArea for i32
```
So far, we've only added trait implementations to structs, but you can
implement a trait for any type. So technically, we _could_ implement
-`HasArea` for `int`:
+`HasArea` for `i32`:
```{rust}
trait HasArea {
fn area(&self) -> f64;
}
-impl HasArea for int {
+impl HasArea for i32 {
fn area(&self) -> f64 {
println!("this is silly");
}
}
-5i.area();
+5.area();
```
It is considered poor style to implement methods on such primitive types, even
```
Requiring us to `use` traits whose methods we want means that even if someone
-does something bad like add methods to `int`, it won't affect us, unless you
+does something bad like add methods to `i32`, it won't affect us, unless you
`use` that trait.
The second condition allows us to `impl` built-in `trait`s for types we define,
from mixing and matching third party or built-in `impl`s with third party or
built-in types.
-We could `impl` the `HasArea` trait for `int`, because `HasArea` is in our
+We could `impl` the `HasArea` trait for `i32`, because `HasArea` is in our
crate. But if we tried to implement `Float`, a standard library `trait`, for
-`int`, we could not, because neither the `trait` nor the `type` are in our
+`i32`, we could not, because neither the `trait` nor the `type` are in our
crate.
## Monomorphization
parent thread after the child thread is spawned:
```{rust,ignore}
-let mut x = vec![1i, 2i, 3i];
+let mut x = vec![1, 2, 3];
spawn(move || {
println!("The value of x[0] is: {}", x[0]);
let mut delayed_value = Future::spawn(move || {
// just return anything for examples' sake
- 12345i
+ 12345
});
println!("value = {}", delayed_value.get());
```
is write code that generates more code. So when we call `println!` like this:
```{rust}
-let x = 5i;
+let x = 5;
println!("x is: {}", x);
```
```{rust}
fn main() {
- let x = 5i;
+ let x = 5;
println!("x is: {}", x);
}
```
#[prelude_import]
use std::prelude::*;
fn main() {
- let x = 5i;
+ let x = 5;
match (&x,) {
(__arg0,) => {
#[inline]
}
```
-Whew! This isn't too terrible. You can see that we still `let x = 5i`,
+Whew! This isn't too terrible. You can see that we still `let x = 5`,
but then things get a little bit hairy. Three more bindings get set: a
static format string, an argument vector, and the arguments. We then
invoke the `println_args` function with the generated arguments.
* [Strings](guide-strings.html)
* [Pointers](guide-pointers.html)
* [Crates and modules](guide-crates.html)
-* [Threads and Communication](guide-threads.html)
+* [Threads and Communication](guide-tasks.html)
* [Error Handling](guide-error-handling.html)
* [Foreign Function Interface](guide-ffi.html)
* [Writing Unsafe and Low-Level Code](guide-unsafe.html)
caller. Every control path in a diverging function must end with a `panic!()` or
a call to another diverging function on every control path. The `!` annotation
does *not* denote a type. Rather, the result type of a diverging function is a
-special type called $\bot$ ("bottom") that unifies with any type. Rust has no
-syntax for $\bot$.
+special type called ⊥ ("bottom") that unifies with any type. Rust has no
+syntax for ⊥.
It might be necessary to declare a diverging function because as mentioned
previously, the typechecker checks that every control path in a function ends
trait Seq<T> {
fn len(&self) -> uint;
fn elt_at(&self, n: uint) -> T;
- fn iter(&self, |T|);
+ fn iter<F>(&self, F) where F: Fn(T);
}
```
function argument, and call it with a lambda expression as an argument.
```
-fn ten_times(f: |int|) {
+fn ten_times<F>(f: F) where F: Fn(int) {
let mut i = 0;
while i < 10 {
f(i);
let mut x = add(5,7);
-type Binop<'a> = |int,int|: 'a -> int;
+type Binop = fn(int, int) -> int;
let bo: Binop = add;
x = bo(5,7);
```
```rust
let captured_var = 10i;
-let closure_no_args = || println!("captured_var={}", captured_var);
+let closure_no_args = |&:| println!("captured_var={}", captured_var);
-let closure_args = |arg: int| -> int {
+let closure_args = |&: arg: int| -> int {
println!("captured_var={}, arg={}", captured_var, arg);
arg // Note lack of semicolon after 'arg'
};
-fn call_closure(c1: ||, c2: |int| -> int) {
+fn call_closure<F: Fn(), G: Fn(int) -> int>(c1: F, c2: G) {
c1();
c2(2);
}
*TODO*.
-# Appendix: Influences and further references
-
-## Influences
-
-> The essential problem that must be solved in making a fault-tolerant
-> software system is therefore that of fault-isolation. Different programmers
-> will write different modules, some modules will be correct, others will have
-> errors. We do not want the errors in one module to adversely affect the
-> behaviour of a module which does not have any errors.
->
-> — Joe Armstrong
-
-> In our approach, all data is private to some process, and processes can
-> only communicate through communications channels. *Security*, as used
-> in this paper, is the property which guarantees that processes in a system
-> cannot affect each other except by explicit communication.
->
-> When security is absent, nothing which can be proven about a single module
-> in isolation can be guaranteed to hold when that module is embedded in a
-> system [...]
->
-> — Robert Strom and Shaula Yemini
-
-> Concurrent and applicative programming complement each other. The
-> ability to send messages on channels provides I/O without side effects,
-> while the avoidance of shared data helps keep concurrent processes from
-> colliding.
->
-> — Rob Pike
-
-Rust is not a particularly original language. It may however appear unusual by
-contemporary standards, as its design elements are drawn from a number of
-"historical" languages that have, with a few exceptions, fallen out of favour.
-Five prominent lineages contribute the most, though their influences have come
-and gone during the course of Rust's development:
-
-* The NIL (1981) and Hermes (1990) family. These languages were developed by
- Robert Strom, Shaula Yemini, David Bacon and others in their group at IBM
- Watson Research Center (Yorktown Heights, NY, USA).
-
-* The Erlang (1987) language, developed by Joe Armstrong, Robert Virding, Claes
- Wikström, Mike Williams and others in their group at the Ericsson Computer
- Science Laboratory (Älvsjö, Stockholm, Sweden) .
-
-* The Sather (1990) language, developed by Stephen Omohundro, Chu-Cheow Lim,
- Heinz Schmidt and others in their group at The International Computer
- Science Institute of the University of California, Berkeley (Berkeley, CA,
- USA).
-
-* The Newsqueak (1988), Alef (1995), and Limbo (1996) family. These
- languages were developed by Rob Pike, Phil Winterbottom, Sean Dorward and
- others in their group at Bell Labs Computing Sciences Research Center
- (Murray Hill, NJ, USA).
-
-* The Napier (1985) and Napier88 (1988) family. These languages were
- developed by Malcolm Atkinson, Ron Morrison and others in their group at
- the University of St. Andrews (St. Andrews, Fife, UK).
-
-Additional specific influences can be seen from the following languages:
-
-* The structural algebraic types and compilation manager of SML.
-* The attribute and assembly systems of C#.
-* The references and deterministic destructor system of C++.
-* The memory region systems of the ML Kit and Cyclone.
-* The typeclass system of Haskell.
-* The lexical identifier rule of Python.
-* The block syntax of Ruby.
+# Appendix: Influences
+
+Rust is not a particularly original language, with design elements coming from
+a wide range of sources. Some of these are listed below (including elements
+that have since been removed):
+
+* SML, OCaml: algebraic datatypes, pattern matching, type inference,
+ semicolon statement separation
+* C++: references, RAII, smart pointers, move semantics, monomorphisation,
+ memory model
+* ML Kit, Cyclone: region based memory management
+* Haskell (GHC): typeclasses, type families
+* Newsqueak, Alef, Limbo: channels, concurrency
+* Erlang: message passing, task failure, ~~linked task failure~~,
+ ~~lightweight concurrency~~
+* Swift: optional bindings
+* Scheme: hygienic macros
+* C#: attributes
+* Ruby: ~~block syntax~~
+* NIL, Hermes: ~~typestate~~
+* [Unicode Annex #31](http://www.unicode.org/reports/tr31/): identifier and
+ pattern syntax
[ffi]: guide-ffi.html
[plugin]: guide-plugin.html
--- /dev/null
+\usepackage{newunicodechar}
+\newunicodechar⊥{{$\bot$}}
}
create_tmp_dir() {
- local TMP_DIR=./rustup-tmp-install
+ local TMP_DIR=`pwd`/rustup-tmp-install
rm -Rf "${TMP_DIR}"
need_ok "failed to remove temporary installation directory"
probe_need CFG_TAR tar
probe_need CFG_FILE file
+probe CFG_SHA256SUM sha256sum
+probe CFG_SHASUM shasum
+
+if [ -z "$CFG_SHA256SUM" -a -z "$CFG_SHASUM" ]; then
+ err "unable to find either sha256sum or shasum"
+fi
+
+calculate_hash() {
+ if [ -n "$CFG_SHA256SUM" ]; then
+ ${CFG_SHA256SUM} $@
+ else
+ ${CFG_SHASUM} -a 256 $@
+ fi
+}
+
CFG_SRC_DIR="$(cd $(dirname $0) && pwd)/"
CFG_SELF="$0"
CFG_ARGS="$@"
flag uninstall "only uninstall from the installation prefix"
valopt prefix "" "set installation prefix"
-opt cargo 1 "install cargo with rust"
+valopt date "" "use the YYYY-MM-DD nightly instead of the current nightly"
+flag save "save the downloaded nightlies to ~/.rustup"
if [ $HELP -eq 1 ]
then
|| mktemp -d -t 'rustup-tmp-install' 2>/dev/null \
|| create_tmp_dir)
+# If we're saving nightlies and we didn't specify which one, grab todays.
+# Otherwise we'll use the latest version.
+if [ -n "${CFG_SAVE}" -a -z "${CFG_DATE}" ];
+then
+ CFG_DATE=`date "+%Y-%m-%d"`
+fi
+
RUST_URL="https://static.rust-lang.org/dist"
RUST_PACKAGE_NAME=rust-nightly
RUST_PACKAGE_NAME_AND_TRIPLE="${RUST_PACKAGE_NAME}-${HOST_TRIPLE}"
RUST_LOCAL_INSTALL_DIR="${CFG_TMP_DIR}/${RUST_PACKAGE_NAME_AND_TRIPLE}"
RUST_LOCAL_INSTALL_SCRIPT="${RUST_LOCAL_INSTALL_DIR}/install.sh"
-CARGO_URL="https://static.rust-lang.org/cargo-dist"
-CARGO_PACKAGE_NAME=cargo-nightly
-CARGO_PACKAGE_NAME_AND_TRIPLE="${CARGO_PACKAGE_NAME}-${HOST_TRIPLE}"
-CARGO_TARBALL_NAME="${CARGO_PACKAGE_NAME_AND_TRIPLE}.tar.gz"
-CARGO_LOCAL_INSTALL_DIR="${CFG_TMP_DIR}/${CARGO_PACKAGE_NAME_AND_TRIPLE}"
-CARGO_LOCAL_INSTALL_SCRIPT="${CARGO_LOCAL_INSTALL_DIR}/install.sh"
+# add a date suffix if we want a particular nighly.
+if [ -n "${CFG_DATE}" ];
+then
+ RUST_URL="${RUST_URL}/${CFG_DATE}"
+fi
+
+verify_hash() {
+ remote_sha256="$1"
+ local_file="$2"
+
+ msg "Downloading ${remote_sha256}"
+ remote_sha256=`"${CFG_CURL}" -f "${remote_sha256}"`
+ if [ "$?" -ne 0 ]; then
+ rm -Rf "${CFG_TMP_DIR}"
+ err "Failed to download ${remote_url}"
+ fi
+
+ msg "Verifying hash"
+ local_sha256=$(calculate_hash "${local_file}")
+ if [ "$?" -ne 0 ]; then
+ rm -Rf "${CFG_TMP_DIR}"
+ err "Failed to compute hash for ${local_tarball}"
+ fi
+
+ # We only need the sha, not the filenames
+ remote_sha256=`echo ${remote_sha256} | cut -f 1 -d ' '`
+ local_sha256=`echo ${local_sha256} | cut -f 1 -d ' '`
+
+ if [ "${remote_sha256}" != "${local_sha256}" ]; then
+ rm -Rf "${CFG_TMP_DIR}"
+ errmsg="invalid sha256.\n"
+ errmsg="$errmsg ${remote_sha256}\t${remote_tarball}\n"
+ errmsg="$errmsg ${local_sha256}\t${local_tarball}"
+ err "$errmsg"
+ fi
+}
-# Fetch the package.
+# Fetch the package. Optionally caches the tarballs.
download_package() {
remote_tarball="$1"
local_tarball="$2"
+ remote_sha256="${remote_tarball}.sha256"
- msg "Downloading ${remote_tarball} to ${local_tarball}"
+ # Check if we've already downloaded this file.
+ if [ -e "${local_tarball}.tmp" ]; then
+ msg "Resuming ${remote_tarball} to ${local_tarball}"
- "${CFG_CURL}" -f -o "${local_tarball}" "${remote_tarball}"
- if [ $? -ne 0 ]
- then
- rm -Rf "${CFG_TMP_DIR}"
- err "failed to download installer"
+ "${CFG_CURL}" -f -C - -o "${local_tarball}.tmp" "${remote_tarball}"
+ if [ $? -ne 0 ]
+ then
+ rm -Rf "${CFG_TMP_DIR}"
+ err "failed to download installer"
+ fi
+
+ mv "${local_tarball}.tmp" "${local_tarball}"
+ elif [ ! -e "${local_tarball}" ]; then
+ msg "Downloading ${remote_tarball} to ${local_tarball}"
+
+ "${CFG_CURL}" -f -o "${local_tarball}.tmp" "${remote_tarball}"
+ if [ $? -ne 0 ]
+ then
+ rm -Rf "${CFG_TMP_DIR}"
+ err "failed to download installer"
+ fi
+
+ mv "${local_tarball}.tmp" "${local_tarball}"
fi
+
+ verify_hash "${remote_sha256}" "${local_tarball}"
}
# Wrap all the commands needed to install a package.
install_package() {
- tarball_name="$1"
+ local_tarball="$1"
install_script="$2"
- msg "Extracting ${tarball_name}"
- (cd "${CFG_TMP_DIR}" && "${CFG_TAR}" -xzf "${tarball_name}")
+ msg "Extracting ${local_tarball}"
+ (cd "${CFG_TMP_DIR}" && "${CFG_TAR}" -xzf "${local_tarball}")
if [ $? -ne 0 ]; then
rm -Rf "${CFG_TMP_DIR}"
err "failed to unpack installer"
mkdir -p "${CFG_TMP_DIR}"
need_ok "failed to create create temporary installation directory"
- RUST_LOCAL_TARBALL="${CFG_TMP_DIR}/${RUST_TARBALL_NAME}"
- CARGO_LOCAL_TARBALL="${CFG_TMP_DIR}/${CARGO_TARBALL_NAME}"
+ # If we're saving our nightlies, put them in $HOME/.rustup.
+ if [ -n "${CFG_SAVE}" ]
+ then
+ RUST_DOWNLOAD_DIR="${HOME}/.rustup/${CFG_DATE}"
+ else
+ RUST_DOWNLOAD_DIR="${CFG_TMP_DIR}"
+ fi
+
+ mkdir -p "${RUST_DOWNLOAD_DIR}"
+ need_ok "failed to create create download directory"
+
+ RUST_LOCAL_TARBALL="${RUST_DOWNLOAD_DIR}/${RUST_TARBALL_NAME}"
download_package \
"${RUST_URL}/${RUST_TARBALL_NAME}" \
"${RUST_LOCAL_TARBALL}"
- if [ -z "${CFG_DISABLE_CARGO}" ]; then
- download_package \
- "${CARGO_URL}/${CARGO_TARBALL_NAME}" \
- "${CARGO_LOCAL_TARBALL}"
- fi
-
install_package \
- "${RUST_TARBALL_NAME}" \
+ "${RUST_LOCAL_TARBALL}" \
"${RUST_LOCAL_INSTALL_SCRIPT}"
- if [ -z "${CFG_DISABLE_CARGO}" ]; then
- install_package \
- "${CARGO_TARBALL_NAME}" \
- "${CARGO_LOCAL_INSTALL_SCRIPT}"
- fi
-
rm -Rf "${CFG_TMP_DIR}"
need_ok "couldn't rm temporary installation directory"
}
syn region rustString start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=rustEscape,rustEscapeUnicode,rustEscapeError,rustStringContinuation,@Spell
syn region rustString start='b\?r\z(#*\)"' end='"\z1' contains=@Spell
-syn region rustAttribute start="#!\?\[" end="\]" contains=rustString,rustDeriving
-syn region rustDeriving start="deriving(" end=")" contained contains=rustTrait
+syn region rustAttribute start="#!\?\[" end="\]" contains=rustString,rustDerive
+syn region rustDerive start="derive(" end=")" contained contains=rustTrait
" Number literals
syn match rustDecNumber display "\<[0-9][0-9_]*\%([iu]\%(8\|16\|32\|64\)\=\)\="
hi def link rustType Type
hi def link rustTodo Todo
hi def link rustAttribute PreProc
-hi def link rustDeriving PreProc
+hi def link rustDerive PreProc
hi def link rustStorage StorageClass
hi def link rustObsoleteStorage Error
hi def link rustLifetime Special
" Other Suggestions:
" hi rustAttribute ctermfg=cyan
-" hi rustDeriving ctermfg=cyan
+" hi rustDerive ctermfg=cyan
" hi rustAssert ctermfg=yellow
" hi rustPanic ctermfg=red
" hi rustMacro ctermfg=magenta
//! use std::sync::Arc;
//! use std::thread::Thread;
//!
-//! let five = Arc::new(5i);
+//! let five = Arc::new(5);
//!
//! for i in range(0u, 10) {
//! let five = five.clone();
//! use std::sync::{Arc, Mutex};
//! use std::thread::Thread;
//!
-//! let five = Arc::new(Mutex::new(5i));
+//! let five = Arc::new(Mutex::new(5));
//!
//! for _ in range(0u, 10) {
//! let five = five.clone();
/// ```
/// use std::sync::Arc;
///
- /// let five = Arc::new(5i);
+ /// let five = Arc::new(5);
/// ```
#[inline]
#[stable]
/// ```
/// use std::sync::Arc;
///
- /// let five = Arc::new(5i);
+ /// let five = Arc::new(5);
///
/// let weak_five = five.downgrade();
/// ```
/// ```
/// use std::sync::Arc;
///
- /// let five = Arc::new(5i);
+ /// let five = Arc::new(5);
///
/// five.clone();
/// ```
/// ```
/// use std::sync::Arc;
///
- /// let mut five = Arc::new(5i);
+ /// let mut five = Arc::new(5);
///
/// let mut_five = five.make_unique();
/// ```
/// use std::sync::Arc;
///
/// {
- /// let five = Arc::new(5i);
+ /// let five = Arc::new(5);
///
/// // stuff
///
/// drop(five); // explict drop
/// }
/// {
- /// let five = Arc::new(5i);
+ /// let five = Arc::new(5);
///
/// // stuff
///
/// ```
/// use std::sync::Arc;
///
- /// let five = Arc::new(5i);
+ /// let five = Arc::new(5);
///
/// let weak_five = five.downgrade();
///
/// ```
/// use std::sync::Arc;
///
- /// let weak_five = Arc::new(5i).downgrade();
+ /// let weak_five = Arc::new(5).downgrade();
///
/// weak_five.clone();
/// ```
/// use std::sync::Arc;
///
/// {
- /// let five = Arc::new(5i);
+ /// let five = Arc::new(5);
/// let weak_five = five.downgrade();
///
/// // stuff
/// drop(weak_five); // explict drop
/// }
/// {
- /// let five = Arc::new(5i);
+ /// let five = Arc::new(5);
/// let weak_five = five.downgrade();
///
/// // stuff
/// ```
/// use std::sync::Arc;
///
- /// let five = Arc::new(5i);
+ /// let five = Arc::new(5);
///
- /// five == Arc::new(5i);
+ /// five == Arc::new(5);
/// ```
fn eq(&self, other: &Arc<T>) -> bool { *(*self) == *(*other) }
/// ```
/// use std::sync::Arc;
///
- /// let five = Arc::new(5i);
+ /// let five = Arc::new(5);
///
- /// five != Arc::new(5i);
+ /// five != Arc::new(5);
/// ```
fn ne(&self, other: &Arc<T>) -> bool { *(*self) != *(*other) }
}
/// ```
/// use std::sync::Arc;
///
- /// let five = Arc::new(5i);
+ /// let five = Arc::new(5);
///
- /// five.partial_cmp(&Arc::new(5i));
+ /// five.partial_cmp(&Arc::new(5));
/// ```
fn partial_cmp(&self, other: &Arc<T>) -> Option<Ordering> {
(**self).partial_cmp(&**other)
/// ```
/// use std::sync::Arc;
///
- /// let five = Arc::new(5i);
+ /// let five = Arc::new(5);
///
- /// five < Arc::new(5i);
+ /// five < Arc::new(5);
/// ```
fn lt(&self, other: &Arc<T>) -> bool { *(*self) < *(*other) }
/// ```
/// use std::sync::Arc;
///
- /// let five = Arc::new(5i);
+ /// let five = Arc::new(5);
///
- /// five <= Arc::new(5i);
+ /// five <= Arc::new(5);
/// ```
fn le(&self, other: &Arc<T>) -> bool { *(*self) <= *(*other) }
/// ```
/// use std::sync::Arc;
///
- /// let five = Arc::new(5i);
+ /// let five = Arc::new(5);
///
- /// five > Arc::new(5i);
+ /// five > Arc::new(5);
/// ```
fn gt(&self, other: &Arc<T>) -> bool { *(*self) > *(*other) }
/// ```
/// use std::sync::Arc;
///
- /// let five = Arc::new(5i);
+ /// let five = Arc::new(5);
///
- /// five >= Arc::new(5i);
+ /// five >= Arc::new(5);
/// ```
fn ge(&self, other: &Arc<T>) -> bool { *(*self) >= *(*other) }
}
#![stable]
-use core::any::{Any, AnyRefExt};
+use core::any::Any;
use core::clone::Clone;
use core::cmp::{PartialEq, PartialOrd, Eq, Ord, Ordering};
use core::default::Default;
/// ```
/// use std::rc::Rc;
///
- /// let five = Rc::new(5i);
+ /// let five = Rc::new(5);
/// ```
#[stable]
pub fn new(value: T) -> Rc<T> {
/// ```
/// use std::rc::Rc;
///
- /// let five = Rc::new(5i);
+ /// let five = Rc::new(5);
///
/// let weak_five = five.downgrade();
/// ```
/// use std::rc;
/// use std::rc::Rc;
///
-/// let five = Rc::new(5i);
+/// let five = Rc::new(5);
///
/// rc::is_unique(&five);
/// ```
/// ```
/// use std::rc::Rc;
///
- /// let mut five = Rc::new(5i);
+ /// let mut five = Rc::new(5);
///
/// let mut_five = five.make_unique();
/// ```
/// use std::rc::Rc;
///
/// {
- /// let five = Rc::new(5i);
+ /// let five = Rc::new(5);
///
/// // stuff
///
/// drop(five); // explict drop
/// }
/// {
- /// let five = Rc::new(5i);
+ /// let five = Rc::new(5);
///
/// // stuff
///
/// ```
/// use std::rc::Rc;
///
- /// let five = Rc::new(5i);
+ /// let five = Rc::new(5);
///
/// five.clone();
/// ```
/// ```
/// use std::rc::Rc;
///
- /// let five = Rc::new(5i);
+ /// let five = Rc::new(5);
///
- /// five == Rc::new(5i);
+ /// five == Rc::new(5);
/// ```
#[inline(always)]
fn eq(&self, other: &Rc<T>) -> bool { **self == **other }
/// ```
/// use std::rc::Rc;
///
- /// let five = Rc::new(5i);
+ /// let five = Rc::new(5);
///
- /// five != Rc::new(5i);
+ /// five != Rc::new(5);
/// ```
#[inline(always)]
fn ne(&self, other: &Rc<T>) -> bool { **self != **other }
/// ```
/// use std::rc::Rc;
///
- /// let five = Rc::new(5i);
+ /// let five = Rc::new(5);
///
- /// five.partial_cmp(&Rc::new(5i));
+ /// five.partial_cmp(&Rc::new(5));
/// ```
#[inline(always)]
fn partial_cmp(&self, other: &Rc<T>) -> Option<Ordering> {
/// ```
/// use std::rc::Rc;
///
- /// let five = Rc::new(5i);
+ /// let five = Rc::new(5);
///
- /// five < Rc::new(5i);
+ /// five < Rc::new(5);
/// ```
#[inline(always)]
fn lt(&self, other: &Rc<T>) -> bool { **self < **other }
/// ```
/// use std::rc::Rc;
///
- /// let five = Rc::new(5i);
+ /// let five = Rc::new(5);
///
- /// five <= Rc::new(5i);
+ /// five <= Rc::new(5);
/// ```
#[inline(always)]
fn le(&self, other: &Rc<T>) -> bool { **self <= **other }
/// ```
/// use std::rc::Rc;
///
- /// let five = Rc::new(5i);
+ /// let five = Rc::new(5);
///
- /// five > Rc::new(5i);
+ /// five > Rc::new(5);
/// ```
#[inline(always)]
fn gt(&self, other: &Rc<T>) -> bool { **self > **other }
/// ```
/// use std::rc::Rc;
///
- /// let five = Rc::new(5i);
+ /// let five = Rc::new(5);
///
- /// five >= Rc::new(5i);
+ /// five >= Rc::new(5);
/// ```
#[inline(always)]
fn ge(&self, other: &Rc<T>) -> bool { **self >= **other }
/// ```
/// use std::rc::Rc;
///
- /// let five = Rc::new(5i);
+ /// let five = Rc::new(5);
///
- /// five.partial_cmp(&Rc::new(5i));
+ /// five.partial_cmp(&Rc::new(5));
/// ```
#[inline]
fn cmp(&self, other: &Rc<T>) -> Ordering { (**self).cmp(&**other) }
/// ```
/// use std::rc::Rc;
///
- /// let five = Rc::new(5i);
+ /// let five = Rc::new(5);
///
/// let weak_five = five.downgrade();
///
/// use std::rc::Rc;
///
/// {
- /// let five = Rc::new(5i);
+ /// let five = Rc::new(5);
/// let weak_five = five.downgrade();
///
/// // stuff
/// drop(weak_five); // explict drop
/// }
/// {
- /// let five = Rc::new(5i);
+ /// let five = Rc::new(5);
/// let weak_five = five.downgrade();
///
/// // stuff
/// ```
/// use std::rc::Rc;
///
- /// let weak_five = Rc::new(5i).downgrade();
+ /// let weak_five = Rc::new(5).downgrade();
///
/// weak_five.clone();
/// ```
use prelude::*;
use std::rand;
use std::rand::Rng;
-use test::Bencher;
+use test::{Bencher, black_box};
pub fn insert_rand_n<M, I, R>(n: uint,
map: &mut M,
let k = rng.gen::<uint>() % n;
insert(map, k);
remove(map, k);
- })
+ });
+ black_box(map);
}
pub fn insert_seq_n<M, I, R>(n: uint,
insert(map, i);
remove(map, i);
i = (i + 2) % n;
- })
+ });
+ black_box(map);
}
pub fn find_rand_n<M, T, I, F>(n: uint,
b.iter(|| {
let t = find(map, keys[i]);
i = (i + 1) % n;
- t
+ black_box(t);
})
}
b.iter(|| {
let x = find(map, i);
i = (i + 1) % n;
- x
+ black_box(x);
})
}
///
/// ```
/// use std::collections::BinaryHeap;
- /// let heap = BinaryHeap::from_vec(vec![9i, 1, 2, 7, 3, 2]);
+ /// let heap = BinaryHeap::from_vec(vec![9, 1, 2, 7, 3, 2]);
/// ```
pub fn from_vec(vec: Vec<T>) -> BinaryHeap<T> {
let mut heap = BinaryHeap { data: vec };
///
/// ```
/// use std::collections::BinaryHeap;
- /// let heap = BinaryHeap::from_vec(vec![1i, 2, 3, 4]);
+ /// let heap = BinaryHeap::from_vec(vec![1, 2, 3, 4]);
///
/// // Print 1, 2, 3, 4 in arbitrary order
/// for x in heap.iter() {
///
/// ```
/// use std::collections::BinaryHeap;
- /// let heap = BinaryHeap::from_vec(vec![1i, 2, 3, 4]);
+ /// let heap = BinaryHeap::from_vec(vec![1, 2, 3, 4]);
///
/// // Print 1, 2, 3, 4 in arbitrary order
/// for x in heap.into_iter() {
/// let mut heap = BinaryHeap::new();
/// assert_eq!(heap.peek(), None);
///
- /// heap.push(1i);
+ /// heap.push(1);
/// heap.push(5);
/// heap.push(2);
/// assert_eq!(heap.peek(), Some(&5));
///
/// ```
/// use std::collections::BinaryHeap;
- /// let mut heap = BinaryHeap::from_vec(vec![1i, 3]);
+ /// let mut heap = BinaryHeap::from_vec(vec![1, 3]);
///
/// assert_eq!(heap.pop(), Some(3));
/// assert_eq!(heap.pop(), Some(1));
/// ```
/// use std::collections::BinaryHeap;
/// let mut heap = BinaryHeap::new();
- /// heap.push(3i);
+ /// heap.push(3);
/// heap.push(5);
/// heap.push(1);
///
/// ```
/// use std::collections::BinaryHeap;
/// let mut heap = BinaryHeap::new();
- /// heap.push(1i);
+ /// heap.push(1);
/// heap.push(5);
///
/// assert_eq!(heap.push_pop(3), 5);
/// use std::collections::BinaryHeap;
/// let mut heap = BinaryHeap::new();
///
- /// assert_eq!(heap.replace(1i), None);
+ /// assert_eq!(heap.replace(1), None);
/// assert_eq!(heap.replace(3), Some(1));
/// assert_eq!(heap.len(), 1);
/// assert_eq!(heap.peek(), Some(&3));
///
/// ```
/// use std::collections::BinaryHeap;
- /// let heap = BinaryHeap::from_vec(vec![1i, 2, 3, 4, 5, 6, 7]);
+ /// let heap = BinaryHeap::from_vec(vec![1, 2, 3, 4, 5, 6, 7]);
/// let vec = heap.into_vec();
///
/// // Will print in some order
/// ```
/// use std::collections::BinaryHeap;
///
- /// let mut heap = BinaryHeap::from_vec(vec![1i, 2, 4, 5, 7]);
+ /// let mut heap = BinaryHeap::from_vec(vec![1, 2, 4, 5, 7]);
/// heap.push(6);
/// heap.push(3);
///
/// let vec = heap.into_sorted_vec();
- /// assert_eq!(vec, vec![1i, 2, 3, 4, 5, 6, 7]);
+ /// assert_eq!(vec, vec![1, 2, 3, 4, 5, 6, 7]);
/// ```
pub fn into_sorted_vec(mut self) -> Vec<T> {
let mut end = self.len();
nbits: uint
}
-// NOTE(stage0): remove impl after a snapshot
-#[cfg(stage0)]
-// FIXME(Gankro): NopeNopeNopeNopeNope (wait for IndexGet to be a thing)
-impl Index<uint,bool> for Bitv {
- #[inline]
- fn index(&self, i: &uint) -> &bool {
- if self.get(*i).expect("index out of bounds") {
- &TRUE
- } else {
- &FALSE
- }
- }
-}
-
-#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot
// FIXME(Gankro): NopeNopeNopeNopeNope (wait for IndexGet to be a thing)
impl Index<uint> for Bitv {
type Output = bool;
use core::prelude::*;
-use core::borrow::BorrowFrom;
+use core::borrow::{BorrowFrom, ToOwned};
use core::cmp::Ordering;
use core::default::Default;
use core::fmt::Show;
inner: Map<(&'a K, &'a V), &'a V, Iter<'a, K, V>, fn((&'a K, &'a V)) -> &'a V>
}
+#[stable]
/// A view into a single entry in a map, which may either be vacant or occupied.
-pub enum Entry<'a, K:'a, V:'a> {
+pub enum Entry<'a, Sized? Q:'a, K:'a, V:'a> {
/// A vacant Entry
- Vacant(VacantEntry<'a, K, V>),
+ Vacant(VacantEntry<'a, Q, K, V>),
/// An occupied Entry
Occupied(OccupiedEntry<'a, K, V>),
}
+#[stable]
/// A vacant Entry.
-pub struct VacantEntry<'a, K:'a, V:'a> {
- key: K,
+pub struct VacantEntry<'a, Sized? Q:'a, K:'a, V:'a> {
+ key: &'a Q,
stack: stack::SearchStack<'a, K, V, node::handle::Edge, node::handle::Leaf>,
}
+#[stable]
/// An occupied Entry.
pub struct OccupiedEntry<'a, K:'a, V:'a> {
stack: stack::SearchStack<'a, K, V, node::handle::KV, node::handle::LeafOrInternal>,
}
}
-// NOTE(stage0): remove impl after a snapshot
-#[cfg(stage0)]
-#[stable]
-impl<K: Ord, Sized? Q, V> Index<Q, V> for BTreeMap<K, V>
- where Q: BorrowFrom<K> + Ord
-{
- fn index(&self, key: &Q) -> &V {
- self.get(key).expect("no entry found for key")
- }
-}
-
-#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot
#[stable]
impl<K: Ord, Sized? Q, V> Index<Q> for BTreeMap<K, V>
where Q: BorrowFrom<K> + Ord
}
}
-// NOTE(stage0): remove impl after a snapshot
-#[cfg(stage0)]
-#[stable]
-impl<K: Ord, Sized? Q, V> IndexMut<Q, V> for BTreeMap<K, V>
- where Q: BorrowFrom<K> + Ord
-{
- fn index_mut(&mut self, key: &Q) -> &mut V {
- self.get_mut(key).expect("no entry found for key")
- }
-}
-
-#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot
#[stable]
impl<K: Ord, Sized? Q, V> IndexMut<Q> for BTreeMap<K, V>
where Q: BorrowFrom<K> + Ord
#[stable]
impl<'a, K, V> ExactSizeIterator for Values<'a, K, V> {}
+impl<'a, Sized? Q, K: Ord, V> Entry<'a, Q, K, V> {
+ #[unstable = "matches collection reform v2 specification, waiting for dust to settle"]
+ /// Returns a mutable reference to the entry if occupied, or the VacantEntry if vacant
+ pub fn get(self) -> Result<&'a mut V, VacantEntry<'a, Q, K, V>> {
+ match self {
+ Occupied(entry) => Ok(entry.into_mut()),
+ Vacant(entry) => Err(entry),
+ }
+ }
+}
-impl<'a, K: Ord, V> VacantEntry<'a, K, V> {
+impl<'a, Sized? Q: ToOwned<K>, K: Ord, V> VacantEntry<'a, Q, K, V> {
+ #[stable]
/// Sets the value of the entry with the VacantEntry's key,
/// and returns a mutable reference to it.
- pub fn set(self, value: V) -> &'a mut V {
- self.stack.insert(self.key, value)
+ pub fn insert(self, value: V) -> &'a mut V {
+ self.stack.insert(self.key.to_owned(), value)
}
}
impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> {
+ #[stable]
/// Gets a reference to the value in the entry.
pub fn get(&self) -> &V {
self.stack.peek()
}
+ #[stable]
/// Gets a mutable reference to the value in the entry.
pub fn get_mut(&mut self) -> &mut V {
self.stack.peek_mut()
}
+ #[stable]
/// Converts the entry into a mutable reference to its value.
pub fn into_mut(self) -> &'a mut V {
self.stack.into_top()
}
+ #[stable]
/// Sets the value of the entry with the OccupiedEntry's key,
/// and returns the entry's old value.
- pub fn set(&mut self, mut value: V) -> V {
+ pub fn insert(&mut self, mut value: V) -> V {
mem::swap(self.stack.peek_mut(), &mut value);
value
}
+ #[stable]
/// Takes the value of the entry out of the map, and returns it.
- pub fn take(self) -> V {
+ pub fn remove(self) -> V {
self.stack.remove()
}
}
///
/// // count the number of occurrences of letters in the vec
/// for x in vec!["a","b","a","c","a","b"].iter() {
- /// match count.entry(*x) {
+ /// match count.entry(x) {
/// Entry::Vacant(view) => {
- /// view.set(1);
+ /// view.insert(1);
/// },
/// Entry::Occupied(mut view) => {
/// let v = view.get_mut();
///
/// assert_eq!(count["a"], 3u);
/// ```
- pub fn entry<'a>(&'a mut self, mut key: K) -> Entry<'a, K, V> {
+ /// The key must have the same ordering before or after `.to_owned()` is called.
+ #[stable]
+ pub fn entry<'a, Sized? Q>(&'a mut self, mut key: &'a Q) -> Entry<'a, Q, K, V>
+ where Q: Ord + ToOwned<K>
+ {
// same basic logic of `swap` and `pop`, blended together
let mut stack = stack::PartialSearchStack::new(self);
loop {
let result = stack.with(move |pusher, node| {
- return match Node::search(node, &key) {
+ return match Node::search(node, key) {
Found(handle) => {
// Perfect match
Finished(Occupied(OccupiedEntry {
#[cfg(test)]
mod test {
use prelude::*;
+ use std::borrow::{ToOwned, BorrowFrom};
use super::{BTreeMap, Occupied, Vacant};
let mut map: BTreeMap<int, int> = xs.iter().map(|&x| x).collect();
// Existing key (insert)
- match map.entry(1) {
+ match map.entry(&1) {
Vacant(_) => unreachable!(),
Occupied(mut view) => {
assert_eq!(view.get(), &10);
- assert_eq!(view.set(100), 10);
+ assert_eq!(view.insert(100), 10);
}
}
assert_eq!(map.get(&1).unwrap(), &100);
// Existing key (update)
- match map.entry(2) {
+ match map.entry(&2) {
Vacant(_) => unreachable!(),
Occupied(mut view) => {
let v = view.get_mut();
assert_eq!(map.len(), 6);
// Existing key (take)
- match map.entry(3) {
+ match map.entry(&3) {
Vacant(_) => unreachable!(),
Occupied(view) => {
- assert_eq!(view.take(), 30);
+ assert_eq!(view.remove(), 30);
}
}
assert_eq!(map.get(&3), None);
// Inexistent key (insert)
- match map.entry(10) {
+ match map.entry(&10) {
Occupied(_) => unreachable!(),
Vacant(view) => {
- assert_eq!(*view.set(1000), 1000);
+ assert_eq!(*view.insert(1000), 1000);
}
}
assert_eq!(map.get(&10).unwrap(), &1000);
///
/// let mut v = BTreeSet::new();
/// assert_eq!(v.len(), 0);
- /// v.insert(1i);
+ /// v.insert(1);
/// assert_eq!(v.len(), 1);
/// ```
#[stable]
///
/// let mut v = BTreeSet::new();
/// assert!(v.is_empty());
- /// v.insert(1i);
+ /// v.insert(1);
/// assert!(!v.is_empty());
/// ```
#[stable]
/// use std::collections::BTreeSet;
///
/// let mut v = BTreeSet::new();
- /// v.insert(1i);
+ /// v.insert(1);
/// v.clear();
/// assert!(v.is_empty());
/// ```
/// ```
/// use std::collections::BTreeSet;
///
- /// let set: BTreeSet<int> = [1i, 2, 3].iter().map(|&x| x).collect();
+ /// let set: BTreeSet<int> = [1, 2, 3].iter().map(|&x| x).collect();
/// assert_eq!(set.contains(&1), true);
/// assert_eq!(set.contains(&4), false);
/// ```
/// ```
/// use std::collections::BTreeSet;
///
- /// let a: BTreeSet<int> = [1i, 2, 3].iter().map(|&x| x).collect();
+ /// let a: BTreeSet<int> = [1, 2, 3].iter().map(|&x| x).collect();
/// let mut b: BTreeSet<int> = BTreeSet::new();
///
/// assert_eq!(a.is_disjoint(&b), true);
/// ```
/// use std::collections::BTreeSet;
///
- /// let sup: BTreeSet<int> = [1i, 2, 3].iter().map(|&x| x).collect();
+ /// let sup: BTreeSet<int> = [1, 2, 3].iter().map(|&x| x).collect();
/// let mut set: BTreeSet<int> = BTreeSet::new();
///
/// assert_eq!(set.is_subset(&sup), true);
/// ```
/// use std::collections::BTreeSet;
///
- /// let sub: BTreeSet<int> = [1i, 2].iter().map(|&x| x).collect();
+ /// let sub: BTreeSet<int> = [1, 2].iter().map(|&x| x).collect();
/// let mut set: BTreeSet<int> = BTreeSet::new();
///
/// assert_eq!(set.is_superset(&sub), false);
///
/// let mut set = BTreeSet::new();
///
- /// assert_eq!(set.insert(2i), true);
- /// assert_eq!(set.insert(2i), false);
+ /// assert_eq!(set.insert(2), true);
+ /// assert_eq!(set.insert(2), false);
/// assert_eq!(set.len(), 1);
/// ```
#[stable]
///
/// let mut set = BTreeSet::new();
///
- /// set.insert(2i);
+ /// set.insert(2);
/// assert_eq!(set.remove(&2), true);
/// assert_eq!(set.remove(&2), false);
/// ```
///
/// let mut a = DList::new();
/// let mut b = DList::new();
- /// a.push_back(1i);
+ /// a.push_back(1);
/// a.push_back(2);
- /// b.push_back(3i);
+ /// b.push_back(3);
/// b.push_back(4);
///
/// a.append(b);
/// use std::collections::DList;
///
/// let mut d = DList::new();
- /// d.push_back(1i);
+ /// d.push_back(1);
/// d.push_back(3);
/// assert_eq!(3, *d.back().unwrap());
/// ```
///
/// let mut d = DList::new();
/// assert_eq!(d.pop_back(), None);
- /// d.push_back(1i);
+ /// d.push_back(1);
/// d.push_back(3);
/// assert_eq!(d.pop_back(), Some(3));
/// ```
/// }
/// {
/// let vec: Vec<int> = list.into_iter().collect();
- /// assert_eq!(vec, vec![1i, 2, 3, 4]);
+ /// assert_eq!(vec, vec![1, 2, 3, 4]);
/// }
/// ```
#[inline]
mod prelude {
// from core.
pub use core::borrow::IntoCow;
- pub use core::char::Char;
pub use core::clone::Clone;
pub use core::cmp::{PartialEq, Eq, PartialOrd, Ord};
pub use core::cmp::Ordering::{Less, Equal, Greater};
// from other crates.
pub use alloc::boxed::Box;
- pub use unicode::char::UnicodeChar;
+ pub use unicode::char::CharExt;
// from collections.
pub use slice::SliceConcatExt;
use core::cmp::Ordering;
use core::default::Default;
use core::fmt;
-use core::iter::{self, FromIterator, RandomAccessIterator};
+use core::iter::{self, repeat, FromIterator, RandomAccessIterator};
use core::kinds::marker;
use core::mem;
use core::num::{Int, UnsignedInt};
use alloc::heap;
-static INITIAL_CAPACITY: uint = 8u; // 2^3
-static MINIMUM_CAPACITY: uint = 2u;
-
-// FIXME(conventions): implement shrink_to_fit. Awkward with the current design, but it should
-// be scrapped anyway. Defer to rewrite?
+static INITIAL_CAPACITY: uint = 7u; // 2^3 - 1
+static MINIMUM_CAPACITY: uint = 1u; // 2 - 1
/// `RingBuf` is a circular buffer, which can be used as a double-ended queue efficiently.
#[stable]
self.cap);
ptr::copy_memory(
self.ptr.offset(dst as int),
- self.ptr.offset(src as int) as *const T,
+ self.ptr.offset(src as int),
+ len);
+ }
+
+ /// Copies a contiguous block of memory len long from src to dst
+ #[inline]
+ unsafe fn copy_nonoverlapping(&self, dst: uint, src: uint, len: uint) {
+ debug_assert!(dst + len <= self.cap, "dst={} src={} len={} cap={}", dst, src, len,
+ self.cap);
+ debug_assert!(src + len <= self.cap, "dst={} src={} len={} cap={}", dst, src, len,
+ self.cap);
+ ptr::copy_nonoverlapping_memory(
+ self.ptr.offset(dst as int),
+ self.ptr.offset(src as int),
len);
}
}
#[stable]
pub fn with_capacity(n: uint) -> RingBuf<T> {
// +1 since the ringbuffer always leaves one space empty
- let cap = cmp::max(n + 1, MINIMUM_CAPACITY).next_power_of_two();
+ let cap = cmp::max(n + 1, MINIMUM_CAPACITY + 1).next_power_of_two();
+ assert!(cap > n, "capacity overflow");
let size = cap.checked_mul(mem::size_of::<T>())
.expect("capacity overflow");
/// use std::collections::RingBuf;
///
/// let mut buf = RingBuf::new();
- /// buf.push_back(3i);
+ /// buf.push_back(3);
/// buf.push_back(4);
/// buf.push_back(5);
/// assert_eq!(buf.get(1).unwrap(), &4);
/// use std::collections::RingBuf;
///
/// let mut buf = RingBuf::new();
- /// buf.push_back(3i);
+ /// buf.push_back(3);
/// buf.push_back(4);
/// buf.push_back(5);
/// match buf.get_mut(1) {
/// use std::collections::RingBuf;
///
/// let mut buf = RingBuf::new();
- /// buf.push_back(3i);
+ /// buf.push_back(3);
/// buf.push_back(4);
/// buf.push_back(5);
/// buf.swap(0, 2);
// Nop
} else if self.head < oldcap - self.tail { // B
unsafe {
- ptr::copy_nonoverlapping_memory(
- self.ptr.offset(oldcap as int),
- self.ptr as *const T,
- self.head
- );
+ self.copy_nonoverlapping(oldcap, 0, self.head);
}
self.head += oldcap;
debug_assert!(self.head > self.tail);
} else { // C
+ let new_tail = count - (oldcap - self.tail);
unsafe {
- ptr::copy_nonoverlapping_memory(
- self.ptr.offset((count - (oldcap - self.tail)) as int),
- self.ptr.offset(self.tail as int) as *const T,
- oldcap - self.tail
- );
+ self.copy_nonoverlapping(new_tail, self.tail, oldcap - self.tail);
}
- self.tail = count - (oldcap - self.tail);
+ self.tail = new_tail;
debug_assert!(self.head < self.tail);
}
debug_assert!(self.head < self.cap);
}
}
+ /// Shrinks the capacity of the ringbuf as much as possible.
+ ///
+ /// It will drop down as close as possible to the length but the allocator may still inform the
+ /// ringbuf that there is space for a few more elements.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::RingBuf;
+ ///
+ /// let mut buf = RingBuf::with_capacity(15);
+ /// buf.extend(range(0u, 4));
+ /// assert_eq!(buf.capacity(), 15);
+ /// buf.shrink_to_fit();
+ /// assert!(buf.capacity() >= 4);
+ /// ```
+ pub fn shrink_to_fit(&mut self) {
+ // +1 since the ringbuffer always leaves one space empty
+ // len + 1 can't overflow for an existing, well-formed ringbuf.
+ let target_cap = cmp::max(self.len() + 1, MINIMUM_CAPACITY + 1).next_power_of_two();
+ if target_cap < self.cap {
+ // There are three cases of interest:
+ // All elements are out of desired bounds
+ // Elements are contiguous, and head is out of desired bounds
+ // Elements are discontiguous, and tail is out of desired bounds
+ //
+ // At all other times, element positions are unaffected.
+ //
+ // Indicates that elements at the head should be moved.
+ let head_outside = self.head == 0 || self.head >= target_cap;
+ // Move elements from out of desired bounds (positions after target_cap)
+ if self.tail >= target_cap && head_outside {
+ // T H
+ // [. . . . . . . . o o o o o o o . ]
+ // T H
+ // [o o o o o o o . ]
+ unsafe {
+ self.copy_nonoverlapping(0, self.tail, self.len());
+ }
+ self.head = self.len();
+ self.tail = 0;
+ } else if self.tail != 0 && self.tail < target_cap && head_outside {
+ // T H
+ // [. . . o o o o o o o . . . . . . ]
+ // H T
+ // [o o . o o o o o ]
+ let len = self.wrap_index(self.head - target_cap);
+ unsafe {
+ self.copy_nonoverlapping(0, target_cap, len);
+ }
+ self.head = len;
+ debug_assert!(self.head < self.tail);
+ } else if self.tail >= target_cap {
+ // H T
+ // [o o o o o . . . . . . . . . o o ]
+ // H T
+ // [o o o o o . o o ]
+ debug_assert!(self.wrap_index(self.head - 1) < target_cap);
+ let len = self.cap - self.tail;
+ let new_tail = target_cap - len;
+ unsafe {
+ self.copy_nonoverlapping(new_tail, self.tail, len);
+ }
+ self.tail = new_tail;
+ debug_assert!(self.head < self.tail);
+ }
+
+ if mem::size_of::<T>() != 0 {
+ let old = self.cap * mem::size_of::<T>();
+ let new_size = target_cap * mem::size_of::<T>();
+ unsafe {
+ self.ptr = heap::reallocate(self.ptr as *mut u8,
+ old,
+ new_size,
+ mem::min_align_of::<T>()) as *mut T;
+ if self.ptr.is_null() { ::alloc::oom() }
+ }
+ }
+ self.cap = target_cap;
+ debug_assert!(self.head < self.cap);
+ debug_assert!(self.tail < self.cap);
+ debug_assert!(self.cap.count_ones() == 1);
+ }
+ }
+
+ /// Shorten a ringbuf, dropping excess elements from the back.
+ ///
+ /// If `len` is greater than the ringbuf's current length, this has no
+ /// effect.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::RingBuf;
+ ///
+ /// let mut buf = RingBuf::new();
+ /// buf.push_back(5i);
+ /// buf.push_back(10i);
+ /// buf.push_back(15);
+ /// buf.truncate(1);
+ /// assert_eq!(buf.len(), 1);
+ /// assert_eq!(Some(&5), buf.get(0));
+ /// ```
+ #[unstable = "matches collection reform specification; waiting on panic semantics"]
+ pub fn truncate(&mut self, len: uint) {
+ for _ in range(len, self.len()) {
+ self.pop_back();
+ }
+ }
+
/// Returns a front-to-back iterator.
///
/// # Examples
/// use std::collections::RingBuf;
///
/// let mut buf = RingBuf::new();
- /// buf.push_back(5i);
+ /// buf.push_back(5);
/// buf.push_back(3);
/// buf.push_back(4);
/// let b: &[_] = &[&5, &3, &4];
/// use std::collections::RingBuf;
///
/// let mut buf = RingBuf::new();
- /// buf.push_back(5i);
+ /// buf.push_back(5);
/// buf.push_back(3);
/// buf.push_back(4);
/// for num in buf.iter_mut() {
///
/// let mut v = RingBuf::new();
/// assert_eq!(v.len(), 0);
- /// v.push_back(1i);
+ /// v.push_back(1);
/// assert_eq!(v.len(), 1);
/// ```
#[stable]
///
/// let mut v = RingBuf::new();
/// assert!(v.is_empty());
- /// v.push_front(1i);
+ /// v.push_front(1);
/// assert!(!v.is_empty());
/// ```
#[stable]
/// use std::collections::RingBuf;
///
/// let mut v = RingBuf::new();
- /// v.push_back(1i);
+ /// v.push_back(1);
/// assert_eq!(v.drain().next(), Some(1));
/// assert!(v.is_empty());
/// ```
/// use std::collections::RingBuf;
///
/// let mut v = RingBuf::new();
- /// v.push_back(1i);
+ /// v.push_back(1);
/// v.clear();
/// assert!(v.is_empty());
/// ```
/// let mut d = RingBuf::new();
/// assert_eq!(d.front(), None);
///
- /// d.push_back(1i);
- /// d.push_back(2i);
- /// assert_eq!(d.front(), Some(&1i));
+ /// d.push_back(1);
+ /// d.push_back(2);
+ /// assert_eq!(d.front(), Some(&1));
/// ```
#[stable]
pub fn front(&self) -> Option<&T> {
/// let mut d = RingBuf::new();
/// assert_eq!(d.front_mut(), None);
///
- /// d.push_back(1i);
- /// d.push_back(2i);
+ /// d.push_back(1);
+ /// d.push_back(2);
/// match d.front_mut() {
- /// Some(x) => *x = 9i,
+ /// Some(x) => *x = 9,
/// None => (),
/// }
- /// assert_eq!(d.front(), Some(&9i));
+ /// assert_eq!(d.front(), Some(&9));
/// ```
#[stable]
pub fn front_mut(&mut self) -> Option<&mut T> {
/// let mut d = RingBuf::new();
/// assert_eq!(d.back(), None);
///
- /// d.push_back(1i);
- /// d.push_back(2i);
- /// assert_eq!(d.back(), Some(&2i));
+ /// d.push_back(1);
+ /// d.push_back(2);
+ /// assert_eq!(d.back(), Some(&2));
/// ```
#[stable]
pub fn back(&self) -> Option<&T> {
/// let mut d = RingBuf::new();
/// assert_eq!(d.back(), None);
///
- /// d.push_back(1i);
- /// d.push_back(2i);
+ /// d.push_back(1);
+ /// d.push_back(2);
/// match d.back_mut() {
- /// Some(x) => *x = 9i,
+ /// Some(x) => *x = 9,
/// None => (),
/// }
- /// assert_eq!(d.back(), Some(&9i));
+ /// assert_eq!(d.back(), Some(&9));
/// ```
#[stable]
pub fn back_mut(&mut self) -> Option<&mut T> {
/// use std::collections::RingBuf;
///
/// let mut d = RingBuf::new();
- /// d.push_back(1i);
- /// d.push_back(2i);
+ /// d.push_back(1);
+ /// d.push_back(2);
///
- /// assert_eq!(d.pop_front(), Some(1i));
- /// assert_eq!(d.pop_front(), Some(2i));
+ /// assert_eq!(d.pop_front(), Some(1));
+ /// assert_eq!(d.pop_front(), Some(2));
/// assert_eq!(d.pop_front(), None);
/// ```
#[stable]
/// use std::collections::RingBuf;
///
/// let mut d = RingBuf::new();
- /// d.push_front(1i);
- /// d.push_front(2i);
- /// assert_eq!(d.front(), Some(&2i));
+ /// d.push_front(1);
+ /// d.push_front(2);
+ /// assert_eq!(d.front(), Some(&2));
/// ```
#[stable]
pub fn push_front(&mut self, t: T) {
/// use std::collections::RingBuf;
///
/// let mut buf = RingBuf::new();
- /// buf.push_back(1i);
+ /// buf.push_back(1);
/// buf.push_back(3);
/// assert_eq!(3, *buf.back().unwrap());
/// ```
///
/// let mut buf = RingBuf::new();
/// assert_eq!(buf.pop_back(), None);
- /// buf.push_back(1i);
+ /// buf.push_back(1);
/// buf.push_back(3);
/// assert_eq!(buf.pop_back(), Some(3));
/// ```
self.tail <= self.head
}
+ /// Removes an element from anywhere in the ringbuf and returns it, replacing it with the last
+ /// element.
+ ///
+ /// This does not preserve ordering, but is O(1).
+ ///
+ /// Returns `None` if `index` is out of bounds.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::RingBuf;
+ ///
+ /// let mut buf = RingBuf::new();
+ /// assert_eq!(buf.swap_back_remove(0), None);
+ /// buf.push_back(5i);
+ /// buf.push_back(99);
+ /// buf.push_back(15);
+ /// buf.push_back(20);
+ /// buf.push_back(10);
+ /// assert_eq!(buf.swap_back_remove(1), Some(99));
+ /// ```
+ #[unstable = "the naming of this function may be altered"]
+ pub fn swap_back_remove(&mut self, index: uint) -> Option<T> {
+ let length = self.len();
+ if length > 0 && index < length - 1 {
+ self.swap(index, length - 1);
+ } else if index >= length {
+ return None;
+ }
+ self.pop_back()
+ }
+
+ /// Removes an element from anywhere in the ringbuf and returns it, replacing it with the first
+ /// element.
+ ///
+ /// This does not preserve ordering, but is O(1).
+ ///
+ /// Returns `None` if `index` is out of bounds.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::RingBuf;
+ ///
+ /// let mut buf = RingBuf::new();
+ /// assert_eq!(buf.swap_front_remove(0), None);
+ /// buf.push_back(15i);
+ /// buf.push_back(5);
+ /// buf.push_back(10);
+ /// buf.push_back(99);
+ /// buf.push_back(20i);
+ /// assert_eq!(buf.swap_front_remove(3), Some(99));
+ /// ```
+ #[unstable = "the naming of this function may be altered"]
+ pub fn swap_front_remove(&mut self, index: uint) -> Option<T> {
+ let length = self.len();
+ if length > 0 && index < length && index != 0 {
+ self.swap(index, 0);
+ } else if index >= length {
+ return None;
+ }
+ self.pop_front()
+ }
+
/// Inserts an element at position `i` within the ringbuf. Whichever
/// end is closer to the insertion point will be moved to make room,
/// and all the affected elements will be moved to new positions.
///
/// Panics if `i` is greater than ringbuf's length
///
- /// # Example
+ /// # Examples
/// ```rust
/// use std::collections::RingBuf;
///
/// let mut buf = RingBuf::new();
- /// buf.push_back(10i);
+ /// buf.push_back(10);
/// buf.push_back(12);
/// buf.insert(1,11);
/// assert_eq!(Some(&11), buf.get(1));
/// room, and all the affected elements will be moved to new positions.
/// Returns `None` if `i` is out of bounds.
///
- /// # Example
+ /// # Examples
/// ```rust
/// use std::collections::RingBuf;
///
/// let mut buf = RingBuf::new();
- /// buf.push_back(5i);
- /// buf.push_back(10i);
- /// buf.push_back(12i);
+ /// buf.push_back(5);
+ /// buf.push_back(10);
+ /// buf.push_back(12);
/// buf.push_back(15);
/// buf.remove(2);
/// assert_eq!(Some(&15), buf.get(2));
let distance_to_tail = i;
let distance_to_head = self.len() - i;
- let contiguous = self.tail <= self.head;
+ let contiguous = self.is_contiguous();
match (contiguous, distance_to_tail <= distance_to_head, idx >= self.tail) {
(true, true, _) => unsafe {
}
}
+impl<T: Clone> RingBuf<T> {
+ /// Modifies the ringbuf in-place so that `len()` is equal to new_len,
+ /// either by removing excess elements or by appending copies of a value to the back.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::RingBuf;
+ ///
+ /// let mut buf = RingBuf::new();
+ /// buf.push_back(5i);
+ /// buf.push_back(10i);
+ /// buf.push_back(15);
+ /// buf.resize(2, 0);
+ /// buf.resize(6, 20);
+ /// for (a, b) in [5, 10, 20, 20, 20, 20].iter().zip(buf.iter()) {
+ /// assert_eq!(a, b);
+ /// }
+ /// ```
+ #[unstable = "matches collection reform specification; waiting on panic semantics"]
+ pub fn resize(&mut self, new_len: uint, value: T) {
+ let len = self.len();
+
+ if new_len > len {
+ self.extend(repeat(value).take(new_len - len))
+ } else {
+ self.truncate(new_len);
+ }
+ }
+}
+
/// Returns the index in the underlying buffer for a given logical element index.
#[inline]
fn wrap_index(index: uint, size: uint) -> uint {
}
}
-// NOTE(stage0): remove impl after a snapshot
-#[cfg(stage0)]
-#[stable]
-impl<A> Index<uint, A> for RingBuf<A> {
- #[inline]
- fn index<'a>(&'a self, i: &uint) -> &'a A {
- self.get(*i).expect("Out of bounds access")
- }
-}
-
-#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot
#[stable]
impl<A> Index<uint> for RingBuf<A> {
type Output = A;
}
}
-// NOTE(stage0): remove impl after a snapshot
-#[cfg(stage0)]
-#[stable]
-impl<A> IndexMut<uint, A> for RingBuf<A> {
- #[inline]
- fn index_mut<'a>(&'a mut self, i: &uint) -> &'a mut A {
- self.get_mut(*i).expect("Out of bounds access")
- }
-}
-
-#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot
#[stable]
impl<A> IndexMut<uint> for RingBuf<A> {
type Output = A;
assert_eq!(ring.get_mut(2), None);
}
+ #[test]
+ fn test_swap_front_back_remove() {
+ fn test(back: bool) {
+ // This test checks that every single combination of tail position and length is tested.
+ // Capacity 15 should be large enough to cover every case.
+ let mut tester = RingBuf::with_capacity(15);
+ let usable_cap = tester.capacity();
+ let final_len = usable_cap / 2;
+
+ for len in range(0, final_len) {
+ let expected = if back {
+ range(0, len).collect()
+ } else {
+ range(0, len).rev().collect()
+ };
+ for tail_pos in range(0, usable_cap) {
+ tester.tail = tail_pos;
+ tester.head = tail_pos;
+ if back {
+ for i in range(0, len * 2) {
+ tester.push_front(i);
+ }
+ for i in range(0, len) {
+ assert_eq!(tester.swap_back_remove(i), Some(len * 2 - 1 - i));
+ }
+ } else {
+ for i in range(0, len * 2) {
+ tester.push_back(i);
+ }
+ for i in range(0, len) {
+ let idx = tester.len() - 1 - i;
+ assert_eq!(tester.swap_front_remove(idx), Some(len * 2 - 1 - i));
+ }
+ }
+ assert!(tester.tail < tester.cap);
+ assert!(tester.head < tester.cap);
+ assert_eq!(tester, expected);
+ }
+ }
+ }
+ test(true);
+ test(false);
+ }
+
#[test]
fn test_insert() {
// This test checks that every single combination of tail position, length, and
}
}
+ #[test]
+ fn test_shrink_to_fit() {
+ // This test checks that every single combination of head and tail position,
+ // is tested. Capacity 15 should be large enough to cover every case.
+
+ let mut tester = RingBuf::with_capacity(15);
+ // can't guarantee we got 15, so have to get what we got.
+ // 15 would be great, but we will definitely get 2^k - 1, for k >= 4, or else
+ // this test isn't covering what it wants to
+ let cap = tester.capacity();
+ tester.reserve(63);
+ let max_cap = tester.capacity();
+
+ for len in range(0, cap + 1) {
+ // 0, 1, 2, .., len - 1
+ let expected = iter::count(0, 1).take(len).collect();
+ for tail_pos in range(0, max_cap + 1) {
+ tester.tail = tail_pos;
+ tester.head = tail_pos;
+ tester.reserve(63);
+ for i in range(0, len) {
+ tester.push_back(i);
+ }
+ tester.shrink_to_fit();
+ assert!(tester.capacity() <= cap);
+ assert!(tester.tail < tester.cap);
+ assert!(tester.head < tester.cap);
+ assert_eq!(tester, expected);
+ }
+ }
+ }
+
#[test]
fn test_front() {
let mut ring = RingBuf::new();
//!
//! ```rust
//! // slicing a Vec
-//! let vec = vec!(1i, 2, 3);
+//! let vec = vec!(1, 2, 3);
//! let int_slice = vec.as_slice();
//! // coercing an array to a slice
//! let str_slice: &[&str] = &["one", "two", "three"];
//! block of memory that a mutable slice points to:
//!
//! ```rust
-//! let x: &mut[int] = &mut [1i, 2, 3];
+//! let x: &mut[int] = &mut [1, 2, 3];
//! x[1] = 7;
//! assert_eq!(x[0], 1);
//! assert_eq!(x[1], 7);
//! ```rust
//! #![feature(slicing_syntax)]
//! fn main() {
-//! let numbers = [0i, 1i, 2i];
+//! let numbers = [0, 1, 2];
//! let last_numbers = numbers[1..3];
-//! // last_numbers is now &[1i, 2i]
+//! // last_numbers is now &[1, 2]
//! }
//! ```
//!
//! type of the slice is `int`, the element type of the iterator is `&int`.
//!
//! ```rust
-//! let numbers = [0i, 1i, 2i];
+//! let numbers = [0, 1, 2];
//! for &x in numbers.iter() {
//! println!("{} is a number!", x);
//! }
use alloc::boxed::Box;
use core::borrow::{BorrowFrom, BorrowFromMut, ToOwned};
-use core::clone::Clone;
-use core::cmp::Ordering::{self, Greater, Less};
-use core::cmp::{self, Ord, PartialEq};
-use core::iter::{Iterator, IteratorExt};
-use core::iter::{range, range_step, MultiplicativeIterator};
+use core::cmp;
+use core::iter::{range_step, MultiplicativeIterator};
use core::kinds::Sized;
use core::mem::size_of;
use core::mem;
-use core::ops::{FnMut, SliceMut};
-use core::option::Option::{self, Some, None};
-use core::ptr::PtrExt;
+use core::ops::{FnMut,SliceMut};
+use core::prelude::{Clone, Greater, Iterator, IteratorExt, Less, None, Option};
+use core::prelude::{Ord, Ordering, PtrExt, Some, range, IteratorCloneExt, Result};
use core::ptr;
-use core::result::Result;
use core::slice as core_slice;
use self::Direction::*;
use vec::Vec;
pub use core::slice::{Chunks, AsSlice, Windows};
-pub use core::slice::{Iter, IterMut};
+pub use core::slice::{Iter, IterMut, PartialEqSliceExt};
pub use core::slice::{IntSliceExt, SplitMut, ChunksMut, Split};
pub use core::slice::{SplitN, RSplitN, SplitNMut, RSplitNMut};
pub use core::slice::{bytes, mut_ref_slice, ref_slice};
pub use core::slice::{from_raw_buf, from_raw_mut_buf};
+#[deprecated = "use Iter instead"]
+pub type Items<'a, T:'a> = Iter<'a, T>;
+
+#[deprecated = "use IterMut instead"]
+pub type MutItems<'a, T:'a> = IterMut<'a, T>;
+
////////////////////////////////////////////////////////////////////////////////
// Basic slice extension methods
////////////////////////////////////////////////////////////////////////////////
/// Allocating extension methods for slices.
#[unstable = "needs associated types, may merge with other traits"]
-pub trait SliceExt for Sized? {
- type Item;
-
+pub trait SliceExt<T> for Sized? {
/// Sorts the slice, in place, using `compare` to compare
/// elements.
///
/// # Examples
///
/// ```rust
- /// let mut v = [5i, 4, 1, 3, 2];
+ /// let mut v = [5, 4, 1, 3, 2];
/// v.sort_by(|a, b| a.cmp(b));
/// assert!(v == [1, 2, 3, 4, 5]);
///
/// assert!(v == [5, 4, 3, 2, 1]);
/// ```
#[stable]
- fn sort_by<F>(&mut self, compare: F) where F: FnMut(&Self::Item, &Self::Item) -> Ordering;
+ fn sort_by<F>(&mut self, compare: F) where F: FnMut(&T, &T) -> Ordering;
/// Consumes `src` and moves as many elements as it can into `self`
/// from the range [start,end).
/// # Examples
///
/// ```rust
- /// let mut a = [1i, 2, 3, 4, 5];
- /// let b = vec![6i, 7, 8];
+ /// let mut a = [1, 2, 3, 4, 5];
+ /// let b = vec![6, 7, 8];
/// let num_moved = a.move_from(b, 0, 3);
/// assert_eq!(num_moved, 3);
- /// assert!(a == [6i, 7, 8, 4, 5]);
+ /// assert!(a == [6, 7, 8, 4, 5]);
/// ```
#[experimental = "uncertain about this API approach"]
- fn move_from(&mut self, src: Vec<Self::Item>, start: uint, end: uint) -> uint;
+ fn move_from(&mut self, src: Vec<T>, start: uint, end: uint) -> uint;
/// Returns a subslice spanning the interval [`start`, `end`).
///
///
/// Slicing with `start` equal to `end` yields an empty slice.
#[experimental = "will be replaced by slice syntax"]
- fn slice(&self, start: uint, end: uint) -> &[Self::Item];
+ fn slice(&self, start: uint, end: uint) -> &[T];
/// Returns a subslice from `start` to the end of the slice.
///
///
/// Slicing from `self.len()` yields an empty slice.
#[experimental = "will be replaced by slice syntax"]
- fn slice_from(&self, start: uint) -> &[Self::Item];
+ fn slice_from(&self, start: uint) -> &[T];
/// Returns a subslice from the start of the slice to `end`.
///
///
/// Slicing to `0` yields an empty slice.
#[experimental = "will be replaced by slice syntax"]
- fn slice_to(&self, end: uint) -> &[Self::Item];
+ fn slice_to(&self, end: uint) -> &[T];
/// Divides one slice into two at an index.
///
///
/// Panics if `mid > len`.
#[stable]
- fn split_at(&self, mid: uint) -> (&[Self::Item], &[Self::Item]);
+ fn split_at(&self, mid: uint) -> (&[T], &[T]);
/// Returns an iterator over the slice
#[stable]
- fn iter(&self) -> Iter<Self::Item>;
+ fn iter(&self) -> Iter<T>;
/// Returns an iterator over subslices separated by elements that match
/// `pred`. The matched element is not contained in the subslices.
#[stable]
- fn split<F>(&self, pred: F) -> Split<Self::Item, F>
- where F: FnMut(&Self::Item) -> bool;
+ fn split<F>(&self, pred: F) -> Split<T, F>
+ where F: FnMut(&T) -> bool;
/// Returns an iterator over subslices separated by elements that match
/// `pred`, limited to splitting at most `n` times. The matched element is
/// not contained in the subslices.
#[stable]
- fn splitn<F>(&self, n: uint, pred: F) -> SplitN<Self::Item, F>
- where F: FnMut(&Self::Item) -> bool;
+ fn splitn<F>(&self, n: uint, pred: F) -> SplitN<T, F>
+ where F: FnMut(&T) -> bool;
/// Returns an iterator over subslices separated by elements that match
/// `pred` limited to splitting at most `n` times. This starts at the end of
/// the slice and works backwards. The matched element is not contained in
/// the subslices.
#[stable]
- fn rsplitn<F>(&self, n: uint, pred: F) -> RSplitN<Self::Item, F>
- where F: FnMut(&Self::Item) -> bool;
+ fn rsplitn<F>(&self, n: uint, pred: F) -> RSplitN<T, F>
+ where F: FnMut(&T) -> bool;
/// Returns an iterator over all contiguous windows of length
/// `size`. The windows overlap. If the slice is shorter than
/// `[3,4]`):
///
/// ```rust
- /// let v = &[1i, 2, 3, 4];
+ /// let v = &[1, 2, 3, 4];
/// for win in v.windows(2) {
/// println!("{}", win);
/// }
/// ```
#[stable]
- fn windows(&self, size: uint) -> Windows<Self::Item>;
+ fn windows(&self, size: uint) -> Windows<T>;
/// Returns an iterator over `size` elements of the slice at a
/// time. The chunks do not overlap. If `size` does not divide the
/// `[3,4]`, `[5]`):
///
/// ```rust
- /// let v = &[1i, 2, 3, 4, 5];
+ /// let v = &[1, 2, 3, 4, 5];
/// for win in v.chunks(2) {
/// println!("{}", win);
/// }
/// ```
#[stable]
- fn chunks(&self, size: uint) -> Chunks<Self::Item>;
+ fn chunks(&self, size: uint) -> Chunks<T>;
/// Returns the element of a slice at the given index, or `None` if the
/// index is out of bounds.
#[stable]
- fn get(&self, index: uint) -> Option<&Self::Item>;
+ fn get(&self, index: uint) -> Option<&T>;
/// Returns the first element of a slice, or `None` if it is empty.
#[stable]
- fn first(&self) -> Option<&Self::Item>;
+ fn first(&self) -> Option<&T>;
+
+ /// Deprecated: renamed to `first`.
+ #[deprecated = "renamed to `first`"]
+ fn head(&self) -> Option<&T> { self.first() }
/// Returns all but the first element of a slice.
#[experimental = "likely to be renamed"]
- fn tail(&self) -> &[Self::Item];
+ fn tail(&self) -> &[T];
/// Returns all but the last element of a slice.
#[experimental = "likely to be renamed"]
- fn init(&self) -> &[Self::Item];
+ fn init(&self) -> &[T];
/// Returns the last element of a slice, or `None` if it is empty.
#[stable]
- fn last(&self) -> Option<&Self::Item>;
+ fn last(&self) -> Option<&T>;
/// Returns a pointer to the element at the given index, without doing
/// bounds checking.
#[stable]
- unsafe fn get_unchecked(&self, index: uint) -> &Self::Item;
+ unsafe fn get_unchecked(&self, index: uint) -> &T;
+
+ /// Deprecated: renamed to `get_unchecked`.
+ #[deprecated = "renamed to get_unchecked"]
+ unsafe fn unsafe_get(&self, index: uint) -> &T {
+ self.get_unchecked(index)
+ }
/// Returns an unsafe pointer to the slice's buffer
///
/// Modifying the slice may cause its buffer to be reallocated, which
/// would also make any pointers to it invalid.
#[stable]
- fn as_ptr(&self) -> *const Self::Item;
+ fn as_ptr(&self) -> *const T;
/// Binary search a sorted slice with a comparator function.
///
/// found; the fourth could match any position in `[1,4]`.
///
/// ```rust
- /// let s = [0i, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
+ /// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
/// let s = s.as_slice();
///
/// let seek = 13;
/// ```
#[stable]
fn binary_search_by<F>(&self, f: F) -> Result<uint, uint> where
- F: FnMut(&Self::Item) -> Ordering;
+ F: FnMut(&T) -> Ordering;
/// Return the number of elements in the slice
///
/// # Example
///
/// ```
- /// let a = [1i, 2, 3];
+ /// let a = [1, 2, 3];
/// assert_eq!(a.len(), 3);
/// ```
#[stable]
/// # Example
///
/// ```
- /// let a = [1i, 2, 3];
+ /// let a = [1, 2, 3];
/// assert!(!a.is_empty());
/// ```
#[inline]
/// Returns a mutable reference to the element at the given index,
/// or `None` if the index is out of bounds
#[stable]
- fn get_mut(&mut self, index: uint) -> Option<&mut Self::Item>;
+ fn get_mut(&mut self, index: uint) -> Option<&mut T>;
/// Work with `self` as a mut slice.
/// Primarily intended for getting a &mut [T] from a [T; N].
#[stable]
- fn as_mut_slice(&mut self) -> &mut [Self::Item];
+ fn as_mut_slice(&mut self) -> &mut [T];
/// Returns a mutable subslice spanning the interval [`start`, `end`).
///
///
/// Slicing with `start` equal to `end` yields an empty slice.
#[experimental = "will be replaced by slice syntax"]
- fn slice_mut(&mut self, start: uint, end: uint) -> &mut [Self::Item];
+ fn slice_mut(&mut self, start: uint, end: uint) -> &mut [T];
/// Returns a mutable subslice from `start` to the end of the slice.
///
///
/// Slicing from `self.len()` yields an empty slice.
#[experimental = "will be replaced by slice syntax"]
- fn slice_from_mut(&mut self, start: uint) -> &mut [Self::Item];
+ fn slice_from_mut(&mut self, start: uint) -> &mut [T];
/// Returns a mutable subslice from the start of the slice to `end`.
///
///
/// Slicing to `0` yields an empty slice.
#[experimental = "will be replaced by slice syntax"]
- fn slice_to_mut(&mut self, end: uint) -> &mut [Self::Item];
+ fn slice_to_mut(&mut self, end: uint) -> &mut [T];
/// Returns an iterator that allows modifying each value
#[stable]
- fn iter_mut(&mut self) -> IterMut<Self::Item>;
+ fn iter_mut(&mut self) -> IterMut<T>;
/// Returns a mutable pointer to the first element of a slice, or `None` if it is empty
#[stable]
- fn first_mut(&mut self) -> Option<&mut Self::Item>;
+ fn first_mut(&mut self) -> Option<&mut T>;
+
+ /// Depreated: renamed to `first_mut`.
+ #[deprecated = "renamed to first_mut"]
+ fn head_mut(&mut self) -> Option<&mut T> {
+ self.first_mut()
+ }
/// Returns all but the first element of a mutable slice
#[experimental = "likely to be renamed or removed"]
- fn tail_mut(&mut self) -> &mut [Self::Item];
+ fn tail_mut(&mut self) -> &mut [T];
/// Returns all but the last element of a mutable slice
#[experimental = "likely to be renamed or removed"]
- fn init_mut(&mut self) -> &mut [Self::Item];
+ fn init_mut(&mut self) -> &mut [T];
/// Returns a mutable pointer to the last item in the slice.
#[stable]
- fn last_mut(&mut self) -> Option<&mut Self::Item>;
+ fn last_mut(&mut self) -> Option<&mut T>;
/// Returns an iterator over mutable subslices separated by elements that
/// match `pred`. The matched element is not contained in the subslices.
#[stable]
- fn split_mut<F>(&mut self, pred: F) -> SplitMut<Self::Item, F>
- where F: FnMut(&Self::Item) -> bool;
+ fn split_mut<F>(&mut self, pred: F) -> SplitMut<T, F>
+ where F: FnMut(&T) -> bool;
/// Returns an iterator over subslices separated by elements that match
/// `pred`, limited to splitting at most `n` times. The matched element is
/// not contained in the subslices.
#[stable]
- fn splitn_mut<F>(&mut self, n: uint, pred: F) -> SplitNMut<Self::Item, F>
- where F: FnMut(&Self::Item) -> bool;
+ fn splitn_mut<F>(&mut self, n: uint, pred: F) -> SplitNMut<T, F>
+ where F: FnMut(&T) -> bool;
/// Returns an iterator over subslices separated by elements that match
/// `pred` limited to splitting at most `n` times. This starts at the end of
/// the slice and works backwards. The matched element is not contained in
/// the subslices.
#[stable]
- fn rsplitn_mut<F>(&mut self, n: uint, pred: F) -> RSplitNMut<Self::Item, F>
- where F: FnMut(&Self::Item) -> bool;
+ fn rsplitn_mut<F>(&mut self, n: uint, pred: F) -> RSplitNMut<T, F>
+ where F: FnMut(&T) -> bool;
/// Returns an iterator over `chunk_size` elements of the slice at a time.
/// The chunks are mutable and do not overlap. If `chunk_size` does
///
/// Panics if `chunk_size` is 0.
#[stable]
- fn chunks_mut(&mut self, chunk_size: uint) -> ChunksMut<Self::Item>;
+ fn chunks_mut(&mut self, chunk_size: uint) -> ChunksMut<T>;
/// Swaps two elements in a slice.
///
/// # Example
///
/// ```rust
- /// let mut v = [1i, 2, 3, 4, 5, 6];
+ /// let mut v = [1, 2, 3, 4, 5, 6];
///
/// // scoped to restrict the lifetime of the borrows
/// {
/// let (left, right) = v.split_at_mut(0);
/// assert!(left == []);
- /// assert!(right == [1i, 2, 3, 4, 5, 6]);
+ /// assert!(right == [1, 2, 3, 4, 5, 6]);
/// }
///
/// {
/// let (left, right) = v.split_at_mut(2);
- /// assert!(left == [1i, 2]);
- /// assert!(right == [3i, 4, 5, 6]);
+ /// assert!(left == [1, 2]);
+ /// assert!(right == [3, 4, 5, 6]);
/// }
///
/// {
/// let (left, right) = v.split_at_mut(6);
- /// assert!(left == [1i, 2, 3, 4, 5, 6]);
+ /// assert!(left == [1, 2, 3, 4, 5, 6]);
/// assert!(right == []);
/// }
/// ```
#[stable]
- fn split_at_mut(&mut self, mid: uint) -> (&mut [Self::Item], &mut [Self::Item]);
+ fn split_at_mut(&mut self, mid: uint) -> (&mut [T], &mut [T]);
/// Reverse the order of elements in a slice, in place.
///
/// # Example
///
/// ```rust
- /// let mut v = [1i, 2, 3];
+ /// let mut v = [1, 2, 3];
/// v.reverse();
- /// assert!(v == [3i, 2, 1]);
+ /// assert!(v == [3, 2, 1]);
/// ```
#[stable]
fn reverse(&mut self);
/// Returns an unsafe mutable pointer to the element in index
#[stable]
- unsafe fn get_unchecked_mut(&mut self, index: uint) -> &mut Self::Item;
+ unsafe fn get_unchecked_mut(&mut self, index: uint) -> &mut T;
+
+ /// Deprecated: renamed to `get_unchecked_mut`.
+ #[deprecated = "renamed to get_unchecked_mut"]
+ unsafe fn unchecked_mut(&mut self, index: uint) -> &mut T {
+ self.get_unchecked_mut(index)
+ }
/// Return an unsafe mutable pointer to the slice's buffer.
///
/// would also make any pointers to it invalid.
#[inline]
#[stable]
- fn as_mut_ptr(&mut self) -> *mut Self::Item;
-
- /// Copies `self` into a new `Vec`.
- #[stable]
- fn to_vec(&self) -> Vec<Self::Item> where Self::Item: Clone;
-
- /// Creates an iterator that yields every possible permutation of the
- /// vector in succession.
- ///
- /// # Examples
- ///
- /// ```rust
- /// let v = [1i, 2, 3];
- /// let mut perms = v.permutations();
- ///
- /// for p in perms {
- /// println!("{}", p);
- /// }
- /// ```
- ///
- /// Iterating through permutations one by one.
- ///
- /// ```rust
- /// let v = [1i, 2, 3];
- /// let mut perms = v.permutations();
- ///
- /// assert_eq!(Some(vec![1i, 2, 3]), perms.next());
- /// assert_eq!(Some(vec![1i, 3, 2]), perms.next());
- /// assert_eq!(Some(vec![3i, 1, 2]), perms.next());
- /// ```
- #[unstable]
- fn permutations(&self) -> Permutations<Self::Item> where Self::Item: Clone;
-
- /// Copies as many elements from `src` as it can into `self` (the
- /// shorter of `self.len()` and `src.len()`). Returns the number
- /// of elements copied.
- ///
- /// # Example
- ///
- /// ```rust
- /// let mut dst = [0i, 0, 0];
- /// let src = [1i, 2];
- ///
- /// assert!(dst.clone_from_slice(&src) == 2);
- /// assert!(dst == [1, 2, 0]);
- ///
- /// let src2 = [3i, 4, 5, 6];
- /// assert!(dst.clone_from_slice(&src2) == 3);
- /// assert!(dst == [3i, 4, 5]);
- /// ```
- #[experimental]
- fn clone_from_slice(&mut self, &[Self::Item]) -> uint where Self::Item: Clone;
-
- /// Sorts the slice, in place.
- ///
- /// This is equivalent to `self.sort_by(|a, b| a.cmp(b))`.
- ///
- /// # Examples
- ///
- /// ```rust
- /// let mut v = [-5i, 4, 1, -3, 2];
- ///
- /// v.sort();
- /// assert!(v == [-5i, -3, 1, 2, 4]);
- /// ```
- #[stable]
- fn sort(&mut self) where Self::Item: Ord;
-
- /// Binary search a sorted slice for a given element.
- ///
- /// If the value is found then `Ok` is returned, containing the
- /// index of the matching element; if the value is not found then
- /// `Err` is returned, containing the index where a matching
- /// element could be inserted while maintaining sorted order.
- ///
- /// # Example
- ///
- /// Looks up a series of four elements. The first is found, with a
- /// uniquely determined position; the second and third are not
- /// found; the fourth could match any position in `[1,4]`.
- ///
- /// ```rust
- /// let s = [0i, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
- /// let s = s.as_slice();
- ///
- /// assert_eq!(s.binary_search(&13), Ok(9));
- /// assert_eq!(s.binary_search(&4), Err(7));
- /// assert_eq!(s.binary_search(&100), Err(13));
- /// let r = s.binary_search(&1);
- /// assert!(match r { Ok(1...4) => true, _ => false, });
- /// ```
- #[stable]
- fn binary_search(&self, x: &Self::Item) -> Result<uint, uint> where Self::Item: Ord;
-
- /// Deprecated: use `binary_search` instead.
- #[deprecated = "use binary_search instead"]
- fn binary_search_elem(&self, x: &Self::Item) -> Result<uint, uint> where Self::Item: Ord {
- self.binary_search(x)
- }
-
- /// Mutates the slice to the next lexicographic permutation.
- ///
- /// Returns `true` if successful and `false` if the slice is at the
- /// last-ordered permutation.
- ///
- /// # Example
- ///
- /// ```rust
- /// let v: &mut [_] = &mut [0i, 1, 2];
- /// v.next_permutation();
- /// let b: &mut [_] = &mut [0i, 2, 1];
- /// assert!(v == b);
- /// v.next_permutation();
- /// let b: &mut [_] = &mut [1i, 0, 2];
- /// assert!(v == b);
- /// ```
- #[unstable = "uncertain if this merits inclusion in std"]
- fn next_permutation(&mut self) -> bool where Self::Item: Ord;
-
- /// Mutates the slice to the previous lexicographic permutation.
- ///
- /// Returns `true` if successful and `false` if the slice is at the
- /// first-ordered permutation.
- ///
- /// # Example
- ///
- /// ```rust
- /// let v: &mut [_] = &mut [1i, 0, 2];
- /// v.prev_permutation();
- /// let b: &mut [_] = &mut [0i, 2, 1];
- /// assert!(v == b);
- /// v.prev_permutation();
- /// let b: &mut [_] = &mut [0i, 1, 2];
- /// assert!(v == b);
- /// ```
- #[unstable = "uncertain if this merits inclusion in std"]
- fn prev_permutation(&mut self) -> bool where Self::Item: Ord;
-
- /// Find the first index containing a matching value.
- #[experimental]
- fn position_elem(&self, t: &Self::Item) -> Option<uint> where Self::Item: PartialEq;
-
- /// Find the last index containing a matching value.
- #[experimental]
- fn rposition_elem(&self, t: &Self::Item) -> Option<uint> where Self::Item: PartialEq;
-
- /// Return true if the slice contains an element with the given value.
- #[stable]
- fn contains(&self, x: &Self::Item) -> bool where Self::Item: PartialEq;
-
- /// Returns true if `needle` is a prefix of the slice.
- #[stable]
- fn starts_with(&self, needle: &[Self::Item]) -> bool where Self::Item: PartialEq;
-
- /// Returns true if `needle` is a suffix of the slice.
- #[stable]
- fn ends_with(&self, needle: &[Self::Item]) -> bool where Self::Item: PartialEq;
-
- /// Convert `self` into a vector without clones or allocation.
- #[experimental]
- fn into_vec(self: Box<Self>) -> Vec<Self::Item>;
+ fn as_mut_ptr(&mut self) -> *mut T;
}
#[unstable = "trait is unstable"]
-impl<T> SliceExt for [T] {
- type Item = T;
-
+impl<T> SliceExt<T> for [T] {
#[inline]
fn sort_by<F>(&mut self, compare: F) where F: FnMut(&T, &T) -> Ordering {
merge_sort(self, compare)
fn as_mut_ptr(&mut self) -> *mut T {
core_slice::SliceExt::as_mut_ptr(self)
}
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Extension traits for slices over specifc kinds of data
+////////////////////////////////////////////////////////////////////////////////
+
+/// Extension methods for boxed slices.
+#[experimental = "likely to merge into SliceExt if it survives"]
+pub trait BoxedSliceExt<T> {
+ /// Convert `self` into a vector without clones or allocation.
+ #[experimental]
+ fn into_vec(self) -> Vec<T>;
+}
+
+#[experimental = "trait is experimental"]
+impl<T> BoxedSliceExt<T> for Box<[T]> {
+ fn into_vec(mut self) -> Vec<T> {
+ unsafe {
+ let xs = Vec::from_raw_parts(self.as_mut_ptr(), self.len(), self.len());
+ mem::forget(self);
+ xs
+ }
+ }
+}
+
+/// Allocating extension methods for slices containing `Clone` elements.
+#[unstable = "likely to be merged into SliceExt"]
+pub trait CloneSliceExt<T> for Sized? {
+ /// Copies `self` into a new `Vec`.
+ #[stable]
+ fn to_vec(&self) -> Vec<T>;
+
+ /// Deprecated: use `iter().cloned().partition(f)` instead.
+ #[deprecated = "use iter().cloned().partition(f) instead"]
+ fn partitioned<F>(&self, f: F) -> (Vec<T>, Vec<T>) where F: FnMut(&T) -> bool;
+ /// Creates an iterator that yields every possible permutation of the
+ /// vector in succession.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// let v = [1, 2, 3];
+ /// let mut perms = v.permutations();
+ ///
+ /// for p in perms {
+ /// println!("{}", p);
+ /// }
+ /// ```
+ ///
+ /// Iterating through permutations one by one.
+ ///
+ /// ```rust
+ /// let v = [1, 2, 3];
+ /// let mut perms = v.permutations();
+ ///
+ /// assert_eq!(Some(vec![1, 2, 3]), perms.next());
+ /// assert_eq!(Some(vec![1, 3, 2]), perms.next());
+ /// assert_eq!(Some(vec![3, 1, 2]), perms.next());
+ /// ```
+ #[unstable]
+ fn permutations(&self) -> Permutations<T>;
+
+ /// Copies as many elements from `src` as it can into `self` (the
+ /// shorter of `self.len()` and `src.len()`). Returns the number
+ /// of elements copied.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// let mut dst = [0, 0, 0];
+ /// let src = [1, 2];
+ ///
+ /// assert!(dst.clone_from_slice(&src) == 2);
+ /// assert!(dst == [1, 2, 0]);
+ ///
+ /// let src2 = [3, 4, 5, 6];
+ /// assert!(dst.clone_from_slice(&src2) == 3);
+ /// assert!(dst == [3, 4, 5]);
+ /// ```
+ #[experimental]
+ fn clone_from_slice(&mut self, &[T]) -> uint;
+}
+
+
+#[unstable = "trait is unstable"]
+impl<T: Clone> CloneSliceExt<T> for [T] {
/// Returns a copy of `v`.
#[inline]
- fn to_vec(&self) -> Vec<T> where T: Clone {
+ fn to_vec(&self) -> Vec<T> {
let mut vector = Vec::with_capacity(self.len());
vector.push_all(self);
vector
}
+
+ #[inline]
+ fn partitioned<F>(&self, f: F) -> (Vec<T>, Vec<T>) where F: FnMut(&T) -> bool {
+ self.iter().cloned().partition(f)
+ }
+
/// Returns an iterator over all permutations of a vector.
- fn permutations(&self) -> Permutations<T> where T: Clone {
+ fn permutations(&self) -> Permutations<T> {
Permutations{
swaps: ElementSwaps::new(self.len()),
v: self.to_vec(),
}
}
- fn clone_from_slice(&mut self, src: &[T]) -> uint where T: Clone {
- core_slice::SliceExt::clone_from_slice(self, src)
- }
-
- #[inline]
- fn sort(&mut self) where T: Ord {
- self.sort_by(|a, b| a.cmp(b))
+ fn clone_from_slice(&mut self, src: &[T]) -> uint {
+ core_slice::CloneSliceExt::clone_from_slice(self, src)
}
+}
- fn binary_search(&self, x: &T) -> Result<uint, uint> where T: Ord {
- core_slice::SliceExt::binary_search(self, x)
- }
+/// Allocating extension methods for slices on Ord values.
+#[unstable = "likely to merge with SliceExt"]
+pub trait OrdSliceExt<T> for Sized? {
+ /// Sorts the slice, in place.
+ ///
+ /// This is equivalent to `self.sort_by(|a, b| a.cmp(b))`.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// let mut v = [-5, 4, 1, -3, 2];
+ ///
+ /// v.sort();
+ /// assert!(v == [-5, -3, 1, 2, 4]);
+ /// ```
+ #[stable]
+ fn sort(&mut self);
- fn next_permutation(&mut self) -> bool where T: Ord {
- core_slice::SliceExt::next_permutation(self)
- }
+ /// Binary search a sorted slice for a given element.
+ ///
+ /// If the value is found then `Ok` is returned, containing the
+ /// index of the matching element; if the value is not found then
+ /// `Err` is returned, containing the index where a matching
+ /// element could be inserted while maintaining sorted order.
+ ///
+ /// # Example
+ ///
+ /// Looks up a series of four elements. The first is found, with a
+ /// uniquely determined position; the second and third are not
+ /// found; the fourth could match any position in `[1,4]`.
+ ///
+ /// ```rust
+ /// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
+ /// let s = s.as_slice();
+ ///
+ /// assert_eq!(s.binary_search(&13), Ok(9));
+ /// assert_eq!(s.binary_search(&4), Err(7));
+ /// assert_eq!(s.binary_search(&100), Err(13));
+ /// let r = s.binary_search(&1);
+ /// assert!(match r { Ok(1...4) => true, _ => false, });
+ /// ```
+ #[stable]
+ fn binary_search(&self, x: &T) -> Result<uint, uint>;
- fn prev_permutation(&mut self) -> bool where T: Ord {
- core_slice::SliceExt::prev_permutation(self)
+ /// Deprecated: use `binary_search` instead.
+ #[deprecated = "use binary_search instead"]
+ fn binary_search_elem(&self, x: &T) -> Result<uint, uint> {
+ self.binary_search(x)
}
- fn position_elem(&self, t: &T) -> Option<uint> where T: PartialEq {
- core_slice::SliceExt::position_elem(self, t)
- }
+ /// Mutates the slice to the next lexicographic permutation.
+ ///
+ /// Returns `true` if successful and `false` if the slice is at the
+ /// last-ordered permutation.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// let v: &mut [_] = &mut [0, 1, 2];
+ /// v.next_permutation();
+ /// let b: &mut [_] = &mut [0, 2, 1];
+ /// assert!(v == b);
+ /// v.next_permutation();
+ /// let b: &mut [_] = &mut [1, 0, 2];
+ /// assert!(v == b);
+ /// ```
+ #[unstable = "uncertain if this merits inclusion in std"]
+ fn next_permutation(&mut self) -> bool;
- fn rposition_elem(&self, t: &T) -> Option<uint> where T: PartialEq {
- core_slice::SliceExt::rposition_elem(self, t)
- }
+ /// Mutates the slice to the previous lexicographic permutation.
+ ///
+ /// Returns `true` if successful and `false` if the slice is at the
+ /// first-ordered permutation.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// let v: &mut [_] = &mut [1, 0, 2];
+ /// v.prev_permutation();
+ /// let b: &mut [_] = &mut [0, 2, 1];
+ /// assert!(v == b);
+ /// v.prev_permutation();
+ /// let b: &mut [_] = &mut [0, 1, 2];
+ /// assert!(v == b);
+ /// ```
+ #[unstable = "uncertain if this merits inclusion in std"]
+ fn prev_permutation(&mut self) -> bool;
+}
- fn contains(&self, x: &T) -> bool where T: PartialEq {
- core_slice::SliceExt::contains(self, x)
+#[unstable = "trait is unstable"]
+impl<T: Ord> OrdSliceExt<T> for [T] {
+ #[inline]
+ fn sort(&mut self) {
+ self.sort_by(|a, b| a.cmp(b))
}
- fn starts_with(&self, needle: &[T]) -> bool where T: PartialEq {
- core_slice::SliceExt::starts_with(self, needle)
+ fn binary_search(&self, x: &T) -> Result<uint, uint> {
+ core_slice::OrdSliceExt::binary_search(self, x)
}
- fn ends_with(&self, needle: &[T]) -> bool where T: PartialEq {
- core_slice::SliceExt::ends_with(self, needle)
+ fn next_permutation(&mut self) -> bool {
+ core_slice::OrdSliceExt::next_permutation(self)
}
- fn into_vec(mut self: Box<Self>) -> Vec<T> {
- unsafe {
- let xs = Vec::from_raw_parts(self.as_mut_ptr(), self.len(), self.len());
- mem::forget(self);
- xs
- }
+ fn prev_permutation(&mut self) -> bool {
+ core_slice::OrdSliceExt::prev_permutation(self)
}
}
-////////////////////////////////////////////////////////////////////////////////
-// Extension traits for slices over specifc kinds of data
-////////////////////////////////////////////////////////////////////////////////
#[unstable = "U should be an associated type"]
/// An extension trait for concatenating slices
pub trait SliceConcatExt<Sized? T, U> for Sized? {
#[stable]
fn concat(&self) -> U;
+ #[deprecated = "renamed to concat"]
+ fn concat_vec(&self) -> U {
+ self.concat()
+ }
+
/// Flattens a slice of `T` into a single value `U`, placing a
/// given seperator between each.
#[stable]
fn connect(&self, sep: &T) -> U;
+
+ #[deprecated = "renamed to connect"]
+ fn connect_vec(&self, sep: &T) -> U {
+ self.connect(sep)
+ }
}
impl<T: Clone, V: AsSlice<T>> SliceConcatExt<T, Vec<T>> for [V] {
/// The last generated swap is always (0, 1), and it returns the
/// sequence to its initial order.
#[experimental]
-#[derive(Clone)]
+#[deriving(Clone)]
pub struct ElementSwaps {
sdir: Vec<SizeDirection>,
/// If `true`, emit the last swap that returns the sequence to initial
// Iterators
////////////////////////////////////////////////////////////////////////////////
-#[derive(Copy, Clone)]
+#[deriving(Copy, Clone)]
enum Direction { Pos, Neg }
/// An `Index` and `Direction` together.
-#[derive(Copy, Clone)]
+#[deriving(Copy, Clone)]
struct SizeDirection {
size: uint,
dir: Direction,
}
-impl Iterator for ElementSwaps {
- type Item = (uint, uint);
-
+impl Iterator<(uint, uint)> for ElementSwaps {
#[inline]
fn next(&mut self) -> Option<(uint, uint)> {
fn new_pos(i: uint, s: Direction) -> uint {
}
#[unstable = "trait is unstable"]
-impl<T: Clone> Iterator for Permutations<T> {
- type Item = Vec<T>;
-
+impl<T: Clone> Iterator<Vec<T>> for Permutations<T> {
#[inline]
fn next(&mut self) -> Option<Vec<T>> {
match self.swaps.next() {
}
}
+/// Deprecated, unsafe operations
+#[deprecated]
+pub mod raw {
+ pub use core::slice::raw::{buf_as_slice, mut_buf_as_slice};
+ pub use core::slice::raw::{shift_ptr, pop_ptr};
+}
+
#[cfg(test)]
mod tests {
+ use std::boxed::Box;
use prelude::{Some, None, range, Vec, ToString, Clone, Greater, Less, Equal};
- use prelude::{SliceExt, Iterator, IteratorExt};
- use prelude::AsSlice;
+ use prelude::{SliceExt, Iterator, IteratorExt, DoubleEndedIteratorExt};
+ use prelude::{OrdSliceExt, CloneSliceExt, PartialEqSliceExt, AsSlice};
use prelude::{RandomAccessIterator, Ord, SliceConcatExt};
+ use core::cell::Cell;
use core::default::Default;
use core::mem;
use std::rand::{Rng, thread_rng};
#[test]
fn test_from_fn() {
// Test on-stack from_fn.
- let mut v = range(0, 3).map(square).collect::<Vec<_>>();
+ let mut v = Vec::from_fn(3u, square);
{
let v = v.as_slice();
assert_eq!(v.len(), 3u);
}
// Test on-heap from_fn.
- v = range(0, 5).map(square).collect::<Vec<_>>();
+ v = Vec::from_fn(5u, square);
{
let v = v.as_slice();
assert_eq!(v.len(), 5u);
#[test]
fn test_from_elem() {
// Test on-stack from_elem.
- let mut v = vec![10u, 10u];
+ let mut v = Vec::from_elem(2u, 10u);
{
let v = v.as_slice();
assert_eq!(v.len(), 2u);
}
// Test on-heap from_elem.
- v = vec![20u, 20u, 20u, 20u, 20u, 20u];
+ v = Vec::from_elem(6u, 20u);
{
let v = v.as_slice();
assert_eq!(v[0], 20u);
}
#[test]
- fn test_first() {
+ fn test_head() {
let mut a = vec![];
- assert_eq!(a.as_slice().first(), None);
+ assert_eq!(a.as_slice().head(), None);
a = vec![11i];
- assert_eq!(a.as_slice().first().unwrap(), &11);
+ assert_eq!(a.as_slice().head().unwrap(), &11);
a = vec![11i, 12];
- assert_eq!(a.as_slice().first().unwrap(), &11);
+ assert_eq!(a.as_slice().head().unwrap(), &11);
}
#[test]
- fn test_first_mut() {
+ fn test_head_mut() {
let mut a = vec![];
- assert_eq!(a.first_mut(), None);
+ assert_eq!(a.head_mut(), None);
a = vec![11i];
- assert_eq!(*a.first_mut().unwrap(), 11);
+ assert_eq!(*a.head_mut().unwrap(), 11);
a = vec![11i, 12];
- assert_eq!(*a.first_mut().unwrap(), 11);
+ assert_eq!(*a.head_mut().unwrap(), 11);
}
#[test]
assert_eq!(v.as_slice()[1], 2);
}
+ #[test]
+ fn test_grow() {
+ // Test on-stack grow().
+ let mut v = vec![];
+ v.grow(2u, 1i);
+ {
+ let v = v.as_slice();
+ assert_eq!(v.len(), 2u);
+ assert_eq!(v[0], 1);
+ assert_eq!(v[1], 1);
+ }
+
+ // Test on-heap grow().
+ v.grow(3u, 2i);
+ {
+ let v = v.as_slice();
+ assert_eq!(v.len(), 5u);
+ assert_eq!(v[0], 1);
+ assert_eq!(v[1], 1);
+ assert_eq!(v[2], 2);
+ assert_eq!(v[3], 2);
+ assert_eq!(v[4], 2);
+ }
+ }
+
+ #[test]
+ fn test_grow_fn() {
+ let mut v = vec![];
+ v.grow_fn(3u, square);
+ let v = v.as_slice();
+ assert_eq!(v.len(), 3u);
+ assert_eq!(v[0], 0u);
+ assert_eq!(v[1], 1u);
+ assert_eq!(v[2], 4u);
+ }
+
#[test]
fn test_truncate() {
let mut v = vec![box 6i,box 5,box 4];
}
}
+ #[test]
+ fn test_partition() {
+ assert_eq!((vec![]).partition(|x: &int| *x < 3), (vec![], vec![]));
+ assert_eq!((vec![1i, 2, 3]).partition(|x: &int| *x < 4), (vec![1, 2, 3], vec![]));
+ assert_eq!((vec![1i, 2, 3]).partition(|x: &int| *x < 2), (vec![1], vec![2, 3]));
+ assert_eq!((vec![1i, 2, 3]).partition(|x: &int| *x < 0), (vec![], vec![1, 2, 3]));
+ }
+
+ #[test]
+ fn test_partitioned() {
+ assert_eq!(([]).partitioned(|x: &int| *x < 3), (vec![], vec![]));
+ assert_eq!(([1i, 2, 3]).partitioned(|x: &int| *x < 4), (vec![1, 2, 3], vec![]));
+ assert_eq!(([1i, 2, 3]).partitioned(|x: &int| *x < 2), (vec![1], vec![2, 3]));
+ assert_eq!(([1i, 2, 3]).partitioned(|x: &int| *x < 0), (vec![], vec![1, 2, 3]));
+ }
+
#[test]
fn test_concat() {
let v: [Vec<int>; 0] = [];
#[test]
fn test_connect() {
let v: [Vec<int>; 0] = [];
- assert_eq!(v.connect(&0), vec![]);
- assert_eq!([vec![1i], vec![2i, 3]].connect(&0), vec![1, 0, 2, 3]);
- assert_eq!([vec![1i], vec![2i], vec![3i]].connect(&0), vec![1, 0, 2, 0, 3]);
+ assert_eq!(v.connect_vec(&0), vec![]);
+ assert_eq!([vec![1i], vec![2i, 3]].connect_vec(&0), vec![1, 0, 2, 3]);
+ assert_eq!([vec![1i], vec![2i], vec![3i]].connect_vec(&0), vec![1, 0, 2, 0, 3]);
let v: [&[int]; 2] = [&[1], &[2, 3]];
- assert_eq!(v.connect(&0), vec![1, 0, 2, 3]);
+ assert_eq!(v.connect_vec(&0), vec![1, 0, 2, 3]);
let v: [&[int]; 3] = [&[1], &[2], &[3]];
- assert_eq!(v.connect(&0), vec![1, 0, 2, 0, 3]);
+ assert_eq!(v.connect_vec(&0), vec![1, 0, 2, 0, 3]);
}
#[test]
assert_eq!(v[1], 3);
}
+
+ #[test]
+ #[should_fail]
+ fn test_from_fn_fail() {
+ Vec::from_fn(100, |v| {
+ if v == 50 { panic!() }
+ box 0i
+ });
+ }
+
+ #[test]
+ #[should_fail]
+ fn test_from_elem_fail() {
+
+ struct S {
+ f: Cell<int>,
+ boxes: (Box<int>, Rc<int>)
+ }
+
+ impl Clone for S {
+ fn clone(&self) -> S {
+ self.f.set(self.f.get() + 1);
+ if self.f.get() == 10 { panic!() }
+ S {
+ f: self.f.clone(),
+ boxes: self.boxes.clone(),
+ }
+ }
+ }
+
+ let s = S {
+ f: Cell::new(0),
+ boxes: (box 0, Rc::new(0)),
+ };
+ let _ = Vec::from_elem(100, s);
+ }
+
+ #[test]
+ #[should_fail]
+ fn test_grow_fn_fail() {
+ let mut v = vec![];
+ v.grow_fn(100, |i| {
+ if i == 50 {
+ panic!()
+ }
+ (box 0i, Rc::new(0i))
+ })
+ }
+
#[test]
#[should_fail]
fn test_permute_fail() {
assert!(values == [2, 3, 5, 6, 7]);
}
- #[derive(Clone, PartialEq)]
+ #[deriving(Clone, PartialEq)]
struct Foo;
#[test]
use prelude::*;
use core::mem;
use core::ptr;
- use core::iter::repeat;
use std::rand::{weak_rng, Rng};
use test::{Bencher, black_box};
fn iterator(b: &mut Bencher) {
// peculiar numbers to stop LLVM from optimising the summation
// out.
- let v = range(0u, 100).map(|i| i ^ (i << 1) ^ (i >> 1)).collect::<Vec<_>>();
+ let v = Vec::from_fn(100, |i| i ^ (i << 1) ^ (i >> 1));
b.iter(|| {
let mut sum = 0;
#[bench]
fn mut_iterator(b: &mut Bencher) {
- let mut v = repeat(0i).take(100).collect::<Vec<_>>();
+ let mut v = Vec::from_elem(100, 0i);
b.iter(|| {
let mut i = 0i;
#[bench]
fn concat(b: &mut Bencher) {
let xss: Vec<Vec<uint>> =
- range(0, 100u).map(|i| range(0, i).collect()).collect();
+ Vec::from_fn(100, |i| range(0u, i).collect());
b.iter(|| {
xss.as_slice().concat();
});
#[bench]
fn connect(b: &mut Bencher) {
let xss: Vec<Vec<uint>> =
- range(0, 100u).map(|i| range(0, i).collect()).collect();
+ Vec::from_fn(100, |i| range(0u, i).collect());
b.iter(|| {
- xss.as_slice().connect(&0)
+ xss.as_slice().connect_vec(&0)
});
}
#[bench]
fn starts_with_same_vector(b: &mut Bencher) {
- let vec: Vec<uint> = range(0, 100).collect();
+ let vec: Vec<uint> = Vec::from_fn(100, |i| i);
b.iter(|| {
vec.as_slice().starts_with(vec.as_slice())
})
#[bench]
fn starts_with_diff_one_element_at_end(b: &mut Bencher) {
- let vec: Vec<uint> = range(0, 100).collect();
- let mut match_vec: Vec<uint> = range(0, 99).collect();
+ let vec: Vec<uint> = Vec::from_fn(100, |i| i);
+ let mut match_vec: Vec<uint> = Vec::from_fn(99, |i| i);
match_vec.push(0);
b.iter(|| {
vec.as_slice().starts_with(match_vec.as_slice())
#[bench]
fn ends_with_same_vector(b: &mut Bencher) {
- let vec: Vec<uint> = range(0, 100).collect();
+ let vec: Vec<uint> = Vec::from_fn(100, |i| i);
b.iter(|| {
vec.as_slice().ends_with(vec.as_slice())
})
#[bench]
fn ends_with_diff_one_element_at_beginning(b: &mut Bencher) {
- let vec: Vec<uint> = range(0, 100).collect();
- let mut match_vec: Vec<uint> = range(0, 100).collect();
+ let vec: Vec<uint> = Vec::from_fn(100, |i| i);
+ let mut match_vec: Vec<uint> = Vec::from_fn(100, |i| i);
match_vec.as_mut_slice()[0] = 200;
b.iter(|| {
vec.as_slice().starts_with(match_vec.as_slice())
#[bench]
fn contains_last_element(b: &mut Bencher) {
- let vec: Vec<uint> = range(0, 100).collect();
+ let vec: Vec<uint> = Vec::from_fn(100, |i| i);
b.iter(|| {
vec.contains(&99u)
})
#[bench]
fn zero_1kb_from_elem(b: &mut Bencher) {
b.iter(|| {
- repeat(0u8).take(1024).collect::<Vec<_>>()
+ Vec::from_elem(1024, 0u8)
});
}
fn random_inserts(b: &mut Bencher) {
let mut rng = weak_rng();
b.iter(|| {
- let mut v = repeat((0u, 0u)).take(30).collect::<Vec<_>>();
- for _ in range(0u, 100) {
- let l = v.len();
- v.insert(rng.gen::<uint>() % (l + 1),
- (1, 1));
- }
- })
+ let mut v = Vec::from_elem(30, (0u, 0u));
+ for _ in range(0u, 100) {
+ let l = v.len();
+ v.insert(rng.gen::<uint>() % (l + 1),
+ (1, 1));
+ }
+ })
}
#[bench]
fn random_removes(b: &mut Bencher) {
let mut rng = weak_rng();
b.iter(|| {
- let mut v = repeat((0u, 0u)).take(130).collect::<Vec<_>>();
- for _ in range(0u, 100) {
- let l = v.len();
- v.remove(rng.gen::<uint>() % l);
- }
- })
+ let mut v = Vec::from_elem(130, (0u, 0u));
+ for _ in range(0u, 100) {
+ let l = v.len();
+ v.remove(rng.gen::<uint>() % l);
+ }
+ })
}
#[bench]
#[bench]
fn sort_sorted(b: &mut Bencher) {
- let mut v = range(0u, 10000).collect::<Vec<_>>();
+ let mut v = Vec::from_fn(10000, |i| i);
b.iter(|| {
v.sort();
});
#[bench]
fn sort_big_sorted(b: &mut Bencher) {
- let mut v = range(0, 10000u).map(|i| (i, i, i, i)).collect::<Vec<_>>();
+ let mut v = Vec::from_fn(10000u, |i| (i, i, i, i));
b.iter(|| {
v.sort();
});
use self::DecompositionType::*;
use core::borrow::{BorrowFrom, ToOwned};
-use core::char::Char;
+use core::char::CharExt;
use core::clone::Clone;
use core::iter::AdditiveIterator;
use core::iter::{range, Iterator, IteratorExt};
}
}
- /// Creates a `String` from a null-terminated `*const u8` buffer.
- ///
- /// This function is unsafe because we dereference memory until we find the
- /// NUL character, which is not guaranteed to be present. Additionally, the
- /// slice is not checked to see whether it contains valid UTF-8
- #[unstable = "just renamed from `mod raw`"]
- pub unsafe fn from_raw_buf(buf: *const u8) -> String {
- String::from_str(str::from_c_str(buf as *const i8))
- }
-
- /// Creates a `String` from a `*const u8` buffer of the given length.
- ///
- /// This function is unsafe because it blindly assumes the validity of the
- /// pointer `buf` for `len` bytes of memory. This function will copy the
- /// memory from `buf` into a new allocation (owned by the returned
- /// `String`).
- ///
- /// This function is also unsafe because it does not validate that the
- /// buffer is valid UTF-8 encoded data.
- #[unstable = "just renamed from `mod raw`"]
- pub unsafe fn from_raw_buf_len(buf: *const u8, len: uint) -> String {
- String::from_utf8_unchecked(Vec::from_raw_buf(buf, len))
- }
-
/// Converts a vector of bytes to a new `String` without checking if
/// it contains valid UTF-8. This is unsafe because it assumes that
/// the UTF-8-ness of the vector has already been validated.
String::from_str("\u{FFFD}𐒋\u{FFFD}"));
}
- #[test]
- fn test_from_buf_len() {
- unsafe {
- let a = vec![65u8, 65, 65, 65, 65, 65, 65, 0];
- assert_eq!(String::from_raw_buf_len(a.as_ptr(), 3), String::from_str("AAA"));
- }
- }
-
- #[test]
- fn test_from_buf() {
- unsafe {
- let a = vec![65, 65, 65, 65, 65, 65, 65, 0];
- let b = a.as_ptr();
- let c = String::from_raw_buf(b);
- assert_eq!(c, String::from_str("AAAAAAA"));
- }
- }
-
#[test]
fn test_push_bytes() {
let mut s = String::from_str("ABC");
//! ```
//! let ys: Vec<i32> = vec![];
//!
-//! let zs = vec![1i32, 2, 3, 4, 5];
+//! let zs = vec![1, 2, 3, 4, 5];
//! ```
//!
//! Push:
//!
//! ```
-//! let mut xs = vec![1i32, 2];
+//! let mut xs = vec![1, 2];
//!
//! xs.push(3);
//! ```
//! And pop:
//!
//! ```
-//! let mut xs = vec![1i32, 2];
+//! let mut xs = vec![1, 2];
//!
//! let two = xs.pop();
//! ```
///
/// ```
/// let mut vec = Vec::new();
-/// vec.push(1i);
-/// vec.push(2i);
+/// vec.push(1);
+/// vec.push(2);
///
/// assert_eq!(vec.len(), 2);
/// assert_eq!(vec[0], 1);
/// assert_eq!(vec.pop(), Some(2));
/// assert_eq!(vec.len(), 1);
///
-/// vec[0] = 7i;
+/// vec[0] = 7;
/// assert_eq!(vec[0], 7);
///
/// vec.push_all(&[1, 2, 3]);
/// for x in vec.iter() {
/// println!("{}", x);
/// }
-/// assert_eq!(vec, vec![7i, 1, 2, 3]);
+/// assert_eq!(vec, vec![7, 1, 2, 3]);
/// ```
///
/// The `vec!` macro is provided to make initialization more convenient:
///
/// ```
-/// let mut vec = vec![1i, 2i, 3i];
+/// let mut vec = vec![1, 2, 3];
/// vec.push(4);
/// assert_eq!(vec, vec![1, 2, 3, 4]);
/// ```
/// ```
/// let mut stack = Vec::new();
///
-/// stack.push(1i);
-/// stack.push(2i);
-/// stack.push(3i);
+/// stack.push(1);
+/// stack.push(2);
+/// stack.push(3);
///
/// loop {
/// let top = match stack.pop() {
/// use std::mem;
///
/// fn main() {
- /// let mut v = vec![1i, 2, 3];
+ /// let mut v = vec![1, 2, 3];
///
/// // Pull out the various important pieces of information about `v`
/// let p = v.as_mut_ptr();
///
/// // Put everything back together into a Vec
/// let rebuilt = Vec::from_raw_parts(p, len, cap);
- /// assert_eq!(rebuilt, vec![4i, 5i, 6i]);
+ /// assert_eq!(rebuilt, vec![4, 5, 6]);
/// }
/// }
/// ```
/// # Examples
///
/// ```
- /// let mut vec = vec![1i, 2, 3, 4];
+ /// let mut vec = vec![1, 2, 3, 4];
/// vec.truncate(2);
/// assert_eq!(vec, vec![1, 2]);
/// ```
/// ```
/// fn foo(slice: &mut [int]) {}
///
- /// let mut vec = vec![1i, 2];
+ /// let mut vec = vec![1, 2];
/// foo(vec.as_mut_slice());
/// ```
#[inline]
/// # Examples
///
/// ```
- /// let mut vec = vec![1i, 2, 3];
+ /// let mut vec = vec![1, 2, 3];
/// vec.insert(1, 4);
/// assert_eq!(vec, vec![1, 4, 2, 3]);
/// vec.insert(4, 5);
/// # Examples
///
/// ```
- /// let mut v = vec![1i, 2, 3];
+ /// let mut v = vec![1, 2, 3];
/// assert_eq!(v.remove(1), 2);
/// assert_eq!(v, vec![1, 3]);
/// ```
/// # Examples
///
/// ```
- /// let mut vec = vec![1i, 2, 3, 4];
+ /// let mut vec = vec![1, 2, 3, 4];
/// vec.retain(|&x| x%2 == 0);
/// assert_eq!(vec, vec![2, 4]);
/// ```
/// # Examples
///
/// ```rust
- /// let mut vec = vec!(1i, 2);
+ /// let mut vec = vec!(1, 2);
/// vec.push(3);
/// assert_eq!(vec, vec!(1, 2, 3));
/// ```
/// # Examples
///
/// ```rust
- /// let mut vec = vec![1i, 2, 3];
+ /// let mut vec = vec![1, 2, 3];
/// assert_eq!(vec.pop(), Some(3));
/// assert_eq!(vec, vec![1, 2]);
/// ```
/// # Examples
///
/// ```
- /// let mut v = vec![1i, 2, 3];
+ /// let mut v = vec![1, 2, 3];
///
/// v.clear();
///
/// # Examples
///
/// ```
- /// let a = vec![1i, 2, 3];
+ /// let a = vec![1, 2, 3];
/// assert_eq!(a.len(), 3);
/// ```
#[inline]
/// let mut v = Vec::new();
/// assert!(v.is_empty());
///
- /// v.push(1i);
+ /// v.push(1);
/// assert!(!v.is_empty());
/// ```
#[stable]
/// vec.resize(3, "world");
/// assert_eq!(vec, vec!["hello", "world", "world"]);
///
- /// let mut vec = vec![1i, 2, 3, 4];
+ /// let mut vec = vec![1, 2, 3, 4];
/// vec.resize(2, 0);
/// assert_eq!(vec, vec![1, 2]);
/// ```
/// # Examples
///
/// ```
- /// let mut vec = vec![1i];
- /// vec.push_all(&[2i, 3, 4]);
+ /// let mut vec = vec![1];
+ /// vec.push_all(&[2, 3, 4]);
/// assert_eq!(vec, vec![1, 2, 3, 4]);
/// ```
#[inline]
/// # Examples
///
/// ```
- /// let mut vec = vec![1i, 2, 2, 3, 2];
+ /// let mut vec = vec![1, 2, 2, 3, 2];
///
/// vec.dedup();
///
- /// assert_eq!(vec, vec![1i, 2, 3, 2]);
+ /// assert_eq!(vec, vec![1, 2, 3, 2]);
/// ```
#[stable]
pub fn dedup(&mut self) {
}
}
-// NOTE(stage0): remove impl after a snapshot
-#[cfg(stage0)]
-#[experimental = "waiting on Index stability"]
-impl<T> Index<uint,T> for Vec<T> {
- #[inline]
- fn index<'a>(&'a self, index: &uint) -> &'a T {
- &self.as_slice()[*index]
- }
-}
-
-#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot
#[experimental = "waiting on Index stability"]
impl<T> Index<uint> for Vec<T> {
type Output = T;
}
}
-// NOTE(stage0): remove impl after a snapshot
-#[cfg(stage0)]
-impl<T> IndexMut<uint,T> for Vec<T> {
- #[inline]
- fn index_mut<'a>(&'a mut self, index: &uint) -> &'a mut T {
- &mut self.as_mut_slice()[*index]
- }
-}
-
-#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot
impl<T> IndexMut<uint> for Vec<T> {
type Output = T;
/// ```
/// fn foo(slice: &[int]) {}
///
- /// let vec = vec![1i, 2];
+ /// let vec = vec![1, 2];
/// foo(vec.as_slice());
/// ```
#[inline]
}
}
-// NOTE(stage0): remove impl after a snapshot
-#[cfg(stage0)]
-#[stable]
-impl<V> Index<uint, V> for VecMap<V> {
- #[inline]
- fn index<'a>(&'a self, i: &uint) -> &'a V {
- self.get(i).expect("key not present")
- }
-}
-
-#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot
impl<V> Index<uint> for VecMap<V> {
type Output = V;
}
}
-// NOTE(stage0): remove impl after a snapshot
-#[cfg(stage0)]
-#[stable]
-impl<V> IndexMut<uint, V> for VecMap<V> {
- #[inline]
- fn index_mut<'a>(&'a mut self, i: &uint) -> &'a mut V {
- self.get_mut(i).expect("key not present")
- }
-}
-
-#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot
#[stable]
impl<V> IndexMut<uint> for VecMap<V> {
type Output = V;
//!
//! ```rust
//! use std::fmt::Show;
-//! use std::any::{Any, AnyRefExt};
+//! use std::any::Any;
//!
//! // Logger function for any type that implements Show.
//! fn log<T: Any+Show>(value: &T) {
// Implemented as three extension traits so that the methods can be generic.
///////////////////////////////////////////////////////////////////////////////
-/// Extension methods for a referenced `Any` trait object
-#[unstable = "this trait will not be necessary once DST lands, it will be a \
- part of `impl Any`"]
-pub trait AnyRefExt<'a> {
+impl Any {
/// Returns true if the boxed type is the same as `T`
#[stable]
- fn is<T: 'static>(self) -> bool;
-
- /// Returns some reference to the boxed value if it is of type `T`, or
- /// `None` if it isn't.
- #[unstable = "naming conventions around acquiring references may change"]
- fn downcast_ref<T: 'static>(self) -> Option<&'a T>;
-}
-
-#[stable]
-impl<'a> AnyRefExt<'a> for &'a Any {
#[inline]
- fn is<T: 'static>(self) -> bool {
+ pub fn is<T: 'static>(&self) -> bool {
// Get TypeId of the type this function is instantiated with
let t = TypeId::of::<T>();
t == boxed
}
+ /// Returns some reference to the boxed value if it is of type `T`, or
+ /// `None` if it isn't.
+ #[unstable = "naming conventions around acquiring references may change"]
#[inline]
- fn downcast_ref<T: 'static>(self) -> Option<&'a T> {
+ pub fn downcast_ref<'a, T: 'static>(&'a self) -> Option<&'a T> {
if self.is::<T>() {
unsafe {
// Get the raw representation of the trait object
None
}
}
-}
-/// Extension methods for a mutable referenced `Any` trait object
-#[unstable = "this trait will not be necessary once DST lands, it will be a \
- part of `impl Any`"]
-pub trait AnyMutRefExt<'a> {
/// Returns some mutable reference to the boxed value if it is of type `T`, or
/// `None` if it isn't.
#[unstable = "naming conventions around acquiring references may change"]
- fn downcast_mut<T: 'static>(self) -> Option<&'a mut T>;
-}
-
-#[stable]
-impl<'a> AnyMutRefExt<'a> for &'a mut Any {
#[inline]
- fn downcast_mut<T: 'static>(self) -> Option<&'a mut T> {
+ pub fn downcast_mut<'a, T: 'static>(&'a mut self) -> Option<&'a mut T> {
if self.is::<T>() {
unsafe {
// Get the raw representation of the trait object
/// ```
/// use std::sync::atomic::AtomicPtr;
///
- /// let ptr = &mut 5i;
+ /// let ptr = &mut 5;
/// let atomic_ptr = AtomicPtr::new(ptr);
/// ```
#[inline]
/// ```
/// use std::sync::atomic::{AtomicPtr, Ordering};
///
- /// let ptr = &mut 5i;
+ /// let ptr = &mut 5;
/// let some_ptr = AtomicPtr::new(ptr);
///
/// let value = some_ptr.load(Ordering::Relaxed);
/// ```
/// use std::sync::atomic::{AtomicPtr, Ordering};
///
- /// let ptr = &mut 5i;
+ /// let ptr = &mut 5;
/// let some_ptr = AtomicPtr::new(ptr);
///
- /// let other_ptr = &mut 10i;
+ /// let other_ptr = &mut 10;
///
/// some_ptr.store(other_ptr, Ordering::Relaxed);
/// ```
/// ```
/// use std::sync::atomic::{AtomicPtr, Ordering};
///
- /// let ptr = &mut 5i;
+ /// let ptr = &mut 5;
/// let some_ptr = AtomicPtr::new(ptr);
///
- /// let other_ptr = &mut 10i;
+ /// let other_ptr = &mut 10;
///
/// let value = some_ptr.swap(other_ptr, Ordering::Relaxed);
/// ```
/// ```
/// use std::sync::atomic::{AtomicPtr, Ordering};
///
- /// let ptr = &mut 5i;
+ /// let ptr = &mut 5;
/// let some_ptr = AtomicPtr::new(ptr);
///
- /// let other_ptr = &mut 10i;
- /// let another_ptr = &mut 10i;
+ /// let other_ptr = &mut 10;
+ /// let another_ptr = &mut 10;
///
/// let value = some_ptr.compare_and_swap(other_ptr, another_ptr, Ordering::Relaxed);
/// ```
/// Converts from `u32` to a `char`
#[inline]
-#[unstable = "pending decisions about costructors for primitives"]
+#[stable]
pub fn from_u32(i: u32) -> Option<char> {
// catch out-of-bounds and surrogates
if (i > MAX as u32) || (i >= 0xD800 && i <= 0xDFFF) {
/// Panics if given an `radix` > 36.
///
#[inline]
-#[unstable = "pending decisions about costructors for primitives"]
+#[unstable = "pending integer conventions"]
pub fn from_digit(num: uint, radix: uint) -> Option<char> {
if radix > 36 {
panic!("from_digit: radix is too high (maximum 36)");
}
/// Basic `char` manipulations.
-#[experimental = "trait organization may change"]
-pub trait Char {
+#[stable]
+pub trait CharExt {
/// Checks if a `char` parses as a numeric digit in the given radix.
///
/// Compared to `is_numeric()`, this function only recognizes the characters
/// # Panics
///
/// Panics if given a radix > 36.
- #[unstable = "pending error conventions"]
+ #[unstable = "pending integer conventions"]
fn is_digit(self, radix: uint) -> bool;
/// Converts a character to the corresponding digit.
/// # Panics
///
/// Panics if given a radix outside the range [0..36].
- #[unstable = "pending error conventions, trait organization"]
+ #[unstable = "pending integer conventions"]
fn to_digit(self, radix: uint) -> Option<uint>;
/// Returns an iterator that yields the hexadecimal Unicode escape
/// All characters are escaped with Rust syntax of the form `\\u{NNNN}`
/// where `NNNN` is the shortest hexadecimal representation of the code
/// point.
- #[unstable = "pending error conventions, trait organization"]
+ #[stable]
fn escape_unicode(self) -> EscapeUnicode;
/// Returns an iterator that yields the 'default' ASCII and
/// escaped.
/// * Any other chars in the range [0x20,0x7e] are not escaped.
/// * Any other chars are given hex Unicode escapes; see `escape_unicode`.
- #[unstable = "pending error conventions, trait organization"]
+ #[stable]
fn escape_default(self) -> EscapeDefault;
/// Returns the amount of bytes this character would need if encoded in
/// UTF-8.
- #[unstable = "pending trait organization"]
+ #[stable]
fn len_utf8(self) -> uint;
/// Returns the amount of bytes this character would need if encoded in
/// UTF-16.
- #[unstable = "pending trait organization"]
+ #[stable]
fn len_utf16(self) -> uint;
/// Encodes this character as UTF-8 into the provided byte buffer,
///
/// If the buffer is not large enough, nothing will be written into it
/// and a `None` will be returned.
- #[unstable = "pending trait organization"]
- fn encode_utf8(&self, dst: &mut [u8]) -> Option<uint>;
+ #[stable]
+ fn encode_utf8(self, dst: &mut [u8]) -> Option<uint>;
/// Encodes this character as UTF-16 into the provided `u16` buffer,
/// and then returns the number of `u16`s written.
///
/// If the buffer is not large enough, nothing will be written into it
/// and a `None` will be returned.
- #[unstable = "pending trait organization"]
- fn encode_utf16(&self, dst: &mut [u16]) -> Option<uint>;
+ #[stable]
+ fn encode_utf16(self, dst: &mut [u16]) -> Option<uint>;
}
-#[experimental = "trait is experimental"]
-impl Char for char {
- #[unstable = "pending trait organization"]
+#[stable]
+impl CharExt for char {
+ #[unstable = "pending integer conventions"]
fn is_digit(self, radix: uint) -> bool {
- match self.to_digit(radix) {
- Some(_) => true,
- None => false,
- }
+ self.to_digit(radix).is_some()
}
- #[unstable = "pending trait organization"]
+ #[unstable = "pending integer conventions"]
fn to_digit(self, radix: uint) -> Option<uint> {
if radix > 36 {
panic!("to_digit: radix is too high (maximum 36)");
else { None }
}
- #[unstable = "pending error conventions, trait organization"]
+ #[stable]
fn escape_unicode(self) -> EscapeUnicode {
EscapeUnicode { c: self, state: EscapeUnicodeState::Backslash }
}
- #[unstable = "pending error conventions, trait organization"]
+ #[stable]
fn escape_default(self) -> EscapeDefault {
let init_state = match self {
'\t' => EscapeDefaultState::Backslash('t'),
}
#[inline]
- #[unstable = "pending trait organization"]
+ #[stable]
fn len_utf8(self) -> uint {
let code = self as u32;
match () {
}
#[inline]
- #[unstable = "pending trait organization"]
+ #[stable]
fn len_utf16(self) -> uint {
let ch = self as u32;
if (ch & 0xFFFF_u32) == ch { 1 } else { 2 }
}
#[inline]
- #[unstable = "pending error conventions, trait organization"]
- fn encode_utf8<'a>(&self, dst: &'a mut [u8]) -> Option<uint> {
+ #[unstable = "pending decision about Iterator/Writer/Reader"]
+ fn encode_utf8(self, dst: &mut [u8]) -> Option<uint> {
// Marked #[inline] to allow llvm optimizing it away
- let code = *self as u32;
+ let code = self as u32;
if code < MAX_ONE_B && dst.len() >= 1 {
dst[0] = code as u8;
Some(1)
}
#[inline]
- #[unstable = "pending error conventions, trait organization"]
- fn encode_utf16(&self, dst: &mut [u16]) -> Option<uint> {
+ #[unstable = "pending decision about Iterator/Writer/Reader"]
+ fn encode_utf16(self, dst: &mut [u16]) -> Option<uint> {
// Marked #[inline] to allow llvm optimizing it away
- let mut ch = *self as u32;
+ let mut ch = self as u32;
if (ch & 0xFFFF_u32) == ch && dst.len() >= 1 {
// The BMP falls through (assuming non-surrogate, as it should)
dst[0] = ch as u16;
/// An iterator over the characters that represent a `char`, as escaped by
/// Rust's unicode escaping rules.
#[derive(Clone)]
+#[stable]
pub struct EscapeUnicode {
c: char,
state: EscapeUnicodeState
Done,
}
+#[stable]
impl Iterator for EscapeUnicode {
type Item = char;
/// An iterator over the characters that represent a `char`, escaped
/// for maximum portability.
#[derive(Clone)]
+#[stable]
pub struct EscapeDefault {
state: EscapeDefaultState
}
Unicode(EscapeUnicode),
}
+#[stable]
impl Iterator for EscapeDefault {
type Item = char;
pub use self::SignFormat::*;
use char;
-use char::Char;
+use char::CharExt;
use fmt;
use iter::{IteratorExt, range};
use num::{cast, Float, ToPrimitive};
prefix: &str,
buf: &str)
-> Result {
- use char::Char;
+ use char::CharExt;
use fmt::rt::{FlagAlternate, FlagSignPlus, FlagSignAwareZeroPad};
let mut width = buf.len();
fn with_padding<F>(&mut self, padding: uint, default: rt::Alignment, f: F) -> Result where
F: FnOnce(&mut Formatter) -> Result,
{
- use char::Char;
+ use char::CharExt;
let align = match self.align {
rt::AlignUnknown => default,
_ => self.align
impl Show for char {
fn fmt(&self, f: &mut Formatter) -> Result {
- use char::Char;
+ use char::CharExt;
let mut utf8 = [0u8; 4];
let amt = self.encode_utf8(&mut utf8).unwrap_or(0);
///
/// ```
/// use std::fmt::radix;
-/// assert_eq!(format!("{}", radix(55i, 36)), "1j".to_string());
+/// assert_eq!(format!("{}", radix(55, 36)), "1j".to_string());
/// ```
#[unstable = "may be renamed or move to a different module"]
pub fn radix<T>(x: T, base: u8) -> RadixFmt<T, Radix> {
//! translated to the `loop` below.
//!
//! ```rust
-//! let values = vec![1i, 2, 3];
+//! let values = vec![1, 2, 3];
//!
//! // "Syntactical sugar" taking advantage of an iterator
//! for &x in values.iter() {
/// # Example
///
/// ```rust
- /// let a = [0i];
- /// let b = [1i];
+ /// let a = [0];
+ /// let b = [1];
/// let mut it = a.iter().chain(b.iter());
/// assert_eq!(it.next().unwrap(), &0);
/// assert_eq!(it.next().unwrap(), &1);
/// # Example
///
/// ```rust
- /// let a = [0i];
- /// let b = [1i];
+ /// let a = [0];
+ /// let b = [1];
/// let mut it = a.iter().zip(b.iter());
- /// let (x0, x1) = (0i, 1i);
+ /// let (x0, x1) = (0, 1);
/// assert_eq!(it.next().unwrap(), (&x0, &x1));
/// assert!(it.next().is_none());
/// ```
/// # Example
///
/// ```rust
- /// let a = [1i, 2];
+ /// let a = [1, 2];
/// let mut it = a.iter().map(|&x| 2 * x);
/// assert_eq!(it.next().unwrap(), 2);
/// assert_eq!(it.next().unwrap(), 4);
/// # Example
///
/// ```rust
- /// let a = [1i, 2];
+ /// let a = [1, 2];
/// let mut it = a.iter().filter(|&x| *x > 1);
/// assert_eq!(it.next().unwrap(), &2);
/// assert!(it.next().is_none());
/// # Example
///
/// ```rust
- /// let a = [1i, 2];
+ /// let a = [1, 2];
/// let mut it = a.iter().filter_map(|&x| if x > 1 {Some(2 * x)} else {None});
/// assert_eq!(it.next().unwrap(), 4);
/// assert!(it.next().is_none());
/// # Example
///
/// ```rust
- /// let a = [100i, 200];
+ /// let a = [100, 200];
/// let mut it = a.iter().enumerate();
- /// let (x100, x200) = (100i, 200i);
+ /// let (x100, x200) = (100, 200);
/// assert_eq!(it.next().unwrap(), (0, &x100));
/// assert_eq!(it.next().unwrap(), (1, &x200));
/// assert!(it.next().is_none());
/// # Example
///
/// ```rust
- /// let xs = [100i, 200, 300];
+ /// let xs = [100, 200, 300];
/// let mut it = xs.iter().map(|x| *x).peekable();
/// assert_eq!(*it.peek().unwrap(), 100);
/// assert_eq!(it.next().unwrap(), 100);
/// # Example
///
/// ```rust
- /// let a = [1i, 2, 3, 2, 1];
+ /// let a = [1, 2, 3, 2, 1];
/// let mut it = a.iter().skip_while(|&a| *a < 3);
/// assert_eq!(it.next().unwrap(), &3);
/// assert_eq!(it.next().unwrap(), &2);
/// # Example
///
/// ```rust
- /// let a = [1i, 2, 3, 2, 1];
+ /// let a = [1, 2, 3, 2, 1];
/// let mut it = a.iter().take_while(|&a| *a < 3);
/// assert_eq!(it.next().unwrap(), &1);
/// assert_eq!(it.next().unwrap(), &2);
/// # Example
///
/// ```rust
- /// let a = [1i, 2, 3, 4, 5];
+ /// let a = [1, 2, 3, 4, 5];
/// let mut it = a.iter().skip(3);
/// assert_eq!(it.next().unwrap(), &4);
/// assert_eq!(it.next().unwrap(), &5);
/// # Example
///
/// ```rust
- /// let a = [1i, 2, 3, 4, 5];
+ /// let a = [1, 2, 3, 4, 5];
/// let mut it = a.iter().take(3);
/// assert_eq!(it.next().unwrap(), &1);
/// assert_eq!(it.next().unwrap(), &2);
/// # Example
///
/// ```rust
- /// let a = [1i, 2, 3, 4, 5];
+ /// let a = [1, 2, 3, 4, 5];
/// let mut it = a.iter().scan(1, |fac, &x| {
/// *fac = *fac * x;
/// Some(*fac)
/// }
/// sum
/// }
- /// let x = vec![1i,2,3,7,8,9];
+ /// let x = vec![1,2,3,7,8,9];
/// assert_eq!(process(x.into_iter()), 6);
- /// let x = vec![1i,2,3];
+ /// let x = vec![1,2,3];
/// assert_eq!(process(x.into_iter()), 1006);
/// ```
#[inline]
/// # Example
///
/// ```rust
- /// let a = [1i, 2, 3, 4, 5];
+ /// let a = [1, 2, 3, 4, 5];
/// let b: Vec<int> = a.iter().map(|&x| x).collect();
/// assert!(a.as_slice() == b.as_slice());
/// ```
/// do not.
///
/// ```
- /// let vec = vec![1i, 2i, 3i, 4i];
+ /// let vec = vec![1, 2, 3, 4];
/// let (even, odd): (Vec<int>, Vec<int>) = vec.into_iter().partition(|&n| n % 2 == 0);
/// assert_eq!(even, vec![2, 4]);
/// assert_eq!(odd, vec![1, 3]);
/// # Example
///
/// ```rust
- /// let a = [1i, 2, 3, 4, 5];
+ /// let a = [1, 2, 3, 4, 5];
/// let mut it = a.iter();
/// assert!(it.nth(2).unwrap() == &3);
/// assert!(it.nth(2) == None);
/// # Example
///
/// ```rust
- /// let a = [1i, 2, 3, 4, 5];
+ /// let a = [1, 2, 3, 4, 5];
/// assert!(a.iter().last().unwrap() == &5);
/// ```
#[inline]
/// # Example
///
/// ```rust
- /// let a = [1i, 2, 3, 4, 5];
+ /// let a = [1, 2, 3, 4, 5];
/// assert!(a.iter().fold(0, |a, &b| a + b) == 15);
/// ```
#[inline]
/// # Example
///
/// ```rust
- /// let a = [1i, 2, 3, 4, 5];
+ /// let a = [1, 2, 3, 4, 5];
/// let mut it = a.iter();
/// assert!(it.count() == 5);
/// ```
/// # Example
///
/// ```rust
- /// let a = [1i, 2, 3, 4, 5];
+ /// let a = [1, 2, 3, 4, 5];
/// assert!(a.iter().all(|x| *x > 0));
/// assert!(!a.iter().all(|x| *x > 2));
/// ```
/// # Example
///
/// ```rust
- /// let a = [1i, 2, 3, 4, 5];
+ /// let a = [1, 2, 3, 4, 5];
/// let mut it = a.iter();
/// assert!(it.any(|x| *x == 3));
/// assert!(!it.any(|x| *x == 3));
/// ```rust
/// use core::num::SignedInt;
///
- /// let xs = [-3i, 0, 1, 5, -10];
+ /// let xs = [-3, 0, 1, 5, -10];
/// assert_eq!(*xs.iter().max_by(|x| x.abs()).unwrap(), -10);
/// ```
#[inline]
/// ```rust
/// use core::num::SignedInt;
///
- /// let xs = [-3i, 0, 1, 5, -10];
+ /// let xs = [-3, 0, 1, 5, -10];
/// assert_eq!(*xs.iter().min_by(|x| x.abs()).unwrap(), 0);
/// ```
#[inline]
/// ```rust
/// use std::iter::AdditiveIterator;
///
- /// let a = [1i, 2, 3, 4, 5];
+ /// let a: [i32] = [1, 2, 3, 4, 5];
/// let mut it = a.iter().map(|&x| x);
/// assert!(it.sum() == 15);
/// ```
/// # Example
///
/// ```rust
- /// let a = [1i, 2, 3, 4, 5];
+ /// let a = [1, 2, 3, 4, 5];
/// assert!(a.iter().max().unwrap() == &5);
/// ```
fn max(self) -> Option<A>;
/// # Example
///
/// ```rust
- /// let a = [1i, 2, 3, 4, 5];
+ /// let a = [1, 2, 3, 4, 5];
/// assert!(a.iter().min().unwrap() == &1);
/// ```
fn min(self) -> Option<A>;
/// let v: [int; 0] = [];
/// assert_eq!(v.iter().min_max(), NoElements);
///
- /// let v = [1i];
+ /// let v = [1];
/// assert!(v.iter().min_max() == OneElement(&1));
///
- /// let v = [1i, 2, 3, 4, 5];
+ /// let v = [1, 2, 3, 4, 5];
/// assert!(v.iter().min_max() == MinMax(&1, &5));
///
- /// let v = [1i, 2, 3, 4, 5, 6];
+ /// let v = [1, 2, 3, 4, 5, 6];
/// assert!(v.iter().min_max() == MinMax(&1, &6));
///
- /// let v = [1i, 1, 1, 1];
+ /// let v = [1, 1, 1, 1];
/// assert!(v.iter().min_max() == MinMax(&1, &1));
/// ```
fn min_max(self) -> MinMaxResult<A>;
/// let r: MinMaxResult<int> = NoElements;
/// assert_eq!(r.into_option(), None);
///
- /// let r = OneElement(1i);
+ /// let r = OneElement(1);
/// assert_eq!(r.into_option(), Some((1,1)));
///
- /// let r = MinMax(1i,2i);
+ /// let r = MinMax(1, 2);
/// assert_eq!(r.into_option(), Some((1,2)));
/// ```
pub fn into_option(self) -> Option<(T,T)> {
/// ```rust
/// use std::iter::{CloneIteratorExt, count};
///
- /// let a = count(1i,1i).take(1);
+ /// let a = count(1, 1).take(1);
/// let mut cy = a.cycle();
/// assert_eq!(cy.next(), Some(1));
/// assert_eq!(cy.next(), Some(1));
/// Change self to the previous object.
fn step_back(&mut self);
/// The steps_between two step objects.
- /// a should always be less than b, so the result should never be negative.
+ /// start should always be less than end, so the result should never be negative.
/// Return None if it is not possible to calculate steps_between without
/// overflow.
- fn steps_between(a: &Self, b: &Self) -> Option<uint>;
+ fn steps_between(start: &Self, end: &Self) -> Option<uint>;
}
macro_rules! step_impl {
#[inline]
fn step_back(&mut self) { *self -= 1; }
#[inline]
- fn steps_between(a: &$t, b: &$t) -> Option<uint> {
- debug_assert!(a < b);
- Some((*a - *b) as uint)
+ fn steps_between(start: &$t, end: &$t) -> Option<uint> {
+ debug_assert!(end >= start);
+ Some((*end - *start) as uint)
}
}
)*)
#[inline]
fn step_back(&mut self) { *self -= 1; }
#[inline]
- fn steps_between(_a: &$t, _b: &$t) -> Option<uint> {
+ fn steps_between(_start: &$t, _end: &$t) -> Option<uint> {
None
}
}
/// ```
/// use std::mem;
///
-/// let x = &mut 5i;
-/// let y = &mut 42i;
+/// let x = &mut 5;
+/// let y = &mut 42;
///
/// mem::swap(x, y);
///
-/// assert_eq!(42i, *x);
-/// assert_eq!(5i, *y);
+/// assert_eq!(42, *x);
+/// assert_eq!(5, *y);
/// ```
#[inline]
#[stable]
#![stable]
#![allow(missing_docs)]
-use char::Char;
+use char::CharExt;
use clone::Clone;
use cmp::{PartialEq, Eq};
use cmp::{PartialOrd, Ord};
/// ```rust
/// use std::num::Int;
///
- /// assert_eq!(2i.pow(4), 16);
+ /// assert_eq!(2.pow(4), 16);
/// ```
#[inline]
fn pow(self, mut exp: uint) -> Self {
shr_impl! { uint u8 u16 u32 u64 int i8 i16 i32 i64 }
-// NOTE(stage0) remove trait after a snapshot
-#[cfg(stage0)]
-#[allow(missing_docs)]
-#[lang="index"]
-pub trait Index<Sized? Index, Sized? Result> for Sized? {
- /// The method for the indexing (`Foo[Bar]`) operation
- fn index<'a>(&'a self, index: &Index) -> &'a Result;
-}
-
/// The `Index` trait is used to specify the functionality of indexing operations
/// like `arr[idx]` when used in an immutable context.
///
/// Foo[Foo];
/// }
/// ```
-#[cfg(not(stage0))] // NOTE(stage0) remove cfg after a snapshot
#[lang="index"]
pub trait Index<Sized? Index> for Sized? {
type Sized? Output;
fn index<'a>(&'a self, index: &Index) -> &'a Self::Output;
}
-// NOTE(stage0) remove trait after a snapshot
-#[cfg(stage0)]
-#[allow(missing_docs)]
-#[lang="index_mut"]
-pub trait IndexMut<Sized? Index, Sized? Result> for Sized? {
- /// The method for the indexing (`Foo[Bar]`) operation
- fn index_mut<'a>(&'a mut self, index: &Index) -> &'a mut Result;
-}
-
/// The `IndexMut` trait is used to specify the functionality of indexing
/// operations like `arr[idx]`, when used in a mutable context.
///
/// &mut Foo[Foo];
/// }
/// ```
-#[cfg(not(stage0))] // NOTE(stage0) remove cfg after a snapshot
#[lang="index_mut"]
pub trait IndexMut<Sized? Index> for Sized? {
type Sized? Output;
#[inline]
fn size_hint(&self) -> (uint, Option<uint>) {
- if let Some(hint) = Step::steps_between(&self.end, &self.start) {
+ if let Some(hint) = Step::steps_between(&self.start, &self.end) {
(hint, Some(hint))
} else {
(0, None)
///
/// ```
/// let x = Some("foo");
- /// assert_eq!(x.ok_or(0i), Ok("foo"));
+ /// assert_eq!(x.ok_or(0), Ok("foo"));
///
/// let x: Option<&str> = None;
- /// assert_eq!(x.ok_or(0i), Err(0i));
+ /// assert_eq!(x.ok_or(0), Err(0));
/// ```
#[inline]
#[experimental]
///
/// ```
/// let x = Some("foo");
- /// assert_eq!(x.ok_or_else(|| 0i), Ok("foo"));
+ /// assert_eq!(x.ok_or_else(|| 0), Ok("foo"));
///
/// let x: Option<&str> = None;
- /// assert_eq!(x.ok_or_else(|| 0i), Err(0i));
+ /// assert_eq!(x.ok_or_else(|| 0), Err(0));
/// ```
#[inline]
#[experimental]
/// let good_year = good_year_from_input.parse().unwrap_or_default();
/// let bad_year = bad_year_from_input.parse().unwrap_or_default();
///
- /// assert_eq!(1909i, good_year);
- /// assert_eq!(0i, bad_year);
+ /// assert_eq!(1909, good_year);
+ /// assert_eq!(0, bad_year);
/// ```
#[inline]
#[stable]
// Reexported types and traits
-pub use char::Char;
+pub use char::CharExt;
pub use clone::Clone;
pub use cmp::{PartialEq, PartialOrd, Eq, Ord};
pub use iter::{Extend, IteratorExt};
}
}
-// NOTE(stage0) remove impl after a snapshot
-#[cfg(stage0)]
-impl<T> ops::Index<uint, T> for [T] {
- fn index(&self, &index: &uint) -> &T {
- assert!(index < self.len());
-
- unsafe { mem::transmute(self.repr().data.offset(index as int)) }
- }
-}
-
-#[cfg(not(stage0))] // NOTE(stage0) remove cfg after a snapshot
impl<T> ops::Index<uint> for [T] {
type Output = T;
}
}
-// NOTE(stage0) remove impl after a snapshot
-#[cfg(stage0)]
-impl<T> ops::IndexMut<uint, T> for [T] {
- fn index_mut(&mut self, &index: &uint) -> &mut T {
- assert!(index < self.len());
-
- unsafe { mem::transmute(self.repr().data.offset(index as int)) }
- }
-}
-
-#[cfg(not(stage0))] // NOTE(stage0) remove cfg after a snapshot
impl<T> ops::IndexMut<uint> for [T] {
type Output = T;
/// # Panics
///
/// This function will panic if the string pointed to by `s` is not valid UTF-8.
-#[unstable = "may change location based on the outcome of the c_str module"]
+#[deprecated = "use std::ffi::c_str_to_bytes + str::from_utf8"]
pub unsafe fn from_c_str(s: *const i8) -> &'static str {
let s = s as *const u8;
let mut len = 0u;
mod ops;
mod option;
mod ptr;
-mod raw;
mod result;
mod slice;
mod str;
assert!(big > None);
}
+/* FIXME(#20575)
#[test]
fn test_collect() {
let v: Option<Vec<int>> = range(0i, 0).map(|_| Some(0i)).collect();
assert!(v == None);
// test that it does not take more elements than it needs
- let mut functions = [|| Some(()), || None, || panic!()];
+ let mut functions: [Box<Fn() -> Option<()>>; 3] =
+ [box || Some(()), box || None, box || panic!()];
let v: Option<Vec<()>> = functions.iter_mut().map(|f| (*f)()).collect();
assert!(v == None);
}
+*/
#[test]
fn test_cloned() {
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use core::raw::*;
-use core::mem;
-
-#[test]
-fn synthesize_closure() {
- unsafe {
- let x = 10;
- let f: |int| -> int = |y| x + y;
-
- assert_eq!(f(20), 30);
-
- let original_closure: Closure = mem::transmute(f);
-
- let actual_function_pointer = original_closure.code;
- let environment = original_closure.env;
-
- let new_closure = Closure {
- code: actual_function_pointer,
- env: environment
- };
-
- let new_f: |int| -> int = mem::transmute(new_closure);
- assert_eq!(new_f(20), 30);
- }
-}
assert!(Err::<int, int>(1).map_err(|x| x + 1) == Err(2));
}
+/* FIXME(#20575)
#[test]
fn test_collect() {
let v: Result<Vec<int>, ()> = range(0i, 0).map(|_| Ok::<int, ()>(0)).collect();
assert!(v == Err(2));
// test that it does not take more elements than it needs
- let mut functions = [|| Ok(()), || Err(1i), || panic!()];
+ let mut functions: [Box<Fn() -> Result<(), int>>; 3] =
+ [box || Ok(()), box || Err(1i), box || panic!()];
let v: Result<Vec<()>, int> = functions.iter_mut().map(|f| (*f)()).collect();
assert!(v == Err(1));
}
+*/
#[test]
pub fn test_fmt_default() {
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/nightly/")]
-#![feature(phase, unboxed_closures)]
+#![feature(phase, unboxed_closures, associated_types)]
#[cfg(test)] #[phase(plugin, link)] extern crate log;
extern crate libc;
use libc::{c_void, size_t, c_int};
-use std::c_vec::CVec;
+use std::ops::Deref;
use std::ptr::Unique;
+use std::slice;
+
+pub struct Bytes {
+ ptr: Unique<u8>,
+ len: uint,
+}
+
+impl Deref for Bytes {
+ type Target = [u8];
+ fn deref(&self) -> &[u8] {
+ unsafe { slice::from_raw_mut_buf(&self.ptr.0, self.len) }
+ }
+}
+
+impl Drop for Bytes {
+ fn drop(&mut self) {
+ unsafe { libc::free(self.ptr.0 as *mut _); }
+ }
+}
#[link(name = "miniz", kind = "static")]
extern {
static TINFL_FLAG_PARSE_ZLIB_HEADER : c_int = 0x1; // parse zlib header and adler32 checksum
static TDEFL_WRITE_ZLIB_HEADER : c_int = 0x01000; // write zlib header and adler32 checksum
-fn deflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option<CVec<u8>> {
+fn deflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option<Bytes> {
unsafe {
let mut outsz : size_t = 0;
let res = tdefl_compress_mem_to_heap(bytes.as_ptr() as *const _,
&mut outsz,
flags);
if !res.is_null() {
- let res = Unique(res);
- Some(CVec::new_with_dtor(res.0 as *mut u8, outsz as uint, move|:| libc::free(res.0)))
+ let res = Unique(res as *mut u8);
+ Some(Bytes { ptr: res, len: outsz as uint })
} else {
None
}
}
/// Compress a buffer, without writing any sort of header on the output.
-pub fn deflate_bytes(bytes: &[u8]) -> Option<CVec<u8>> {
+pub fn deflate_bytes(bytes: &[u8]) -> Option<Bytes> {
deflate_bytes_internal(bytes, LZ_NORM)
}
/// Compress a buffer, using a header that zlib can understand.
-pub fn deflate_bytes_zlib(bytes: &[u8]) -> Option<CVec<u8>> {
+pub fn deflate_bytes_zlib(bytes: &[u8]) -> Option<Bytes> {
deflate_bytes_internal(bytes, LZ_NORM | TDEFL_WRITE_ZLIB_HEADER)
}
-fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option<CVec<u8>> {
+fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option<Bytes> {
unsafe {
let mut outsz : size_t = 0;
let res = tinfl_decompress_mem_to_heap(bytes.as_ptr() as *const _,
&mut outsz,
flags);
if !res.is_null() {
- let res = Unique(res);
- Some(CVec::new_with_dtor(res.0 as *mut u8, outsz as uint, move|:| libc::free(res.0)))
+ let res = Unique(res as *mut u8);
+ Some(Bytes { ptr: res, len: outsz as uint })
} else {
None
}
}
/// Decompress a buffer, without parsing any sort of header on the input.
-pub fn inflate_bytes(bytes: &[u8]) -> Option<CVec<u8>> {
+pub fn inflate_bytes(bytes: &[u8]) -> Option<Bytes> {
inflate_bytes_internal(bytes, 0)
}
/// Decompress a buffer that starts with a zlib header.
-pub fn inflate_bytes_zlib(bytes: &[u8]) -> Option<CVec<u8>> {
+pub fn inflate_bytes_zlib(bytes: &[u8]) -> Option<Bytes> {
inflate_bytes_internal(bytes, TINFL_FLAG_PARSE_ZLIB_HEADER)
}
//! dot::Id::new(format!("N{}", n)).unwrap()
//! }
//! fn node_label<'b>(&'b self, n: &Nd) -> dot::LabelText<'b> {
-//! dot::LabelStr(self.nodes[*n].as_slice().into_cow())
+//! dot::LabelText::LabelStr(self.nodes[*n].as_slice().into_cow())
//! }
//! fn edge_label<'b>(&'b self, _: &Ed) -> dot::LabelText<'b> {
-//! dot::LabelStr("⊆".into_cow())
+//! dot::LabelText::LabelStr("⊆".into_cow())
//! }
//! }
//!
//! }
//! fn node_label<'b>(&'b self, n: &Nd<'b>) -> dot::LabelText<'b> {
//! let &(i, _) = n;
-//! dot::LabelStr(self.nodes[i].as_slice().into_cow())
+//! dot::LabelText::LabelStr(self.nodes[i].as_slice().into_cow())
//! }
//! fn edge_label<'b>(&'b self, _: &Ed<'b>) -> dot::LabelText<'b> {
-//! dot::LabelStr("⊆".into_cow())
+//! dot::LabelText::LabelStr("⊆".into_cow())
//! }
//! }
//!
#![feature(globs, slicing_syntax)]
#![feature(unboxed_closures)]
-pub use self::LabelText::*;
+use self::LabelText::*;
use std::borrow::IntoCow;
use std::io;
#[cfg(test)]
mod tests {
use self::NodeLabels::*;
- use super::{Id, LabelText, LabelStr, EscStr, Labeller};
- use super::{Nodes, Edges, GraphWalk, render};
+ use super::{Id, Labeller, Nodes, Edges, GraphWalk, render};
+ use super::LabelText::{mod, LabelStr, EscStr};
use std::io::IoResult;
use std::borrow::IntoCow;
use std::iter::repeat;
/// #[phase(plugin, link)] extern crate log;
///
/// fn main() {
-/// let ret = 3i;
+/// let ret = 3;
/// info!("this function is about to return: {}", ret);
/// }
/// ```
/// #[phase(plugin, link)] extern crate log;
///
/// fn main() {
-/// debug!("x = {x}, y = {y}", x=10i, y=20i);
+/// debug!("x = {x}, y = {y}", x=10, y=20);
/// }
/// ```
///
use core::prelude::*;
use core::num::Int;
-
use {Rng, SeedableRng, Rand};
const KEY_WORDS : uint = 8; // 8 words for the 256-bit key
///
/// [1]: D. J. Bernstein, [*ChaCha, a variant of
/// Salsa20*](http://cr.yp.to/chacha.html)
-
-#[derive(Copy)]
+#[deriving(Copy, Clone)]
pub struct ChaChaRng {
buffer: [u32; STATE_WORDS], // Internal buffer of output
state: [u32; STATE_WORDS], // Initial state
0x11cfa18e, 0xd3c50049, 0x75c775f6, 0x434c6530,
0x2c5bad8f, 0x898881dc, 0x5f1c86d9, 0xc1f8e7f4));
}
+
+ #[test]
+ fn test_rng_clone() {
+ let seed : &[_] = &[0u32, ..8];
+ let mut rng: ChaChaRng = SeedableRng::from_seed(seed);
+ let mut clone = rng.clone();
+ for _ in range(0u, 16) {
+ assert_eq!(rng.next_u64(), clone.next_u64());
+ }
+ }
}
}
}
+// Cannot be derived because [u32; 256] does not implement Clone
+impl Clone for IsaacRng {
+ fn clone(&self) -> IsaacRng {
+ *self
+ }
+}
+
impl Rng for IsaacRng {
#[inline]
fn next_u32(&mut self) -> u32 {
}
}
+// Cannot be derived because [u32; 256] does not implement Clone
+impl Clone for Isaac64Rng {
+ fn clone(&self) -> Isaac64Rng {
+ *self
+ }
+}
+
impl Rng for Isaac64Rng {
// FIXME #7771: having next_u32 like this should be unnecessary
#[inline]
}
}
+
#[cfg(test)]
mod test {
use std::prelude::v1::*;
596345674630742204, 9947027391921273664, 11788097613744130851,
10391409374914919106));
}
+
+ #[test]
+ fn test_rng_clone() {
+ let seed: &[_] = &[1, 23, 456, 7890, 12345];
+ let mut rng: Isaac64Rng = SeedableRng::from_seed(seed);
+ let mut clone = rng.clone();
+ for _ in range(0u, 16) {
+ assert_eq!(rng.next_u64(), clone.next_u64());
+ }
+ }
}
/// ```
/// use std::rand::{thread_rng, Rng};
///
- /// let choices = [1i, 2, 4, 8, 16, 32];
+ /// let choices = [1, 2, 4, 8, 16, 32];
/// let mut rng = thread_rng();
/// println!("{}", rng.choose(&choices));
/// # // replace with slicing syntax when it's stable!
/// use std::rand::{thread_rng, Rng};
///
/// let mut rng = thread_rng();
- /// let mut y = [1i, 2, 3];
+ /// let mut y = [1, 2, 3];
/// rng.shuffle(&mut y);
/// println!("{}", y.as_slice());
/// rng.shuffle(&mut y);
/// RNGs"](http://www.jstatsoft.org/v08/i14/paper). *Journal of
/// Statistical Software*. Vol. 8 (Issue 14).
#[allow(missing_copy_implementations)]
+#[deriving(Clone)]
pub struct XorShiftRng {
x: u32,
y: u32,
w: u32,
}
-impl Clone for XorShiftRng {
- fn clone(&self) -> XorShiftRng {
- XorShiftRng {
- x: self.x,
- y: self.y,
- z: self.z,
- w: self.w,
- }
- }
-}
-
impl XorShiftRng {
/// Creates a new XorShiftRng instance which is not seeded.
///
#[cfg(not(test))]
mod std {
pub use core::{option, fmt}; // panic!()
+ pub use core::clone; // derive Clone
pub use core::kinds;
}
html_playground_url = "http://play.rust-lang.org/")]
#![allow(unknown_features)]
#![feature(macro_rules, phase, slicing_syntax, globs)]
-#![feature(unboxed_closures)]
+#![feature(unboxed_closures, associated_types)]
#![allow(missing_docs)]
extern crate serialize;
}
}
+ #[cfg(stage0)]
impl<'doc> serialize::Decoder<Error> for Decoder<'doc> {
fn read_nil(&mut self) -> DecodeResult<()> { Ok(()) }
ApplicationError(err.to_string())
}
}
+
+ #[cfg(not(stage0))]
+ impl<'doc> serialize::Decoder for Decoder<'doc> {
+ type Error = Error;
+ fn read_nil(&mut self) -> DecodeResult<()> { Ok(()) }
+
+ fn read_u64(&mut self) -> DecodeResult<u64> { Ok(doc_as_u64(try!(self.next_doc(EsU64)))) }
+ fn read_u32(&mut self) -> DecodeResult<u32> { Ok(doc_as_u32(try!(self.next_doc(EsU32)))) }
+ fn read_u16(&mut self) -> DecodeResult<u16> { Ok(doc_as_u16(try!(self.next_doc(EsU16)))) }
+ fn read_u8 (&mut self) -> DecodeResult<u8 > { Ok(doc_as_u8 (try!(self.next_doc(EsU8 )))) }
+ fn read_uint(&mut self) -> DecodeResult<uint> {
+ let v = doc_as_u64(try!(self.next_doc(EsUint)));
+ if v > (::std::uint::MAX as u64) {
+ Err(IntTooBig(v as uint))
+ } else {
+ Ok(v as uint)
+ }
+ }
+
+ fn read_i64(&mut self) -> DecodeResult<i64> {
+ Ok(doc_as_u64(try!(self.next_doc(EsI64))) as i64)
+ }
+ fn read_i32(&mut self) -> DecodeResult<i32> {
+ Ok(doc_as_u32(try!(self.next_doc(EsI32))) as i32)
+ }
+ fn read_i16(&mut self) -> DecodeResult<i16> {
+ Ok(doc_as_u16(try!(self.next_doc(EsI16))) as i16)
+ }
+ fn read_i8 (&mut self) -> DecodeResult<i8> {
+ Ok(doc_as_u8(try!(self.next_doc(EsI8 ))) as i8)
+ }
+ fn read_int(&mut self) -> DecodeResult<int> {
+ let v = doc_as_u64(try!(self.next_doc(EsInt))) as i64;
+ if v > (int::MAX as i64) || v < (int::MIN as i64) {
+ debug!("FIXME \\#6122: Removing this makes this function miscompile");
+ Err(IntTooBig(v as uint))
+ } else {
+ Ok(v as int)
+ }
+ }
+
+ fn read_bool(&mut self) -> DecodeResult<bool> {
+ Ok(doc_as_u8(try!(self.next_doc(EsBool))) != 0)
+ }
+
+ fn read_f64(&mut self) -> DecodeResult<f64> {
+ let bits = doc_as_u64(try!(self.next_doc(EsF64)));
+ Ok(unsafe { transmute(bits) })
+ }
+ fn read_f32(&mut self) -> DecodeResult<f32> {
+ let bits = doc_as_u32(try!(self.next_doc(EsF32)));
+ Ok(unsafe { transmute(bits) })
+ }
+ fn read_char(&mut self) -> DecodeResult<char> {
+ Ok(char::from_u32(doc_as_u32(try!(self.next_doc(EsChar)))).unwrap())
+ }
+ fn read_str(&mut self) -> DecodeResult<String> {
+ Ok(try!(self.next_doc(EsStr)).as_str())
+ }
+
+ // Compound types:
+ fn read_enum<T, F>(&mut self, name: &str, f: F) -> DecodeResult<T> where
+ F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>,
+ {
+ debug!("read_enum({})", name);
+ try!(self._check_label(name));
+
+ let doc = try!(self.next_doc(EsEnum));
+
+ let (old_parent, old_pos) = (self.parent, self.pos);
+ self.parent = doc;
+ self.pos = self.parent.start;
+
+ let result = try!(f(self));
+
+ self.parent = old_parent;
+ self.pos = old_pos;
+ Ok(result)
+ }
+
+ fn read_enum_variant<T, F>(&mut self, _: &[&str],
+ mut f: F) -> DecodeResult<T>
+ where F: FnMut(&mut Decoder<'doc>, uint) -> DecodeResult<T>,
+ {
+ debug!("read_enum_variant()");
+ let idx = try!(self._next_uint(EsEnumVid));
+ debug!(" idx={}", idx);
+
+ let doc = try!(self.next_doc(EsEnumBody));
+
+ let (old_parent, old_pos) = (self.parent, self.pos);
+ self.parent = doc;
+ self.pos = self.parent.start;
+
+ let result = try!(f(self, idx));
+
+ self.parent = old_parent;
+ self.pos = old_pos;
+ Ok(result)
+ }
+
+ fn read_enum_variant_arg<T, F>(&mut self, idx: uint, f: F) -> DecodeResult<T> where
+ F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>,
+ {
+ debug!("read_enum_variant_arg(idx={})", idx);
+ f(self)
+ }
+
+ fn read_enum_struct_variant<T, F>(&mut self, _: &[&str],
+ mut f: F) -> DecodeResult<T>
+ where F: FnMut(&mut Decoder<'doc>, uint) -> DecodeResult<T>,
+ {
+ debug!("read_enum_struct_variant()");
+ let idx = try!(self._next_uint(EsEnumVid));
+ debug!(" idx={}", idx);
+
+ let doc = try!(self.next_doc(EsEnumBody));
+
+ let (old_parent, old_pos) = (self.parent, self.pos);
+ self.parent = doc;
+ self.pos = self.parent.start;
+
+ let result = try!(f(self, idx));
+
+ self.parent = old_parent;
+ self.pos = old_pos;
+ Ok(result)
+ }
+
+ fn read_enum_struct_variant_field<T, F>(&mut self,
+ name: &str,
+ idx: uint,
+ f: F)
+ -> DecodeResult<T> where
+ F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>,
+ {
+ debug!("read_enum_struct_variant_arg(name={}, idx={})", name, idx);
+ f(self)
+ }
+
+ fn read_struct<T, F>(&mut self, name: &str, _: uint, f: F) -> DecodeResult<T> where
+ F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>,
+ {
+ debug!("read_struct(name={})", name);
+ f(self)
+ }
+
+ fn read_struct_field<T, F>(&mut self, name: &str, idx: uint, f: F) -> DecodeResult<T> where
+ F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>,
+ {
+ debug!("read_struct_field(name={}, idx={})", name, idx);
+ try!(self._check_label(name));
+ f(self)
+ }
+
+ fn read_tuple<T, F>(&mut self, tuple_len: uint, f: F) -> DecodeResult<T> where
+ F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>,
+ {
+ debug!("read_tuple()");
+ self.read_seq(move |d, len| {
+ if len == tuple_len {
+ f(d)
+ } else {
+ Err(Expected(format!("Expected tuple of length `{}`, \
+ found tuple of length `{}`", tuple_len, len)))
+ }
+ })
+ }
+
+ fn read_tuple_arg<T, F>(&mut self, idx: uint, f: F) -> DecodeResult<T> where
+ F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>,
+ {
+ debug!("read_tuple_arg(idx={})", idx);
+ self.read_seq_elt(idx, f)
+ }
+
+ fn read_tuple_struct<T, F>(&mut self, name: &str, len: uint, f: F) -> DecodeResult<T> where
+ F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>,
+ {
+ debug!("read_tuple_struct(name={})", name);
+ self.read_tuple(len, f)
+ }
+
+ fn read_tuple_struct_arg<T, F>(&mut self,
+ idx: uint,
+ f: F)
+ -> DecodeResult<T> where
+ F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>,
+ {
+ debug!("read_tuple_struct_arg(idx={})", idx);
+ self.read_tuple_arg(idx, f)
+ }
+
+ fn read_option<T, F>(&mut self, mut f: F) -> DecodeResult<T> where
+ F: FnMut(&mut Decoder<'doc>, bool) -> DecodeResult<T>,
+ {
+ debug!("read_option()");
+ self.read_enum("Option", move |this| {
+ this.read_enum_variant(&["None", "Some"], move |this, idx| {
+ match idx {
+ 0 => f(this, false),
+ 1 => f(this, true),
+ _ => {
+ Err(Expected(format!("Expected None or Some")))
+ }
+ }
+ })
+ })
+ }
+
+ fn read_seq<T, F>(&mut self, f: F) -> DecodeResult<T> where
+ F: FnOnce(&mut Decoder<'doc>, uint) -> DecodeResult<T>,
+ {
+ debug!("read_seq()");
+ self.push_doc(EsVec, move |d| {
+ let len = try!(d._next_uint(EsVecLen));
+ debug!(" len={}", len);
+ f(d, len)
+ })
+ }
+
+ fn read_seq_elt<T, F>(&mut self, idx: uint, f: F) -> DecodeResult<T> where
+ F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>,
+ {
+ debug!("read_seq_elt(idx={})", idx);
+ self.push_doc(EsVecElt, f)
+ }
+
+ fn read_map<T, F>(&mut self, f: F) -> DecodeResult<T> where
+ F: FnOnce(&mut Decoder<'doc>, uint) -> DecodeResult<T>,
+ {
+ debug!("read_map()");
+ self.push_doc(EsMap, move |d| {
+ let len = try!(d._next_uint(EsMapLen));
+ debug!(" len={}", len);
+ f(d, len)
+ })
+ }
+
+ fn read_map_elt_key<T, F>(&mut self, idx: uint, f: F) -> DecodeResult<T> where
+ F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>,
+ {
+ debug!("read_map_elt_key(idx={})", idx);
+ self.push_doc(EsMapKey, f)
+ }
+
+ fn read_map_elt_val<T, F>(&mut self, idx: uint, f: F) -> DecodeResult<T> where
+ F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>,
+ {
+ debug!("read_map_elt_val(idx={})", idx);
+ self.push_doc(EsMapVal, f)
+ }
+
+ fn error(&mut self, err: &str) -> Error {
+ ApplicationError(err.to_string())
+ }
+ }
}
pub mod writer {
}
}
+ #[cfg(stage0)]
impl<'a, W: Writer + Seek> serialize::Encoder<io::IoError> for Encoder<'a, W> {
+
+ fn emit_nil(&mut self) -> EncodeResult {
+ Ok(())
+ }
+
+ fn emit_uint(&mut self, v: uint) -> EncodeResult {
+ self.wr_tagged_u64(EsUint as uint, v as u64)
+ }
+ fn emit_u64(&mut self, v: u64) -> EncodeResult {
+ self.wr_tagged_u64(EsU64 as uint, v)
+ }
+ fn emit_u32(&mut self, v: u32) -> EncodeResult {
+ self.wr_tagged_u32(EsU32 as uint, v)
+ }
+ fn emit_u16(&mut self, v: u16) -> EncodeResult {
+ self.wr_tagged_u16(EsU16 as uint, v)
+ }
+ fn emit_u8(&mut self, v: u8) -> EncodeResult {
+ self.wr_tagged_u8(EsU8 as uint, v)
+ }
+
+ fn emit_int(&mut self, v: int) -> EncodeResult {
+ self.wr_tagged_i64(EsInt as uint, v as i64)
+ }
+ fn emit_i64(&mut self, v: i64) -> EncodeResult {
+ self.wr_tagged_i64(EsI64 as uint, v)
+ }
+ fn emit_i32(&mut self, v: i32) -> EncodeResult {
+ self.wr_tagged_i32(EsI32 as uint, v)
+ }
+ fn emit_i16(&mut self, v: i16) -> EncodeResult {
+ self.wr_tagged_i16(EsI16 as uint, v)
+ }
+ fn emit_i8(&mut self, v: i8) -> EncodeResult {
+ self.wr_tagged_i8(EsI8 as uint, v)
+ }
+
+ fn emit_bool(&mut self, v: bool) -> EncodeResult {
+ self.wr_tagged_u8(EsBool as uint, v as u8)
+ }
+
+ fn emit_f64(&mut self, v: f64) -> EncodeResult {
+ let bits = unsafe { mem::transmute(v) };
+ self.wr_tagged_u64(EsF64 as uint, bits)
+ }
+ fn emit_f32(&mut self, v: f32) -> EncodeResult {
+ let bits = unsafe { mem::transmute(v) };
+ self.wr_tagged_u32(EsF32 as uint, bits)
+ }
+ fn emit_char(&mut self, v: char) -> EncodeResult {
+ self.wr_tagged_u32(EsChar as uint, v as u32)
+ }
+
+ fn emit_str(&mut self, v: &str) -> EncodeResult {
+ self.wr_tagged_str(EsStr as uint, v)
+ }
+
+ fn emit_enum<F>(&mut self, name: &str, f: F) -> EncodeResult where
+ F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult,
+ {
+ try!(self._emit_label(name));
+ try!(self.start_tag(EsEnum as uint));
+ try!(f(self));
+ self.end_tag()
+ }
+
+ fn emit_enum_variant<F>(&mut self,
+ _: &str,
+ v_id: uint,
+ _: uint,
+ f: F) -> EncodeResult where
+ F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult,
+ {
+ try!(self._emit_tagged_uint(EsEnumVid, v_id));
+ try!(self.start_tag(EsEnumBody as uint));
+ try!(f(self));
+ self.end_tag()
+ }
+
+ fn emit_enum_variant_arg<F>(&mut self, _: uint, f: F) -> EncodeResult where
+ F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult,
+ {
+ f(self)
+ }
+
+ fn emit_enum_struct_variant<F>(&mut self,
+ v_name: &str,
+ v_id: uint,
+ cnt: uint,
+ f: F) -> EncodeResult where
+ F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult,
+ {
+ self.emit_enum_variant(v_name, v_id, cnt, f)
+ }
+
+ fn emit_enum_struct_variant_field<F>(&mut self,
+ _: &str,
+ idx: uint,
+ f: F) -> EncodeResult where
+ F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult,
+ {
+ self.emit_enum_variant_arg(idx, f)
+ }
+
+ fn emit_struct<F>(&mut self, _: &str, _len: uint, f: F) -> EncodeResult where
+ F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult,
+ {
+ f(self)
+ }
+
+ fn emit_struct_field<F>(&mut self, name: &str, _: uint, f: F) -> EncodeResult where
+ F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult,
+ {
+ try!(self._emit_label(name));
+ f(self)
+ }
+
+ fn emit_tuple<F>(&mut self, len: uint, f: F) -> EncodeResult where
+ F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult,
+ {
+ self.emit_seq(len, f)
+ }
+ fn emit_tuple_arg<F>(&mut self, idx: uint, f: F) -> EncodeResult where
+ F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult,
+ {
+ self.emit_seq_elt(idx, f)
+ }
+
+ fn emit_tuple_struct<F>(&mut self, _: &str, len: uint, f: F) -> EncodeResult where
+ F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult,
+ {
+ self.emit_seq(len, f)
+ }
+ fn emit_tuple_struct_arg<F>(&mut self, idx: uint, f: F) -> EncodeResult where
+ F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult,
+ {
+ self.emit_seq_elt(idx, f)
+ }
+
+ fn emit_option<F>(&mut self, f: F) -> EncodeResult where
+ F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult,
+ {
+ self.emit_enum("Option", f)
+ }
+ fn emit_option_none(&mut self) -> EncodeResult {
+ self.emit_enum_variant("None", 0, 0, |_| Ok(()))
+ }
+ fn emit_option_some<F>(&mut self, f: F) -> EncodeResult where
+ F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult,
+ {
+
+ self.emit_enum_variant("Some", 1, 1, f)
+ }
+
+ fn emit_seq<F>(&mut self, len: uint, f: F) -> EncodeResult where
+ F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult,
+ {
+
+ try!(self.start_tag(EsVec as uint));
+ try!(self._emit_tagged_uint(EsVecLen, len));
+ try!(f(self));
+ self.end_tag()
+ }
+
+ fn emit_seq_elt<F>(&mut self, _idx: uint, f: F) -> EncodeResult where
+ F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult,
+ {
+
+ try!(self.start_tag(EsVecElt as uint));
+ try!(f(self));
+ self.end_tag()
+ }
+
+ fn emit_map<F>(&mut self, len: uint, f: F) -> EncodeResult where
+ F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult,
+ {
+
+ try!(self.start_tag(EsMap as uint));
+ try!(self._emit_tagged_uint(EsMapLen, len));
+ try!(f(self));
+ self.end_tag()
+ }
+
+ fn emit_map_elt_key<F>(&mut self, _idx: uint, mut f: F) -> EncodeResult where
+ F: FnMut(&mut Encoder<'a, W>) -> EncodeResult,
+ {
+
+ try!(self.start_tag(EsMapKey as uint));
+ try!(f(self));
+ self.end_tag()
+ }
+
+ fn emit_map_elt_val<F>(&mut self, _idx: uint, f: F) -> EncodeResult where
+ F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult,
+ {
+ try!(self.start_tag(EsMapVal as uint));
+ try!(f(self));
+ self.end_tag()
+ }
+ }
+ #[cfg(not(stage0))]
+ impl<'a, W: Writer + Seek> serialize::Encoder for Encoder<'a, W> {
+ type Error = io::IoError;
+
fn emit_nil(&mut self) -> EncodeResult {
Ok(())
}
let mut n_uniq = 0i;
ty::fold_ty(cx.tcx, ty, |t| {
match t.sty {
- ty::ty_uniq(_) |
- ty::ty_closure(box ty::ClosureTy {
- store: ty::UniqTraitStore,
- ..
- }) => {
+ ty::ty_uniq(_) => {
n_uniq += 1;
}
}
declare_lint! {
- RAW_POINTER_DERIVING,
+ RAW_POINTER_DERIVE,
Warn,
"uses of #[derive] with raw pointers are rarely correct"
}
-struct RawPtrDerivingVisitor<'a, 'tcx: 'a> {
+struct RawPtrDeriveVisitor<'a, 'tcx: 'a> {
cx: &'a Context<'a, 'tcx>
}
-impl<'a, 'tcx, 'v> Visitor<'v> for RawPtrDerivingVisitor<'a, 'tcx> {
+impl<'a, 'tcx, 'v> Visitor<'v> for RawPtrDeriveVisitor<'a, 'tcx> {
fn visit_ty(&mut self, ty: &ast::Ty) {
static MSG: &'static str = "use of `#[derive]` with a raw pointer";
if let ast::TyPtr(..) = ty.node {
- self.cx.span_lint(RAW_POINTER_DERIVING, ty.span, MSG);
+ self.cx.span_lint(RAW_POINTER_DERIVE, ty.span, MSG);
}
visit::walk_ty(self, ty);
}
fn visit_block(&mut self, _: &ast::Block) {}
}
-pub struct RawPointerDeriving {
+pub struct RawPointerDerive {
checked_raw_pointers: NodeSet,
}
-impl RawPointerDeriving {
- pub fn new() -> RawPointerDeriving {
- RawPointerDeriving {
+impl RawPointerDerive {
+ pub fn new() -> RawPointerDerive {
+ RawPointerDerive {
checked_raw_pointers: NodeSet::new(),
}
}
}
-impl LintPass for RawPointerDeriving {
+impl LintPass for RawPointerDerive {
fn get_lints(&self) -> LintArray {
- lint_array!(RAW_POINTER_DERIVING)
+ lint_array!(RAW_POINTER_DERIVE)
}
fn check_item(&mut self, cx: &Context, item: &ast::Item) {
if !self.checked_raw_pointers.insert(item.id) { return }
match item.node {
ast::ItemStruct(..) | ast::ItemEnum(..) => {
- let mut visitor = RawPtrDerivingVisitor { cx: cx };
+ let mut visitor = RawPtrDeriveVisitor { cx: cx };
visit::walk_item(&mut visitor, &*item);
}
_ => {}
let ident = path1.node;
if let ast::BindByValue(ast::MutMutable) = mode {
if !token::get_ident(ident).get().starts_with("_") {
- match mutables.entry(ident.name.uint()) {
- Vacant(entry) => { entry.set(vec![id]); },
+ match mutables.entry(&ident.name.uint()) {
+ Vacant(entry) => { entry.insert(vec![id]); },
Occupied(mut entry) => { entry.get_mut().push(id); },
}
}
}
}
}
- ast::ItemImpl(_, _, Some(ref t), _, _) => {
+ ast::ItemImpl(_, _, _, Some(ref t), _, _) => {
let id = ty::trait_ref_to_def_id(cx.tcx, t);
self.lint(cx, id, t.path.span);
}
add_builtin_with_new!(sess,
TypeLimits,
- RawPointerDeriving,
+ RawPointerDerive,
MissingDoc,
);
self.register_renamed("unknown_crate_type", "unknown_crate_types");
self.register_renamed("variant_size_difference", "variant_size_differences");
self.register_renamed("transmute_fat_ptr", "fat_ptr_transmutes");
+ self.register_renamed("raw_pointer_deriving", "raw_pointer_derive");
}
pub const tag_associated_type_names: uint = 0xb2;
pub const tag_associated_type_name: uint = 0xb3;
+
+pub const tag_polarity: uint = 0xb4;
fn warn_if_multiple_versions(diag: &SpanHandler, cstore: &CStore) {
let mut map = FnvHashMap::new();
cstore.iter_crate_data(|cnum, data| {
- match map.entry(data.name()) {
- Vacant(entry) => { entry.set(vec![cnum]); },
+ match map.entry(&data.name()) {
+ Vacant(entry) => { entry.insert(vec![cnum]); },
Occupied(mut entry) => { entry.get_mut().push(cnum); },
}
});
use util::nodemap::{FnvHashMap, NodeMap};
use std::cell::RefCell;
-use std::c_vec::CVec;
use std::rc::Rc;
+use flate::Bytes;
use syntax::ast;
use syntax::codemap::Span;
use syntax::parse::token::IdentInterner;
pub type cnum_map = FnvHashMap<ast::CrateNum, ast::CrateNum>;
pub enum MetadataBlob {
- MetadataVec(CVec<u8>),
+ MetadataVec(Bytes),
MetadataArchive(loader::ArchiveMetadata),
}
item_path(lookup_item(id, cdata.data()))
}
-pub type DecodeInlinedItem<'a> = for<'tcx> |cdata: Cmd,
- tcx: &ty::ctxt<'tcx>,
- path: Vec<ast_map::PathElem>,
- par_doc: rbml::Doc|: 'a
- -> Result<&'tcx ast::InlinedItem,
- Vec<ast_map::PathElem>>;
+pub type DecodeInlinedItem<'a> =
+ Box<for<'tcx> FnMut(Cmd,
+ &ty::ctxt<'tcx>,
+ Vec<ast_map::PathElem>,
+ rbml::Doc)
+ -> Result<&'tcx ast::InlinedItem, Vec<ast_map::PathElem>> + 'a>;
pub fn maybe_get_item_ast<'tcx>(cdata: Cmd, tcx: &ty::ctxt<'tcx>, id: ast::NodeId,
- decode_inlined_item: DecodeInlinedItem)
+ mut decode_inlined_item: DecodeInlinedItem)
-> csearch::found_ast<'tcx> {
debug!("Looking up item: {}", id);
let item_doc = lookup_item(id, cdata.data());
let path = item_path(item_doc).init().to_vec();
- match decode_inlined_item(cdata, tcx, path, item_doc) {
+ match decode_inlined_item.call_mut((cdata, tcx, path, item_doc)) {
Ok(ii) => csearch::found(ii),
Err(path) => {
match item_parent_item(item_doc) {
Some(did) => {
let did = translate_def_id(cdata, did);
let parent_item = lookup_item(did.node, cdata.data());
- match decode_inlined_item(cdata, tcx, path, parent_item) {
+ match decode_inlined_item.call_mut((cdata, tcx, path, parent_item)) {
Ok(ii) => csearch::found_parent(did, ii),
Err(_) => csearch::not_found
}
pub type Encoder<'a> = writer::Encoder<'a, SeekableMemWriter>;
-pub type EncodeInlinedItem<'a> = |ecx: &EncodeContext,
- rbml_w: &mut Encoder,
- ii: InlinedItemRef|: 'a;
+pub type EncodeInlinedItem<'a> =
+ Box<FnMut(&EncodeContext, &mut Encoder, InlinedItemRef) + 'a>;
pub struct EncodeParams<'a, 'tcx: 'a> {
pub diag: &'a SpanHandler,
ii: InlinedItemRef) {
let mut eii = ecx.encode_inlined_item.borrow_mut();
let eii: &mut EncodeInlinedItem = &mut *eii;
- (*eii)(ecx, rbml_w, ii)
+ eii.call_mut((ecx, rbml_w, ii))
}
const FN_FAMILY: char = 'f';
None => {}
}
}
- ast::ItemImpl(unsafety, _, ref opt_trait, ref ty, ref ast_items) => {
+ ast::ItemImpl(unsafety, polarity, _, ref opt_trait, ref ty, ref ast_items) => {
// We need to encode information about the default methods we
// have inherited, so we drive this based on the impl structure.
let impl_items = tcx.impl_items.borrow();
encode_name(rbml_w, item.ident.name);
encode_attributes(rbml_w, item.attrs[]);
encode_unsafety(rbml_w, unsafety);
+ encode_polarity(rbml_w, polarity);
match ty.node {
ast::TyPath(ref path, _) if path.segments.len() == 1 => {
let ident = path.segments.last().unwrap().identifier;
rbml_w.end_tag();
}
+fn encode_polarity(rbml_w: &mut Encoder, polarity: ast::ImplPolarity) {
+ let byte: u8 = match polarity {
+ ast::ImplPolarity::Positive => 0,
+ ast::ImplPolarity::Negative => 1,
+ };
+ rbml_w.wr_tagged_u8(tag_polarity, byte);
+}
+
fn encode_crate_deps(rbml_w: &mut Encoder, cstore: &cstore::CStore) {
fn get_ordered_deps(cstore: &cstore::CStore) -> Vec<decoder::CrateDep> {
// Pull the cnums and name,vers,hash out of cstore
impl<'a, 'b, 'c, 'tcx, 'v> Visitor<'v> for ImplVisitor<'a, 'b, 'c, 'tcx> {
fn visit_item(&mut self, item: &ast::Item) {
- if let ast::ItemImpl(_, _, Some(ref trait_ref), _, _) = item.node {
+ if let ast::ItemImpl(_, _, _, Some(ref trait_ref), _, _) = item.node {
let def_map = &self.ecx.tcx.def_map;
let trait_def = def_map.borrow()[trait_ref.ref_id].clone();
let def_id = trait_def.def_id();
use syntax::diagnostic::SpanHandler;
use util::fs;
-use std::c_str::ToCStr;
+use std::ffi::CString;
use std::cmp;
-use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::collections::{HashMap, HashSet};
use std::io::fs::PathExtensions;
use std::io;
};
info!("lib candidate: {}", path.display());
- let slot = match candidates.entry(hash.to_string()) {
- Occupied(entry) => entry.into_mut(),
- Vacant(entry) => entry.set((HashSet::new(), HashSet::new())),
- };
+ let hash_str = hash.to_string();
+ let slot = candidates.entry(&hash_str).get().unwrap_or_else(
+ |vacant_entry| vacant_entry.insert((HashSet::new(), HashSet::new())));
let (ref mut rlibs, ref mut dylibs) = *slot;
if rlib {
rlibs.insert(fs::realpath(path).unwrap());
}
}
unsafe {
- let mb = filename.with_c_str(|buf| {
- llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf)
- });
+ let buf = CString::from_slice(filename.as_vec());
+ let mb = llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf.as_ptr());
if mb as int == 0 {
return Err(format!("error reading library: '{}'",
filename.display()))
while llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False {
let mut name_buf = ptr::null();
let name_len = llvm::LLVMRustGetSectionName(si.llsi, &mut name_buf);
- let name = String::from_raw_buf_len(name_buf as *const u8,
- name_len as uint);
+ let name = slice::from_raw_buf(&(name_buf as *const u8),
+ name_len as uint).to_vec();
+ let name = String::from_utf8(name).unwrap();
debug!("get_metadata_section: name {}", name);
if read_meta_section_name(is_osx) == name {
let cbuf = llvm::LLVMGetSectionContents(si.llsi);
UnboxedClosureSource
}
-pub type conv_did<'a> =
- |source: DefIdSource, ast::DefId|: 'a -> ast::DefId;
+// type conv_did = impl FnMut(DefIdSource, ast::DefId) -> ast::DefId;
pub struct PState<'a, 'tcx: 'a> {
data: &'a [u8],
buf
}
-pub fn parse_ty_closure_data<'tcx>(data: &[u8],
- crate_num: ast::CrateNum,
- pos: uint,
- tcx: &ty::ctxt<'tcx>,
- conv: conv_did)
- -> ty::ClosureTy<'tcx> {
+pub fn parse_ty_closure_data<'tcx, F>(data: &[u8],
+ crate_num: ast::CrateNum,
+ pos: uint,
+ tcx: &ty::ctxt<'tcx>,
+ conv: F)
+ -> ty::ClosureTy<'tcx> where
+ F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
+{
let mut st = parse_state_from_data(data, crate_num, pos, tcx);
parse_closure_ty(&mut st, conv)
}
-pub fn parse_ty_data<'tcx>(data: &[u8], crate_num: ast::CrateNum, pos: uint,
- tcx: &ty::ctxt<'tcx>, conv: conv_did) -> Ty<'tcx> {
+pub fn parse_ty_data<'tcx, F>(data: &[u8], crate_num: ast::CrateNum, pos: uint,
+ tcx: &ty::ctxt<'tcx>, conv: F) -> Ty<'tcx> where
+ F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
+{
debug!("parse_ty_data {}", data_log_string(data, pos));
let mut st = parse_state_from_data(data, crate_num, pos, tcx);
parse_ty(&mut st, conv)
}
-pub fn parse_region_data(data: &[u8], crate_num: ast::CrateNum, pos: uint, tcx: &ty::ctxt,
- conv: conv_did) -> ty::Region {
+pub fn parse_region_data<F>(data: &[u8], crate_num: ast::CrateNum, pos: uint, tcx: &ty::ctxt,
+ conv: F) -> ty::Region where
+ F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
+{
debug!("parse_region_data {}", data_log_string(data, pos));
let mut st = parse_state_from_data(data, crate_num, pos, tcx);
parse_region(&mut st, conv)
}
-pub fn parse_bare_fn_ty_data<'tcx>(data: &[u8], crate_num: ast::CrateNum, pos: uint,
- tcx: &ty::ctxt<'tcx>, conv: conv_did)
- -> ty::BareFnTy<'tcx> {
+pub fn parse_bare_fn_ty_data<'tcx, F>(data: &[u8], crate_num: ast::CrateNum, pos: uint,
+ tcx: &ty::ctxt<'tcx>, conv: F)
+ -> ty::BareFnTy<'tcx> where
+ F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
+{
debug!("parse_bare_fn_ty_data {}", data_log_string(data, pos));
let mut st = parse_state_from_data(data, crate_num, pos, tcx);
parse_bare_fn_ty(&mut st, conv)
}
-pub fn parse_trait_ref_data<'tcx>(data: &[u8], crate_num: ast::CrateNum, pos: uint,
- tcx: &ty::ctxt<'tcx>, conv: conv_did)
- -> Rc<ty::TraitRef<'tcx>> {
+pub fn parse_trait_ref_data<'tcx, F>(data: &[u8], crate_num: ast::CrateNum, pos: uint,
+ tcx: &ty::ctxt<'tcx>, conv: F)
+ -> Rc<ty::TraitRef<'tcx>> where
+ F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
+{
debug!("parse_trait_ref_data {}", data_log_string(data, pos));
let mut st = parse_state_from_data(data, crate_num, pos, tcx);
parse_trait_ref(&mut st, conv)
}
-pub fn parse_substs_data<'tcx>(data: &[u8], crate_num: ast::CrateNum, pos: uint,
- tcx: &ty::ctxt<'tcx>, conv: conv_did) -> subst::Substs<'tcx> {
+pub fn parse_substs_data<'tcx, F>(data: &[u8], crate_num: ast::CrateNum, pos: uint,
+ tcx: &ty::ctxt<'tcx>, conv: F) -> subst::Substs<'tcx> where
+ F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
+{
debug!("parse_substs_data {}", data_log_string(data, pos));
let mut st = parse_state_from_data(data, crate_num, pos, tcx);
parse_substs(&mut st, conv)
}
-pub fn parse_bounds_data<'tcx>(data: &[u8], crate_num: ast::CrateNum,
- pos: uint, tcx: &ty::ctxt<'tcx>, conv: conv_did)
- -> ty::ParamBounds<'tcx> {
+pub fn parse_bounds_data<'tcx, F>(data: &[u8], crate_num: ast::CrateNum,
+ pos: uint, tcx: &ty::ctxt<'tcx>, conv: F)
+ -> ty::ParamBounds<'tcx> where
+ F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
+{
let mut st = parse_state_from_data(data, crate_num, pos, tcx);
parse_bounds(&mut st, conv)
}
-pub fn parse_existential_bounds_data<'tcx>(data: &[u8], crate_num: ast::CrateNum,
- pos: uint, tcx: &ty::ctxt<'tcx>, conv: conv_did)
- -> ty::ExistentialBounds<'tcx> {
+pub fn parse_existential_bounds_data<'tcx, F>(data: &[u8], crate_num: ast::CrateNum,
+ pos: uint, tcx: &ty::ctxt<'tcx>, conv: F)
+ -> ty::ExistentialBounds<'tcx> where
+ F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
+{
let mut st = parse_state_from_data(data, crate_num, pos, tcx);
parse_existential_bounds(&mut st, conv)
}
-pub fn parse_builtin_bounds_data(data: &[u8], crate_num: ast::CrateNum,
- pos: uint, tcx: &ty::ctxt, conv: conv_did)
- -> ty::BuiltinBounds {
+pub fn parse_builtin_bounds_data<F>(data: &[u8], crate_num: ast::CrateNum,
+ pos: uint, tcx: &ty::ctxt, conv: F)
+ -> ty::BuiltinBounds where
+ F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
+{
let mut st = parse_state_from_data(data, crate_num, pos, tcx);
parse_builtin_bounds(&mut st, conv)
}
}
}
-fn parse_trait_store(st: &mut PState, conv: conv_did) -> ty::TraitStore {
+fn parse_trait_store_<F>(st: &mut PState, conv: &mut F) -> ty::TraitStore where
+ F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
+{
match next(st) {
'~' => ty::UniqTraitStore,
- '&' => ty::RegionTraitStore(parse_region(st, conv), parse_mutability(st)),
+ '&' => ty::RegionTraitStore(parse_region_(st, conv), parse_mutability(st)),
c => {
st.tcx.sess.bug(format!("parse_trait_store(): bad input '{}'",
c)[])
r
}
-fn parse_substs<'a, 'tcx>(st: &mut PState<'a, 'tcx>,
- conv: conv_did) -> subst::Substs<'tcx> {
+fn parse_substs<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>,
+ mut conv: F) -> subst::Substs<'tcx> where
+ F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
+{
+ parse_substs_(st, &mut conv)
+}
+
+fn parse_substs_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>,
+ conv: &mut F) -> subst::Substs<'tcx> where
+ F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
+{
let regions =
- parse_region_substs(st, |x,y| conv(x,y));
+ parse_region_substs_(st, conv);
let types =
- parse_vec_per_param_space(st, |st| parse_ty(st, |x,y| conv(x,y)));
+ parse_vec_per_param_space(st, |st| parse_ty_(st, conv));
subst::Substs { types: types,
regions: regions }
}
-fn parse_region_substs(st: &mut PState, conv: conv_did) -> subst::RegionSubsts {
+fn parse_region_substs_<F>(st: &mut PState, conv: &mut F) -> subst::RegionSubsts where
+ F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
+{
match next(st) {
'e' => subst::ErasedRegions,
'n' => {
subst::NonerasedRegions(
parse_vec_per_param_space(
- st, |st| parse_region(st, |x,y| conv(x,y))))
+ st, |st| parse_region_(st, conv)))
}
_ => panic!("parse_bound_region: bad input")
}
}
-fn parse_bound_region(st: &mut PState, conv: conv_did) -> ty::BoundRegion {
+fn parse_bound_region_<F>(st: &mut PState, conv: &mut F) -> ty::BoundRegion where
+ F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
+{
match next(st) {
'a' => {
let id = parse_u32(st);
ty::BrAnon(id)
}
'[' => {
- let def = parse_def(st, RegionParameter, |x,y| conv(x,y));
+ let def = parse_def_(st, RegionParameter, conv);
let ident = token::str_to_ident(parse_str(st, ']')[]);
ty::BrNamed(def, ident.name)
}
}
}
-fn parse_region(st: &mut PState, conv: conv_did) -> ty::Region {
+fn parse_region<F>(st: &mut PState, mut conv: F) -> ty::Region where
+ F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
+{
+ parse_region_(st, &mut conv)
+}
+
+fn parse_region_<F>(st: &mut PState, conv: &mut F) -> ty::Region where
+ F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
+{
match next(st) {
'b' => {
assert_eq!(next(st), '[');
let id = ty::DebruijnIndex::new(parse_u32(st));
assert_eq!(next(st), '|');
- let br = parse_bound_region(st, |x,y| conv(x,y));
+ let br = parse_bound_region_(st, conv);
assert_eq!(next(st), ']');
ty::ReLateBound(id, br)
}
assert_eq!(next(st), '[');
let scope = parse_scope(st);
assert_eq!(next(st), '|');
- let br = parse_bound_region(st, |x,y| conv(x,y));
+ let br = parse_bound_region_(st, conv);
assert_eq!(next(st), ']');
ty::ReFree(ty::FreeRegion { scope: scope,
bound_region: br})
result
}
-fn parse_trait_ref<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did)
- -> Rc<ty::TraitRef<'tcx>> {
- let def = parse_def(st, NominalType, |x,y| conv(x,y));
- let substs = st.tcx.mk_substs(parse_substs(st, |x,y| conv(x,y)));
+fn parse_trait_ref<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, mut conv: F)
+ -> Rc<ty::TraitRef<'tcx>> where
+ F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
+{
+ parse_trait_ref_(st, &mut conv)
+}
+
+fn parse_trait_ref_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F)
+ -> Rc<ty::TraitRef<'tcx>> where
+ F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
+{
+ let def = parse_def_(st, NominalType, conv);
+ let substs = st.tcx.mk_substs(parse_substs_(st, conv));
Rc::new(ty::TraitRef {def_id: def, substs: substs})
}
-fn parse_ty<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did) -> Ty<'tcx> {
+fn parse_ty<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, mut conv: F) -> Ty<'tcx> where
+ F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
+{
+ parse_ty_(st, &mut conv)
+}
+
+fn parse_ty_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F) -> Ty<'tcx> where
+ F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
+{
let tcx = st.tcx;
match next(st) {
'b' => return tcx.types.bool,
'c' => return tcx.types.char,
't' => {
assert_eq!(next(st), '[');
- let def = parse_def(st, NominalType, |x,y| conv(x,y));
- let substs = parse_substs(st, |x,y| conv(x,y));
+ let def = parse_def_(st, NominalType, conv);
+ let substs = parse_substs_(st, conv);
assert_eq!(next(st), ']');
return ty::mk_enum(tcx, def, st.tcx.mk_substs(substs));
}
'x' => {
assert_eq!(next(st), '[');
- let trait_ref = ty::Binder(parse_trait_ref(st, |x,y| conv(x,y)));
- let bounds = parse_existential_bounds(st, |x,y| conv(x,y));
+ let trait_ref = ty::Binder(parse_trait_ref_(st, conv));
+ let bounds = parse_existential_bounds_(st, conv);
assert_eq!(next(st), ']');
return ty::mk_trait(tcx, trait_ref, bounds);
}
let name = token::intern(parse_str(st, ']')[]);
return ty::mk_param(tcx, space, index, name);
}
- '~' => return ty::mk_uniq(tcx, parse_ty(st, |x,y| conv(x,y))),
- '*' => return ty::mk_ptr(tcx, parse_mt(st, |x,y| conv(x,y))),
+ '~' => return ty::mk_uniq(tcx, parse_ty_(st, conv)),
+ '*' => return ty::mk_ptr(tcx, parse_mt_(st, conv)),
'&' => {
- let r = parse_region(st, |x,y| conv(x,y));
- let mt = parse_mt(st, |x,y| conv(x,y));
+ let r = parse_region_(st, conv);
+ let mt = parse_mt_(st, conv);
return ty::mk_rptr(tcx, tcx.mk_region(r), mt);
}
'V' => {
- let t = parse_ty(st, |x,y| conv(x,y));
+ let t = parse_ty_(st, conv);
let sz = parse_size(st);
return ty::mk_vec(tcx, t, sz);
}
'T' => {
assert_eq!(next(st), '[');
let mut params = Vec::new();
- while peek(st) != ']' { params.push(parse_ty(st, |x,y| conv(x,y))); }
+ while peek(st) != ']' { params.push(parse_ty_(st, conv)); }
st.pos = st.pos + 1u;
return ty::mk_tup(tcx, params);
}
- 'f' => {
- return ty::mk_closure(tcx, parse_closure_ty(st, |x,y| conv(x,y)));
- }
'F' => {
- let def_id = parse_def(st, NominalType, |x,y| conv(x,y));
+ let def_id = parse_def_(st, NominalType, conv);
return ty::mk_bare_fn(tcx, Some(def_id),
- tcx.mk_bare_fn(parse_bare_fn_ty(st, |x,y| conv(x,y))));
+ tcx.mk_bare_fn(parse_bare_fn_ty_(st, conv)));
}
'G' => {
return ty::mk_bare_fn(tcx, None,
- tcx.mk_bare_fn(parse_bare_fn_ty(st, |x,y| conv(x,y))));
+ tcx.mk_bare_fn(parse_bare_fn_ty_(st, conv)));
}
'#' => {
let pos = parse_hex(st);
pos: pos,
.. *st
};
- let tt = parse_ty(&mut ps, |x,y| conv(x,y));
+ let tt = parse_ty_(&mut ps, conv);
tcx.rcache.borrow_mut().insert(key, tt);
return tt;
}
'\"' => {
- let _ = parse_def(st, TypeWithId, |x,y| conv(x,y));
- let inner = parse_ty(st, |x,y| conv(x,y));
+ let _ = parse_def_(st, TypeWithId, conv);
+ let inner = parse_ty_(st, conv);
inner
}
'a' => {
assert_eq!(next(st), '[');
- let did = parse_def(st, NominalType, |x,y| conv(x,y));
- let substs = parse_substs(st, |x,y| conv(x,y));
+ let did = parse_def_(st, NominalType, conv);
+ let substs = parse_substs_(st, conv);
assert_eq!(next(st), ']');
return ty::mk_struct(st.tcx, did, st.tcx.mk_substs(substs));
}
'k' => {
assert_eq!(next(st), '[');
- let did = parse_def(st, UnboxedClosureSource, |x,y| conv(x,y));
- let region = parse_region(st, |x,y| conv(x,y));
- let substs = parse_substs(st, |x,y| conv(x,y));
+ let did = parse_def_(st, UnboxedClosureSource, conv);
+ let region = parse_region_(st, conv);
+ let substs = parse_substs_(st, conv);
assert_eq!(next(st), ']');
return ty::mk_unboxed_closure(st.tcx, did,
st.tcx.mk_region(region), st.tcx.mk_substs(substs));
}
'P' => {
assert_eq!(next(st), '[');
- let trait_ref = parse_trait_ref(st, |x,y| conv(x,y));
+ let trait_ref = parse_trait_ref_(st, conv);
let name = token::intern(parse_str(st, ']').as_slice());
return ty::mk_projection(tcx, trait_ref, name);
}
}
}
-fn parse_mt<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did) -> ty::mt<'tcx> {
+fn parse_mt_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F) -> ty::mt<'tcx> where
+ F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
+{
let m = parse_mutability(st);
- ty::mt { ty: parse_ty(st, |x,y| conv(x,y)), mutbl: m }
+ ty::mt { ty: parse_ty_(st, conv), mutbl: m }
}
-fn parse_def(st: &mut PState, source: DefIdSource,
- conv: conv_did) -> ast::DefId {
- return conv(source, scan(st, |c| { c == '|' }, parse_def_id));
+fn parse_def_<F>(st: &mut PState, source: DefIdSource, conv: &mut F) -> ast::DefId where
+ F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
+{
+ return (*conv)(source, scan(st, |c| { c == '|' }, parse_def_id));
}
fn parse_uint(st: &mut PState) -> uint {
}
}
-fn parse_closure_ty<'a, 'tcx>(st: &mut PState<'a, 'tcx>,
- conv: conv_did) -> ty::ClosureTy<'tcx> {
+fn parse_closure_ty<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>,
+ mut conv: F) -> ty::ClosureTy<'tcx> where
+ F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
+{
+ parse_closure_ty_(st, &mut conv)
+}
+
+fn parse_closure_ty_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>,
+ conv: &mut F) -> ty::ClosureTy<'tcx> where
+ F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
+{
let unsafety = parse_unsafety(next(st));
let onceness = parse_onceness(next(st));
- let store = parse_trait_store(st, |x,y| conv(x,y));
- let bounds = parse_existential_bounds(st, |x,y| conv(x,y));
- let sig = parse_sig(st, |x,y| conv(x,y));
+ let store = parse_trait_store_(st, conv);
+ let bounds = parse_existential_bounds_(st, conv);
+ let sig = parse_sig_(st, conv);
let abi = parse_abi_set(st);
ty::ClosureTy {
unsafety: unsafety,
}
}
-fn parse_bare_fn_ty<'a, 'tcx>(st: &mut PState<'a, 'tcx>,
- conv: conv_did) -> ty::BareFnTy<'tcx> {
+fn parse_bare_fn_ty<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>,
+ mut conv: F) -> ty::BareFnTy<'tcx> where
+ F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
+{
+ parse_bare_fn_ty_(st, &mut conv)
+}
+
+fn parse_bare_fn_ty_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>,
+ conv: &mut F) -> ty::BareFnTy<'tcx> where
+ F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
+{
let unsafety = parse_unsafety(next(st));
let abi = parse_abi_set(st);
- let sig = parse_sig(st, |x,y| conv(x,y));
+ let sig = parse_sig_(st, conv);
ty::BareFnTy {
unsafety: unsafety,
abi: abi,
}
}
-fn parse_sig<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did) -> ty::PolyFnSig<'tcx> {
+fn parse_sig_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F) -> ty::PolyFnSig<'tcx> where
+ F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
+{
assert_eq!(next(st), '[');
let mut inputs = Vec::new();
while peek(st) != ']' {
- inputs.push(parse_ty(st, |x,y| conv(x,y)));
+ inputs.push(parse_ty_(st, conv));
}
st.pos += 1u; // eat the ']'
let variadic = match next(st) {
st.pos += 1u;
ty::FnDiverging
}
- _ => ty::FnConverging(parse_ty(st, |x,y| conv(x,y)))
+ _ => ty::FnConverging(parse_ty_(st, conv))
};
ty::Binder(ty::FnSig {inputs: inputs,
output: output,
ast::DefId { krate: crate_num, node: def_num }
}
-pub fn parse_predicate_data<'tcx>(data: &[u8],
- start: uint,
- crate_num: ast::CrateNum,
- tcx: &ty::ctxt<'tcx>,
- conv: conv_did)
- -> ty::Predicate<'tcx>
+pub fn parse_predicate_data<'tcx, F>(data: &[u8],
+ start: uint,
+ crate_num: ast::CrateNum,
+ tcx: &ty::ctxt<'tcx>,
+ conv: F)
+ -> ty::Predicate<'tcx> where
+ F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
{
let mut st = parse_state_from_data(data, crate_num, start, tcx);
parse_predicate(&mut st, conv)
}
-pub fn parse_predicate<'a,'tcx>(st: &mut PState<'a, 'tcx>,
- conv: conv_did)
- -> ty::Predicate<'tcx>
+pub fn parse_predicate<'a,'tcx, F>(st: &mut PState<'a, 'tcx>,
+ mut conv: F)
+ -> ty::Predicate<'tcx> where
+ F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
+{
+ parse_predicate_(st, &mut conv)
+}
+
+fn parse_predicate_<'a,'tcx, F>(st: &mut PState<'a, 'tcx>,
+ conv: &mut F)
+ -> ty::Predicate<'tcx> where
+ F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
{
match next(st) {
- 't' => ty::Binder(parse_trait_ref(st, conv)).as_predicate(),
- 'e' => ty::Binder(ty::EquatePredicate(parse_ty(st, |x,y| conv(x,y)),
- parse_ty(st, |x,y| conv(x,y)))).as_predicate(),
- 'r' => ty::Binder(ty::OutlivesPredicate(parse_region(st, |x,y| conv(x,y)),
- parse_region(st, |x,y| conv(x,y)))).as_predicate(),
- 'o' => ty::Binder(ty::OutlivesPredicate(parse_ty(st, |x,y| conv(x,y)),
- parse_region(st, |x,y| conv(x,y)))).as_predicate(),
- 'p' => ty::Binder(parse_projection_predicate(st, conv)).as_predicate(),
+ 't' => ty::Binder(parse_trait_ref_(st, conv)).as_predicate(),
+ 'e' => ty::Binder(ty::EquatePredicate(parse_ty_(st, conv),
+ parse_ty_(st, conv))).as_predicate(),
+ 'r' => ty::Binder(ty::OutlivesPredicate(parse_region_(st, conv),
+ parse_region_(st, conv))).as_predicate(),
+ 'o' => ty::Binder(ty::OutlivesPredicate(parse_ty_(st, conv),
+ parse_region_(st, conv))).as_predicate(),
+ 'p' => ty::Binder(parse_projection_predicate_(st, conv)).as_predicate(),
c => panic!("Encountered invalid character in metadata: {}", c)
}
}
-fn parse_projection_predicate<'a,'tcx>(
+fn parse_projection_predicate_<'a,'tcx, F>(
st: &mut PState<'a, 'tcx>,
- conv: conv_did)
- -> ty::ProjectionPredicate<'tcx>
+ conv: &mut F,
+) -> ty::ProjectionPredicate<'tcx> where
+ F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
{
ty::ProjectionPredicate {
projection_ty: ty::ProjectionTy {
- trait_ref: parse_trait_ref(st, |x,y| conv(x,y)),
+ trait_ref: parse_trait_ref_(st, conv),
item_name: token::str_to_ident(parse_str(st, '|').as_slice()).name,
},
- ty: parse_ty(st, |x,y| conv(x,y)),
+ ty: parse_ty_(st, conv),
}
}
-pub fn parse_type_param_def_data<'tcx>(data: &[u8], start: uint,
- crate_num: ast::CrateNum, tcx: &ty::ctxt<'tcx>,
- conv: conv_did) -> ty::TypeParameterDef<'tcx>
+pub fn parse_type_param_def_data<'tcx, F>(data: &[u8], start: uint,
+ crate_num: ast::CrateNum, tcx: &ty::ctxt<'tcx>,
+ conv: F) -> ty::TypeParameterDef<'tcx> where
+ F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
{
let mut st = parse_state_from_data(data, crate_num, start, tcx);
parse_type_param_def(&mut st, conv)
}
-fn parse_type_param_def<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did)
- -> ty::TypeParameterDef<'tcx> {
+fn parse_type_param_def<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, mut conv: F)
+ -> ty::TypeParameterDef<'tcx> where
+ F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
+{
+ parse_type_param_def_(st, &mut conv)
+}
+
+fn parse_type_param_def_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F)
+ -> ty::TypeParameterDef<'tcx> where
+ F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
+{
let name = parse_name(st, ':');
- let def_id = parse_def(st, NominalType, |x,y| conv(x,y));
+ let def_id = parse_def_(st, NominalType, conv);
let space = parse_param_space(st);
assert_eq!(next(st), '|');
let index = parse_u32(st);
assert_eq!(next(st), '|');
- let bounds = parse_bounds(st, |x,y| conv(x,y));
- let default = parse_opt(st, |st| parse_ty(st, |x,y| conv(x,y)));
+ let bounds = parse_bounds_(st, conv);
+ let default = parse_opt(st, |st| parse_ty_(st, conv));
ty::TypeParameterDef {
name: name,
}
}
-fn parse_existential_bounds<'a,'tcx>(st: &mut PState<'a,'tcx>,
- conv: conv_did)
- -> ty::ExistentialBounds<'tcx>
+fn parse_existential_bounds<'a,'tcx, F>(st: &mut PState<'a,'tcx>,
+ mut conv: F)
+ -> ty::ExistentialBounds<'tcx> where
+ F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
+{
+ parse_existential_bounds_(st, &mut conv)
+}
+
+fn parse_existential_bounds_<'a,'tcx, F>(st: &mut PState<'a,'tcx>,
+ conv: &mut F)
+ -> ty::ExistentialBounds<'tcx> where
+ F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
{
let ty::ParamBounds { trait_bounds, mut region_bounds, builtin_bounds, projection_bounds } =
- parse_bounds(st, conv);
+ parse_bounds_(st, conv);
assert_eq!(region_bounds.len(), 1);
assert_eq!(trait_bounds.len(), 0);
let region_bound = region_bounds.pop().unwrap();
projection_bounds: projection_bounds };
}
-fn parse_builtin_bounds(st: &mut PState, _conv: conv_did) -> ty::BuiltinBounds {
+fn parse_builtin_bounds<F>(st: &mut PState, mut _conv: F) -> ty::BuiltinBounds where
+ F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
+{
+ parse_builtin_bounds_(st, &mut _conv)
+}
+
+fn parse_builtin_bounds_<F>(st: &mut PState, _conv: &mut F) -> ty::BuiltinBounds where
+ F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
+{
let mut builtin_bounds = ty::empty_builtin_bounds();
loop {
}
}
-fn parse_bounds<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did)
- -> ty::ParamBounds<'tcx> {
- let builtin_bounds = parse_builtin_bounds(st, |x,y| conv(x,y));
+fn parse_bounds<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, mut conv: F)
+ -> ty::ParamBounds<'tcx> where
+ F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
+{
+ parse_bounds_(st, &mut conv)
+}
+
+fn parse_bounds_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F)
+ -> ty::ParamBounds<'tcx> where
+ F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
+{
+ let builtin_bounds = parse_builtin_bounds_(st, conv);
let mut param_bounds = ty::ParamBounds {
region_bounds: Vec::new(),
match next(st) {
'R' => {
param_bounds.region_bounds.push(
- parse_region(st, |x, y| conv (x, y)));
+ parse_region_(st, conv));
}
'I' => {
param_bounds.trait_bounds.push(
- ty::Binder(parse_trait_ref(st, |x,y| conv(x,y))));
+ ty::Binder(parse_trait_ref_(st, conv)));
}
'P' => {
param_bounds.projection_bounds.push(
- ty::Binder(parse_projection_predicate(st, |x,y| conv(x,y))));
+ ty::Binder(parse_projection_predicate_(st, conv)));
}
'.' => {
return param_bounds;
ty::ty_str => {
mywrite!(w, "v");
}
- ty::ty_closure(ref f) => {
- mywrite!(w, "f");
- enc_closure_ty(w, cx, &**f);
- }
ty::ty_bare_fn(Some(def_id), f) => {
mywrite!(w, "F");
mywrite!(w, "{}|", (cx.ds)(def_id));
fn emit_def_id(&mut self, did: ast::DefId);
}
+#[cfg(stage0)]
impl<S:serialize::Encoder<E>, E> def_id_encoder_helpers for S {
fn emit_def_id(&mut self, did: ast::DefId) {
did.encode(self).ok().unwrap()
}
}
+#[cfg(not(stage0))]
+impl<S:serialize::Encoder> def_id_encoder_helpers for S {
+ fn emit_def_id(&mut self, did: ast::DefId) {
+ did.encode(self).ok().unwrap()
+ }
+}
+
trait def_id_decoder_helpers {
fn read_def_id(&mut self, dcx: &DecodeContext) -> ast::DefId;
fn read_def_id_nodcx(&mut self,
cdata: &cstore::crate_metadata) -> ast::DefId;
}
+#[cfg(stage0)]
impl<D:serialize::Decoder<E>, E> def_id_decoder_helpers for D {
fn read_def_id(&mut self, dcx: &DecodeContext) -> ast::DefId {
let did: ast::DefId = Decodable::decode(self).ok().unwrap();
}
}
+#[cfg(not(stage0))]
+impl<D:serialize::Decoder> def_id_decoder_helpers for D {
+ fn read_def_id(&mut self, dcx: &DecodeContext) -> ast::DefId {
+ let did: ast::DefId = Decodable::decode(self).ok().unwrap();
+ did.tr(dcx)
+ }
+
+ fn read_def_id_nodcx(&mut self,
+ cdata: &cstore::crate_metadata) -> ast::DefId {
+ let did: ast::DefId = Decodable::decode(self).ok().unwrap();
+ decoder::translate_def_id(cdata, did)
+ }
+}
+
// ______________________________________________________________________
// Encoding and decoding the AST itself
//
self.emit_enum("AutoAdjustment", |this| {
match *adj {
- ty::AdjustAddEnv(def_id, store) => {
- this.emit_enum_variant("AdjustAddEnv", 0, 2, |this| {
- this.emit_enum_variant_arg(0, |this| def_id.encode(this));
- this.emit_enum_variant_arg(1, |this| store.encode(this))
- })
- }
-
ty::AdjustReifyFnPointer(def_id) => {
this.emit_enum_variant("AdjustReifyFnPointer", 1, 2, |this| {
this.emit_enum_variant_arg(0, |this| def_id.encode(this))
let variants = ["AutoAddEnv", "AutoDerefRef"];
this.read_enum_variant(&variants, |this, i| {
Ok(match i {
- 0 => {
- let def_id: ast::DefId =
- this.read_def_id(dcx);
- let store: ty::TraitStore =
- this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap();
-
- ty::AdjustAddEnv(def_id, store.tr(dcx))
- }
1 => {
let def_id: ast::DefId =
this.read_def_id(dcx);
let method_call = ty::MethodCall::expr(call_expr.id);
let return_ty = ty::ty_fn_ret(match self.tcx.method_map.borrow().get(&method_call) {
Some(method) => method.ty,
- None => ty::expr_ty(self.tcx, func_or_rcvr)
+ None => ty::expr_ty_adjusted(self.tcx, func_or_rcvr)
});
let func_or_rcvr_exit = self.expr(func_or_rcvr, pred);
fn node_label(&'a self, &(i, n): &Node<'a>) -> dot::LabelText<'a> {
if i == self.cfg.entry {
- dot::LabelStr("entry".into_cow())
+ dot::LabelText::LabelStr("entry".into_cow())
} else if i == self.cfg.exit {
- dot::LabelStr("exit".into_cow())
+ dot::LabelText::LabelStr("exit".into_cow())
} else if n.data.id == ast::DUMMY_NODE_ID {
- dot::LabelStr("(dummy_node)".into_cow())
+ dot::LabelText::LabelStr("(dummy_node)".into_cow())
} else {
let s = self.ast_map.node_to_string(n.data.id);
// left-aligns the lines
let s = replace_newline_with_backslash_l(s);
- dot::EscStr(s.into_cow())
+ dot::LabelText::EscStr(s.into_cow())
}
}
let s = replace_newline_with_backslash_l(s);
label.push_str(format!("exiting scope_{} {}", i, s[])[]);
}
- dot::EscStr(label.into_cow())
+ dot::LabelText::EscStr(label.into_cow())
}
}
use util::ppaux;
use syntax::ast;
-use syntax::ast_util;
-use syntax::visit::Visitor;
-use syntax::visit;
+use syntax::visit::{self, Visitor};
struct CheckCrateVisitor<'a, 'tcx: 'a> {
tcx: &'a ty::ctxt<'tcx>,
{
self.with_const(true, f);
}
- fn outside_const<F>(&mut self, f: F) where
- F: FnOnce(&mut CheckCrateVisitor<'a, 'tcx>),
- {
- self.with_const(false, f);
- }
}
impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
fn visit_item(&mut self, i: &ast::Item) {
- check_item(self, i);
+ match i.node {
+ ast::ItemStatic(_, _, ref ex) |
+ ast::ItemConst(_, ref ex) => {
+ self.inside_const(|v| v.visit_expr(&**ex));
+ }
+ ast::ItemEnum(ref enum_definition, _) => {
+ self.inside_const(|v| {
+ for var in enum_definition.variants.iter() {
+ if let Some(ref ex) = var.node.disr_expr {
+ v.visit_expr(&**ex);
+ }
+ }
+ });
+ }
+ _ => self.with_const(false, |v| visit::walk_item(v, i))
+ }
}
fn visit_pat(&mut self, p: &ast::Pat) {
- check_pat(self, p);
+ let is_const = match p.node {
+ ast::PatLit(_) | ast::PatRange(..) => true,
+ _ => false
+ };
+ self.with_const(is_const, |v| visit::walk_pat(v, p))
}
fn visit_expr(&mut self, ex: &ast::Expr) {
- if check_expr(self, ex) {
- visit::walk_expr(self, ex);
+ if self.in_const {
+ check_expr(self, ex);
}
+ visit::walk_expr(self, ex);
}
}
tcx.sess.abort_if_errors();
}
-fn check_item(v: &mut CheckCrateVisitor, it: &ast::Item) {
- match it.node {
- ast::ItemStatic(_, _, ref ex) |
- ast::ItemConst(_, ref ex) => {
- v.inside_const(|v| v.visit_expr(&**ex));
- }
- ast::ItemEnum(ref enum_definition, _) => {
- for var in (*enum_definition).variants.iter() {
- for ex in var.node.disr_expr.iter() {
- v.inside_const(|v| v.visit_expr(&**ex));
- }
- }
- }
- _ => v.outside_const(|v| visit::walk_item(v, it))
- }
-}
-
-fn check_pat(v: &mut CheckCrateVisitor, p: &ast::Pat) {
- fn is_str(e: &ast::Expr) -> bool {
- match e.node {
- ast::ExprBox(_, ref expr) => {
- match expr.node {
- ast::ExprLit(ref lit) => ast_util::lit_is_str(&**lit),
- _ => false,
- }
- }
- _ => false,
- }
- }
- match p.node {
- // Let through plain ~-string literals here
- ast::PatLit(ref a) => if !is_str(&**a) { v.inside_const(|v| v.visit_expr(&**a)); },
- ast::PatRange(ref a, ref b) => {
- if !is_str(&**a) { v.inside_const(|v| v.visit_expr(&**a)); }
- if !is_str(&**b) { v.inside_const(|v| v.visit_expr(&**b)); }
- }
- _ => v.outside_const(|v| visit::walk_pat(v, p))
- }
-}
-
-fn check_expr(v: &mut CheckCrateVisitor, e: &ast::Expr) -> bool {
- if !v.in_const { return true }
-
+fn check_expr(v: &mut CheckCrateVisitor, e: &ast::Expr) {
match e.node {
ast::ExprUnary(ast::UnDeref, _) => {}
ast::ExprUnary(ast::UnUniq, _) => {
span_err!(v.tcx.sess, e.span, E0010,
"cannot do allocations in constant expressions");
- return false;
}
- ast::ExprLit(ref lit) if ast_util::lit_is_str(&**lit) => {}
ast::ExprBinary(..) | ast::ExprUnary(..) => {
let method_call = ty::MethodCall::expr(e.id);
if v.tcx.method_map.borrow().contains_key(&method_call) {
expressions");
}
}
- ast::ExprLit(_) => (),
+ ast::ExprLit(_) => {}
ast::ExprCast(ref from, _) => {
let toty = ty::expr_ty(v.tcx, e);
let fromty = ty::expr_ty(v.tcx, &**from);
expression");
}
}
- ast::ExprPath(ref pth) => {
- // NB: In the future you might wish to relax this slightly
- // to handle on-demand instantiation of functions via
- // foo::<bar> in a const. Currently that is only done on
- // a path in trans::callee that only works in block contexts.
- if !pth.segments.iter().all(|segment| segment.parameters.is_empty()) {
- span_err!(v.tcx.sess, e.span, E0013,
- "paths in constants may only refer to items without \
- type parameters");
- }
- match v.tcx.def_map.borrow().get(&e.id) {
- Some(&DefStatic(..)) |
- Some(&DefConst(..)) |
- Some(&DefFn(..)) |
- Some(&DefVariant(_, _, _)) |
- Some(&DefStruct(_)) => { }
+ ast::ExprPath(_) => {
+ match v.tcx.def_map.borrow()[e.id] {
+ DefStatic(..) | DefConst(..) |
+ DefFn(..) | DefStaticMethod(..) | DefMethod(..) |
+ DefStruct(_) | DefVariant(_, _, _) => {}
- Some(&def) => {
+ def => {
debug!("(checking const) found bad def: {}", def);
span_err!(v.tcx.sess, e.span, E0014,
"paths in constants may only refer to constants \
or functions");
}
- None => {
- v.tcx.sess.span_bug(e.span, "unbound path in const?!");
- }
}
}
ast::ExprCall(ref callee, _) => {
- match v.tcx.def_map.borrow().get(&callee.id) {
- Some(&DefStruct(..)) |
- Some(&DefVariant(..)) => {} // OK.
-
+ match v.tcx.def_map.borrow()[callee.id] {
+ DefStruct(..) | DefVariant(..) => {} // OK.
_ => {
span_err!(v.tcx.sess, e.span, E0015,
"function calls in constants are limited to \
"blocks in constants are limited to items and \
tail expressions");
match stmt.node {
- ast::StmtDecl(ref span, _) => {
- match span.node {
- ast::DeclLocal(_) => block_span_err(span.span),
+ ast::StmtDecl(ref decl, _) => {
+ match decl.node {
+ ast::DeclLocal(_) => block_span_err(decl.span),
// Item statements are allowed
ast::DeclItem(_) => {}
}
}
}
- match block.expr {
- Some(ref expr) => { check_expr(v, &**expr); }
- None => {}
- }
}
ast::ExprVec(_) |
ast::ExprAddrOf(ast::MutImmutable, _) |
}
}
- _ => {
- span_err!(v.tcx.sess, e.span, E0019,
- "constant contains unimplemented expression type");
- return false;
- }
+ _ => span_err!(v.tcx.sess, e.span, E0019,
+ "constant contains unimplemented expression type")
}
- true
}
None => {}
}
let expr_id = match csearch::maybe_get_item_ast(tcx, enum_def,
- |a, b, c, d| astencode::decode_inlined_item(a, b, c, d)) {
+ box |a, b, c, d| astencode::decode_inlined_item(a, b, c, d)) {
csearch::found(&ast::IIItem(ref item)) => match item.node {
ast::ItemEnum(ast::EnumDef { ref variants }, _) => {
// NOTE this doesn't do the right thing, it compares inlined
None => {}
}
let expr_id = match csearch::maybe_get_item_ast(tcx, def_id,
- |a, b, c, d| astencode::decode_inlined_item(a, b, c, d)) {
+ box |a, b, c, d| astencode::decode_inlined_item(a, b, c, d)) {
csearch::found(&ast::IIItem(ref item)) => match item.node {
ast::ItemConst(_, ref const_expr) => Some(const_expr.id),
_ => None
ast::ExprCall(ref callee, ref args) => {
let def = tcx.def_map.borrow()[callee.id].clone();
- if let Vacant(entry) = tcx.def_map.borrow_mut().entry(expr.id) {
- entry.set(def);
+ if let Vacant(entry) = tcx.def_map.borrow_mut().entry(&expr.id) {
+ entry.insert(def);
}
let path = match def {
def::DefStruct(def_id) => def_to_path(tcx, def_id),
ast::ItemEnum(ref enum_def, _) if allow_dead_code => {
self.worklist.extend(enum_def.variants.iter().map(|variant| variant.node.id));
}
- ast::ItemImpl(_, _, Some(ref _trait_ref), _, ref impl_items) => {
+ ast::ItemImpl(_, _, _, Some(ref _trait_ref), _, ref impl_items) => {
for impl_item in impl_items.iter() {
match *impl_item {
ast::MethodImplItem(ref method) => {
fn type_is_unsafe_function(ty: Ty) -> bool {
match ty.sty {
ty::ty_bare_fn(_, ref f) => f.unsafety == ast::Unsafety::Unsafe,
- ty::ty_closure(ref f) => f.unsafety == ast::Unsafety::Unsafe,
_ => false,
}
}
ty::ty_bare_fn(..) => {
self.consume_expr(callee);
}
- ty::ty_closure(ref f) => {
- match f.onceness {
- ast::Many => {
- self.borrow_expr(callee,
- ty::ReScope(call_scope),
- ty::UniqueImmBorrow,
- ClosureInvocation);
- }
- ast::Once => {
- self.consume_expr(callee);
- }
- }
- }
ty::ty_err => { }
_ => {
let overloaded_call_type =
None => { }
Some(adjustment) => {
match *adjustment {
- ty::AdjustAddEnv(..) |
ty::AdjustReifyFnPointer(..) => {
// Creating a closure/fn-pointer consumes the
// input and stores it into the resulting
ty::ty_tup(ref tys) => {
Some(TupleSimplifiedType(tys.len()))
}
- ty::ty_closure(ref f) => {
- Some(FunctionSimplifiedType(f.sig.0.inputs.len()))
- }
ty::ty_bare_fn(_, ref f) => {
Some(FunctionSimplifiedType(f.sig.0.inputs.len()))
}
use util::ppaux;
use util::ppaux::Repr;
-use syntax::abi;
use syntax::ast;
// Note: Coerce is not actually a combiner, in that it does not
};
}
- ty::ty_closure(box ty::ClosureTy {
- store: ty::RegionTraitStore(..),
- ..
- }) => {
- return self.unpack_actual_value(a, |a| {
- self.coerce_borrowed_fn(a, b)
- });
- }
-
_ => {}
}
a.repr(self.tcx()), b.repr(self.tcx()));
match b.sty {
- ty::ty_closure(ref f) => {
- if fn_ty_a.abi != abi::Rust || fn_ty_a.unsafety != ast::Unsafety::Normal {
- return self.subtype(a, b);
- }
-
- let fn_ty_b = (*f).clone();
- let adj = ty::AdjustAddEnv(fn_def_id_a, fn_ty_b.store);
- let a_closure = ty::mk_closure(self.tcx(),
- ty::ClosureTy {
- sig: fn_ty_a.sig.clone(),
- .. *fn_ty_b
- });
- try!(self.subtype(a_closure, b));
- Ok(Some(adj))
- }
ty::ty_bare_fn(None, _) => {
let a_fn_pointer = ty::mk_bare_fn(self.tcx(), None, fn_ty_a);
try!(self.subtype(a_fn_pointer, b));
Ok(ty::mk_bare_fn(tcx, a_opt_def_id, tcx.mk_bare_fn(fty)))
}
- (&ty::ty_closure(ref a_fty), &ty::ty_closure(ref b_fty)) => {
- this.closure_tys(&**a_fty, &**b_fty).and_then(|fty| {
- Ok(ty::mk_closure(tcx, fty))
- })
- }
-
(&ty::ty_projection(ref a_data), &ty::ty_projection(ref b_data)) => {
let projection_ty = try!(this.projection_tys(a_data, b_data));
Ok(ty::mk_projection(tcx, projection_ty.trait_ref, projection_ty.item_name))
use super::region_inference::ConcreteFailure;
use super::region_inference::SubSupConflict;
use super::region_inference::SupSupConflict;
-use super::region_inference::ParamBoundFailure;
+use super::region_inference::GenericBoundFailure;
+use super::region_inference::GenericKind;
use super::region_inference::ProcessedErrors;
use super::region_inference::SameRegions;
sub: Region,
sup: Region);
- fn report_param_bound_failure(&self,
- origin: SubregionOrigin<'tcx>,
- param_ty: ty::ParamTy,
- sub: Region,
- sups: Vec<Region>);
+ fn report_generic_bound_failure(&self,
+ origin: SubregionOrigin<'tcx>,
+ kind: GenericKind<'tcx>,
+ sub: Region,
+ sups: Vec<Region>);
fn report_sub_sup_conflict(&self,
var_origin: RegionVariableOrigin,
self.report_concrete_failure(origin, sub, sup);
}
- ParamBoundFailure(origin, param_ty, sub, sups) => {
- self.report_param_bound_failure(origin, param_ty, sub, sups);
+ GenericBoundFailure(kind, param_ty, sub, sups) => {
+ self.report_generic_bound_failure(kind, param_ty, sub, sups);
}
SubSupConflict(var_origin,
found.user_string(self.tcx)))
}
- fn report_param_bound_failure(&self,
- origin: SubregionOrigin<'tcx>,
- param_ty: ty::ParamTy,
- sub: Region,
- _sups: Vec<Region>) {
-
+ fn report_generic_bound_failure(&self,
+ origin: SubregionOrigin<'tcx>,
+ bound_kind: GenericKind<'tcx>,
+ sub: Region,
+ _sups: Vec<Region>)
+ {
// FIXME: it would be better to report the first error message
// with the span of the parameter itself, rather than the span
// where the error was detected. But that span is not readily
// accessible.
+ let labeled_user_string = match bound_kind {
+ GenericKind::Param(ref p) =>
+ format!("the parameter type `{}`", p.user_string(self.tcx)),
+ GenericKind::Projection(ref p) =>
+ format!("the associated type `{}`", p.user_string(self.tcx)),
+ };
+
match sub {
ty::ReFree(ty::FreeRegion {bound_region: ty::BrNamed(..), ..}) => {
// Does the required lifetime have a nice name we can print?
self.tcx.sess.span_err(
origin.span(),
- format!(
- "the parameter type `{}` may not live long enough",
- param_ty.user_string(self.tcx))[]);
+ format!("{} may not live long enough", labeled_user_string)[]);
self.tcx.sess.span_help(
origin.span(),
format!(
"consider adding an explicit lifetime bound `{}: {}`...",
- param_ty.user_string(self.tcx),
+ bound_kind.user_string(self.tcx),
sub.user_string(self.tcx))[]);
}
// Does the required lifetime have a nice name we can print?
self.tcx.sess.span_err(
origin.span(),
- format!(
- "the parameter type `{}` may not live long enough",
- param_ty.user_string(self.tcx))[]);
+ format!("{} may not live long enough", labeled_user_string)[]);
self.tcx.sess.span_help(
origin.span(),
format!(
"consider adding an explicit lifetime bound `{}: 'static`...",
- param_ty.user_string(self.tcx))[]);
+ bound_kind.user_string(self.tcx))[]);
}
_ => {
self.tcx.sess.span_err(
origin.span(),
format!(
- "the parameter type `{}` may not live long enough",
- param_ty.user_string(self.tcx))[]);
+ "{} may not live long enough",
+ labeled_user_string)[]);
self.tcx.sess.span_help(
origin.span(),
format!(
- "consider adding an explicit lifetime bound to `{}`",
- param_ty.user_string(self.tcx))[]);
+ "consider adding an explicit lifetime bound for `{}`",
+ bound_kind.user_string(self.tcx))[]);
note_and_explain_region(
self.tcx,
- format!("the parameter type `{}` must be valid for ",
- param_ty.user_string(self.tcx))[],
+ format!("{} must be valid for ", labeled_user_string)[],
sub,
"...");
}
match tcx.map.find(parent) {
Some(node) => match node {
ast_map::NodeItem(item) => match item.node {
- ast::ItemImpl(_, ref gen, _, _, _) => {
+ ast::ItemImpl(_, _, ref gen, _, _, _) => {
taken.push_all(gen.lifetimes.as_slice());
}
_ => ()
None => { }
}
- match self.freshen_map.entry(key) {
+ match self.freshen_map.entry(&key) {
Entry::Occupied(entry) => *entry.get(),
Entry::Vacant(entry) => {
let index = self.freshen_count;
self.freshen_count += 1;
let t = ty::mk_infer(self.infcx.tcx, freshener(index));
- entry.set(t);
+ entry.insert(t);
t
}
}
ty::ty_ptr(..) |
ty::ty_rptr(..) |
ty::ty_bare_fn(..) |
- ty::ty_closure(..) |
ty::ty_trait(..) |
ty::ty_struct(..) |
ty::ty_unboxed_closure(..) |
pub use self::fixup_err::*;
pub use middle::ty::IntVarValue;
pub use self::freshen::TypeFreshener;
+pub use self::region_inference::GenericKind;
use middle::subst;
use middle::subst::Substs;
cx.region_vars.commit(snapshot);
}
-pub fn verify_param_bound<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
- origin: SubregionOrigin<'tcx>,
- param_ty: ty::ParamTy,
- a: ty::Region,
- bs: Vec<ty::Region>) {
- debug!("verify_param_bound({}, {} <: {})",
- param_ty.repr(cx.tcx),
- a.repr(cx.tcx),
- bs.repr(cx.tcx));
-
- cx.region_vars.verify_param_bound(origin, param_ty, a, bs);
-}
-
pub fn mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
a_is_expected: bool,
origin: TypeOrigin,
value,
|br, _| self.next_region_var(LateBoundRegion(span, br, lbrct)))
}
+
+ /// See `verify_generic_bound` method in `region_inference`
+ pub fn verify_generic_bound(&self,
+ origin: SubregionOrigin<'tcx>,
+ kind: GenericKind<'tcx>,
+ a: ty::Region,
+ bs: Vec<ty::Region>) {
+ debug!("verify_generic_bound({}, {} <: {})",
+ kind.repr(self.tcx),
+ a.repr(self.tcx),
+ bs.repr(self.tcx));
+
+ self.region_vars.verify_generic_bound(origin, kind, a, bs);
+ }
}
impl<'tcx> TypeTrace<'tcx> {
let mut node_ids = FnvHashMap::new();
{
let mut add_node = |&mut : node| {
- if let Vacant(e) = node_ids.entry(node) {
- e.set(i);
+ if let Vacant(e) = node_ids.entry(&node) {
+ e.insert(i);
i += 1;
}
};
use super::{RegionVariableOrigin, SubregionOrigin, TypeTrace, MiscVariable};
use middle::region;
-use middle::ty;
+use middle::ty::{mod, Ty};
use middle::ty::{BoundRegion, FreeRegion, Region, RegionVid};
use middle::ty::{ReEmpty, ReStatic, ReInfer, ReFree, ReEarlyBound};
use middle::ty::{ReLateBound, ReScope, ReVar, ReSkolemized, BrFresh};
use middle::graph::{Direction, NodeIndex};
use util::common::indenter;
use util::nodemap::{FnvHashMap, FnvHashSet};
-use util::ppaux::Repr;
+use util::ppaux::{Repr, UserString};
use std::cell::{Cell, RefCell};
use std::cmp::Ordering::{self, Less, Greater, Equal};
// `b` are inference variables.
VerifyRegSubReg(SubregionOrigin<'tcx>, Region, Region),
- // VerifyParamBound(T, _, R, RS): The parameter type `T` must
- // outlive the region `R`. `T` is known to outlive `RS`. Therefore
- // verify that `R <= RS[i]` for some `i`. Inference variables may
- // be involved (but this verification step doesn't influence
- // inference).
- VerifyParamBound(ty::ParamTy, SubregionOrigin<'tcx>, Region, Vec<Region>),
+ // VerifyGenericBound(T, _, R, RS): The parameter type `T` (or
+ // associated type) must outlive the region `R`. `T` is known to
+ // outlive `RS`. Therefore verify that `R <= RS[i]` for some
+ // `i`. Inference variables may be involved (but this verification
+ // step doesn't influence inference).
+ VerifyGenericBound(GenericKind<'tcx>, SubregionOrigin<'tcx>, Region, Vec<Region>),
+}
+
+#[deriving(Clone, Show, PartialEq, Eq)]
+pub enum GenericKind<'tcx> {
+ Param(ty::ParamTy),
+ Projection(ty::ProjectionTy<'tcx>),
}
#[derive(Copy, PartialEq, Eq, Hash)]
/// `o` requires that `a <= b`, but this does not hold
ConcreteFailure(SubregionOrigin<'tcx>, Region, Region),
- /// `ParamBoundFailure(p, s, a, bs)
+ /// `GenericBoundFailure(p, s, a, bs)
///
- /// The parameter type `p` must be known to outlive the lifetime
+ /// The parameter/assocated-type `p` must be known to outlive the lifetime
/// `a`, but it is only known to outlive `bs` (and none of the
/// regions in `bs` outlive `a`).
- ParamBoundFailure(SubregionOrigin<'tcx>, ty::ParamTy, Region, Vec<Region>),
+ GenericBoundFailure(SubregionOrigin<'tcx>, GenericKind<'tcx>, Region, Vec<Region>),
/// `SubSupConflict(v, sub_origin, sub_r, sup_origin, sup_r)`:
///
}
}
- pub fn verify_param_bound(&self,
- origin: SubregionOrigin<'tcx>,
- param_ty: ty::ParamTy,
- sub: Region,
- sups: Vec<Region>) {
- self.add_verify(VerifyParamBound(param_ty, origin, sub, sups));
+ /// See `Verify::VerifyGenericBound`
+ pub fn verify_generic_bound(&self,
+ origin: SubregionOrigin<'tcx>,
+ kind: GenericKind<'tcx>,
+ sub: Region,
+ sups: Vec<Region>) {
+ self.add_verify(VerifyGenericBound(kind, origin, sub, sups));
}
pub fn lub_regions(&self,
&mut result_set, r,
a, b);
}
- VerifyParamBound(_, _, a, ref bs) => {
+ VerifyGenericBound(_, _, a, ref bs) => {
for &b in bs.iter() {
consider_adding_bidirectional_edges(
&mut result_set, r,
errors.push(ConcreteFailure((*origin).clone(), sub, sup));
}
- VerifyParamBound(ref param_ty, ref origin, sub, ref sups) => {
+ VerifyGenericBound(ref kind, ref origin, sub, ref sups) => {
let sub = normalize(values, sub);
if sups.iter()
.map(|&sup| normalize(values, sup))
let sups = sups.iter().map(|&sup| normalize(values, sup))
.collect();
errors.push(
- ParamBoundFailure(
- (*origin).clone(), *param_ty, sub, sups));
+ GenericBoundFailure(
+ (*origin).clone(), kind.clone(), sub, sups));
}
}
}
VerifyRegSubReg(_, ref a, ref b) => {
format!("VerifyRegSubReg({}, {})", a.repr(tcx), b.repr(tcx))
}
- VerifyParamBound(_, ref p, ref a, ref bs) => {
- format!("VerifyParamBound({}, {}, {})",
+ VerifyGenericBound(_, ref p, ref a, ref bs) => {
+ format!("VerifyGenericBound({}, {}, {})",
p.repr(tcx), a.repr(tcx), bs.repr(tcx))
}
}
self.origin.repr(tcx))
}
}
+
+impl<'tcx> Repr<'tcx> for GenericKind<'tcx> {
+ fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
+ match *self {
+ GenericKind::Param(ref p) => p.repr(tcx),
+ GenericKind::Projection(ref p) => p.repr(tcx),
+ }
+ }
+}
+
+impl<'tcx> UserString<'tcx> for GenericKind<'tcx> {
+ fn user_string(&self, tcx: &ty::ctxt<'tcx>) -> String {
+ match *self {
+ GenericKind::Param(ref p) => p.user_string(tcx),
+ GenericKind::Projection(ref p) => p.user_string(tcx),
+ }
+ }
+}
+
+impl<'tcx> GenericKind<'tcx> {
+ pub fn to_ty(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx> {
+ match *self {
+ GenericKind::Param(ref p) =>
+ p.to_ty(tcx),
+ GenericKind::Projection(ref p) =>
+ ty::mk_projection(tcx, p.trait_ref.clone(), p.item_name),
+ }
+ }
+}
ast::ExprCall(ref f, ref args) => {
let diverges = !self.ir.tcx.is_method_call(expr.id) && {
- let t_ret = ty::ty_fn_ret(ty::expr_ty(self.ir.tcx, &**f));
+ let t_ret = ty::ty_fn_ret(ty::expr_ty_adjusted(self.ir.tcx, &**f));
t_ret == ty::FnDiverging
};
let succ = if diverges {
// pointer adjustment).
pub fn deref_kind(t: Ty) -> McResult<deref_kind> {
match t.sty {
- ty::ty_uniq(_) |
- ty::ty_closure(box ty::ClosureTy {store: ty::UniqTraitStore, ..}) => {
+ ty::ty_uniq(_) => {
Ok(deref_ptr(Unique))
}
Ok(deref_ptr(BorrowedPtr(kind, *r)))
}
- ty::ty_closure(box ty::ClosureTy {
- store: ty::RegionTraitStore(r, _),
- ..
- }) => {
- Ok(deref_ptr(BorrowedPtr(ty::ImmBorrow, r)))
- }
-
ty::ty_ptr(ref mt) => {
Ok(deref_ptr(UnsafePtr(mt.mutbl)))
}
Some(adjustment) => {
match *adjustment {
- ty::AdjustAddEnv(..) | ty::AdjustReifyFnPointer(..) => {
- debug!("cat_expr(AdjustAddEnv|AdjustReifyFnPointer): {}",
+ ty::AdjustReifyFnPointer(..) => {
+ debug!("cat_expr(AdjustReifyFnPointer): {}",
expr.repr(self.tcx()));
// Convert a bare fn to a closure by adding NULL env.
// Result is an rvalue.
id, expr_ty.repr(self.tcx()), def);
match def {
- def::DefStruct(..) | def::DefVariant(..) | def::DefFn(..) |
- def::DefStaticMethod(..) | def::DefConst(..) => {
+ def::DefStruct(..) | def::DefVariant(..) | def::DefConst(..) |
+ def::DefFn(..) | def::DefStaticMethod(..) | def::DefMethod(..) => {
Ok(self.cat_rvalue_node(id, span, expr_ty))
}
def::DefMod(_) | def::DefForeignMod(_) | def::DefUse(_) |
def::DefTrait(_) | def::DefTy(..) | def::DefPrimTy(_) |
def::DefTyParam(..) | def::DefTyParamBinder(..) | def::DefRegion(_) |
- def::DefLabel(_) | def::DefSelfTy(..) | def::DefMethod(..) |
+ def::DefLabel(_) | def::DefSelfTy(..) |
def::DefAssociatedTy(..) | def::DefAssociatedPath(..)=> {
Ok(Rc::new(cmt_ {
id:id,
def::DefUpvar(var_id, fn_node_id, _) => {
let ty = try!(self.node_ty(fn_node_id));
match ty.sty {
- ty::ty_closure(ref closure_ty) => {
- // Translate old closure type info into unboxed
- // closure kind/capture mode
- let (mode, kind) = match (closure_ty.store, closure_ty.onceness) {
- // stack closure
- (ty::RegionTraitStore(..), ast::Many) => {
- (ast::CaptureByRef, ty::FnMutUnboxedClosureKind)
- }
- // proc or once closure
- (_, ast::Once) => {
- (ast::CaptureByValue, ty::FnOnceUnboxedClosureKind)
- }
- // There should be no such old closure type
- (ty::UniqTraitStore, ast::Many) => {
- self.tcx().sess.span_bug(span, "Impossible closure type");
- }
- };
- self.cat_upvar(id, span, var_id, fn_node_id, kind, mode, false)
- }
ty::ty_unboxed_closure(closure_id, _, _) => {
let kind = self.typer.unboxed_closure_kind(closure_id);
let mode = self.typer.capture_mode(fn_node_id);
// undefined symbols at linkage time if this case is not handled.
//
// * Private trait impls for private types can be completely ignored
- ast::ItemImpl(_, _, _, ref ty, ref impl_items) => {
+ ast::ItemImpl(_, _, _, _, ref ty, ref impl_items) => {
let public_ty = match ty.node {
ast::TyPath(_, id) => {
match self.tcx.def_map.borrow()[id].clone() {
// invoked, and the struct/enum itself is private. Crawl
// back up the chains to find the relevant struct/enum that
// was private.
- ast::ItemImpl(_, _, _, ref ty, _) => {
+ ast::ItemImpl(_, _, _, _, ref ty, _) => {
let id = match ty.node {
ast::TyPath(_, id) => id,
_ => return Some((err_span, err_msg, None)),
debug!("privacy - path {}", self.nodestr(path_id));
let orig_def = self.tcx.def_map.borrow()[path_id].clone();
let ck = |&: tyname: &str| {
- let ck_public = |def: ast::DefId| {
+ let ck_public = |&: def: ast::DefId| {
let name = token::get_ident(path.segments.last().unwrap().identifier);
let origdid = orig_def.def_id();
self.ensure_public(span,
match item.node {
// implementations of traits don't need visibility qualifiers because
// that's controlled by having the trait in scope.
- ast::ItemImpl(_, _, Some(..), _, ref impl_items) => {
+ ast::ItemImpl(_, _, _, Some(..), _, ref impl_items) => {
check_inherited(item.span, item.vis,
"visibility qualifiers have no effect on trait \
impls");
};
check_inherited(tcx, item.span, item.vis);
match item.node {
- ast::ItemImpl(_, _, _, _, ref impl_items) => {
+ ast::ItemImpl(_, _, _, _, _, ref impl_items) => {
for impl_item in impl_items.iter() {
match *impl_item {
ast::MethodImplItem(ref m) => {
// (i.e. we could just return here to not check them at
// all, or some worse estimation of whether an impl is
// publicly visible.
- ast::ItemImpl(_, ref g, ref trait_ref, ref self_, ref impl_items) => {
+ ast::ItemImpl(_, _, ref g, ref trait_ref, ref self_, ref impl_items) => {
// `impl [... for] Private` is never visible.
let self_contains_private;
// impl [... for] Public<...>, but not `impl [... for]
}
match item.node {
- ast::ItemImpl(_, ref generics, _, _, _) |
+ ast::ItemImpl(_, _, ref generics, _, _, _) |
ast::ItemFn(_, _, _, ref generics, _) => {
generics_require_inlining(generics)
}
.map
.expect_item(impl_did.node)
.node {
- ast::ItemImpl(_, ref generics, _, _, _) => {
+ ast::ItemImpl(_, _, ref generics, _, _, _) => {
generics_require_inlining(generics)
}
_ => false
ast::ItemEnum(_, ref generics) |
ast::ItemStruct(_, ref generics) |
ast::ItemTrait(_, ref generics, _, _) |
- ast::ItemImpl(_, ref generics, _, _, _) => {
+ ast::ItemImpl(_, _, ref generics, _, _, _) => {
// These kinds of items have only early bound lifetime parameters.
let lifetimes = &generics.lifetimes;
let early_scope = EarlyScope(subst::TypeSpace, lifetimes, &ROOT_SCOPE);
fn visit_ty(&mut self, ty: &ast::Ty) {
match ty.node {
- ast::TyClosure(ref c) => {
- // Careful, the bounds on a closure/proc are *not* within its binder.
- visit::walk_ty_param_bounds_helper(self, &c.bounds);
- visit::walk_lifetime_decls_helper(self, &c.lifetimes);
- self.with(LateScope(&c.lifetimes, self.scope), |old_scope, this| {
- this.check_lifetime_defs(old_scope, &c.lifetimes);
- for argument in c.decl.inputs.iter() {
- this.visit_ty(&*argument.ty)
- }
- visit::walk_fn_ret_ty(this, &c.decl.output);
- });
- }
ast::TyBareFn(ref c) => {
visit::walk_lifetime_decls_helper(self, &c.lifetimes);
self.with(LateScope(&c.lifetimes, self.scope), |old_scope, this| {
// stability of the trait. This is WRONG, but expedient to get
// libstd stabilized for the 1.0 release.
let use_parent = match i.node {
- ast::ItemImpl(_, _, Some(_), _, _) => false,
+ ast::ItemImpl(_, _, _, Some(_), _, _) => false,
_ => true,
};
ty::ty_float(..) |
ty::ty_str(..) |
ty::ty_bare_fn(..) |
- ty::ty_closure(..) |
ty::ty_vec(..) |
ty::ty_ptr(..) |
ty::ty_rptr(..) |
debug!("register_region_obligation({})",
region_obligation.repr(tcx));
- match region_obligations.entry(region_obligation.cause.body_id) {
- Vacant(entry) => { entry.set(vec![region_obligation]); },
+ let body_id = region_obligation.cause.body_id;
+ match region_obligations.entry(&body_id) {
+ Vacant(entry) => { entry.insert(vec![region_obligation]); },
Occupied(mut entry) => { entry.get_mut().push(region_obligation); },
}
match impl_ty {
Some(ty) => (ty, impl_vtable.nested.to_vec()),
None => {
- selcx.tcx().sess.span_bug(
- obligation.cause.span,
- format!("impl `{}` did not contain projection for `{}`",
- impl_vtable.repr(selcx.tcx()),
- obligation.repr(selcx.tcx())).as_slice());
+ // This means that the impl is missing a
+ // definition for the associated type. This error
+ // ought to be reported by the type checker method
+ // `check_impl_items_against_trait`, so here we
+ // just return ty_err.
+ (selcx.tcx().types.err, vec!())
}
}
}
}
}
- ty::ty_closure(ref c) => {
- match c.store {
- ty::UniqTraitStore => {
- // proc: Equivalent to `Box<FnOnce>`
- match bound {
- ty::BoundCopy => {
- Err(Unimplemented)
- }
-
- ty::BoundSized => {
- Ok(If(Vec::new()))
- }
-
- ty::BoundSync |
- ty::BoundSend => {
- if c.bounds.builtin_bounds.contains(&bound) {
- Ok(If(Vec::new()))
- } else {
- Err(Unimplemented)
- }
- }
- }
- }
- ty::RegionTraitStore(_, mutbl) => {
- // ||: Equivalent to `&FnMut` or `&mut FnMut` or something like that.
- match bound {
- ty::BoundCopy => {
- match mutbl {
- ast::MutMutable => {
- // &mut T is affine
- Err(Unimplemented)
- }
- ast::MutImmutable => {
- // &T is copyable, no matter what T is
- Ok(If(Vec::new()))
- }
- }
- }
-
- ty::BoundSized => {
- Ok(If(Vec::new()))
- }
-
- ty::BoundSync |
- ty::BoundSend => {
- if c.bounds.builtin_bounds.contains(&bound) {
- Ok(If(Vec::new()))
- } else {
- Err(Unimplemented)
- }
- }
- }
- }
- }
- }
-
ty::ty_trait(ref data) => {
match bound {
ty::BoundSized => {
use std::rc::Rc;
use collections::enum_set::{EnumSet, CLike};
use std::collections::{HashMap, HashSet};
-use std::collections::hash_map::Entry::{Occupied, Vacant};
use syntax::abi;
use syntax::ast::{CrateNum, DefId, Ident, ItemTrait, LOCAL_CRATE};
use syntax::ast::{MutImmutable, MutMutable, Name, NamedField, NodeId};
#[derive(Clone, Show)]
pub enum AutoAdjustment<'tcx> {
- AdjustAddEnv(ast::DefId, ty::TraitStore),
AdjustReifyFnPointer(ast::DefId), // go from a fn-item type to a fn-pointer type
AdjustDerefRef(AutoDerefRef<'tcx>)
}
pub fn print_debug_stats(&self) {
sty_debug_print!(
self,
- ty_enum, ty_uniq, ty_vec, ty_ptr, ty_rptr, ty_bare_fn, ty_closure, ty_trait,
+ ty_enum, ty_uniq, ty_vec, ty_ptr, ty_rptr, ty_bare_fn, ty_trait,
ty_struct, ty_unboxed_closure, ty_tup, ty_param, ty_open, ty_infer, ty_projection);
println!("Substs interner: #{}", self.substs_interner.borrow().len());
// fn item. Otherwise, if None(_), it a fn pointer type.
ty_bare_fn(Option<DefId>, &'tcx BareFnTy<'tcx>),
- ty_closure(Box<ClosureTy<'tcx>>),
ty_trait(Box<TyTrait<'tcx>>),
ty_struct(DefId, &'tcx Substs<'tcx>),
!self.regions.is_empty_in(space)
}
+ pub fn is_empty(&self) -> bool {
+ self.types.is_empty() && self.regions.is_empty()
+ }
+
pub fn to_bounds(&self, tcx: &ty::ctxt<'tcx>, substs: &Substs<'tcx>)
-> GenericBounds<'tcx> {
GenericBounds {
&ty_bare_fn(_, ref f) => {
self.add_fn_sig(&f.sig);
}
-
- &ty_closure(ref f) => {
- if let RegionTraitStore(r, _) = f.store {
- self.add_region(r);
- }
- self.add_fn_sig(&f.sig);
- self.add_bounds(&f.bounds);
- }
}
}
mk_tup(cx, Vec::new())
}
-pub fn mk_closure<'tcx>(cx: &ctxt<'tcx>, fty: ClosureTy<'tcx>) -> Ty<'tcx> {
- mk_t(cx, ty_closure(box fty))
-}
-
pub fn mk_bare_fn<'tcx>(cx: &ctxt<'tcx>,
opt_def_id: Option<ast::DefId>,
fty: &'tcx BareFnTy<'tcx>) -> Ty<'tcx> {
pub fn type_is_structural(ty: Ty) -> bool {
match ty.sty {
- ty_struct(..) | ty_tup(_) | ty_enum(..) | ty_closure(_) |
+ ty_struct(..) | ty_tup(_) | ty_enum(..) |
ty_vec(_, Some(_)) | ty_unboxed_closure(..) => true,
_ => type_is_slice(ty) | type_is_trait(ty)
}
TC::None
}
- ty_closure(ref c) => {
- closure_contents(&**c) | TC::ReachesFfiUnsafe
- }
-
ty_uniq(typ) => {
TC::ReachesFfiUnsafe | match typ.sty {
ty_str => TC::OwnsOwned,
b | (TC::ReachesBorrowed).when(region != ty::ReStatic)
}
- fn closure_contents(cty: &ClosureTy) -> TypeContents {
- // Closure contents are just like trait contents, but with potentially
- // even more stuff.
- let st = object_contents(&cty.bounds);
-
- let st = match cty.store {
- UniqTraitStore => {
- st.owned_pointer()
- }
- RegionTraitStore(r, mutbl) => {
- st.reference(borrowed_contents(r, mutbl))
- }
- };
-
- st
- }
-
fn object_contents(bounds: &ExistentialBounds) -> TypeContents {
// These are the type contents of the (opaque) interior. We
// make no assumptions (other than that it cannot have an
ty_float(_) |
ty_str |
ty_bare_fn(..) |
- ty_closure(_) |
ty_param(_) |
ty_projection(_) |
ty_vec(_, None) => {
pub fn fn_is_variadic(fty: Ty) -> bool {
match fty.sty {
ty_bare_fn(_, ref f) => f.sig.0.variadic,
- ty_closure(ref f) => f.sig.0.variadic,
ref s => {
panic!("fn_is_variadic() called on non-fn type: {}", s)
}
pub fn ty_fn_sig<'tcx>(fty: Ty<'tcx>) -> &'tcx PolyFnSig<'tcx> {
match fty.sty {
ty_bare_fn(_, ref f) => &f.sig,
- ty_closure(ref f) => &f.sig,
ref s => {
panic!("ty_fn_sig() called on non-fn type: {}", s)
}
pub fn ty_fn_abi(fty: Ty) -> abi::Abi {
match fty.sty {
ty_bare_fn(_, ref f) => f.abi,
- ty_closure(ref f) => f.abi,
_ => panic!("ty_fn_abi() called on non-fn type"),
}
}
pub fn ty_closure_store(fty: Ty) -> TraitStore {
match fty.sty {
- ty_closure(ref f) => f.store,
ty_unboxed_closure(..) => {
// Close enough for the purposes of all the callers of this
// function (which is soon to be deprecated anyhow).
pub fn ty_fn_ret<'tcx>(fty: Ty<'tcx>) -> FnOutput<'tcx> {
match fty.sty {
ty_bare_fn(_, ref f) => f.sig.0.output,
- ty_closure(ref f) => f.sig.0.output,
ref s => {
panic!("ty_fn_ret() called on non-fn type: {}", s)
}
pub fn is_fn_ty(fty: Ty) -> bool {
match fty.sty {
ty_bare_fn(..) => true,
- ty_closure(_) => true,
_ => false
}
}
return match adjustment {
Some(adjustment) => {
match *adjustment {
- AdjustAddEnv(_, store) => {
- match unadjusted_ty.sty {
- ty::ty_bare_fn(Some(_), ref b) => {
- let bounds = ty::ExistentialBounds {
- region_bound: ReStatic,
- builtin_bounds: all_builtin_bounds(),
- projection_bounds: vec!(),
- };
-
- ty::mk_closure(
- cx,
- ty::ClosureTy {unsafety: b.unsafety,
- onceness: ast::Many,
- store: store,
- bounds: bounds,
- sig: b.sig.clone(),
- abi: b.abi})
- }
- ref b => {
- cx.sess.bug(
- format!("add_env adjustment on non-fn-item: \
- {}",
- b).as_slice());
- }
- }
- }
-
AdjustReifyFnPointer(_) => {
match unadjusted_ty.sty {
ty::ty_bare_fn(Some(_), b) => {
ty_rptr(_, _) => "&-ptr".to_string(),
ty_bare_fn(Some(_), _) => format!("fn item"),
ty_bare_fn(None, _) => "fn pointer".to_string(),
- ty_closure(_) => "fn".to_string(),
ty_trait(ref inner) => {
format!("trait {}", item_path_str(cx, inner.principal_def_id()))
}
match cx.map.find(id.node) {
Some(ast_map::NodeItem(item)) => {
match item.node {
- ast::ItemImpl(_, _, ref opt_trait, _, _) => {
+ ast::ItemImpl(_, _, _, ref opt_trait, _, _) => {
match opt_trait {
&Some(ref t) => {
let trait_ref = ty::node_id_to_trait_ref(cx, t.ref_id);
node_id_to_type(tcx, id.node)
} else {
let mut tcache = tcx.tcache.borrow_mut();
- let pty = match tcache.entry(id) {
- Occupied(entry) => entry.into_mut(),
- Vacant(entry) => entry.set(csearch::get_field_type(tcx, struct_id, id)),
- };
+ let pty = tcache.entry(&id).get().unwrap_or_else(
+ |vacant_entry| vacant_entry.insert(csearch::get_field_type(tcx, struct_id, id)));
pty.ty
};
ty.subst(tcx, substs)
fn_sig(state, &b.sig);
return false;
}
- ty_closure(ref c) => {
- byte!(15);
- hash!(c.unsafety);
- hash!(c.onceness);
- hash!(c.bounds);
- match c.store {
- UniqTraitStore => byte!(0),
- RegionTraitStore(r, m) => {
- byte!(1);
- region(state, r);
- assert_eq!(m, ast::MutMutable);
- }
- }
-
- fn_sig(state, &c.sig);
-
- return false;
- }
ty_trait(ref data) => {
byte!(17);
did(state, data.principal_def_id());
ty_struct(_, substs) => {
accum_substs(accumulator, substs);
}
- ty_closure(ref closure_ty) => {
- match closure_ty.store {
- RegionTraitStore(region, _) => accumulator.push(region),
- UniqTraitStore => {}
- }
- }
ty_unboxed_closure(_, region, substs) => {
accumulator.push(*region);
accum_substs(accumulator, substs);
impl<'tcx> AutoAdjustment<'tcx> {
pub fn is_identity(&self) -> bool {
match *self {
- AdjustAddEnv(..) => false,
AdjustReifyFnPointer(..) => false,
AdjustDerefRef(ref r) => r.is_identity(),
}
debug!("region={}", region.repr(tcx));
match region {
ty::ReLateBound(debruijn, br) if debruijn.depth == current_depth => {
- * match map.entry(br) {
- Vacant(entry) => entry.set(mapf(br, debruijn)),
- Occupied(entry) => entry.into_mut(),
- }
+ * map.entry(&br).get().unwrap_or_else(
+ |vacant_entry| vacant_entry.insert(mapf(br, debruijn)))
}
_ => {
region
impl<'tcx> Repr<'tcx> for AutoAdjustment<'tcx> {
fn repr(&self, tcx: &ctxt<'tcx>) -> String {
match *self {
- AdjustAddEnv(def_id, ref trait_store) => {
- format!("AdjustAddEnv({},{})", def_id.repr(tcx), trait_store)
- }
AdjustReifyFnPointer(def_id) => {
- format!("AdjustAddEnv({})", def_id.repr(tcx))
+ format!("AdjustReifyFnPointer({})", def_id.repr(tcx))
}
AdjustDerefRef(ref data) => {
data.repr(tcx)
/// track the Debruijn index nesting level.
fn exit_region_binder(&mut self) { }
+ fn fold_binder<T>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T>
+ where T : TypeFoldable<'tcx> + Repr<'tcx>
+ {
+ // FIXME(#20526) this should replace `enter_region_binder`/`exit_region_binder`.
+ super_fold_binder(self, t)
+ }
+
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
super_fold_ty(self, t)
}
}
}
-impl<'tcx, T:TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder<T> {
+impl<'tcx, T:TypeFoldable<'tcx>+Repr<'tcx>> TypeFoldable<'tcx> for ty::Binder<T> {
fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::Binder<T> {
- folder.enter_region_binder();
- let result = ty::Binder(self.0.fold_with(folder));
- folder.exit_region_binder();
- result
+ folder.fold_binder(self)
}
}
//
// They should invoke `foo.fold_with()` to do recursive folding.
+pub fn super_fold_binder<'tcx, T, U>(this: &mut T,
+ binder: &ty::Binder<U>)
+ -> ty::Binder<U>
+ where T : TypeFolder<'tcx>, U : TypeFoldable<'tcx>
+{
+ this.enter_region_binder();
+ let result = ty::Binder(binder.0.fold_with(this));
+ this.exit_region_binder();
+ result
+}
+
pub fn super_fold_ty<'tcx, T: TypeFolder<'tcx>>(this: &mut T,
ty: Ty<'tcx>)
-> Ty<'tcx> {
let bfn = f.fold_with(this);
ty::ty_bare_fn(opt_def_id, this.tcx().mk_bare_fn(bfn))
}
- ty::ty_closure(ref f) => {
- ty::ty_closure(f.fold_with(this))
- }
ty::ty_rptr(r, ref tm) => {
let r = r.fold_with(this);
ty::ty_rptr(this.tcx().mk_region(r), tm.fold_with(this))
ty::ty_bare_fn(_, ref ft) => {
self.push_sig_subtypes(&ft.sig);
}
- ty::ty_closure(ref ft) => {
- self.push_sig_subtypes(&ft.sig);
- }
}
}
pub prints: Vec<PrintRequest>,
pub cg: CodegenOptions,
pub color: ColorConfig,
+ pub show_span: Option<String>,
pub externs: HashMap<String, Vec<String>>,
pub crate_name: Option<String>,
/// An optional name to use as the crate for std during std injection,
prints: Vec::new(),
cg: basic_codegen_options(),
color: Auto,
+ show_span: None,
externs: HashMap::new(),
crate_name: None,
alt_std_name: None,
BORROWCK_STATS,
NO_LANDING_PADS,
DEBUG_LLVM,
- SHOW_SPAN,
COUNT_TYPE_SIZES,
META_STATS,
GC,
("no-landing-pads", "omit landing pads for unwinding",
NO_LANDING_PADS),
("debug-llvm", "enable debug output from LLVM", DEBUG_LLVM),
- ("show-span", "show spans for compiler debugging", SHOW_SPAN),
("count-type-sizes", "count the sizes of aggregate types",
COUNT_TYPE_SIZES),
("meta-stats", "gather metadata statistics", META_STATS),
"[asm|llvm-bc|llvm-ir|obj|link|dep-info]"),
opt::multi("", "print", "Comma separated list of compiler information to \
print on stdout",
- "[crate-name|output-file-names|sysroot]"),
+ "[crate-name|file-names|sysroot]"),
opt::flag("g", "", "Equivalent to -C debuginfo=2"),
opt::flag("O", "", "Equivalent to -C opt-level=2"),
opt::opt("o", "", "Write output to <filename>", "FILENAME"),
`flowgraph=<nodeid>` (graphviz formatted flowgraph for node), or
`everybody_loops` (all function bodies replaced with `loop {}`).",
"TYPE"),
+ opt::opt_u("", "show-span", "Show spans for compiler debugging", "expr|pat|ty"),
opt::flagopt("", "dep-info",
"Output dependency info to <filename> after compiling, \
in a format suitable for use by Makefiles", "FILENAME"),
None => early_error("--extern value must be of the format `foo=bar`"),
};
- match externs.entry(name.to_string()) {
- Vacant(entry) => { entry.set(vec![location.to_string()]); },
+ match externs.entry(&name.to_string()) {
+ Vacant(entry) => { entry.insert(vec![location.to_string()]); },
Occupied(mut entry) => { entry.get_mut().push(location.to_string()); },
}
}
prints: prints,
cg: cg,
color: color,
+ show_span: None,
externs: externs,
crate_name: crate_name,
alt_std_name: None,
pub fn no_landing_pads(&self) -> bool {
self.debugging_opt(config::NO_LANDING_PADS)
}
- pub fn show_span(&self) -> bool {
- self.debugging_opt(config::SHOW_SPAN)
+ pub fn unstable_options(&self) -> bool {
+ self.debugging_opt(config::UNSTABLE_OPTIONS)
}
pub fn print_enum_sizes(&self) -> bool {
self.debugging_opt(config::PRINT_ENUM_SIZES)
use middle::ty::{ReSkolemized, ReVar, BrEnv};
use middle::ty::{mt, Ty, ParamTy};
use middle::ty::{ty_bool, ty_char, ty_struct, ty_enum};
-use middle::ty::{ty_err, ty_str, ty_vec, ty_float, ty_bare_fn, ty_closure};
+use middle::ty::{ty_err, ty_str, ty_vec, ty_float, ty_bare_fn};
use middle::ty::{ty_param, ty_ptr, ty_rptr, ty_tup, ty_open};
use middle::ty::{ty_unboxed_closure};
use middle::ty::{ty_uniq, ty_trait, ty_int, ty_uint, ty_infer};
strs => format!("({})", strs.connect(", "))
}
}
- ty_closure(ref f) => {
- closure_to_string(cx, &**f)
- }
ty_bare_fn(opt_def_id, ref f) => {
bare_fn_to_string(cx, opt_def_id, f.unsafety, f.abi, None, &f.sig)
}
default_msgs: (&'static str, &'static str))
-> (&'static str, &'static str) {
match ty.sty {
- ty::ty_closure(box ty::ClosureTy {
- store: ty::RegionTraitStore(..),
- ..
- }) => {
- ("a non-copyable stack closure",
- "capture it in a new closure, e.g. `|x| f(x)`, to override")
- }
_ => {
if ty::type_moves_by_default(param_env, span, ty) {
("non-copyable",
let suffix = self.dataflow_for(dataflow::Exit, n);
let inner_label = self.inner.node_label(n);
inner_label
- .prefix_line(dot::LabelStr(prefix.into_cow()))
- .suffix_line(dot::LabelStr(suffix.into_cow()))
+ .prefix_line(dot::LabelText::LabelStr(prefix.into_cow()))
+ .suffix_line(dot::LabelText::LabelStr(suffix.into_cow()))
}
fn edge_label(&'a self, e: &Edge<'a>) -> dot::LabelText<'a> { self.inner.edge_label(e) }
}
println!("{}", json::as_json(&krate));
}
- if sess.show_span() {
- syntax::show_span::run(sess.diagnostic(), &krate);
+ if let Some(ref s) = sess.opts.show_span {
+ syntax::show_span::run(sess.diagnostic(), s.as_slice(), &krate);
}
krate
debug!("invoked with --parse-only, returning early from compile_input");
return true;
}
- if sess.show_span() {
+ if sess.opts.show_span.is_some() {
return true;
}
return sess.opts.debugging_opts & config::AST_JSON_NOEXPAND != 0;
_ => return,
};
- let result = (|| -> io::IoResult<()> {
+ let result = (|&:| -> io::IoResult<()> {
// Build a list of files used to compile the output and
// write Makefile-compatible dependency rules
let files: Vec<String> = sess.codemap().files.borrow()
use rustc::metadata;
use rustc::DIAGNOSTICS;
-use std::any::AnyRefExt;
use std::cmp::Ordering::Equal;
use std::io;
use std::iter::repeat;
_ => early_error("multiple input filenames provided")
};
- let sess = build_session(sopts, input_file_path, descriptions);
+ let mut sess = build_session(sopts, input_file_path, descriptions);
let cfg = config::build_configuration(&sess);
if print_crate_info(&sess, Some(&input), &odir, &ofile) {
return
pretty::parse_pretty(&sess, a.as_slice(), false)
});
let pretty = if pretty.is_none() &&
- sess.debugging_opt(config::UNSTABLE_OPTIONS) {
+ sess.unstable_options() {
matches.opt_str("xpretty").map(|a| {
// extended with unstable pretty-print variants
pretty::parse_pretty(&sess, a.as_slice(), true)
None => {/* continue */ }
}
+ if sess.unstable_options() {
+ sess.opts.show_span = matches.opt_str("show-span");
+ }
+
let r = matches.opt_strs("Z");
if r.contains(&("ls".to_string())) {
match input {
ty::mk_tup(self.infcx.tcx, vec![ty1, ty2])
}
- pub fn t_closure(&self,
- input_tys: &[Ty<'tcx>],
- output_ty: Ty<'tcx>,
- region_bound: ty::Region)
- -> Ty<'tcx>
- {
- ty::mk_closure(self.infcx.tcx, ty::ClosureTy {
- unsafety: ast::Unsafety::Normal,
- onceness: ast::Many,
- store: ty::RegionTraitStore(region_bound, ast::MutMutable),
- bounds: ty::region_existential_bound(region_bound),
- sig: ty::Binder(ty::FnSig {
- inputs: input_tys.to_vec(),
- output: ty::FnConverging(output_ty),
- variadic: false,
- }),
- abi: abi::Rust,
- })
- }
-
pub fn t_param(&self, space: subst::ParamSpace, index: u32) -> Ty<'tcx> {
let name = format!("T{}", index);
ty::mk_param(self.infcx.tcx, space, index, token::intern(name[]))
assert!(!ty::type_has_escaping_regions(t_param));
let t_fn = env.t_fn(&[t_param], env.t_nil());
assert!(!ty::type_has_escaping_regions(t_fn));
-
- // t_fn = |&int|+'a
- let t_fn = env.t_closure(&[t_rptr_bound1], env.t_nil(), env.re_free(0, 1));
- assert!(!ty::type_has_escaping_regions(t_fn));
-
- // t_fn = |&int|+'a (where &int has depth 2)
- let t_fn = env.t_closure(&[t_rptr_bound2], env.t_nil(), env.re_free(0, 1));
- assert!(ty::type_has_escaping_regions(t_fn));
-
- // t_fn = |&int|+&int
- let t_fn = env.t_closure(&[t_rptr_bound1], env.t_nil(),
- env.re_late_bound_with_debruijn(1, ty::DebruijnIndex::new(1)));
- assert!(ty::type_has_escaping_regions(t_fn));
})
}
use libc;
use ArchiveRef;
-use std::c_str::ToCStr;
+use std::ffi::CString;
use std::mem;
use std::raw;
/// raised.
pub fn open(dst: &Path) -> Option<ArchiveRO> {
unsafe {
- let ar = dst.with_c_str(|dst| {
- ::LLVMRustOpenArchive(dst)
- });
+ let s = CString::from_slice(dst.as_vec());
+ let ar = ::LLVMRustOpenArchive(s.as_ptr());
if ar.is_null() {
None
} else {
pub fn read<'a>(&'a self, file: &str) -> Option<&'a [u8]> {
unsafe {
let mut size = 0 as libc::size_t;
- let ptr = file.with_c_str(|file| {
- ::LLVMRustArchiveReadSection(self.ptr, file, &mut size)
- });
+ let file = CString::from_slice(file.as_bytes());
+ let ptr = ::LLVMRustArchiveReadSection(self.ptr, file.as_ptr(),
+ &mut size);
if ptr.is_null() {
None
} else {
pub use self::DiagnosticSeverity::*;
pub use self::Linkage::*;
-use std::c_str::ToCStr;
+use std::ffi::CString;
use std::cell::RefCell;
use std::{raw, mem};
use libc::{c_uint, c_ushort, uint64_t, c_int, size_t, c_char};
}
pub fn mk_target_data(string_rep: &str) -> TargetData {
+ let string_rep = CString::from_slice(string_rep.as_bytes());
TargetData {
- lltd: string_rep.with_c_str(|buf| {
- unsafe { LLVMCreateTargetData(buf) }
- })
+ lltd: unsafe { LLVMCreateTargetData(string_rep.as_ptr()) }
}
}
parent.clone()
}
- ItemImpl(_, _, None, ref ty, ref impl_items) => {
+ ItemImpl(_, _, _, None, ref ty, ref impl_items) => {
// If this implements an anonymous trait, then add all the
// methods within to a new module, if the type was defined
// within this module.
parent.clone()
}
- ItemImpl(_, _, Some(_), _, _) => parent.clone(),
+ ItemImpl(_, _, _, Some(_), _, _) => parent.clone(),
ItemTrait(_, _, _, ref items) => {
let name_bindings =
use syntax::ast::{PolyTraitRef, PrimTy, SelfExplicit};
use syntax::ast::{RegionTyParamBound, StructField};
use syntax::ast::{TraitRef, TraitTyParamBound};
-use syntax::ast::{Ty, TyBool, TyChar, TyClosure, TyF32};
+use syntax::ast::{Ty, TyBool, TyChar, TyF32};
use syntax::ast::{TyF64, TyFloat, TyI, TyI8, TyI16, TyI32, TyI64, TyInt, TyObjectSum};
use syntax::ast::{TyParam, TyParamBound, TyPath, TyPtr, TyPolyTraitRef, TyQPath};
use syntax::ast::{TyRptr, TyStr, TyU, TyU8, TyU16, TyU32, TyU64, TyUint};
}
}
-
// Import resolution
//
// This is a fixed-point algorithm. We resolve imports until our efforts
let is_public = import_directive.is_public;
let mut import_resolutions = module_.import_resolutions.borrow_mut();
- let dest_import_resolution = match import_resolutions.entry(name) {
- Occupied(entry) => {
- entry.into_mut()
- }
- Vacant(entry) => {
+ let dest_import_resolution = import_resolutions.entry(&name).get().unwrap_or_else(
+ |vacant_entry| {
// Create a new import resolution from this child.
- entry.set(ImportResolution::new(id, is_public))
- }
- };
+ vacant_entry.insert(ImportResolution::new(id, is_public))
+ });
debug!("(resolving glob import) writing resolution `{}` in `{}` \
to `{}`",
def = DefUpvar(node_id, function_id, last_proc_body_id);
let mut seen = self.freevars_seen.borrow_mut();
- let seen = match seen.entry(function_id) {
+ let seen = match seen.entry(&function_id) {
Occupied(v) => v.into_mut(),
- Vacant(v) => v.set(NodeSet::new()),
+ Vacant(v) => v.insert(NodeSet::new()),
};
if seen.contains(&node_id) {
continue;
}
- match self.freevars.borrow_mut().entry(function_id) {
+ match self.freevars.borrow_mut().entry(&function_id) {
Occupied(v) => v.into_mut(),
- Vacant(v) => v.set(vec![]),
+ Vacant(v) => v.insert(vec![]),
}.push(Freevar { def: prev_def, span: span });
seen.insert(node_id);
}
});
}
- ItemImpl(_,
+ ItemImpl(_, _,
ref generics,
ref implemented_traits,
ref self_type,
self.resolve_trait_reference(ty.id, &*qpath.trait_ref, TraitQPath);
}
- TyClosure(ref c) => {
- self.resolve_type_parameter_bounds(
- ty.id,
- &c.bounds,
- TraitBoundingTypeParameter);
- visit::walk_ty(self, ty);
- }
-
TyPolyTraitRef(ref bounds) => {
self.resolve_type_parameter_bounds(
ty.id,
"Import should only be used for `use` directives");
self.last_private.insert(node_id, lp);
- match self.def_map.borrow_mut().entry(node_id) {
+ match self.def_map.borrow_mut().entry(&node_id) {
// Resolve appears to "resolve" the same ID multiple
// times, so here is a sanity check it at least comes to
// the same conclusion! - nmatsakis
*entry.get(),
def)[]);
},
- Vacant(entry) => { entry.set(def); },
+ Vacant(entry) => { entry.insert(def); },
}
}
use libc;
use flate;
-use std::c_str::ToCStr;
+use std::ffi::CString;
use std::iter;
use std::mem;
use std::num::Int;
}
// Internalize everything but the reachable symbols of the current module
- let cstrs: Vec<::std::c_str::CString> =
- reachable.iter().map(|s| s.to_c_str()).collect();
- let arr: Vec<*const libc::c_char> = cstrs.iter().map(|c| c.as_ptr()).collect();
+ let cstrs: Vec<CString> = reachable.iter().map(|s| {
+ CString::from_slice(s.as_bytes())
+ }).collect();
+ let arr: Vec<*const i8> = cstrs.iter().map(|c| c.as_ptr()).collect();
let ptr = arr.as_ptr();
unsafe {
llvm::LLVMRustRunRestrictionPass(llmod,
unsafe {
let pm = llvm::LLVMCreatePassManager();
llvm::LLVMRustAddAnalysisPasses(tm, pm, llmod);
- "verify".with_c_str(|s| llvm::LLVMRustAddPass(pm, s));
+ llvm::LLVMRustAddPass(pm, "verify\0".as_ptr() as *const _);
let builder = llvm::LLVMPassManagerBuilderCreate();
llvm::LLVMPassManagerBuilderPopulateLTOPassManager(builder, pm,
/* RunInliner = */ True);
llvm::LLVMPassManagerBuilderDispose(builder);
- "verify".with_c_str(|s| llvm::LLVMRustAddPass(pm, s));
+ llvm::LLVMRustAddPass(pm, "verify\0".as_ptr() as *const _);
time(sess.time_passes(), "LTO passes", (), |()|
llvm::LLVMRunPassManager(pm, llmod));
use syntax::diagnostic;
use syntax::diagnostic::{Emitter, Handler, Level, mk_handler};
-use std::c_str::{ToCStr, CString};
+use std::ffi::{mod, CString};
use std::io::Command;
use std::io::fs;
use std::iter::Unfold;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::channel;
use std::thread;
-use libc::{c_uint, c_int, c_void};
+use libc::{mod, c_uint, c_int, c_void};
#[derive(Clone, Copy, PartialEq, PartialOrd, Ord, Eq)]
pub enum OutputType {
if cstr == ptr::null() {
handler.fatal(msg[]);
} else {
- let err = CString::new(cstr, true);
- let err = String::from_utf8_lossy(err.as_bytes());
+ let err = ffi::c_str_to_bytes(&cstr);
+ let err = String::from_utf8_lossy(err.as_slice()).to_string();
+ libc::free(cstr as *mut _);
handler.fatal(format!("{}: {}",
msg[],
err[])[]);
output: &Path,
file_type: llvm::FileType) {
unsafe {
- output.with_c_str(|output| {
- let result = llvm::LLVMRustWriteOutputFile(
- target, pm, m, output, file_type);
- if !result {
- llvm_err(handler, "could not write output".to_string());
- }
- })
+ let output = CString::from_slice(output.as_vec());
+ let result = llvm::LLVMRustWriteOutputFile(
+ target, pm, m, output.as_ptr(), file_type);
+ if !result {
+ llvm_err(handler, "could not write output".to_string());
+ }
}
}
let triple = sess.target.target.llvm_target[];
let tm = unsafe {
- triple.with_c_str(|t| {
- let cpu = match sess.opts.cg.target_cpu {
- Some(ref s) => s[],
- None => sess.target.target.options.cpu[]
- };
- cpu.with_c_str(|cpu| {
- target_feature(sess).with_c_str(|features| {
- llvm::LLVMRustCreateTargetMachine(
- t, cpu, features,
- code_model,
- reloc_model,
- opt_level,
- true /* EnableSegstk */,
- use_softfp,
- no_fp_elim,
- !any_library && reloc_model == llvm::RelocPIC,
- ffunction_sections,
- fdata_sections,
- )
- })
- })
- })
+ let triple = CString::from_slice(triple.as_bytes());
+ let cpu = match sess.opts.cg.target_cpu {
+ Some(ref s) => s.as_slice(),
+ None => sess.target.target.options.cpu.as_slice()
+ };
+ let cpu = CString::from_slice(cpu.as_bytes());
+ let features = CString::from_slice(target_feature(sess).as_bytes());
+ llvm::LLVMRustCreateTargetMachine(
+ triple.as_ptr(), cpu.as_ptr(), features.as_ptr(),
+ code_model,
+ reloc_model,
+ opt_level,
+ true /* EnableSegstk */,
+ use_softfp,
+ no_fp_elim,
+ !any_library && reloc_model == llvm::RelocPIC,
+ ffunction_sections,
+ fdata_sections,
+ )
};
if tm.is_null() {
match llvm::diagnostic::Diagnostic::unpack(info) {
llvm::diagnostic::Optimization(opt) => {
- let pass_name = CString::new(opt.pass_name, false);
- let pass_name = pass_name.as_str().expect("got a non-UTF8 pass name from LLVM");
+ let pass_name = str::from_utf8(ffi::c_str_to_bytes(&opt.pass_name))
+ .ok()
+ .expect("got a non-UTF8 pass name from LLVM");
let enabled = match cgcx.remark {
AllPasses => true,
SomePasses(ref v) => v.iter().any(|s| *s == pass_name),
if config.emit_no_opt_bc {
let ext = format!("{}.no-opt.bc", name_extra);
- output_names.with_extension(ext[]).with_c_str(|buf| {
- llvm::LLVMWriteBitcodeToFile(llmod, buf);
- })
+ let out = output_names.with_extension(ext.as_slice());
+ let out = CString::from_slice(out.as_vec());
+ llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr());
}
match config.opt_level {
// If we're verifying or linting, add them to the function pass
// manager.
let addpass = |&: pass: &str| {
- pass.with_c_str(|s| llvm::LLVMRustAddPass(fpm, s))
+ let pass = CString::from_slice(pass.as_bytes());
+ llvm::LLVMRustAddPass(fpm, pass.as_ptr())
};
if !config.no_verify { assert!(addpass("verify")); }
}
for pass in config.passes.iter() {
- pass.with_c_str(|s| {
- if !llvm::LLVMRustAddPass(mpm, s) {
- cgcx.handler.warn(format!("unknown pass {}, ignoring",
- *pass)[]);
- }
- })
+ let pass = CString::from_slice(pass.as_bytes());
+ if !llvm::LLVMRustAddPass(mpm, pass.as_ptr()) {
+ cgcx.handler.warn(format!("unknown pass {}, ignoring",
+ pass).as_slice());
+ }
}
// Finally, run the actual optimization passes
if config.emit_lto_bc {
let name = format!("{}.lto.bc", name_extra);
- output_names.with_extension(name[]).with_c_str(|buf| {
- llvm::LLVMWriteBitcodeToFile(llmod, buf);
- })
+ let out = output_names.with_extension(name.as_slice());
+ let out = CString::from_slice(out.as_vec());
+ llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr());
}
},
_ => {},
if config.emit_bc {
let ext = format!("{}.bc", name_extra);
- output_names.with_extension(ext[]).with_c_str(|buf| {
- llvm::LLVMWriteBitcodeToFile(llmod, buf);
- })
+ let out = output_names.with_extension(ext.as_slice());
+ let out = CString::from_slice(out.as_vec());
+ llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr());
}
time(config.time_passes, "codegen passes", (), |()| {
if config.emit_ir {
let ext = format!("{}.ll", name_extra);
- output_names.with_extension(ext[]).with_c_str(|output| {
- with_codegen(tm, llmod, config.no_builtins, |cpm| {
- llvm::LLVMRustPrintModule(cpm, llmod, output);
- })
+ let out = output_names.with_extension(ext.as_slice());
+ let out = CString::from_slice(out.as_vec());
+ with_codegen(tm, llmod, config.no_builtins, |cpm| {
+ llvm::LLVMRustPrintModule(cpm, llmod, out.as_ptr());
})
}
let mut llvm_args = Vec::new();
{
let mut add = |&mut : arg: &str| {
- let s = arg.to_c_str();
+ let s = CString::from_slice(arg.as_bytes());
llvm_args.push(s.as_ptr());
llvm_c_strs.push(s);
};
match opt {
llvm::CodeGenLevelDefault | llvm::CodeGenLevelAggressive => {
- "mergefunc".with_c_str(|s| llvm::LLVMRustAddPass(mpm, s));
+ llvm::LLVMRustAddPass(mpm, "mergefunc\0".as_ptr() as *const _);
}
_ => {}
};
NodeItem(item) => {
scope_id = item.id;
match item.node {
- ast::ItemImpl(_, _, _, ref ty, _) => {
+ ast::ItemImpl(_, _, _, _, ref ty, _) => {
let mut result = String::from_str("<");
result.push_str(ty_to_string(&**ty)[]);
self.process_const(item, &**typ, &**expr),
ast::ItemStruct(ref def, ref ty_params) => self.process_struct(item, &**def, ty_params),
ast::ItemEnum(ref def, ref ty_params) => self.process_enum(item, def, ty_params),
- ast::ItemImpl(_,
+ ast::ItemImpl(_, _,
ref ty_params,
ref trait_ref,
ref typ,
// Functions are just pointers
ty::ty_bare_fn(..) => Some(path),
- // Closures are a pair of pointers: the code and environment
- ty::ty_closure(..) => {
- path.push(FAT_PTR_ADDR);
- Some(path)
- },
-
// Is this the NonZero lang item wrapping a pointer or integer type?
ty::ty_struct(did, substs) if Some(did) == tcx.lang_items.non_zero() => {
let nonzero_fields = ty::lookup_struct_fields(tcx, did);
use trans::type_of;
use trans::type_::Type;
-use std::c_str::ToCStr;
-use std::string::String;
use syntax::ast;
+use std::ffi::CString;
use libc::{c_uint, c_char};
// Take an inline assembly expression and splat it out via LLVM
ast::AsmIntel => llvm::AD_Intel
};
- let r = ia.asm.get().with_c_str(|a| {
- constraints.with_c_str(|c| {
- InlineAsmCall(bcx,
- a,
- c,
- inputs[],
+ let asm = CString::from_slice(ia.asm.get().as_bytes());
+ let constraints = CString::from_slice(constraints.as_bytes());
+ let r = InlineAsmCall(bcx,
+ asm.as_ptr(),
+ constraints.as_ptr(),
+ inputs.as_slice(),
output_type,
ia.volatile,
ia.alignstack,
- dialect)
- })
- });
+ dialect);
// Again, based on how many outputs we have
if num_outputs == 1 {
use arena::TypedArena;
use libc::{c_uint, uint64_t};
-use std::c_str::ToCStr;
+use std::ffi::{mod, CString};
use std::cell::{Cell, RefCell};
use std::collections::HashSet;
use std::mem;
use std::rc::Rc;
+use std::str;
use std::{i8, i16, i32, i64};
use syntax::abi::{Rust, RustCall, RustIntrinsic, Abi};
use syntax::ast_util::local_def;
pub fn decl_fn(ccx: &CrateContext, name: &str, cc: llvm::CallConv,
ty: Type, output: ty::FnOutput) -> ValueRef {
- let llfn: ValueRef = name.with_c_str(|buf| {
- unsafe {
- llvm::LLVMGetOrInsertFunction(ccx.llmod(), buf, ty.to_ref())
- }
- });
+ let buf = CString::from_slice(name.as_bytes());
+ let llfn: ValueRef = unsafe {
+ llvm::LLVMGetOrInsertFunction(ccx.llmod(), buf.as_ptr(), ty.to_ref())
+ };
// diverging functions may unwind, but can never return normally
if output == ty::FnDiverging {
ty::ty_bare_fn(_, ref f) => {
(f.sig.0.inputs.clone(), f.sig.0.output, f.abi, None)
}
- ty::ty_closure(ref f) => {
- (f.sig.0.inputs.clone(), f.sig.0.output, f.abi, Some(Type::i8p(ccx)))
- }
ty::ty_unboxed_closure(closure_did, _, substs) => {
let typer = common::NormalizingUnboxedClosureTyper::new(ccx.tcx());
let function_type = typer.unboxed_closure_type(closure_did, substs);
None => ()
}
unsafe {
- let c = name.with_c_str(|buf| {
- llvm::LLVMAddGlobal(ccx.llmod(), ty.to_ref(), buf)
- });
+ let buf = CString::from_slice(name.as_bytes());
+ let c = llvm::LLVMAddGlobal(ccx.llmod(), ty.to_ref(), buf.as_ptr());
// Thread-local statics in some other crate need to *always* be linked
// against in a thread-local fashion, so we need to be sure to apply the
// thread-local attribute locally if it was present remotely. If we
}
pub fn set_split_stack(f: ValueRef) {
- "split-stack".with_c_str(|buf| {
- unsafe { llvm::LLVMAddFunctionAttrString(f, llvm::FunctionIndex as c_uint, buf); }
- })
+ unsafe {
+ llvm::LLVMAddFunctionAttrString(f, llvm::FunctionIndex as c_uint,
+ "split-stack\0".as_ptr() as *const _);
+ }
}
pub fn unset_split_stack(f: ValueRef) {
- "split-stack".with_c_str(|buf| {
- unsafe { llvm::LLVMRemoveFunctionAttrString(f, llvm::FunctionIndex as c_uint, buf); }
- })
+ unsafe {
+ llvm::LLVMRemoveFunctionAttrString(f, llvm::FunctionIndex as c_uint,
+ "split-stack\0".as_ptr() as *const _);
+ }
}
// Double-check that we never ask LLVM to declare the same symbol twice. It
// Since we're in trans we don't care for any region parameters
let substs = subst::Substs::erased(substs.types.clone());
- let (val, _) = monomorphize::monomorphic_fn(ccx, did, &substs, None);
+ let (val, _, _) = monomorphize::monomorphic_fn(ccx, did, &substs, None);
val
} else if did.krate == ast::LOCAL_CRATE {
// Structural comparison: a rather involved form of glue.
pub fn maybe_name_value(cx: &CrateContext, v: ValueRef, s: &str) {
if cx.sess().opts.cg.save_temps {
- s.with_c_str(|buf| {
- unsafe {
- llvm::LLVMSetValueName(v, buf)
- }
- })
+ let buf = CString::from_slice(s.as_bytes());
+ unsafe { llvm::LLVMSetValueName(v, buf.as_ptr()) }
}
}
}
}
-pub type val_and_ty_fn<'a, 'blk, 'tcx> =
- |Block<'blk, 'tcx>, ValueRef, Ty<'tcx>|: 'a -> Block<'blk, 'tcx>;
-
// Iterates through the elements of a structural type.
-pub fn iter_structural_ty<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>,
- av: ValueRef,
- t: Ty<'tcx>,
- f: val_and_ty_fn<'a, 'blk, 'tcx>)
- -> Block<'blk, 'tcx> {
+pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>,
+ av: ValueRef,
+ t: Ty<'tcx>,
+ mut f: F)
+ -> Block<'blk, 'tcx> where
+ F: FnMut(Block<'blk, 'tcx>, ValueRef, Ty<'tcx>) -> Block<'blk, 'tcx>,
+{
let _icx = push_ctxt("iter_structural_ty");
- fn iter_variant<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>,
- repr: &adt::Repr<'tcx>,
- av: ValueRef,
- variant: &ty::VariantInfo<'tcx>,
- substs: &subst::Substs<'tcx>,
- f: val_and_ty_fn<'a, 'blk, 'tcx>)
- -> Block<'blk, 'tcx> {
+ fn iter_variant<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>,
+ repr: &adt::Repr<'tcx>,
+ av: ValueRef,
+ variant: &ty::VariantInfo<'tcx>,
+ substs: &subst::Substs<'tcx>,
+ f: &mut F)
+ -> Block<'blk, 'tcx> where
+ F: FnMut(Block<'blk, 'tcx>, ValueRef, Ty<'tcx>) -> Block<'blk, 'tcx>,
+ {
let _icx = push_ctxt("iter_variant");
let tcx = cx.tcx();
let mut cx = cx;
for (i, &arg) in variant.args.iter().enumerate() {
- cx = f(cx,
+ cx = (*f)(cx,
adt::trans_field_ptr(cx, repr, av, variant.disr_val, i),
arg.subst(tcx, substs));
}
match adt::trans_switch(cx, &*repr, av) {
(_match::Single, None) => {
cx = iter_variant(cx, &*repr, av, &*(*variants)[0],
- substs, f);
+ substs, &mut f);
}
(_match::Switch, Some(lldiscrim_a)) => {
cx = f(cx, lldiscrim_a, cx.tcx().types.int);
data_ptr,
&**variant,
substs,
- |x,y,z| f(x,y,z));
+ &mut f);
Br(variant_cx, next_cx.llbb);
}
cx = next_cx;
}
}
}
- ty::ty_closure(_) => {
- get_extern_rust_fn(ccx, t, name[], did)
- }
_ => {
get_extern_const(ccx, did, t)
}
let mut v = TransItemVisitor{ ccx: ccx };
v.visit_block(&**body);
}
- ast::ItemImpl(_, ref generics, _, _, ref impl_items) => {
+ ast::ItemImpl(_, _, ref generics, _, _, ref impl_items) => {
meth::trans_impl(ccx,
item.ident,
impl_items[],
use middle::ty::{BrAnon, ReLateBound};
let (fn_sig, abi, has_env) = match fn_ty.sty {
- ty::ty_closure(ref f) => (f.sig.clone(), f.abi, true),
ty::ty_bare_fn(_, ref f) => (f.sig.clone(), f.abi, false),
ty::ty_unboxed_closure(closure_did, _, substs) => {
let typer = common::NormalizingUnboxedClosureTyper::new(ccx.tcx());
unsafe { llvm::LLVMRustSetDLLExportStorageClass(llfn) }
}
- let llbb = "top".with_c_str(|buf| {
- unsafe {
- llvm::LLVMAppendBasicBlockInContext(ccx.llcx(), llfn, buf)
- }
- });
+ let llbb = unsafe {
+ llvm::LLVMAppendBasicBlockInContext(ccx.llcx(), llfn,
+ "top\0".as_ptr() as *const _)
+ };
let bld = ccx.raw_builder();
unsafe {
llvm::LLVMPositionBuilderAtEnd(bld, llbb);
};
let args = {
- let opaque_rust_main = "rust_main".with_c_str(|buf| {
- llvm::LLVMBuildPointerCast(bld, rust_main, Type::i8p(ccx).to_ref(), buf)
- });
+ let opaque_rust_main = llvm::LLVMBuildPointerCast(bld,
+ rust_main, Type::i8p(ccx).to_ref(),
+ "rust_main\0".as_ptr() as *const _);
vec!(
opaque_rust_main,
format!("Illegal null byte in export_name \
value: `{}`", sym)[]);
}
- let g = sym.with_c_str(|buf| {
- llvm::LLVMAddGlobal(ccx.llmod(), llty, buf)
- });
+ let buf = CString::from_slice(sym.as_bytes());
+ let g = llvm::LLVMAddGlobal(ccx.llmod(), llty,
+ buf.as_ptr());
if attr::contains_name(i.attrs[],
"thread_local") {
sect.get())[]);
}
unsafe {
- sect.get().with_c_str(|buf| {
- llvm::LLVMSetSection(v, buf);
- })
+ let buf = CString::from_slice(sect.get().as_bytes());
+ llvm::LLVMSetSection(v, buf.as_ptr());
}
},
None => ()
}
let encode_inlined_item: encoder::EncodeInlinedItem =
- |ecx, rbml_w, ii| astencode::encode_inlined_item(ecx, rbml_w, ii);
+ box |ecx, rbml_w, ii| astencode::encode_inlined_item(ecx, rbml_w, ii);
let encode_parms = crate_ctxt_to_encode_parms(cx, encode_inlined_item);
let metadata = encoder::encode_metadata(encode_parms, krate);
let name = format!("rust_metadata_{}_{}",
cx.link_meta().crate_name,
cx.link_meta().crate_hash);
- let llglobal = name.with_c_str(|buf| {
- unsafe {
- llvm::LLVMAddGlobal(cx.metadata_llmod(), val_ty(llconst).to_ref(), buf)
- }
- });
+ let buf = CString::from_vec(name.into_bytes());
+ let llglobal = unsafe {
+ llvm::LLVMAddGlobal(cx.metadata_llmod(), val_ty(llconst).to_ref(),
+ buf.as_ptr())
+ };
unsafe {
llvm::LLVMSetInitializer(llglobal, llconst);
let name = loader::meta_section_name(cx.sess().target.target.options.is_like_osx);
- name.with_c_str(|buf| {
- llvm::LLVMSetSection(llglobal, buf)
- });
+ let name = CString::from_slice(name.as_bytes());
+ llvm::LLVMSetSection(llglobal, name.as_ptr())
}
return metadata;
}
/// Find any symbols that are defined in one compilation unit, but not declared
/// in any other compilation unit. Give these symbols internal linkage.
fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet<String>) {
- use std::c_str::CString;
-
unsafe {
let mut declared = HashSet::new();
continue
}
- let name = CString::new(llvm::LLVMGetValueName(val), false);
+ let name = ffi::c_str_to_bytes(&llvm::LLVMGetValueName(val))
+ .to_vec();
declared.insert(name);
}
}
continue
}
- let name = CString::new(llvm::LLVMGetValueName(val), false);
+ let name = ffi::c_str_to_bytes(&llvm::LLVMGetValueName(val))
+ .to_vec();
if !declared.contains(&name) &&
- !reachable.contains(name.as_str().unwrap()) {
+ !reachable.contains(str::from_utf8(name.as_slice()).unwrap()) {
llvm::SetLinkage(val, llvm::InternalLinkage);
}
}
use trans::type_::Type;
use util::nodemap::FnvHashMap;
use libc::{c_uint, c_char};
-use std::c_str::ToCStr;
+
+use std::ffi::CString;
use syntax::codemap::Span;
pub struct Builder<'a, 'tcx: 'a> {
if name.is_empty() {
llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(), noname())
} else {
- name.with_c_str(|c| {
- llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(), c)
- })
+ let name = CString::from_slice(name.as_bytes());
+ llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(),
+ name.as_ptr())
}
}
}
let comment_text = format!("{} {}", "#",
sanitized.replace("\n", "\n\t# "));
self.count_insn("inlineasm");
- let asm = comment_text.with_c_str(|c| {
- unsafe {
- llvm::LLVMConstInlineAsm(Type::func(&[], &Type::void(self.ccx)).to_ref(),
- c, noname(), False, False)
- }
- });
+ let comment_text = CString::from_vec(comment_text.into_bytes());
+ let asm = unsafe {
+ llvm::LLVMConstInlineAsm(Type::func(&[], &Type::void(self.ccx)).to_ref(),
+ comment_text.as_ptr(), noname(), False,
+ False)
+ };
self.call(asm, &[], None);
}
}
let bb: BasicBlockRef = llvm::LLVMGetInsertBlock(self.llbuilder);
let fn_: ValueRef = llvm::LLVMGetBasicBlockParent(bb);
let m: ModuleRef = llvm::LLVMGetGlobalParent(fn_);
- let t: ValueRef = "llvm.trap".with_c_str(|buf| {
- llvm::LLVMGetNamedFunction(m, buf)
- });
+ let p = "llvm.trap\0".as_ptr();
+ let t: ValueRef = llvm::LLVMGetNamedFunction(m, p as *const _);
assert!((t as int != 0));
let args: &[ValueRef] = &[];
self.count_insn("trap");
pub use self::CallArgs::*;
use arena::TypedArena;
-use back::{abi,link};
+use back::link;
use session;
use llvm::{ValueRef};
use llvm::get_param;
use trans::closure;
use trans::common;
use trans::common::*;
+use trans::consts;
use trans::datum::*;
use trans::expr;
use trans::glue;
}
pub enum CalleeData<'tcx> {
- Closure(Datum<'tcx, Lvalue>),
-
// Constructor for enum variant/tuple-like-struct
// i.e. Some, Ok
NamedTupleConstructor(subst::Substs<'tcx>, ty::Disr),
fn datum_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr)
-> Callee<'blk, 'tcx> {
- let DatumBlock {mut bcx, datum} = expr::trans(bcx, expr);
+ let DatumBlock { bcx, datum, .. } = expr::trans(bcx, expr);
match datum.ty.sty {
ty::ty_bare_fn(..) => {
let llval = datum.to_llscalarish(bcx);
data: Fn(llval),
};
}
- ty::ty_closure(..) => {
- let datum = unpack_datum!(
- bcx, datum.to_lvalue_datum(bcx, "callee", expr.id));
- return Callee {
- bcx: bcx,
- data: Closure(datum),
- };
- }
_ => {
bcx.tcx().sess.span_bug(
expr.span,
_ => false
}
} => {
- let substs = node_id_substs(bcx, ExprId(ref_expr.id));
+ let substs = node_id_substs(bcx.ccx(), ExprId(ref_expr.id),
+ bcx.fcx.param_substs);
Callee {
bcx: bcx,
data: NamedTupleConstructor(substs, 0)
ty::ty_bare_fn(_, ref f) => f.abi == synabi::RustIntrinsic,
_ => false
} => {
- let substs = node_id_substs(bcx, ExprId(ref_expr.id));
+ let substs = node_id_substs(bcx.ccx(), ExprId(ref_expr.id),
+ bcx.fcx.param_substs);
let def_id = inline::maybe_instantiate_inline(bcx.ccx(), did);
Callee { bcx: bcx, data: Intrinsic(def_id.node, substs) }
}
def::DefFn(did, _) | def::DefMethod(did, _, def::FromImpl(_)) |
def::DefStaticMethod(did, def::FromImpl(_)) => {
- fn_callee(bcx, trans_fn_ref(bcx, did, ExprId(ref_expr.id)))
+ fn_callee(bcx, trans_fn_ref(bcx.ccx(), did, ExprId(ref_expr.id),
+ bcx.fcx.param_substs).val)
}
def::DefStaticMethod(meth_did, def::FromTrait(trait_did)) |
def::DefMethod(meth_did, _, def::FromTrait(trait_did)) => {
- fn_callee(bcx, meth::trans_static_method_callee(bcx, meth_did,
+ fn_callee(bcx, meth::trans_static_method_callee(bcx.ccx(),
+ meth_did,
trait_did,
- ref_expr.id))
+ ref_expr.id,
+ bcx.fcx.param_substs).val)
}
def::DefVariant(tid, vid, _) => {
let vinfo = ty::enum_variant_with_id(bcx.tcx(), tid, vid);
- let substs = node_id_substs(bcx, ExprId(ref_expr.id));
+ let substs = node_id_substs(bcx.ccx(), ExprId(ref_expr.id),
+ bcx.fcx.param_substs);
// Nullary variants are not callable
assert!(vinfo.args.len() > 0u);
}
}
def::DefStruct(_) => {
- let substs = node_id_substs(bcx, ExprId(ref_expr.id));
+ let substs = node_id_substs(bcx.ccx(), ExprId(ref_expr.id),
+ bcx.fcx.param_substs);
Callee {
bcx: bcx,
data: NamedTupleConstructor(substs, 0)
/// Translates a reference (with id `ref_id`) to the fn/method with id `def_id` into a function
/// pointer. This may require monomorphization or inlining.
-pub fn trans_fn_ref(bcx: Block, def_id: ast::DefId, node: ExprOrMethodCall) -> ValueRef {
+pub fn trans_fn_ref<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+ def_id: ast::DefId,
+ node: ExprOrMethodCall,
+ param_substs: &subst::Substs<'tcx>)
+ -> Datum<'tcx, Rvalue> {
let _icx = push_ctxt("trans_fn_ref");
- let substs = node_id_substs(bcx, node);
+ let substs = node_id_substs(ccx, node, param_substs);
debug!("trans_fn_ref(def_id={}, node={}, substs={})",
- def_id.repr(bcx.tcx()),
+ def_id.repr(ccx.tcx()),
node,
- substs.repr(bcx.tcx()));
- trans_fn_ref_with_substs(bcx, def_id, node, substs)
+ substs.repr(ccx.tcx()));
+ trans_fn_ref_with_substs(ccx, def_id, node, param_substs, substs)
}
fn trans_fn_ref_with_substs_to_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-> Callee<'blk, 'tcx> {
Callee {
bcx: bcx,
- data: Fn(trans_fn_ref_with_substs(bcx,
+ data: Fn(trans_fn_ref_with_substs(bcx.ccx(),
def_id,
ExprId(ref_id),
- substs)),
+ bcx.fcx.param_substs,
+ substs).val),
}
}
///
/// # Parameters
///
-/// - `bcx`: the current block where the reference to the fn occurs
+/// - `ccx`: the crate context
/// - `def_id`: def id of the fn or method item being referenced
/// - `node`: node id of the reference to the fn/method, if applicable.
/// This parameter may be zero; but, if so, the resulting value may not
/// have the right type, so it must be cast before being used.
+/// - `param_substs`: if the `node` is in a polymorphic function, these
+/// are the substitutions required to monomorphize its type
/// - `substs`: values for each of the fn/method's parameters
-pub fn trans_fn_ref_with_substs<'blk, 'tcx>(
- bcx: Block<'blk, 'tcx>, //
- def_id: ast::DefId, // def id of fn
- node: ExprOrMethodCall, // node id of use of fn; may be zero if N/A
- substs: subst::Substs<'tcx>) // vtables for the call
- -> ValueRef
+pub fn trans_fn_ref_with_substs<'a, 'tcx>(
+ ccx: &CrateContext<'a, 'tcx>,
+ def_id: ast::DefId,
+ node: ExprOrMethodCall,
+ param_substs: &subst::Substs<'tcx>,
+ substs: subst::Substs<'tcx>)
+ -> Datum<'tcx, Rvalue>
{
let _icx = push_ctxt("trans_fn_ref_with_substs");
- let ccx = bcx.ccx();
- let tcx = bcx.tcx();
+ let tcx = ccx.tcx();
- debug!("trans_fn_ref_with_substs(bcx={}, def_id={}, node={}, \
- substs={})",
- bcx.to_str(),
+ debug!("trans_fn_ref_with_substs(def_id={}, node={}, \
+ param_substs={}, substs={})",
def_id.repr(tcx),
node,
+ param_substs.repr(tcx),
substs.repr(tcx));
assert!(substs.types.all(|t| !ty::type_needs_infer(*t)));
(true, source_id, new_substs)
}
ty::TypeTraitItem(_) => {
- bcx.tcx().sess.bug("trans_fn_ref_with_vtables() tried \
- to translate an associated type?!")
+ tcx.sess.bug("trans_fn_ref_with_vtables() tried \
+ to translate an associated type?!")
}
}
}
};
// If this is an unboxed closure, redirect to it.
- match closure::get_or_create_declaration_if_unboxed_closure(bcx,
+ match closure::get_or_create_declaration_if_unboxed_closure(ccx,
def_id,
&substs) {
None => {}
MethodCallKey(_) => None,
};
- let (val, must_cast) =
+ let (val, fn_ty, must_cast) =
monomorphize::monomorphic_fn(ccx, def_id, &substs, opt_ref_id);
- let mut val = val;
if must_cast && node != ExprId(0) {
// Monotype of the REFERENCE to the function (type params
// are subst'd)
let ref_ty = match node {
- ExprId(id) => node_id_type(bcx, id),
+ ExprId(id) => ty::node_id_to_type(tcx, id),
MethodCallKey(method_call) => {
- let t = (*bcx.tcx().method_map.borrow())[method_call].ty;
- monomorphize_type(bcx, t)
+ (*tcx.method_map.borrow())[method_call].ty
}
};
-
- val = PointerCast(
- bcx, val, type_of::type_of_fn_from_ty(ccx, ref_ty).ptr_to());
+ let ref_ty = monomorphize::apply_param_substs(tcx,
+ param_substs,
+ &ref_ty);
+ let llptrty = type_of::type_of_fn_from_ty(ccx, ref_ty).ptr_to();
+ if llptrty != val_ty(val) {
+ let val = consts::ptrcast(val, llptrty);
+ return Datum::new(val, ref_ty, Rvalue::new(ByValue));
+ }
}
- return val;
+ return Datum::new(val, fn_ty, Rvalue::new(ByValue));
}
// Type scheme of the function item (may have type params)
let llptrty = llty.ptr_to();
if val_ty(val) != llptrty {
debug!("trans_fn_ref_with_vtables(): casting pointer!");
- val = BitCast(bcx, val, llptrty);
+ val = consts::ptrcast(val, llptrty);
} else {
debug!("trans_fn_ref_with_vtables(): not casting pointer!");
}
- val
+ Datum::new(val, fn_type, Rvalue::new(ByValue))
}
// ______________________________________________________________________
let _icx = push_ctxt("trans_call");
trans_call_inner(in_cx,
Some(common::expr_info(call_ex)),
- expr_ty(in_cx, f),
+ expr_ty_adjusted(in_cx, f),
|cx, _| trans(cx, f),
args,
Some(dest)).bcx
let (abi, ret_ty) = match callee_ty.sty {
ty::ty_bare_fn(_, ref f) => (f.abi, f.sig.0.output),
- ty::ty_closure(ref f) => (f.abi, f.sig.0.output),
_ => panic!("expected bare rust fn or closure in trans_call_inner")
};
TraitItem(d) => {
(d.llfn, None, Some(d.llself))
}
- Closure(d) => {
- // Closures are represented as (llfn, llclosure) pair:
- // load the requisite values out.
- let pair = d.to_llref();
- let llfn = GEPi(bcx, pair, &[0u, abi::FAT_PTR_ADDR]);
- let llfn = Load(bcx, llfn);
- let llenv = GEPi(bcx, pair, &[0u, abi::FAT_PTR_EXTRA]);
- let llenv = Load(bcx, llenv);
- (llfn, Some(llenv), None)
- }
Intrinsic(node, substs) => {
assert!(abi == synabi::RustIntrinsic);
assert!(dest.is_some());
// specify any of the types for the function, we just make it a symbol
// that LLVM can later use.
let llpersonality = match pad_bcx.tcx().lang_items.eh_personality() {
- Some(def_id) => callee::trans_fn_ref(pad_bcx, def_id, ExprId(0)),
+ Some(def_id) => {
+ callee::trans_fn_ref(pad_bcx.ccx(), def_id, ExprId(0),
+ pad_bcx.fcx.param_substs).val
+ }
None => {
let mut personality = self.ccx.eh_personality().borrow_mut();
match *personality {
use trans::build::*;
use trans::cleanup::{CleanupMethods, ScopeId};
use trans::common::*;
-use trans::datum::{Datum, DatumBlock, Expr, Lvalue, rvalue_scratch_datum};
+use trans::datum::{Datum, Lvalue, rvalue_scratch_datum};
+use trans::datum::{Rvalue, ByValue};
use trans::debuginfo;
use trans::expr;
use trans::monomorphize::{self, MonoId};
use middle::ty::{self, Ty, UnboxedClosureTyper};
use middle::subst::{Substs};
use session::config::FullDebugInfo;
-use util::ppaux::Repr;
use util::ppaux::ty_to_string;
-use arena::TypedArena;
use syntax::ast;
use syntax::ast_util;
/// Returns the LLVM function declaration for an unboxed closure, creating it
/// if necessary. If the ID does not correspond to a closure ID, returns None.
-pub fn get_or_create_declaration_if_unboxed_closure<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
- closure_id: ast::DefId,
- substs: &Substs<'tcx>)
- -> Option<ValueRef> {
- let ccx = bcx.ccx();
+pub fn get_or_create_declaration_if_unboxed_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+ closure_id: ast::DefId,
+ substs: &Substs<'tcx>)
+ -> Option<Datum<'tcx, Rvalue>> {
if !ccx.tcx().unboxed_closures.borrow().contains_key(&closure_id) {
// Not an unboxed closure.
return None
}
- let function_type = ty::node_id_to_type(bcx.tcx(), closure_id.node);
- let function_type = monomorphize::apply_param_substs(bcx.tcx(), substs, &function_type);
+ let function_type = ty::node_id_to_type(ccx.tcx(), closure_id.node);
+ let function_type = monomorphize::apply_param_substs(ccx.tcx(), substs, &function_type);
// Normalize type so differences in regions and typedefs don't cause
// duplicate declarations
- let function_type = ty::normalize_ty(bcx.tcx(), function_type);
+ let function_type = ty::normalize_ty(ccx.tcx(), function_type);
let params = match function_type.sty {
ty::ty_unboxed_closure(_, _, ref substs) => substs.types.clone(),
_ => unreachable!()
};
match ccx.unboxed_closure_vals().borrow().get(&mono_id) {
- Some(llfn) => {
+ Some(&llfn) => {
debug!("get_or_create_declaration_if_unboxed_closure(): found \
closure");
- return Some(*llfn)
+ return Some(Datum::new(llfn, function_type, Rvalue::new(ByValue)))
}
None => {}
}
ccx.tn().type_to_string(val_ty(llfn)));
ccx.unboxed_closure_vals().borrow_mut().insert(mono_id, llfn);
- Some(llfn)
+ Some(Datum::new(llfn, function_type, Rvalue::new(ByValue)))
}
pub fn trans_unboxed_closure<'blk, 'tcx>(
let closure_id = ast_util::local_def(id);
let llfn = get_or_create_declaration_if_unboxed_closure(
- bcx,
+ bcx.ccx(),
closure_id,
bcx.fcx.param_substs).unwrap();
// of the closure expression.
let typer = NormalizingUnboxedClosureTyper::new(bcx.tcx());
let function_type = typer.unboxed_closure_type(closure_id, bcx.fcx.param_substs);
- let function_type = ty::mk_closure(bcx.tcx(), function_type);
let freevars: Vec<ty::Freevar> =
ty::with_freevars(bcx.tcx(), id, |fv| fv.iter().map(|&fv| fv).collect());
trans_closure(bcx.ccx(),
decl,
body,
- llfn,
+ llfn.val,
bcx.fcx.param_substs,
id,
&[],
- ty::ty_fn_ret(function_type),
- ty::ty_fn_abi(function_type),
+ function_type.sig.0.output,
+ function_type.abi,
ClosureEnv::new(freevars[],
UnboxedClosure(freevar_mode)));
bcx
}
-
-pub fn get_wrapper_for_bare_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
- closure_ty: Ty<'tcx>,
- def_id: ast::DefId,
- fn_ptr: ValueRef,
- is_local: bool) -> ValueRef {
-
- match ccx.closure_bare_wrapper_cache().borrow().get(&fn_ptr) {
- Some(&llval) => return llval,
- None => {}
- }
-
- let tcx = ccx.tcx();
-
- debug!("get_wrapper_for_bare_fn(closure_ty={})", closure_ty.repr(tcx));
-
- let f = match closure_ty.sty {
- ty::ty_closure(ref f) => f,
- _ => {
- ccx.sess().bug(format!("get_wrapper_for_bare_fn: \
- expected a closure ty, got {}",
- closure_ty.repr(tcx))[]);
- }
- };
-
- let name = ty::with_path(tcx, def_id, |path| {
- mangle_internal_name_by_path_and_seq(path, "as_closure")
- });
- let llfn = if is_local {
- decl_internal_rust_fn(ccx, closure_ty, name[])
- } else {
- decl_rust_fn(ccx, closure_ty, name[])
- };
-
- ccx.closure_bare_wrapper_cache().borrow_mut().insert(fn_ptr, llfn);
-
- // This is only used by statics inlined from a different crate.
- if !is_local {
- // Don't regenerate the wrapper, just reuse the original one.
- return llfn;
- }
-
- let _icx = push_ctxt("closure::get_wrapper_for_bare_fn");
-
- let arena = TypedArena::new();
- let empty_param_substs = Substs::trans_empty();
- let fcx = new_fn_ctxt(ccx, llfn, ast::DUMMY_NODE_ID, true, f.sig.0.output,
- &empty_param_substs, None, &arena);
- let bcx = init_function(&fcx, true, f.sig.0.output);
-
- let args = create_datums_for_fn_args(&fcx,
- ty::ty_fn_args(closure_ty)
- []);
- let mut llargs = Vec::new();
- match fcx.llretslotptr.get() {
- Some(llretptr) => {
- assert!(!fcx.needs_ret_allocas);
- llargs.push(llretptr);
- }
- None => {}
- }
- llargs.extend(args.iter().map(|arg| arg.val));
-
- let retval = Call(bcx, fn_ptr, llargs.as_slice(), None);
- match f.sig.0.output {
- ty::FnConverging(output_type) => {
- if return_type_is_void(ccx, output_type) || fcx.llretslotptr.get().is_some() {
- RetVoid(bcx);
- } else {
- Ret(bcx, retval);
- }
- }
- ty::FnDiverging => {
- RetVoid(bcx);
- }
- }
-
- // HACK(eddyb) finish_fn cannot be used here, we returned directly.
- debuginfo::clear_source_location(&fcx);
- fcx.cleanup();
-
- llfn
-}
-
-pub fn make_closure_from_bare_fn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
- closure_ty: Ty<'tcx>,
- def_id: ast::DefId,
- fn_ptr: ValueRef)
- -> DatumBlock<'blk, 'tcx, Expr> {
- let scratch = rvalue_scratch_datum(bcx, closure_ty, "__adjust");
- let wrapper = get_wrapper_for_bare_fn(bcx.ccx(), closure_ty, def_id, fn_ptr, true);
- fill_fn_pair(bcx, scratch.val, wrapper, C_null(Type::i8p(bcx.ccx())));
-
- DatumBlock::new(bcx, scratch.to_expr_datum())
-}
use trans::base;
use trans::build;
use trans::cleanup;
+use trans::consts;
use trans::datum;
use trans::debuginfo;
use trans::machine;
use arena::TypedArena;
use libc::{c_uint, c_char};
-use std::c_str::ToCStr;
+use std::ffi::CString;
use std::cell::{Cell, RefCell};
use std::vec::Vec;
use syntax::ast::Ident;
if self.llreturn.get().is_none() {
self.llreturn.set(Some(unsafe {
- "return".with_c_str(|buf| {
- llvm::LLVMAppendBasicBlockInContext(self.ccx.llcx(), self.llfn, buf)
- })
+ llvm::LLVMAppendBasicBlockInContext(self.ccx.llcx(), self.llfn,
+ "return\0".as_ptr() as *const _)
}))
}
opt_node_id: Option<ast::NodeId>)
-> Block<'a, 'tcx> {
unsafe {
- let llbb = name.with_c_str(|buf| {
- llvm::LLVMAppendBasicBlockInContext(self.ccx.llcx(),
- self.llfn,
- buf)
- });
+ let name = CString::from_slice(name.as_bytes());
+ let llbb = llvm::LLVMAppendBasicBlockInContext(self.ccx.llcx(),
+ self.llfn,
+ name.as_ptr());
BlockS::new(llbb, is_lpad, opt_node_id, self)
}
}
pub fn C_floating(s: &str, t: Type) -> ValueRef {
unsafe {
- s.with_c_str(|buf| llvm::LLVMConstRealOfString(t.to_ref(), buf))
+ let s = CString::from_slice(s.as_bytes());
+ llvm::LLVMConstRealOfString(t.to_ref(), s.as_ptr())
}
}
!null_terminated as Bool);
let gsym = token::gensym("str");
- let g = format!("str{}", gsym.uint()).with_c_str(|buf| {
- llvm::LLVMAddGlobal(cx.llmod(), val_ty(sc).to_ref(), buf)
- });
+ let buf = CString::from_vec(format!("str{}", gsym.uint()).into_bytes());
+ let g = llvm::LLVMAddGlobal(cx.llmod(), val_ty(sc).to_ref(), buf.as_ptr());
llvm::LLVMSetInitializer(g, sc);
llvm::LLVMSetGlobalConstant(g, True);
llvm::SetLinkage(g, llvm::InternalLinkage);
// NB: Do not use `do_spill_noroot` to make this into a constant string, or
// you will be kicked off fast isel. See issue #4352 for an example of this.
pub fn C_str_slice(cx: &CrateContext, s: InternedString) -> ValueRef {
- unsafe {
- let len = s.get().len();
- let cs = llvm::LLVMConstPointerCast(C_cstr(cx, s, false),
- Type::i8p(cx).to_ref());
- C_named_struct(cx.tn().find_type("str_slice").unwrap(), &[cs, C_uint(cx, len)])
- }
+ let len = s.get().len();
+ let cs = consts::ptrcast(C_cstr(cx, s, false), Type::i8p(cx));
+ C_named_struct(cx.tn().find_type("str_slice").unwrap(), &[cs, C_uint(cx, len)])
}
pub fn C_binary_slice(cx: &CrateContext, data: &[u8]) -> ValueRef {
let lldata = C_bytes(cx, data);
let gsym = token::gensym("binary");
- let g = format!("binary{}", gsym.uint()).with_c_str(|buf| {
- llvm::LLVMAddGlobal(cx.llmod(), val_ty(lldata).to_ref(), buf)
- });
+ let name = format!("binary{}", gsym.uint());
+ let name = CString::from_vec(name.into_bytes());
+ let g = llvm::LLVMAddGlobal(cx.llmod(), val_ty(lldata).to_ref(),
+ name.as_ptr());
llvm::LLVMSetInitializer(g, lldata);
llvm::LLVMSetGlobalConstant(g, True);
llvm::SetLinkage(g, llvm::InternalLinkage);
- let cs = llvm::LLVMConstPointerCast(g, Type::i8p(cx).to_ref());
+ let cs = consts::ptrcast(g, Type::i8p(cx));
C_struct(cx, &[cs, C_uint(cx, len)], false)
}
}
MethodCallKey(ty::MethodCall)
}
-pub fn node_id_substs<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
- node: ExprOrMethodCall)
- -> subst::Substs<'tcx>
-{
- let tcx = bcx.tcx();
+pub fn node_id_substs<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+ node: ExprOrMethodCall,
+ param_substs: &subst::Substs<'tcx>)
+ -> subst::Substs<'tcx> {
+ let tcx = ccx.tcx();
let substs = match node {
ExprId(id) => {
};
if substs.types.any(|t| ty::type_needs_infer(*t)) {
- bcx.sess().bug(
- format!("type parameters for node {} include inference types: \
- {}",
- node,
- substs.repr(bcx.tcx()))[]);
+ tcx.sess.bug(format!("type parameters for node {} include inference types: {}",
+ node, substs.repr(tcx))[]);
}
- let substs = substs.erase_regions();
- bcx.monomorphize(&substs)
+ monomorphize::apply_param_substs(tcx,
+ param_substs,
+ &substs.erase_regions())
}
pub fn langcall(bcx: Block,
use llvm::{ConstFCmp, ConstICmp, SetLinkage, PrivateLinkage, ValueRef, Bool, True, False};
use llvm::{IntEQ, IntNE, IntUGT, IntUGE, IntULT, IntULE, IntSGT, IntSGE, IntSLT, IntSLE,
RealOEQ, RealOGT, RealOGE, RealOLT, RealOLE, RealONE};
-use metadata::csearch;
use middle::{const_eval, def};
-use trans::{adt, closure, consts, debuginfo, expr, inline, machine};
+use trans::{adt, consts, debuginfo, expr, inline, machine};
use trans::base::{self, push_ctxt};
use trans::common::*;
use trans::type_::Type;
use trans::type_of;
+use middle::subst::Substs;
use middle::ty::{self, Ty};
use util::ppaux::{Repr, ty_to_string};
-use std::c_str::ToCStr;
use std::iter::repeat;
use libc::c_uint;
use syntax::{ast, ast_util};
}
}
-pub fn const_ptrcast(cx: &CrateContext, a: ValueRef, t: Type) -> ValueRef {
+pub fn ptrcast(val: ValueRef, ty: Type) -> ValueRef {
unsafe {
- let b = llvm::LLVMConstPointerCast(a, t.ptr_to().to_ref());
- assert!(cx.const_globals().borrow_mut().insert(b as int, a).is_none());
- b
+ llvm::LLVMConstPointerCast(val, ty.to_ref())
}
}
pub fn const_addr_of(cx: &CrateContext, cv: ValueRef, mutbl: ast::Mutability) -> ValueRef {
unsafe {
- let gv = "const".with_c_str(|name| {
- llvm::LLVMAddGlobal(cx.llmod(), val_ty(cv).to_ref(), name)
- });
+ let gv = llvm::LLVMAddGlobal(cx.llmod(), val_ty(cv).to_ref(),
+ "const\0".as_ptr() as *const _);
llvm::LLVMSetInitializer(gv, cv);
llvm::LLVMSetGlobalConstant(gv,
if mutbl == ast::MutImmutable {True} else {False});
None => { }
Some(adj) => {
match adj {
- ty::AdjustAddEnv(def_id, ty::RegionTraitStore(ty::ReStatic, _)) => {
- let wrapper = closure::get_wrapper_for_bare_fn(cx,
- ety_adjusted,
- def_id,
- llconst,
- true);
- llconst = C_struct(cx, &[wrapper, C_null(Type::i8p(cx))], false)
- }
- ty::AdjustAddEnv(_, store) => {
- cx.sess()
- .span_bug(e.span,
- format!("unexpected static function: {}",
- store)[])
- }
ty::AdjustReifyFnPointer(_def_id) => {
// FIXME(#19925) once fn item types are
// zero-sized, we'll need to do something here
match ty.sty {
ty::ty_vec(unit_ty, Some(len)) => {
let llunitty = type_of::type_of(cx, unit_ty);
- let llptr = const_ptrcast(cx, llconst, llunitty);
+ let llptr = ptrcast(llconst, llunitty.ptr_to());
+ assert!(cx.const_globals().borrow_mut()
+ .insert(llptr as int, llconst).is_none());
assert_eq!(abi::FAT_PTR_ADDR, 0);
assert_eq!(abi::FAT_PTR_EXTRA, 1);
llconst = C_struct(cx, &[
}
}
(expr::cast_pointer, expr::cast_pointer) => {
- llvm::LLVMConstPointerCast(v, llty.to_ref())
+ ptrcast(v, llty)
}
(expr::cast_integral, expr::cast_pointer) => {
llvm::LLVMConstIntToPtr(v, llty.to_ref())
C_array(llunitty, vs[])
}
}
- ast::ExprPath(ref pth) => {
- // Assert that there are no type parameters in this path.
- assert!(pth.segments.iter().all(|seg| !seg.parameters.has_types()));
-
- let opt_def = cx.tcx().def_map.borrow().get(&e.id).cloned();
- match opt_def {
- Some(def::DefFn(def_id, _)) => {
- if !ast_util::is_local(def_id) {
- let ty = csearch::get_type(cx.tcx(), def_id).ty;
- base::trans_external_path(cx, def_id, ty)
- } else {
- assert!(ast_util::is_local(def_id));
- base::get_item_val(cx, def_id.node)
- }
+ ast::ExprPath(_) => {
+ let def = cx.tcx().def_map.borrow()[e.id];
+ match def {
+ def::DefFn(..) | def::DefStaticMethod(..) | def::DefMethod(..) => {
+ expr::trans_def_fn_unadjusted(cx, e, def, &Substs::trans_empty()).val
}
- Some(def::DefConst(def_id)) => {
+ def::DefConst(def_id) => {
get_const_val(cx, def_id)
}
- Some(def::DefVariant(enum_did, variant_did, _)) => {
- let ety = ty::expr_ty(cx.tcx(), e);
- let repr = adt::represent_type(cx, ety);
+ def::DefVariant(enum_did, variant_did, _) => {
let vinfo = ty::enum_variant_with_id(cx.tcx(),
enum_did,
variant_did);
- adt::trans_const(cx, &*repr, vinfo.disr_val, &[])
+ if vinfo.args.len() > 0 {
+ // N-ary variant.
+ expr::trans_def_fn_unadjusted(cx, e, def, &Substs::trans_empty()).val
+ } else {
+ // Nullary variant.
+ let ety = ty::expr_ty(cx.tcx(), e);
+ let repr = adt::represent_type(cx, ety);
+ adt::trans_const(cx, &*repr, vinfo.disr_val, &[])
+ }
}
- Some(def::DefStruct(_)) => {
+ def::DefStruct(_) => {
let ety = ty::expr_ty(cx.tcx(), e);
- let llty = type_of::type_of(cx, ety);
- C_null(llty)
+ if let ty::ty_bare_fn(..) = ety.sty {
+ // Tuple struct.
+ expr::trans_def_fn_unadjusted(cx, e, def, &Substs::trans_empty()).val
+ } else {
+ // Unit struct.
+ C_null(type_of::type_of(cx, ety))
+ }
}
_ => {
cx.sess().span_bug(e.span, "expected a const, fn, struct, \
use util::sha2::Sha256;
use util::nodemap::{NodeMap, NodeSet, DefIdMap, FnvHashMap, FnvHashSet};
+use std::ffi::CString;
use std::cell::{Cell, RefCell};
-use std::c_str::ToCStr;
use std::ptr;
use std::rc::Rc;
use syntax::ast;
unsafe fn create_context_and_module(sess: &Session, mod_name: &str) -> (ContextRef, ModuleRef) {
let llcx = llvm::LLVMContextCreate();
- let llmod = mod_name.with_c_str(|buf| {
- llvm::LLVMModuleCreateWithNameInContext(buf, llcx)
- });
- sess.target
- .target
- .data_layout
- .with_c_str(|buf| {
- llvm::LLVMSetDataLayout(llmod, buf);
- });
- sess.target
- .target
- .llvm_target
- .with_c_str(|buf| {
- llvm::LLVMRustSetNormalizedTarget(llmod, buf);
- });
+ let mod_name = CString::from_slice(mod_name.as_bytes());
+ let llmod = llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx);
+
+ let data_layout = sess.target.target.data_layout.as_slice();
+ let data_layout = CString::from_slice(data_layout.as_bytes());
+ llvm::LLVMSetDataLayout(llmod, data_layout.as_ptr());
+
+ let llvm_target = sess.target.target.llvm_target.as_slice();
+ let llvm_target = CString::from_slice(llvm_target.as_bytes());
+ llvm::LLVMRustSetNormalizedTarget(llmod, llvm_target.as_ptr());
(llcx, llmod)
}
use util::ppaux;
use libc::c_uint;
-use std::c_str::{CString, ToCStr};
+use std::ffi::CString;
use std::cell::{Cell, RefCell};
use std::ptr;
use std::rc::{Rc, Weak};
}
}
},
- ty::ty_closure(box ref closure_ty) => {
- self.get_unique_type_id_of_closure_type(cx,
- closure_ty.clone(),
- &mut unique_type_id);
- },
ty::ty_unboxed_closure(def_id, _, substs) => {
let typer = NormalizingUnboxedClosureTyper::new(cx.tcx());
let closure_ty = typer.unboxed_closure_type(def_id, substs);
// for OS X to understand. For more info see #11352
// This can be overridden using --llvm-opts -dwarf-version,N.
if cx.sess().target.target.options.is_like_osx {
- "Dwarf Version".with_c_str(
- |s| llvm::LLVMRustAddModuleFlag(cx.llmod(), s, 2));
+ llvm::LLVMRustAddModuleFlag(cx.llmod(),
+ "Dwarf Version\0".as_ptr() as *const _,
+ 2)
}
// Prevent bitcode readers from deleting the debug info.
- "Debug Info Version".with_c_str(
- |s| llvm::LLVMRustAddModuleFlag(cx.llmod(), s,
- llvm::LLVMRustDebugMetadataVersion));
+ let ptr = "Debug Info Version\0".as_ptr();
+ llvm::LLVMRustAddModuleFlag(cx.llmod(), ptr as *const _,
+ llvm::LLVMRustDebugMetadataVersion);
};
}
namespace_node.mangled_name_of_contained_item(var_name[]);
let var_scope = namespace_node.scope;
- var_name.with_c_str(|var_name| {
- linkage_name.with_c_str(|linkage_name| {
- unsafe {
- llvm::LLVMDIBuilderCreateStaticVariable(DIB(cx),
- var_scope,
- var_name,
- linkage_name,
- file_metadata,
- line_number,
- type_metadata,
- is_local_to_unit,
- global,
- ptr::null_mut());
- }
- })
- });
+ let var_name = CString::from_slice(var_name.as_bytes());
+ let linkage_name = CString::from_slice(linkage_name.as_bytes());
+ unsafe {
+ llvm::LLVMDIBuilderCreateStaticVariable(DIB(cx),
+ var_scope,
+ var_name.as_ptr(),
+ linkage_name.as_ptr(),
+ file_metadata,
+ line_number,
+ type_metadata,
+ is_local_to_unit,
+ global,
+ ptr::null_mut());
+ }
}
/// Creates debug information for the given local variable.
let is_local_to_unit = is_node_local_to_unit(cx, fn_ast_id);
- let fn_metadata = function_name.with_c_str(|function_name| {
- linkage_name.with_c_str(|linkage_name| {
- unsafe {
- llvm::LLVMDIBuilderCreateFunction(
- DIB(cx),
- containing_scope,
- function_name,
- linkage_name,
- file_metadata,
- loc.line as c_uint,
- function_type_metadata,
- is_local_to_unit,
- true,
- scope_line as c_uint,
- FlagPrototyped as c_uint,
- cx.sess().opts.optimize != config::No,
- llfn,
- template_parameters,
- ptr::null_mut())
- }
- })
- });
+ let function_name = CString::from_slice(function_name.as_bytes());
+ let linkage_name = CString::from_slice(linkage_name.as_bytes());
+ let fn_metadata = unsafe {
+ llvm::LLVMDIBuilderCreateFunction(
+ DIB(cx),
+ containing_scope,
+ function_name.as_ptr(),
+ linkage_name.as_ptr(),
+ file_metadata,
+ loc.line as c_uint,
+ function_type_metadata,
+ is_local_to_unit,
+ true,
+ scope_line as c_uint,
+ FlagPrototyped as c_uint,
+ cx.sess().opts.optimize != config::No,
+ llfn,
+ template_parameters,
+ ptr::null_mut())
+ };
let scope_map = create_scope_map(cx,
fn_decl.inputs.as_slice(),
let ident = special_idents::type_self;
- let param_metadata = token::get_ident(ident).get()
- .with_c_str(|name| {
- unsafe {
- llvm::LLVMDIBuilderCreateTemplateTypeParameter(
- DIB(cx),
- file_metadata,
- name,
- actual_self_type_metadata,
- ptr::null_mut(),
- 0,
- 0)
- }
- });
+ let ident = token::get_ident(ident);
+ let name = CString::from_slice(ident.get().as_bytes());
+ let param_metadata = unsafe {
+ llvm::LLVMDIBuilderCreateTemplateTypeParameter(
+ DIB(cx),
+ file_metadata,
+ name.as_ptr(),
+ actual_self_type_metadata,
+ ptr::null_mut(),
+ 0,
+ 0)
+ };
template_params.push(param_metadata);
}
// Again, only create type information if full debuginfo is enabled
if cx.sess().opts.debuginfo == FullDebugInfo {
let actual_type_metadata = type_metadata(cx, actual_type, codemap::DUMMY_SP);
- let param_metadata = token::get_ident(ident).get()
- .with_c_str(|name| {
- unsafe {
- llvm::LLVMDIBuilderCreateTemplateTypeParameter(
- DIB(cx),
- file_metadata,
- name,
- actual_type_metadata,
- ptr::null_mut(),
- 0,
- 0)
- }
- });
+ let ident = token::get_ident(ident);
+ let name = CString::from_slice(ident.get().as_bytes());
+ let param_metadata = unsafe {
+ llvm::LLVMDIBuilderCreateTemplateTypeParameter(
+ DIB(cx),
+ file_metadata,
+ name.as_ptr(),
+ actual_type_metadata,
+ ptr::null_mut(),
+ 0,
+ 0)
+ };
template_params.push(param_metadata);
}
}
} else {
match abs_path.path_relative_from(work_dir) {
Some(ref p) if p.is_relative() => {
- // prepend "./" if necessary
- let dotdot = b"..";
- let prefix = [dotdot[0], ::std::path::SEP_BYTE];
- let mut path_bytes = p.as_vec().to_vec();
-
- if path_bytes.slice_to(2) != prefix &&
- path_bytes.slice_to(2) != dotdot {
- path_bytes.insert(0, prefix[0]);
- path_bytes.insert(1, prefix[1]);
- }
-
- path_bytes.to_c_str()
+ // prepend "./" if necessary
+ let dotdot = b"..";
+ let prefix: &[u8] = &[dotdot[0], ::std::path::SEP_BYTE];
+ let mut path_bytes = p.as_vec().to_vec();
+
+ if path_bytes.slice_to(2) != prefix &&
+ path_bytes.slice_to(2) != dotdot {
+ path_bytes.insert(0, prefix[0]);
+ path_bytes.insert(1, prefix[1]);
}
+
+ CString::from_vec(path_bytes)
+ }
_ => fallback_path(cx)
}
}
(option_env!("CFG_VERSION")).expect("CFG_VERSION"));
let compile_unit_name = compile_unit_name.as_ptr();
- return work_dir.as_vec().with_c_str(|work_dir| {
- producer.with_c_str(|producer| {
- "".with_c_str(|flags| {
- "".with_c_str(|split_name| {
- unsafe {
- llvm::LLVMDIBuilderCreateCompileUnit(
- debug_context(cx).builder,
- DW_LANG_RUST,
- compile_unit_name,
- work_dir,
- producer,
- cx.sess().opts.optimize != config::No,
- flags,
- 0,
- split_name)
- }
- })
- })
- })
- });
+ let work_dir = CString::from_slice(work_dir.as_vec());
+ let producer = CString::from_slice(producer.as_bytes());
+ let flags = "\0";
+ let split_name = "\0";
+ return unsafe {
+ llvm::LLVMDIBuilderCreateCompileUnit(
+ debug_context(cx).builder,
+ DW_LANG_RUST,
+ compile_unit_name,
+ work_dir.as_ptr(),
+ producer.as_ptr(),
+ cx.sess().opts.optimize != config::No,
+ flags.as_ptr() as *const _,
+ 0,
+ split_name.as_ptr() as *const _)
+ };
fn fallback_path(cx: &CrateContext) -> CString {
- cx.link_meta().crate_name.to_c_str()
+ CString::from_slice(cx.link_meta().crate_name.as_bytes())
}
}
CapturedVariable => (0, DW_TAG_auto_variable)
};
- let (var_alloca, var_metadata) = name.get().with_c_str(|name| {
- match variable_access {
- DirectVariable { alloca } => (
- alloca,
- unsafe {
- llvm::LLVMDIBuilderCreateLocalVariable(
- DIB(cx),
- dwarf_tag,
- scope_metadata,
- name,
- file_metadata,
- loc.line as c_uint,
- type_metadata,
- cx.sess().opts.optimize != config::No,
- 0,
- argument_index)
- }
- ),
- IndirectVariable { alloca, address_operations } => (
- alloca,
- unsafe {
- llvm::LLVMDIBuilderCreateComplexVariable(
- DIB(cx),
- dwarf_tag,
- scope_metadata,
- name,
- file_metadata,
- loc.line as c_uint,
- type_metadata,
- address_operations.as_ptr(),
- address_operations.len() as c_uint,
- argument_index)
- }
- )
- }
- });
+ let name = CString::from_slice(name.get().as_bytes());
+ let (var_alloca, var_metadata) = match variable_access {
+ DirectVariable { alloca } => (
+ alloca,
+ unsafe {
+ llvm::LLVMDIBuilderCreateLocalVariable(
+ DIB(cx),
+ dwarf_tag,
+ scope_metadata,
+ name.as_ptr(),
+ file_metadata,
+ loc.line as c_uint,
+ type_metadata,
+ cx.sess().opts.optimize != config::No,
+ 0,
+ argument_index)
+ }
+ ),
+ IndirectVariable { alloca, address_operations } => (
+ alloca,
+ unsafe {
+ llvm::LLVMDIBuilderCreateComplexVariable(
+ DIB(cx),
+ dwarf_tag,
+ scope_metadata,
+ name.as_ptr(),
+ file_metadata,
+ loc.line as c_uint,
+ type_metadata,
+ address_operations.as_ptr(),
+ address_operations.len() as c_uint,
+ argument_index)
+ }
+ )
+ };
set_debug_location(cx, DebugLocation::new(scope_metadata,
loc.line,
full_path
};
- let file_metadata =
- file_name.with_c_str(|file_name| {
- work_dir.with_c_str(|work_dir| {
- unsafe {
- llvm::LLVMDIBuilderCreateFile(DIB(cx), file_name, work_dir)
- }
- })
- });
+ let file_name = CString::from_slice(file_name.as_bytes());
+ let work_dir = CString::from_slice(work_dir.as_bytes());
+ let file_metadata = unsafe {
+ llvm::LLVMDIBuilderCreateFile(DIB(cx), file_name.as_ptr(),
+ work_dir.as_ptr())
+ };
let mut created_files = debug_context(cx).created_files.borrow_mut();
created_files.insert(full_path.to_string(), file_metadata);
}
fn diverging_type_metadata(cx: &CrateContext) -> DIType {
- "!".with_c_str(|name| {
- unsafe {
- llvm::LLVMDIBuilderCreateBasicType(
- DIB(cx),
- name,
- bytes_to_bits(0),
- bytes_to_bits(0),
- DW_ATE_unsigned)
- }
- })
+ unsafe {
+ llvm::LLVMDIBuilderCreateBasicType(
+ DIB(cx),
+ "!\0".as_ptr() as *const _,
+ bytes_to_bits(0),
+ bytes_to_bits(0),
+ DW_ATE_unsigned)
+ }
}
fn basic_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
let llvm_type = type_of::type_of(cx, t);
let (size, align) = size_and_align_of(cx, llvm_type);
- let ty_metadata = name.with_c_str(|name| {
- unsafe {
- llvm::LLVMDIBuilderCreateBasicType(
- DIB(cx),
- name,
- bytes_to_bits(size),
- bytes_to_bits(align),
- encoding)
- }
- });
+ let name = CString::from_slice(name.as_bytes());
+ let ty_metadata = unsafe {
+ llvm::LLVMDIBuilderCreateBasicType(
+ DIB(cx),
+ name.as_ptr(),
+ bytes_to_bits(size),
+ bytes_to_bits(align),
+ encoding)
+ };
return ty_metadata;
}
let pointer_llvm_type = type_of::type_of(cx, pointer_type);
let (pointer_size, pointer_align) = size_and_align_of(cx, pointer_llvm_type);
let name = compute_debuginfo_type_name(cx, pointer_type, false);
- let ptr_metadata = name.with_c_str(|name| {
- unsafe {
- llvm::LLVMDIBuilderCreatePointerType(
- DIB(cx),
- pointee_type_metadata,
- bytes_to_bits(pointer_size),
- bytes_to_bits(pointer_align),
- name)
- }
- });
+ let name = CString::from_slice(name.as_bytes());
+ let ptr_metadata = unsafe {
+ llvm::LLVMDIBuilderCreatePointerType(
+ DIB(cx),
+ pointee_type_metadata,
+ bytes_to_bits(pointer_size),
+ bytes_to_bits(pointer_align),
+ name.as_ptr())
+ };
return ptr_metadata;
}
let enumerators_metadata: Vec<DIDescriptor> = variants
.iter()
.map(|v| {
- token::get_name(v.name).get().with_c_str(|name| {
- unsafe {
- llvm::LLVMDIBuilderCreateEnumerator(
- DIB(cx),
- name,
- v.disr_val as u64)
- }
- })
+ let token = token::get_name(v.name);
+ let name = CString::from_slice(token.get().as_bytes());
+ unsafe {
+ llvm::LLVMDIBuilderCreateEnumerator(
+ DIB(cx),
+ name.as_ptr(),
+ v.disr_val as u64)
+ }
})
.collect();
codemap::DUMMY_SP);
let discriminant_name = get_enum_discriminant_name(cx, enum_def_id);
- let discriminant_type_metadata = discriminant_name.get().with_c_str(|name| {
- unsafe {
- llvm::LLVMDIBuilderCreateEnumerationType(
- DIB(cx),
- containing_scope,
- name,
- UNKNOWN_FILE_METADATA,
- UNKNOWN_LINE_NUMBER,
- bytes_to_bits(discriminant_size),
- bytes_to_bits(discriminant_align),
- create_DIArray(DIB(cx), enumerators_metadata[]),
- discriminant_base_type_metadata)
- }
- });
+ let name = CString::from_slice(discriminant_name.get().as_bytes());
+ let discriminant_type_metadata = unsafe {
+ llvm::LLVMDIBuilderCreateEnumerationType(
+ DIB(cx),
+ containing_scope,
+ name.as_ptr(),
+ UNKNOWN_FILE_METADATA,
+ UNKNOWN_LINE_NUMBER,
+ bytes_to_bits(discriminant_size),
+ bytes_to_bits(discriminant_align),
+ create_DIArray(DIB(cx), enumerators_metadata.as_slice()),
+ discriminant_base_type_metadata)
+ };
debug_context(cx).created_enum_disr_types
.borrow_mut()
.borrow()
.get_unique_type_id_as_string(unique_type_id);
- let enum_metadata = enum_name.with_c_str(|enum_name| {
- unique_type_id_str.with_c_str(|unique_type_id_str| {
- unsafe {
- llvm::LLVMDIBuilderCreateUnionType(
- DIB(cx),
- containing_scope,
- enum_name,
- UNKNOWN_FILE_METADATA,
- UNKNOWN_LINE_NUMBER,
- bytes_to_bits(enum_type_size),
- bytes_to_bits(enum_type_align),
- 0, // Flags
- ptr::null_mut(),
- 0, // RuntimeLang
- unique_type_id_str)
- }
- })
- });
+ let enum_name = CString::from_slice(enum_name.as_bytes());
+ let unique_type_id_str = CString::from_slice(unique_type_id_str.as_bytes());
+ let enum_metadata = unsafe {
+ llvm::LLVMDIBuilderCreateUnionType(
+ DIB(cx),
+ containing_scope,
+ enum_name.as_ptr(),
+ UNKNOWN_FILE_METADATA,
+ UNKNOWN_LINE_NUMBER,
+ bytes_to_bits(enum_type_size),
+ bytes_to_bits(enum_type_align),
+ 0, // Flags
+ ptr::null_mut(),
+ 0, // RuntimeLang
+ unique_type_id_str.as_ptr())
+ };
return create_and_register_recursive_type_forward_declaration(
cx,
ComputedMemberOffset => machine::llelement_offset(cx, composite_llvm_type, i)
};
- member_description.name.with_c_str(|member_name| {
- unsafe {
- llvm::LLVMDIBuilderCreateMemberType(
- DIB(cx),
- composite_type_metadata,
- member_name,
- UNKNOWN_FILE_METADATA,
- UNKNOWN_LINE_NUMBER,
- bytes_to_bits(member_size),
- bytes_to_bits(member_align),
- bytes_to_bits(member_offset),
- member_description.flags,
- member_description.type_metadata)
- }
- })
+ let member_name = CString::from_slice(member_description.name.as_bytes());
+ unsafe {
+ llvm::LLVMDIBuilderCreateMemberType(
+ DIB(cx),
+ composite_type_metadata,
+ member_name.as_ptr(),
+ UNKNOWN_FILE_METADATA,
+ UNKNOWN_LINE_NUMBER,
+ bytes_to_bits(member_size),
+ bytes_to_bits(member_align),
+ bytes_to_bits(member_offset),
+ member_description.flags,
+ member_description.type_metadata)
+ }
})
.collect();
let unique_type_id_str = debug_context(cx).type_map
.borrow()
.get_unique_type_id_as_string(unique_type_id);
+ let name = CString::from_slice(struct_type_name.as_bytes());
+ let unique_type_id = CString::from_slice(unique_type_id_str.as_bytes());
let metadata_stub = unsafe {
- struct_type_name.with_c_str(|name| {
- unique_type_id_str.with_c_str(|unique_type_id| {
- // LLVMDIBuilderCreateStructType() wants an empty array. A null
- // pointer will lead to hard to trace and debug LLVM assertions
- // later on in llvm/lib/IR/Value.cpp.
- let empty_array = create_DIArray(DIB(cx), &[]);
-
- llvm::LLVMDIBuilderCreateStructType(
- DIB(cx),
- containing_scope,
- name,
- UNKNOWN_FILE_METADATA,
- UNKNOWN_LINE_NUMBER,
- bytes_to_bits(struct_size),
- bytes_to_bits(struct_align),
- 0,
- ptr::null_mut(),
- empty_array,
- 0,
- ptr::null_mut(),
- unique_type_id)
- })
- })
+ // LLVMDIBuilderCreateStructType() wants an empty array. A null
+ // pointer will lead to hard to trace and debug LLVM assertions
+ // later on in llvm/lib/IR/Value.cpp.
+ let empty_array = create_DIArray(DIB(cx), &[]);
+
+ llvm::LLVMDIBuilderCreateStructType(
+ DIB(cx),
+ containing_scope,
+ name.as_ptr(),
+ UNKNOWN_FILE_METADATA,
+ UNKNOWN_LINE_NUMBER,
+ bytes_to_bits(struct_size),
+ bytes_to_bits(struct_align),
+ 0,
+ ptr::null_mut(),
+ empty_array,
+ 0,
+ ptr::null_mut(),
+ unique_type_id.as_ptr())
};
return metadata_stub;
ty::ty_bare_fn(_, ref barefnty) => {
subroutine_type_metadata(cx, unique_type_id, &barefnty.sig, usage_site_span)
}
- ty::ty_closure(ref closurety) => {
- subroutine_type_metadata(cx, unique_type_id, &closurety.sig, usage_site_span)
- }
ty::ty_unboxed_closure(def_id, _, substs) => {
let typer = NormalizingUnboxedClosureTyper::new(cx.tcx());
let sig = typer.unboxed_closure_type(def_id, substs).sig;
}
}
},
- ty::ty_closure(box ty::ClosureTy { unsafety,
- onceness,
- store,
- ref sig,
- .. // omitting bounds ...
- }) => {
- if unsafety == ast::Unsafety::Unsafe {
- output.push_str("unsafe ");
- }
-
- if onceness == ast::Once {
- output.push_str("once ");
- }
-
- let param_list_closing_char;
- match store {
- ty::UniqTraitStore => {
- output.push_str("proc(");
- param_list_closing_char = ')';
- }
- ty::RegionTraitStore(_, ast::MutMutable) => {
- output.push_str("&mut|");
- param_list_closing_char = '|';
- }
- ty::RegionTraitStore(_, ast::MutImmutable) => {
- output.push_str("&|");
- param_list_closing_char = '|';
- }
- };
-
- if sig.0.inputs.len() > 0 {
- for ¶meter_type in sig.0.inputs.iter() {
- push_debuginfo_type_name(cx, parameter_type, true, output);
- output.push_str(", ");
- }
- output.pop();
- output.pop();
- }
-
- if sig.0.variadic {
- if sig.0.inputs.len() > 0 {
- output.push_str(", ...");
- } else {
- output.push_str("...");
- }
- }
-
- output.push(param_list_closing_char);
-
- match sig.0.output {
- ty::FnConverging(result_type) if ty::type_is_nil(result_type) => {}
- ty::FnConverging(result_type) => {
- output.push_str(" -> ");
- push_debuginfo_type_name(cx, result_type, true, output);
- }
- ty::FnDiverging => {
- output.push_str(" -> !");
- }
- }
- },
ty::ty_unboxed_closure(..) => {
output.push_str("closure");
}
None => ptr::null_mut()
};
let namespace_name = token::get_name(name);
- let scope = namespace_name.get().with_c_str(|namespace_name| {
- unsafe {
- llvm::LLVMDIBuilderCreateNameSpace(
- DIB(cx),
- parent_scope,
- namespace_name,
- // cannot reconstruct file ...
- ptr::null_mut(),
- // ... or line information, but that's not so important.
- 0)
- }
- });
+ let namespace_name = CString::from_slice(namespace_name
+ .get().as_bytes());
+ let scope = unsafe {
+ llvm::LLVMDIBuilderCreateNameSpace(
+ DIB(cx),
+ parent_scope,
+ namespace_name.as_ptr(),
+ // cannot reconstruct file ...
+ ptr::null_mut(),
+ // ... or line information, but that's not so important.
+ 0)
+ };
let node = Rc::new(NamespaceTreeNode {
name: name,
/// .debug_gdb_scripts global is referenced, so it isn't removed by the linker.
pub fn insert_reference_to_gdb_debug_scripts_section_global(ccx: &CrateContext) {
if needs_gdb_debug_scripts_section(ccx) {
- let empty = b"".to_c_str();
+ let empty = CString::from_slice(b"");
let gdb_debug_scripts_section_global =
get_or_insert_gdb_debug_scripts_section_global(ccx);
unsafe {
/// section.
fn get_or_insert_gdb_debug_scripts_section_global(ccx: &CrateContext)
-> llvm::ValueRef {
- let section_var_name = b"__rustc_debug_gdb_scripts_section__".to_c_str();
+ let section_var_name = b"__rustc_debug_gdb_scripts_section__\0";
let section_var = unsafe {
- llvm::LLVMGetNamedGlobal(ccx.llmod(), section_var_name.as_ptr())
+ llvm::LLVMGetNamedGlobal(ccx.llmod(),
+ section_var_name.as_ptr() as *const _)
};
if section_var == ptr::null_mut() {
- let section_name = b".debug_gdb_scripts".to_c_str();
+ let section_name = b".debug_gdb_scripts\0";
let section_contents = b"\x01gdb_load_rust_pretty_printers.py\0";
unsafe {
section_contents.len() as u64);
let section_var = llvm::LLVMAddGlobal(ccx.llmod(),
llvm_type.to_ref(),
- section_var_name.as_ptr());
- llvm::LLVMSetSection(section_var, section_name.as_ptr());
+ section_var_name.as_ptr()
+ as *const _);
+ llvm::LLVMSetSection(section_var, section_name.as_ptr() as *const _);
llvm::LLVMSetInitializer(section_var, C_bytes(ccx, section_contents));
llvm::LLVMSetGlobalConstant(section_var, llvm::True);
llvm::LLVMSetUnnamedAddr(section_var, llvm::True);
use trans::tvec;
use trans::type_of;
use middle::ty::{struct_fields, tup_fields};
-use middle::ty::{AdjustDerefRef, AdjustReifyFnPointer, AdjustAddEnv, AutoUnsafe};
+use middle::ty::{AdjustDerefRef, AdjustReifyFnPointer, AutoUnsafe};
use middle::ty::{AutoPtr};
use middle::ty::{self, Ty};
use middle::ty::MethodCall;
datum.to_string(bcx.ccx()),
adjustment.repr(bcx.tcx()));
match adjustment {
- AdjustAddEnv(def_id, _) => {
- datum = unpack_datum!(bcx, add_env(bcx, def_id, expr, datum));
- }
AdjustReifyFnPointer(_def_id) => {
// FIXME(#19925) once fn item types are
// zero-sized, we'll need to do something here
DatumBlock::new(bcx, scratch.to_expr_datum())
}
-
- fn add_env<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
- def_id: ast::DefId,
- expr: &ast::Expr,
- datum: Datum<'tcx, Expr>)
- -> DatumBlock<'blk, 'tcx, Expr> {
- // This is not the most efficient thing possible; since closures
- // are two words it'd be better if this were compiled in
- // 'dest' mode, but I can't find a nice way to structure the
- // code and keep it DRY that accommodates that use case at the
- // moment.
-
- let closure_ty = expr_ty_adjusted(bcx, expr);
- let fn_ptr = datum.to_llscalarish(bcx);
- closure::make_closure_from_bare_fn(bcx, closure_ty, def_id, fn_ptr)
- }
}
/// Translates an expression in "lvalue" mode -- meaning that it returns a reference to the memory
match def {
def::DefFn(..) | def::DefStaticMethod(..) | def::DefMethod(..) |
def::DefStruct(_) | def::DefVariant(..) => {
- trans_def_fn_unadjusted(bcx, ref_expr, def)
+ let datum = trans_def_fn_unadjusted(bcx.ccx(), ref_expr, def,
+ bcx.fcx.param_substs);
+ DatumBlock::new(bcx, datum.to_expr_datum())
}
def::DefStatic(did, _) => {
// There are two things that may happen here:
let variant_info = ty::enum_variant_with_id(bcx.tcx(), tid, vid);
if variant_info.args.len() > 0u {
// N-ary variant.
- let llfn = callee::trans_fn_ref(bcx, vid, ExprId(ref_expr.id));
+ let llfn = callee::trans_fn_ref(bcx.ccx(), vid,
+ ExprId(ref_expr.id),
+ bcx.fcx.param_substs).val;
Store(bcx, llfn, lldest);
return bcx;
} else {
}
}
-fn trans_def_fn_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
- ref_expr: &ast::Expr,
- def: def::Def)
- -> DatumBlock<'blk, 'tcx, Expr> {
+pub fn trans_def_fn_unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+ ref_expr: &ast::Expr,
+ def: def::Def,
+ param_substs: &subst::Substs<'tcx>)
+ -> Datum<'tcx, Rvalue> {
let _icx = push_ctxt("trans_def_datum_unadjusted");
- let llfn = match def {
+ match def {
def::DefFn(did, _) |
def::DefStruct(did) | def::DefVariant(_, did, _) |
def::DefStaticMethod(did, def::FromImpl(_)) |
def::DefMethod(did, _, def::FromImpl(_)) => {
- callee::trans_fn_ref(bcx, did, ExprId(ref_expr.id))
+ callee::trans_fn_ref(ccx, did, ExprId(ref_expr.id), param_substs)
}
def::DefStaticMethod(impl_did, def::FromTrait(trait_did)) |
def::DefMethod(impl_did, _, def::FromTrait(trait_did)) => {
- meth::trans_static_method_callee(bcx, impl_did,
- trait_did, ref_expr.id)
+ meth::trans_static_method_callee(ccx, impl_did,
+ trait_did, ref_expr.id,
+ param_substs)
}
_ => {
- bcx.tcx().sess.span_bug(ref_expr.span, format!(
+ ccx.tcx().sess.span_bug(ref_expr.span, format!(
"trans_def_fn_unadjusted invoked on: {} for {}",
def,
- ref_expr.repr(bcx.tcx()))[]);
+ ref_expr.repr(ccx.tcx()))[]);
}
- };
-
- let fn_ty = expr_ty(bcx, ref_expr);
- DatumBlock::new(bcx, Datum::new(llfn, fn_ty, RvalueExpr(Rvalue::new(ByValue))))
+ }
}
/// Translates a reference to a local variable or argument. This always results in an lvalue datum.
use trans::type_of::*;
use trans::type_of;
use middle::ty::{self, Ty};
-use middle::subst::{Substs};
+use middle::subst::Substs;
+
+use std::ffi::CString;
use std::cmp;
-use std::c_str::ToCStr;
use libc::c_uint;
use syntax::abi::{Cdecl, Aapcs, C, Win64, Abi};
use syntax::abi::{RustIntrinsic, Rust, RustCall, Stdcall, Fastcall, System};
};
unsafe {
// Declare a symbol `foo` with the desired linkage.
- let g1 = ident.get().with_c_str(|buf| {
- llvm::LLVMAddGlobal(ccx.llmod(), llty2.to_ref(), buf)
- });
+ let buf = CString::from_slice(ident.get().as_bytes());
+ let g1 = llvm::LLVMAddGlobal(ccx.llmod(), llty2.to_ref(),
+ buf.as_ptr());
llvm::SetLinkage(g1, linkage);
// Declare an internal global `extern_with_linkage_foo` which
// zero.
let mut real_name = "_rust_extern_with_linkage_".to_string();
real_name.push_str(ident.get());
- let g2 = real_name.with_c_str(|buf| {
- llvm::LLVMAddGlobal(ccx.llmod(), llty.to_ref(), buf)
- });
+ let real_name = CString::from_vec(real_name.into_bytes());
+ let g2 = llvm::LLVMAddGlobal(ccx.llmod(), llty.to_ref(),
+ real_name.as_ptr());
llvm::SetLinkage(g2, llvm::InternalLinkage);
llvm::LLVMSetInitializer(g2, g1);
g2
}
None => unsafe {
// Generate an external declaration.
- ident.get().with_c_str(|buf| {
- llvm::LLVMAddGlobal(ccx.llmod(), llty.to_ref(), buf)
- })
+ let buf = CString::from_slice(ident.get().as_bytes());
+ llvm::LLVMAddGlobal(ccx.llmod(), llty.to_ref(), buf.as_ptr())
}
}
}
// return r;
// }
- let the_block =
- "the block".with_c_str(
- |s| llvm::LLVMAppendBasicBlockInContext(ccx.llcx(), llwrapfn, s));
+ let ptr = "the block\0".as_ptr();
+ let the_block = llvm::LLVMAppendBasicBlockInContext(ccx.llcx(), llwrapfn,
+ ptr as *const _);
let builder = ccx.builder();
builder.position_at_end(the_block);
use trans::callee;
use trans::cleanup;
use trans::cleanup::CleanupMethods;
+use trans::consts;
use trans::common::*;
use trans::datum;
use trans::debuginfo;
use util::ppaux;
use arena::TypedArena;
-use std::c_str::ToCStr;
use libc::c_uint;
+use std::ffi::CString;
use syntax::ast;
use syntax::parse::token;
v0,
t,
|bb, vv, tt| drop_ty(bb, vv, tt, None)),
- ty::ty_closure(ref f) if f.store == ty::UniqTraitStore => {
- let box_cell_v = GEPi(bcx, v0, &[0u, abi::FAT_PTR_EXTRA]);
- let env = Load(bcx, box_cell_v);
- let env_ptr_ty = Type::at_box(bcx.ccx(), Type::i8(bcx.ccx())).ptr_to();
- let env = PointerCast(bcx, env, env_ptr_ty);
- with_cond(bcx, IsNotNull(bcx, env), |bcx| {
- let dtor_ptr = GEPi(bcx, env, &[0u, abi::BOX_FIELD_DROP_GLUE]);
- let dtor = Load(bcx, dtor_ptr);
- Call(bcx, dtor, &[PointerCast(bcx, box_cell_v, Type::i8p(bcx.ccx()))], None);
- bcx
- })
- }
ty::ty_trait(..) => {
// No need to do a null check here (as opposed to the Box<trait case
// above), because this happens for a trait field in an unsized
let llalign = llalign_of(ccx, llty);
let name = mangle_internal_name_by_type_and_seq(ccx, t, "tydesc");
debug!("+++ declare_tydesc {} {}", ppaux::ty_to_string(ccx.tcx(), t), name);
- let gvar = name.with_c_str(|buf| {
- unsafe {
- llvm::LLVMAddGlobal(ccx.llmod(), ccx.tydesc_type().to_ref(), buf)
- }
- });
+ let buf = CString::from_slice(name.as_bytes());
+ let gvar = unsafe {
+ llvm::LLVMAddGlobal(ccx.llmod(), ccx.tydesc_type().to_ref(),
+ buf.as_ptr())
+ };
note_unique_llvm_symbol(ccx, name);
let ty_name = token::intern_and_get_ident(
return (fn_nm, llfn);
}
-fn make_generic_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
- t: Ty<'tcx>,
- llfn: ValueRef,
- helper: for<'blk> |Block<'blk, 'tcx>, ValueRef, Ty<'tcx>|
- -> Block<'blk, 'tcx>,
- name: &str)
- -> ValueRef {
+fn make_generic_glue<'a, 'tcx, F>(ccx: &CrateContext<'a, 'tcx>,
+ t: Ty<'tcx>,
+ llfn: ValueRef,
+ helper: F,
+ name: &str)
+ -> ValueRef where
+ F: for<'blk> FnOnce(Block<'blk, 'tcx>, ValueRef, Ty<'tcx>) -> Block<'blk, 'tcx>,
+{
let _icx = push_ctxt("make_generic_glue");
let glue_name = format!("glue {} {}", name, ty_to_short_str(ccx.tcx(), t));
let _s = StatRecorder::new(ccx, glue_name);
// before being put into the tydesc because we only have a singleton
// tydesc type. Then we'll recast each function to its real type when
// calling it.
- let drop_glue = unsafe {
- llvm::LLVMConstPointerCast(get_drop_glue(ccx, ti.ty), glue_fn_ty.to_ref())
- };
+ let drop_glue = consts::ptrcast(get_drop_glue(ccx, ti.ty), glue_fn_ty);
ccx.stats().n_real_glues.set(ccx.stats().n_real_glues.get() + 1);
let tydesc = C_named_struct(ccx.tydesc_type(),
let csearch_result =
csearch::maybe_get_item_ast(
ccx.tcx(), fn_id,
- |a,b,c,d| astencode::decode_inlined_item(a, b, c, d));
+ box |a,b,c,d| astencode::decode_inlined_item(a, b, c, d));
let inline_def = match csearch_result {
csearch::not_found => {
use middle::ty::MethodCall;
use util::ppaux::Repr;
-use std::c_str::ToCStr;
+use std::ffi::CString;
use std::rc::Rc;
use syntax::abi::{Rust, RustCall};
use syntax::parse::token;
ty::MethodStaticUnboxedClosure(did) => {
Callee {
bcx: bcx,
- data: Fn(callee::trans_fn_ref(bcx,
+ data: Fn(callee::trans_fn_ref(bcx.ccx(),
did,
- MethodCallKey(method_call))),
+ MethodCallKey(method_call),
+ bcx.fcx.param_substs).val),
}
}
}
}
-pub fn trans_static_method_callee(bcx: Block,
- method_id: ast::DefId,
- trait_id: ast::DefId,
- expr_id: ast::NodeId)
- -> ValueRef
+pub fn trans_static_method_callee<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+ method_id: ast::DefId,
+ trait_id: ast::DefId,
+ expr_id: ast::NodeId,
+ param_substs: &subst::Substs<'tcx>)
+ -> Datum<'tcx, Rvalue>
{
let _icx = push_ctxt("meth::trans_static_method_callee");
- let ccx = bcx.ccx();
+ let tcx = ccx.tcx();
debug!("trans_static_method_callee(method_id={}, trait_id={}, \
expr_id={})",
method_id,
- ty::item_path_str(bcx.tcx(), trait_id),
+ ty::item_path_str(tcx, trait_id),
expr_id);
let mname = if method_id.krate == ast::LOCAL_CRATE {
- match bcx.tcx().map.get(method_id.node) {
+ match tcx.map.get(method_id.node) {
ast_map::NodeTraitItem(method) => {
let ident = match *method {
ast::RequiredMethod(ref m) => m.ident,
ast::ProvidedMethod(ref m) => m.pe_ident(),
ast::TypeTraitItem(_) => {
- bcx.tcx().sess.bug("trans_static_method_callee() on \
- an associated type?!")
+ tcx.sess.bug("trans_static_method_callee() on \
+ an associated type?!")
}
};
ident.name
_ => panic!("callee is not a trait method")
}
} else {
- csearch::get_item_path(bcx.tcx(), method_id).last().unwrap().name()
+ csearch::get_item_path(tcx, method_id).last().unwrap().name()
};
debug!("trans_static_method_callee: method_id={}, expr_id={}, \
name={}", method_id, expr_id, token::get_name(mname));
// Find the substitutions for the fn itself. This includes
// type parameters that belong to the trait but also some that
// belong to the method:
- let rcvr_substs = node_id_substs(bcx, ExprId(expr_id));
+ let rcvr_substs = node_id_substs(ccx, ExprId(expr_id), param_substs);
let subst::SeparateVecsPerParamSpace {
types: rcvr_type,
selfs: rcvr_self,
Substs::erased(VecPerParamSpace::new(rcvr_type,
rcvr_self,
Vec::new()));
- let trait_substs = bcx.tcx().mk_substs(trait_substs);
- debug!("trait_substs={}", trait_substs.repr(bcx.tcx()));
+ let trait_substs = tcx.mk_substs(trait_substs);
+ debug!("trait_substs={}", trait_substs.repr(tcx));
let trait_ref = ty::Binder(Rc::new(ty::TraitRef { def_id: trait_id,
substs: trait_substs }));
- let vtbl = fulfill_obligation(bcx.ccx(),
+ let vtbl = fulfill_obligation(ccx,
DUMMY_SP,
trait_ref);
rcvr_method));
let mth_id = method_with_name(ccx, impl_did, mname);
- let llfn = trans_fn_ref_with_substs(bcx, mth_id, ExprId(expr_id),
- callee_substs);
-
- let callee_ty = node_id_type(bcx, expr_id);
- let llty = type_of_fn_from_ty(ccx, callee_ty).ptr_to();
- PointerCast(bcx, llfn, llty)
+ trans_fn_ref_with_substs(ccx, mth_id, ExprId(expr_id),
+ param_substs,
+ callee_substs)
}
_ => {
- bcx.tcx().sess.bug(
- format!("static call to invalid vtable: {}",
- vtbl.repr(bcx.tcx()))[]);
+ tcx.sess.bug(format!("static call to invalid vtable: {}",
+ vtbl.repr(tcx))[]);
}
}
}
bcx, MethodCallKey(method_call), vtable_impl.substs);
// translate the function
- let llfn = trans_fn_ref_with_substs(bcx,
+ let llfn = trans_fn_ref_with_substs(bcx.ccx(),
mth_id,
MethodCallKey(method_call),
- callee_substs);
+ bcx.fcx.param_substs,
+ callee_substs).val;
Callee { bcx: bcx, data: Fn(llfn) }
}
traits::VtableUnboxedClosure(closure_def_id, substs) => {
// The substitutions should have no type parameters remaining
// after passing through fulfill_obligation
- let llfn = trans_fn_ref_with_substs(bcx,
+ let llfn = trans_fn_ref_with_substs(bcx.ccx(),
closure_def_id,
MethodCallKey(method_call),
- substs);
+ bcx.fcx.param_substs,
+ substs).val;
Callee {
bcx: bcx,
{
let ccx = bcx.ccx();
- let node_substs = node_id_substs(bcx, node);
+ let node_substs = node_id_substs(ccx, node, bcx.fcx.param_substs);
debug!("rcvr_substs={}", rcvr_substs.repr(ccx.tcx()));
debug!("node_substs={}", node_substs.repr(ccx.tcx()));
bcx.val_to_string(llobject));
// the remaining arguments will be, well, whatever they are
+ let input_tys =
+ match fty.abi {
+ RustCall => {
+ // unpack the tuple to extract the input type arguments:
+ match fty.sig.0.inputs[1].sty {
+ ty::ty_tup(ref tys) => tys.as_slice(),
+ _ => {
+ bcx.sess().bug(
+ format!("rust-call expects a tuple not {}",
+ fty.sig.0.inputs[1].repr(tcx)).as_slice());
+ }
+ }
+ }
+ _ => {
+ // skip the self parameter:
+ fty.sig.0.inputs.slice_from(1)
+ }
+ };
+
let llargs: Vec<_> =
- fty.sig.0.inputs[1..].iter()
+ input_tys.iter()
.enumerate()
.map(|(i, _)| {
let llarg = get_param(fcx.llfn, fcx.arg_pos(i+1) as u32);
llarg
})
.collect();
+
assert!(!fcx.needs_ret_allocas);
let dest =
}
traits::VtableUnboxedClosure(closure_def_id, substs) => {
let llfn = trans_fn_ref_with_substs(
- bcx,
+ bcx.ccx(),
closure_def_id,
ExprId(0),
- substs.clone());
+ bcx.fcx.param_substs,
+ substs.clone()).val;
(vec!(llfn)).into_iter()
}
unsafe {
let tbl = C_struct(ccx, components[], false);
let sym = token::gensym("vtable");
- let vt_gvar = format!("vtable{}", sym.uint()).with_c_str(|buf| {
- llvm::LLVMAddGlobal(ccx.llmod(), val_ty(tbl).to_ref(), buf)
- });
+ let buf = CString::from_vec(format!("vtable{}", sym.uint()).into_bytes());
+ let vt_gvar = llvm::LLVMAddGlobal(ccx.llmod(), val_ty(tbl).to_ref(),
+ buf.as_ptr());
llvm::LLVMSetInitializer(vt_gvar, tbl);
llvm::LLVMSetGlobalConstant(vt_gvar, llvm::True);
llvm::SetLinkage(vt_gvar, llvm::InternalLinkage);
Some(C_null(Type::nil(ccx).ptr_to())).into_iter()
} else {
let fn_ref = trans_fn_ref_with_substs(
- bcx,
+ ccx,
m_id,
ExprId(0),
- substs.clone());
+ bcx.fcx.param_substs,
+ substs.clone()).val;
// currently, at least, by-value self is not object safe
assert!(m.explicit_self != ty::ByValueExplicitSelfCategory);
fn_id: ast::DefId,
psubsts: &subst::Substs<'tcx>,
ref_id: Option<ast::NodeId>)
- -> (ValueRef, bool) {
+ -> (ValueRef, Ty<'tcx>, bool) {
debug!("monomorphic_fn(\
fn_id={}, \
real_substs={}, \
params: psubsts.types.clone()
};
+ let item_ty = ty::lookup_item_type(ccx.tcx(), fn_id).ty;
+ let mono_ty = item_ty.subst(ccx.tcx(), psubsts);
+
match ccx.monomorphized().borrow().get(&hash_id) {
Some(&val) => {
debug!("leaving monomorphic fn {}",
ty::item_path_str(ccx.tcx(), fn_id));
- return (val, false);
+ return (val, mono_ty, false);
}
None => ()
}
psubsts.repr(ccx.tcx()),
hash_id);
- let tpt = ty::lookup_item_type(ccx.tcx(), fn_id);
- let llitem_ty = tpt.ty;
let map_node = session::expect(
ccx.sess(),
if let ast_map::NodeForeignItem(_) = map_node {
if ccx.tcx().map.get_foreign_abi(fn_id.node) != abi::RustIntrinsic {
// Foreign externs don't have to be monomorphized.
- return (get_item_val(ccx, fn_id.node), true);
+ return (get_item_val(ccx, fn_id.node), mono_ty, true);
}
}
- debug!("monomorphic_fn about to subst into {}", llitem_ty.repr(ccx.tcx()));
+ debug!("monomorphic_fn about to subst into {}", item_ty.repr(ccx.tcx()));
- let mono_ty = llitem_ty.subst(ccx.tcx(), psubsts);
debug!("mono_ty = {} (post-substitution)", mono_ty.repr(ccx.tcx()));
let mono_ty = normalize_associated_type(ccx.tcx(), &mono_ty);
ccx.monomorphizing().borrow_mut().insert(fn_id, depth);
debug!("leaving monomorphic fn {}", ty::item_path_str(ccx.tcx(), fn_id));
- (lldecl, true)
+ (lldecl, mono_ty, true)
}
#[derive(PartialEq, Eq, Hash, Show)]
use trans::cleanup;
use trans::cleanup::CleanupMethods;
use trans::common::*;
+use trans::consts;
use trans::datum::*;
use trans::expr::{Dest, Ignore, SaveIn};
use trans::expr;
match dest {
Ignore => bcx,
SaveIn(lldest) => {
- unsafe {
- let bytes = str_lit.get().len();
- let llbytes = C_uint(bcx.ccx(), bytes);
- let llcstr = C_cstr(bcx.ccx(), str_lit, false);
- let llcstr = llvm::LLVMConstPointerCast(llcstr, Type::i8p(bcx.ccx()).to_ref());
- Store(bcx, llcstr, GEPi(bcx, lldest, &[0u, abi::FAT_PTR_ADDR]));
- Store(bcx, llbytes, GEPi(bcx, lldest, &[0u, abi::FAT_PTR_EXTRA]));
- bcx
- }
+ let bytes = str_lit.get().len();
+ let llbytes = C_uint(bcx.ccx(), bytes);
+ let llcstr = C_cstr(bcx.ccx(), str_lit, false);
+ let llcstr = consts::ptrcast(llcstr, Type::i8p(bcx.ccx()));
+ Store(bcx, llcstr, GEPi(bcx, lldest, &[0u, abi::FAT_PTR_ADDR]));
+ Store(bcx, llbytes, GEPi(bcx, lldest, &[0u, abi::FAT_PTR_EXTRA]));
+ bcx
}
}
}
}
}
-pub type iter_vec_block<'a, 'blk, 'tcx> =
- |Block<'blk, 'tcx>, ValueRef, Ty<'tcx>|: 'a -> Block<'blk, 'tcx>;
-
-pub fn iter_vec_loop<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+pub fn iter_vec_loop<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
data_ptr: ValueRef,
vt: &VecTypes<'tcx>,
count: ValueRef,
- f: iter_vec_block<'a, 'blk, 'tcx>)
- -> Block<'blk, 'tcx> {
+ f: F)
+ -> Block<'blk, 'tcx> where
+ F: FnOnce(Block<'blk, 'tcx>, ValueRef, Ty<'tcx>) -> Block<'blk, 'tcx>,
+{
let _icx = push_ctxt("tvec::iter_vec_loop");
let fcx = bcx.fcx;
next_bcx
}
-pub fn iter_vec_raw<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
- data_ptr: ValueRef,
- unit_ty: Ty<'tcx>,
- len: ValueRef,
- f: iter_vec_block<'a, 'blk, 'tcx>)
- -> Block<'blk, 'tcx> {
+pub fn iter_vec_raw<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
+ data_ptr: ValueRef,
+ unit_ty: Ty<'tcx>,
+ len: ValueRef,
+ f: F)
+ -> Block<'blk, 'tcx> where
+ F: FnOnce(Block<'blk, 'tcx>, ValueRef, Ty<'tcx>) -> Block<'blk, 'tcx>,
+{
let _icx = push_ctxt("tvec::iter_vec_raw");
let fcx = bcx.fcx;
use syntax::ast;
-use std::c_str::ToCStr;
+use std::ffi::CString;
use std::mem;
use std::cell::RefCell;
use std::iter::repeat;
}
pub fn named_struct(ccx: &CrateContext, name: &str) -> Type {
- ty!(name.with_c_str(|s| llvm::LLVMStructCreateNamed(ccx.llcx(), s)))
+ let name = CString::from_slice(name.as_bytes());
+ ty!(llvm::LLVMStructCreateNamed(ccx.llcx(), name.as_ptr()))
}
pub fn empty_struct(ccx: &CrateContext) -> Type {
// Given a function type and a count of ty params, construct an llvm type
pub fn type_of_fn_from_ty<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fty: Ty<'tcx>) -> Type {
match fty.sty {
- ty::ty_closure(ref f) => {
- type_of_rust_fn(cx,
- Some(Type::i8p(cx)),
- f.sig.0.inputs.as_slice(),
- f.sig.0.output,
- f.abi)
- }
ty::ty_bare_fn(_, ref f) => {
// FIXME(#19925) once fn item types are
// zero-sized, we'll need to do something here
}
ty::ty_bare_fn(..) => Type::i8p(cx),
- ty::ty_closure(..) => Type::struct_(cx, &[Type::i8p(cx), Type::i8p(cx)], false),
ty::ty_vec(ty, Some(size)) => {
let llty = sizing_type_of(cx, ty);
ty::ty_bare_fn(..) => {
type_of_fn_from_ty(cx, t).ptr_to()
}
- ty::ty_closure(_) => {
- let fn_ty = type_of_fn_from_ty(cx, t).ptr_to();
- Type::struct_(cx, &[fn_ty, Type::i8p(cx)], false)
- }
ty::ty_tup(ref tys) if tys.is_empty() => Type::nil(cx),
ty::ty_tup(..) => {
let repr = adt::represent_type(cx, t);
use middle::resolve_lifetime as rl;
use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs};
use middle::subst::{VecPerParamSpace};
-use middle::ty::{self, RegionEscape, Ty};
+use middle::traits;
+use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty};
use rscope::{self, UnelidableRscope, RegionScope, SpecificRscope,
ShiftedRscope, BindingRscope};
use TypeAndSubsts;
pub trait AstConv<'tcx> {
fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx>;
+
fn get_item_type_scheme(&self, id: ast::DefId) -> ty::TypeScheme<'tcx>;
+
fn get_trait_def(&self, id: ast::DefId) -> Rc<ty::TraitDef<'tcx>>;
/// Return an (optional) substitution to convert bound type parameters that
r
}
-pub fn opt_ast_region_to_region<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
- this: &AC,
- rscope: &RS,
+pub fn opt_ast_region_to_region<'tcx>(
+ this: &AstConv<'tcx>,
+ rscope: &RegionScope,
default_span: Span,
opt_lifetime: &Option<ast::Lifetime>) -> ty::Region
{
/// Given a path `path` that refers to an item `I` with the declared generics `decl_generics`,
/// returns an appropriate set of substitutions for this particular reference to `I`.
-fn ast_path_substs_for_ty<'tcx,AC,RS>(
- this: &AC,
- rscope: &RS,
+fn ast_path_substs_for_ty<'tcx>(
+ this: &AstConv<'tcx>,
+ rscope: &RegionScope,
decl_generics: &ty::Generics<'tcx>,
path: &ast::Path)
-> Substs<'tcx>
- where AC: AstConv<'tcx>, RS: RegionScope
{
let tcx = this.tcx();
regions)
}
-fn create_substs_for_ast_path<'tcx,AC,RS>(
- this: &AC,
- rscope: &RS,
+fn create_substs_for_ast_path<'tcx>(
+ this: &AstConv<'tcx>,
+ rscope: &RegionScope,
span: Span,
decl_generics: &ty::Generics<'tcx>,
self_ty: Option<Ty<'tcx>>,
types: Vec<Ty<'tcx>>,
regions: Vec<ty::Region>)
- -> Substs<'tcx>
- where AC: AstConv<'tcx>, RS: RegionScope
+ -> Substs<'tcx>
{
let tcx = this.tcx();
span: Span,
}
-fn convert_angle_bracketed_parameters<'tcx, AC, RS>(this: &AC,
- rscope: &RS,
- data: &ast::AngleBracketedParameterData)
- -> (Vec<ty::Region>,
- Vec<Ty<'tcx>>,
- Vec<ConvertedBinding<'tcx>>)
- where AC: AstConv<'tcx>, RS: RegionScope
+fn convert_angle_bracketed_parameters<'tcx>(this: &AstConv<'tcx>,
+ rscope: &RegionScope,
+ data: &ast::AngleBracketedParameterData)
+ -> (Vec<ty::Region>,
+ Vec<Ty<'tcx>>,
+ Vec<ConvertedBinding<'tcx>>)
{
let regions: Vec<_> =
data.lifetimes.iter()
(implied_output_region, lifetimes_for_params)
}
-fn convert_ty_with_lifetime_elision<'tcx,AC>(this: &AC,
- implied_output_region: Option<ty::Region>,
- param_lifetimes: Vec<(String, uint)>,
- ty: &ast::Ty)
- -> Ty<'tcx>
- where AC: AstConv<'tcx>
+fn convert_ty_with_lifetime_elision<'tcx>(this: &AstConv<'tcx>,
+ implied_output_region: Option<ty::Region>,
+ param_lifetimes: Vec<(String, uint)>,
+ ty: &ast::Ty)
+ -> Ty<'tcx>
{
match implied_output_region {
Some(implied_output_region) => {
}
}
-fn convert_parenthesized_parameters<'tcx,AC>(this: &AC,
- data: &ast::ParenthesizedParameterData)
- -> Vec<Ty<'tcx>>
- where AC: AstConv<'tcx>
+fn convert_parenthesized_parameters<'tcx>(this: &AstConv<'tcx>,
+ data: &ast::ParenthesizedParameterData)
+ -> Vec<Ty<'tcx>>
{
let binding_rscope = BindingRscope::new();
let inputs = data.inputs.iter()
vec![input_ty, output]
}
-pub fn instantiate_poly_trait_ref<'tcx,AC,RS>(
- this: &AC,
- rscope: &RS,
+pub fn instantiate_poly_trait_ref<'tcx>(
+ this: &AstConv<'tcx>,
+ rscope: &RegionScope,
ast_trait_ref: &ast::PolyTraitRef,
self_ty: Option<Ty<'tcx>>,
poly_projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
-> ty::PolyTraitRef<'tcx>
- where AC: AstConv<'tcx>, RS: RegionScope
{
let mut projections = Vec::new();
///
/// If the `projections` argument is `None`, then assoc type bindings like `Foo<T=X>`
/// are disallowed. Otherwise, they are pushed onto the vector given.
-pub fn instantiate_trait_ref<'tcx,AC,RS>(
- this: &AC,
- rscope: &RS,
+pub fn instantiate_trait_ref<'tcx>(
+ this: &AstConv<'tcx>,
+ rscope: &RegionScope,
ast_trait_ref: &ast::TraitRef,
self_ty: Option<Ty<'tcx>>,
projections: Option<&mut Vec<ty::ProjectionPredicate<'tcx>>>)
-> Rc<ty::TraitRef<'tcx>>
- where AC: AstConv<'tcx>, RS: RegionScope
{
match ::lookup_def_tcx(this.tcx(), ast_trait_ref.path.span, ast_trait_ref.ref_id) {
def::DefTrait(trait_def_id) => {
}
}
-fn ast_path_to_trait_ref<'a,'tcx,AC,RS>(
- this: &AC,
- rscope: &RS,
+fn ast_path_to_trait_ref<'a,'tcx>(
+ this: &AstConv<'tcx>,
+ rscope: &RegionScope,
trait_def_id: ast::DefId,
self_ty: Option<Ty<'tcx>>,
path: &ast::Path,
mut projections: Option<&mut Vec<ty::ProjectionPredicate<'tcx>>>)
-> Rc<ty::TraitRef<'tcx>>
- where AC: AstConv<'tcx>, RS: RegionScope
{
debug!("ast_path_to_trait_ref {}", path);
let trait_def = this.get_trait_def(trait_def_id);
}
Some(ref mut v) => {
for binding in assoc_bindings.iter() {
- match ast_type_binding_to_projection_predicate(this, trait_ref.clone(), binding) {
+ match ast_type_binding_to_projection_predicate(this, trait_ref.clone(),
+ self_ty, binding) {
Ok(pp) => { v.push(pp); }
Err(ErrorReported) => { }
}
trait_ref
}
-pub fn ast_type_binding_to_projection_predicate<'tcx,AC>(
- this: &AC,
- trait_ref: Rc<ty::TraitRef<'tcx>>,
+fn ast_type_binding_to_projection_predicate<'tcx>(
+ this: &AstConv<'tcx>,
+ mut trait_ref: Rc<ty::TraitRef<'tcx>>,
+ self_ty: Option<Ty<'tcx>>,
binding: &ConvertedBinding<'tcx>)
-> Result<ty::ProjectionPredicate<'tcx>, ErrorReported>
- where AC : AstConv<'tcx>
{
+ let tcx = this.tcx();
+
// Given something like `U : SomeTrait<T=X>`, we want to produce a
// predicate like `<U as SomeTrait>::T = X`. This is somewhat
// subtle in the event that `T` is defined in a supertrait of
//
// We want to produce `<B as SuperTrait<int>>::T == foo`.
- // FIXME(#19541): supertrait upcasting not actually impl'd :)
+ // Simple case: X is defined in the current trait.
+ if trait_defines_associated_type_named(this, trait_ref.def_id, binding.item_name) {
+ return Ok(ty::ProjectionPredicate {
+ projection_ty: ty::ProjectionTy {
+ trait_ref: trait_ref,
+ item_name: binding.item_name,
+ },
+ ty: binding.ty,
+ });
+ }
- if !trait_defines_associated_type_named(this, trait_ref.def_id, binding.item_name) {
- this.tcx().sess.span_err(
+ // Otherwise, we have to walk through the supertraits to find
+ // those that do. This is complicated by the fact that, for an
+ // object type, the `Self` type is not present in the
+ // substitutions (after all, it's being constructed right now),
+ // but the `supertraits` iterator really wants one. To handle
+ // this, we currently insert a dummy type and then remove it
+ // later. Yuck.
+
+ let dummy_self_ty = ty::mk_infer(tcx, ty::FreshTy(0));
+ if self_ty.is_none() { // if converting for an object type
+ let mut dummy_substs = trait_ref.substs.clone();
+ assert!(dummy_substs.self_ty().is_none());
+ dummy_substs.types.push(SelfSpace, dummy_self_ty);
+ trait_ref = Rc::new(ty::TraitRef::new(trait_ref.def_id,
+ tcx.mk_substs(dummy_substs)));
+ }
+
+ let mut candidates: Vec<ty::PolyTraitRef> =
+ traits::supertraits(tcx, trait_ref.to_poly_trait_ref())
+ .filter(|r| trait_defines_associated_type_named(this, r.def_id(), binding.item_name))
+ .collect();
+
+ // If converting for an object type, then remove the dummy-ty from `Self` now.
+ // Yuckety yuck.
+ if self_ty.is_none() {
+ for candidate in candidates.iter_mut() {
+ let mut dummy_substs = candidate.0.substs.clone();
+ assert!(dummy_substs.self_ty() == Some(dummy_self_ty));
+ dummy_substs.types.pop(SelfSpace);
+ *candidate = ty::Binder(Rc::new(ty::TraitRef::new(candidate.def_id(),
+ tcx.mk_substs(dummy_substs))));
+ }
+ }
+
+ if candidates.len() > 1 {
+ tcx.sess.span_err(
+ binding.span,
+ format!("ambiguous associated type: `{}` defined in multiple supertraits `{}`",
+ token::get_name(binding.item_name),
+ candidates.user_string(tcx)).as_slice());
+ return Err(ErrorReported);
+ }
+
+ let candidate = match candidates.pop() {
+ Some(c) => c,
+ None => {
+ tcx.sess.span_err(
+ binding.span,
+ format!("no associated type `{}` defined in `{}`",
+ token::get_name(binding.item_name),
+ trait_ref.user_string(tcx)).as_slice());
+ return Err(ErrorReported);
+ }
+ };
+
+ if ty::binds_late_bound_regions(tcx, &candidate) {
+ tcx.sess.span_err(
binding.span,
- format!("no associated type `{}` defined in `{}`",
+ format!("associated type `{}` defined in higher-ranked supertrait `{}`",
token::get_name(binding.item_name),
- trait_ref.user_string(this.tcx())).as_slice());
+ candidate.user_string(tcx)).as_slice());
return Err(ErrorReported);
}
Ok(ty::ProjectionPredicate {
projection_ty: ty::ProjectionTy {
- trait_ref: trait_ref,
+ trait_ref: candidate.0,
item_name: binding.item_name,
},
ty: binding.ty,
})
}
-pub fn ast_path_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
- this: &AC,
- rscope: &RS,
+pub fn ast_path_to_ty<'tcx>(
+ this: &AstConv<'tcx>,
+ rscope: &RegionScope,
did: ast::DefId,
path: &ast::Path)
-> TypeAndSubsts<'tcx>
/// and/or region variables are substituted.
///
/// This is used when checking the constructor in struct literals.
-pub fn ast_path_to_ty_relaxed<'tcx,AC,RS>(
- this: &AC,
- rscope: &RS,
+pub fn ast_path_to_ty_relaxed<'tcx>(
+ this: &AstConv<'tcx>,
+ rscope: &RegionScope,
did: ast::DefId,
path: &ast::Path)
-> TypeAndSubsts<'tcx>
- where AC : AstConv<'tcx>, RS : RegionScope
{
let tcx = this.tcx();
let ty::TypeScheme {
/// Converts the given AST type to a built-in type. A "built-in type" is, at
/// present, either a core numeric type, a string, or `Box`.
-pub fn ast_ty_to_builtin_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
- this: &AC,
- rscope: &RS,
+pub fn ast_ty_to_builtin_ty<'tcx>(
+ this: &AstConv<'tcx>,
+ rscope: &RegionScope,
ast_ty: &ast::Ty)
-> Option<Ty<'tcx>> {
match ast_ty_to_prim_ty(this.tcx(), ast_ty) {
type TraitAndProjections<'tcx> = (ty::PolyTraitRef<'tcx>, Vec<ty::PolyProjectionPredicate<'tcx>>);
-fn ast_ty_to_trait_ref<'tcx,AC,RS>(this: &AC,
- rscope: &RS,
- ty: &ast::Ty,
- bounds: &[ast::TyParamBound])
- -> Result<TraitAndProjections<'tcx>, ErrorReported>
- where AC : AstConv<'tcx>, RS : RegionScope
+fn ast_ty_to_trait_ref<'tcx>(this: &AstConv<'tcx>,
+ rscope: &RegionScope,
+ ty: &ast::Ty,
+ bounds: &[ast::TyParamBound])
+ -> Result<TraitAndProjections<'tcx>, ErrorReported>
{
/*!
* In a type like `Foo + Send`, we want to wait to collect the
}
}
-fn trait_ref_to_object_type<'tcx,AC,RS>(this: &AC,
- rscope: &RS,
- span: Span,
- trait_ref: ty::PolyTraitRef<'tcx>,
- projection_bounds: Vec<ty::PolyProjectionPredicate<'tcx>>,
- bounds: &[ast::TyParamBound])
- -> Ty<'tcx>
- where AC : AstConv<'tcx>, RS : RegionScope
+fn trait_ref_to_object_type<'tcx>(this: &AstConv<'tcx>,
+ rscope: &RegionScope,
+ span: Span,
+ trait_ref: ty::PolyTraitRef<'tcx>,
+ projection_bounds: Vec<ty::PolyProjectionPredicate<'tcx>>,
+ bounds: &[ast::TyParamBound])
+ -> Ty<'tcx>
{
let existential_bounds = conv_existential_bounds(this,
rscope,
{
let tcx = this.tcx();
let ty_param_def_id = provenance.def_id();
+
let mut suitable_bounds: Vec<_>;
let ty_param_name: ast::Name;
{ // contain scope of refcell:
let ty_param_def = &ty_param_defs[ty_param_def_id.node];
ty_param_name = ty_param_def.name;
- // FIXME(#19541): we should consider associated types in
- // super-traits. Probably by elaborating the bounds.
-
+ // FIXME(#20300) -- search where clauses, not bounds
suitable_bounds =
- ty_param_def.bounds.trait_bounds // FIXME(#20300) -- search where clauses, not bounds
- .iter()
- .cloned()
+ traits::transitive_bounds(tcx, ty_param_def.bounds.trait_bounds.as_slice())
.filter(|b| trait_defines_associated_type_named(this, b.def_id(), assoc_name))
.collect();
}
trait_def.associated_type_names.contains(&assoc_name)
}
-fn qpath_to_ty<'tcx,AC,RS>(this: &AC,
- rscope: &RS,
- ast_ty: &ast::Ty, // the TyQPath
- qpath: &ast::QPath)
- -> Ty<'tcx>
- where AC: AstConv<'tcx>, RS: RegionScope
+fn qpath_to_ty<'tcx>(this: &AstConv<'tcx>,
+ rscope: &RegionScope,
+ ast_ty: &ast::Ty, // the TyQPath
+ qpath: &ast::QPath)
+ -> Ty<'tcx>
{
debug!("qpath_to_ty(ast_ty={})",
ast_ty.repr(this.tcx()));
// Parses the programmer's textual representation of a type into our
// internal notion of a type.
-pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
- this: &AC, rscope: &RS, ast_ty: &ast::Ty) -> Ty<'tcx>
+pub fn ast_ty_to_ty<'tcx>(
+ this: &AstConv<'tcx>, rscope: &RegionScope, ast_ty: &ast::Ty) -> Ty<'tcx>
{
debug!("ast_ty_to_ty(ast_ty={})",
ast_ty.repr(this.tcx()));
let bare_fn = ty_of_bare_fn(this, bf.unsafety, bf.abi, &*bf.decl);
ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(bare_fn))
}
- ast::TyClosure(ref f) => {
- // Use corresponding trait store to figure out default bounds
- // if none were specified.
- let bounds = conv_existential_bounds(this,
- rscope,
- ast_ty.span,
- None,
- Vec::new(),
- f.bounds.as_slice());
- let region_bound = bounds.region_bound;
- let fn_decl = ty_of_closure(this,
- f.unsafety,
- f.onceness,
- bounds,
- ty::RegionTraitStore(
- region_bound,
- ast::MutMutable),
- &*f.decl,
- abi::Rust,
- None);
- ty::mk_closure(tcx, fn_decl)
- }
ast::TyPolyTraitRef(ref bounds) => {
conv_ty_poly_trait_ref(this, rscope, ast_ty.span, bounds[])
}
return typ;
}
-pub fn ty_of_arg<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(this: &AC, rscope: &RS,
- a: &ast::Arg,
- expected_ty: Option<Ty<'tcx>>)
- -> Ty<'tcx> {
+pub fn ty_of_arg<'tcx>(this: &AstConv<'tcx>,
+ rscope: &RegionScope,
+ a: &ast::Arg,
+ expected_ty: Option<Ty<'tcx>>)
+ -> Ty<'tcx>
+{
match a.ty.node {
ast::TyInfer if expected_ty.is_some() => expected_ty.unwrap(),
ast::TyInfer => this.ty_infer(a.ty.span),
explicit_self: &'a ast::ExplicitSelf,
}
-pub fn ty_of_method<'tcx, AC: AstConv<'tcx>>(
- this: &AC,
- unsafety: ast::Unsafety,
- untransformed_self_ty: Ty<'tcx>,
- explicit_self: &ast::ExplicitSelf,
- decl: &ast::FnDecl,
- abi: abi::Abi)
- -> (ty::BareFnTy<'tcx>, ty::ExplicitSelfCategory) {
+pub fn ty_of_method<'tcx>(this: &AstConv<'tcx>,
+ unsafety: ast::Unsafety,
+ untransformed_self_ty: Ty<'tcx>,
+ explicit_self: &ast::ExplicitSelf,
+ decl: &ast::FnDecl,
+ abi: abi::Abi)
+ -> (ty::BareFnTy<'tcx>, ty::ExplicitSelfCategory) {
let self_info = Some(SelfInfo {
untransformed_self_ty: untransformed_self_ty,
explicit_self: explicit_self,
(bare_fn_ty, optional_explicit_self_category.unwrap())
}
-pub fn ty_of_bare_fn<'tcx, AC: AstConv<'tcx>>(this: &AC, unsafety: ast::Unsafety, abi: abi::Abi,
+pub fn ty_of_bare_fn<'tcx>(this: &AstConv<'tcx>, unsafety: ast::Unsafety, abi: abi::Abi,
decl: &ast::FnDecl) -> ty::BareFnTy<'tcx> {
let (bare_fn_ty, _) = ty_of_method_or_bare_fn(this, unsafety, abi, None, decl);
bare_fn_ty
}
-fn ty_of_method_or_bare_fn<'a, 'tcx, AC: AstConv<'tcx>>(
- this: &AC,
- unsafety: ast::Unsafety,
- abi: abi::Abi,
- opt_self_info: Option<SelfInfo<'a, 'tcx>>,
- decl: &ast::FnDecl)
- -> (ty::BareFnTy<'tcx>,
- Option<ty::ExplicitSelfCategory>)
+fn ty_of_method_or_bare_fn<'a, 'tcx>(this: &AstConv<'tcx>,
+ unsafety: ast::Unsafety,
+ abi: abi::Abi,
+ opt_self_info: Option<SelfInfo<'a, 'tcx>>,
+ decl: &ast::FnDecl)
+ -> (ty::BareFnTy<'tcx>, Option<ty::ExplicitSelfCategory>)
{
debug!("ty_of_method_or_bare_fn");
}, explicit_self_category_result)
}
-fn determine_explicit_self_category<'a, 'tcx, AC: AstConv<'tcx>,
- RS:RegionScope>(
- this: &AC,
- rscope: &RS,
- self_info: &SelfInfo<'a, 'tcx>)
- -> ty::ExplicitSelfCategory
+fn determine_explicit_self_category<'a, 'tcx>(this: &AstConv<'tcx>,
+ rscope: &RegionScope,
+ self_info: &SelfInfo<'a, 'tcx>)
+ -> ty::ExplicitSelfCategory
{
return match self_info.explicit_self.node {
ast::SelfStatic => ty::StaticExplicitSelfCategory,
}
}
-pub fn ty_of_closure<'tcx, AC: AstConv<'tcx>>(
- this: &AC,
+pub fn ty_of_closure<'tcx>(
+ this: &AstConv<'tcx>,
unsafety: ast::Unsafety,
onceness: ast::Onceness,
bounds: ty::ExistentialBounds<'tcx>,
/// `ExistentialBounds` struct. The `main_trait_refs` argument specifies the `Foo` -- it is absent
/// for closures. Eventually this should all be normalized, I think, so that there is no "main
/// trait ref" and instead we just have a flat list of bounds as the existential type.
-pub fn conv_existential_bounds<'tcx, AC: AstConv<'tcx>, RS:RegionScope>(
- this: &AC,
- rscope: &RS,
+pub fn conv_existential_bounds<'tcx>(
+ this: &AstConv<'tcx>,
+ rscope: &RegionScope,
span: Span,
principal_trait_ref: Option<ty::PolyTraitRef<'tcx>>, // None for boxed closures
projection_bounds: Vec<ty::PolyProjectionPredicate<'tcx>>,
this, rscope, span, principal_trait_ref, projection_bounds, partitioned_bounds)
}
-fn conv_ty_poly_trait_ref<'tcx, AC, RS>(
- this: &AC,
- rscope: &RS,
+fn conv_ty_poly_trait_ref<'tcx>(
+ this: &AstConv<'tcx>,
+ rscope: &RegionScope,
span: Span,
ast_bounds: &[ast::TyParamBound])
-> Ty<'tcx>
- where AC: AstConv<'tcx>, RS:RegionScope
{
let mut partitioned_bounds = partition_bounds(this.tcx(), span, ast_bounds[]);
}
}
-pub fn conv_existential_bounds_from_partitioned_bounds<'tcx, AC, RS>(
- this: &AC,
- rscope: &RS,
+pub fn conv_existential_bounds_from_partitioned_bounds<'tcx>(
+ this: &AstConv<'tcx>,
+ rscope: &RegionScope,
span: Span,
principal_trait_ref: Option<ty::PolyTraitRef<'tcx>>, // None for boxed closures
mut projection_bounds: Vec<ty::PolyProjectionPredicate<'tcx>>, // Empty for boxed closures
partitioned_bounds: PartitionedBounds)
-> ty::ExistentialBounds<'tcx>
- where AC: AstConv<'tcx>, RS:RegionScope
{
let PartitionedBounds { builtin_bounds,
trait_bounds,
/// A version of `compute_opt_region_bound` for use where some region bound is required
/// (existential types, basically). Reports an error if no region bound can be derived and we are
/// in an `rscope` that does not provide a default.
-fn compute_region_bound<'tcx, AC: AstConv<'tcx>, RS:RegionScope>(
- this: &AC,
- rscope: &RS,
+fn compute_region_bound<'tcx>(
+ this: &AstConv<'tcx>,
+ rscope: &RegionScope,
span: Span,
region_bounds: &[&ast::Lifetime],
principal_trait_ref: Option<ty::PolyTraitRef<'tcx>>, // None for closures
use syntax::ptr::P;
pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
- pat: &ast::Pat, expected: Ty<'tcx>) {
+ pat: &ast::Pat,
+ expected: Ty<'tcx>)
+{
let fcx = pcx.fcx;
let tcx = pcx.fcx.ccx.tcx;
check_expr(fcx, &**lt);
let expr_ty = fcx.expr_ty(&**lt);
fcx.write_ty(pat.id, expr_ty);
+
+ // somewhat surprising: in this case, the subtyping
+ // relation goes the opposite way as the other
+ // cases. Actually what we really want is not a subtyping
+ // relation at all but rather that there exists a LUB (so
+ // that they can be compared). However, in practice,
+ // constants are always scalars or strings. For scalars
+ // subtyping is irrelevant, and for strings `expr_ty` is
+ // type is `&'static str`, so if we say that
+ //
+ // &'static str <: expected
+ //
+ // that's equivalent to there existing a LUB.
demand::suptype(fcx, pat.span, expected, expr_ty);
}
ast::PatRange(ref begin, ref end) => {
let lhs_ty = fcx.expr_ty(&**begin);
let rhs_ty = fcx.expr_ty(&**end);
- if require_same_types(
- tcx, Some(fcx.infcx()), false, pat.span, lhs_ty, rhs_ty,
- || "mismatched types in range".to_string())
- && (ty::type_is_numeric(lhs_ty) || ty::type_is_char(rhs_ty)) {
+
+ let lhs_eq_rhs =
+ require_same_types(
+ tcx, Some(fcx.infcx()), false, pat.span, lhs_ty, rhs_ty,
+ || "mismatched types in range".to_string());
+
+ let numeric_or_char =
+ lhs_eq_rhs && (ty::type_is_numeric(lhs_ty) || ty::type_is_char(lhs_ty));
+
+ if numeric_or_char {
match valid_range_bounds(fcx.ccx, &**begin, &**end) {
Some(false) => {
span_err!(tcx.sess, begin.span, E0030,
}
} else {
span_err!(tcx.sess, begin.span, E0029,
- "only char and numeric types are allowed in range");
+ "only char and numeric types are allowed in range");
}
fcx.write_ty(pat.id, lhs_ty);
+
+ // subtyping doens't matter here, as the value is some kind of scalar
demand::eqtype(fcx, pat.span, expected, lhs_ty);
}
ast::PatEnum(..) | ast::PatIdent(..) if pat_is_const(&tcx.def_map, pat) => {
let const_did = tcx.def_map.borrow()[pat.id].clone().def_id();
let const_scheme = ty::lookup_item_type(tcx, const_did);
- fcx.write_ty(pat.id, const_scheme.ty);
- demand::suptype(fcx, pat.span, expected, const_scheme.ty);
+ assert!(const_scheme.generics.is_empty());
+ let const_ty = pcx.fcx.instantiate_type_scheme(pat.span,
+ &Substs::empty(),
+ &const_scheme.ty);
+ fcx.write_ty(pat.id, const_ty);
+
+ // FIXME(#20489) -- we should limit the types here to scalars or something!
+
+ // As with PatLit, what we really want here is that there
+ // exist a LUB, but for the cases that can occur, subtype
+ // is good enough.
+ demand::suptype(fcx, pat.span, expected, const_ty);
}
ast::PatIdent(bm, ref path, ref sub) if pat_is_binding(&tcx.def_map, pat) => {
let typ = fcx.local_ty(pat.span, pat.id);
ast::BindByRef(mutbl) => {
// if the binding is like
// ref x | ref const x | ref mut x
- // then the type of x is &M T where M is the mutability
- // and T is the expected type
+ // then `x` is assigned a value of type `&M T` where M is the mutability
+ // and T is the expected type.
let region_var = fcx.infcx().next_region_var(infer::PatternRegion(pat.span));
let mt = ty::mt { ty: expected, mutbl: mutbl };
let region_ty = ty::mk_rptr(tcx, tcx.mk_region(region_var), mt);
+
+ // `x` is assigned a value of type `&M T`, hence `&M T <: typeof(x)` is
+ // required. However, we use equality, which is stronger. See (*) for
+ // an explanation.
demand::eqtype(fcx, pat.span, region_ty, typ);
}
// otherwise the type of x is the expected type T
ast::BindByValue(_) => {
+ // As above, `T <: typeof(x)` is required but we
+ // use equality, see (*) below.
demand::eqtype(fcx, pat.span, expected, typ);
}
}
+
fcx.write_ty(pat.id, typ);
+ // if there are multiple arms, make sure they all agree on
+ // what the type of the binding `x` ought to be
let canon_id = pcx.map[path.node];
if canon_id != pat.id {
let ct = fcx.local_ty(pat.span, canon_id);
check_pat_struct(pcx, pat, path, fields.as_slice(), etc, expected);
}
ast::PatTup(ref elements) => {
- let element_tys: Vec<_> = range(0, elements.len()).map(|_| fcx.infcx()
- .next_ty_var()).collect();
+ let element_tys: Vec<_> =
+ range(0, elements.len()).map(|_| fcx.infcx().next_ty_var())
+ .collect();
let pat_ty = ty::mk_tup(tcx, element_tys.clone());
fcx.write_ty(pat.id, pat_ty);
demand::eqtype(fcx, pat.span, expected, pat_ty);
let uniq_ty = ty::mk_uniq(tcx, inner_ty);
if check_dereferencable(pcx, pat.span, expected, &**inner) {
- demand::suptype(fcx, pat.span, expected, uniq_ty);
+ // Here, `demand::subtype` is good enough, but I don't
+ // think any errors can be introduced by using
+ // `demand::eqtype`.
+ demand::eqtype(fcx, pat.span, expected, uniq_ty);
fcx.write_ty(pat.id, uniq_ty);
check_pat(pcx, &**inner, inner_ty);
} else {
let inner_ty = fcx.infcx().next_ty_var();
let mutbl =
- ty::deref(fcx.infcx().shallow_resolve(expected), true)
- .map_or(ast::MutImmutable, |mt| mt.mutbl);
+ ty::deref(fcx.infcx().shallow_resolve(expected), true).map(|mt| mt.mutbl)
+ .unwrap_or(ast::MutImmutable);
let mt = ty::mt { ty: inner_ty, mutbl: mutbl };
let region = fcx.infcx().next_region_var(infer::PatternRegion(pat.span));
let rptr_ty = ty::mk_rptr(tcx, tcx.mk_region(region), mt);
if check_dereferencable(pcx, pat.span, expected, &**inner) {
- demand::suptype(fcx, pat.span, expected, rptr_ty);
+ // `demand::subtype` would be good enough, but using
+ // `eqtype` turns out to be equally general. See (*)
+ // below for details.
+ demand::eqtype(fcx, pat.span, expected, rptr_ty);
fcx.write_ty(pat.id, rptr_ty);
check_pat(pcx, &**inner, inner_ty);
} else {
let region = fcx.infcx().next_region_var(infer::PatternRegion(pat.span));
ty::mk_slice(tcx, tcx.mk_region(region), ty::mt {
ty: inner_ty,
- mutbl: ty::deref(expected_ty, true)
- .map_or(ast::MutImmutable, |mt| mt.mutbl)
+ mutbl: ty::deref(expected_ty, true).map(|mt| mt.mutbl)
+ .unwrap_or(ast::MutImmutable)
})
}
};
fcx.write_ty(pat.id, pat_ty);
- demand::suptype(fcx, pat.span, expected, pat_ty);
+
+ // `demand::subtype` would be good enough, but using
+ // `eqtype` turns out to be equally general. See (*)
+ // below for details.
+ demand::eqtype(fcx, pat.span, expected, pat_ty);
for elt in before.iter() {
check_pat(pcx, &**elt, inner_ty);
}
ast::PatMac(_) => tcx.sess.bug("unexpanded macro")
}
+
+
+ // (*) In most of the cases above (literals and constants being
+ // the exception), we relate types using strict equality, evewn
+ // though subtyping would be sufficient. There are a few reasons
+ // for this, some of which are fairly subtle and which cost me
+ // (nmatsakis) an hour or two debugging to remember, so I thought
+ // I'd write them down this time.
+ //
+ // 1. Most importantly, there is no loss of expressiveness
+ // here. What we are saying is that the type of `x`
+ // becomes *exactly* what is expected. This might seem
+ // like it will cause errors in a case like this:
+ //
+ // ```
+ // fn foo<'x>(x: &'x int) {
+ // let a = 1;
+ // let mut z = x;
+ // z = &a;
+ // }
+ // ```
+ //
+ // The reason we might get an error is that `z` might be
+ // assigned a type like `&'x int`, and then we would have
+ // a problem when we try to assign `&a` to `z`, because
+ // the lifetime of `&a` (i.e., the enclosing block) is
+ // shorter than `'x`.
+ //
+ // HOWEVER, this code works fine. The reason is that the
+ // expected type here is whatever type the user wrote, not
+ // the initializer's type. In this case the user wrote
+ // nothing, so we are going to create a type variable `Z`.
+ // Then we will assign the type of the initializer (`&'x
+ // int`) as a subtype of `Z`: `&'x int <: Z`. And hence we
+ // will instantiate `Z` as a type `&'0 int` where `'0` is
+ // a fresh region variable, with the constraint that `'x :
+ // '0`. So basically we're all set.
+ //
+ // Note that there are two tests to check that this remains true
+ // (`regions-reassign-{match,let}-bound-pointer.rs`).
+ //
+ // 2. Things go horribly wrong if we use subtype. The reason for
+ // THIS is a fairly subtle case involving bound regions. See the
+ // `givens` field in `region_inference`, as well as the test
+ // `regions-relate-bound-regions-on-closures-to-inference-variables.rs`,
+ // for details. Short version is that we must sometimes detect
+ // relationships between specific region variables and regions
+ // bound in a closure signature, and that detection gets thrown
+ // off when we substitute fresh region variables here to enable
+ // subtyping.
}
pub fn check_dereferencable<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
// Typecheck each field.
for &Spanned { node: ref field, span } in fields.iter() {
- let field_type = match used_fields.entry(field.ident.name) {
+ let field_type = match used_fields.entry(&field.ident.name) {
Occupied(occupied) => {
span_err!(tcx.sess, span, E0025,
"field `{}` bound multiple times in the pattern",
tcx.types.err
}
Vacant(vacant) => {
- vacant.set(span);
+ vacant.insert(span);
field_type_map.get(&field.ident.name).cloned()
.unwrap_or_else(|| {
span_err!(tcx.sess, span, E0026,
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use super::autoderef;
+use super::AutorefArgs;
+use super::check_argument_types;
+use super::check_expr;
+use super::check_method_argument_types;
+use super::err_args;
+use super::FnCtxt;
+use super::LvaluePreference;
+use super::method;
+use super::structurally_resolved_type;
+use super::TupleArgumentsFlag;
+use super::write_call;
+
+use middle::infer;
+use middle::ty::{mod, Ty};
use syntax::ast;
use syntax::codemap::Span;
+use syntax::parse::token;
+use syntax::ptr::P;
use CrateCtxt;
/// Check that it is legal to call methods of the trait corresponding
"add `#![feature(unboxed_closures)]` to the crate attributes to enable");
}
}
+
+pub fn check_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
+ call_expr: &ast::Expr,
+ callee_expr: &ast::Expr,
+ arg_exprs: &[P<ast::Expr>])
+{
+ check_expr(fcx, callee_expr);
+ let original_callee_ty = fcx.expr_ty(callee_expr);
+ let (callee_ty, _, result) =
+ autoderef(fcx,
+ callee_expr.span,
+ original_callee_ty,
+ Some(callee_expr.id),
+ LvaluePreference::NoPreference,
+ |adj_ty, idx| {
+ let autoderefref = ty::AutoDerefRef { autoderefs: idx, autoref: None };
+ try_overloaded_call_step(fcx, call_expr, callee_expr,
+ adj_ty, autoderefref)
+ });
+
+ match result {
+ None => {
+ // this will report an error since original_callee_ty is not a fn
+ confirm_builtin_call(fcx, call_expr, original_callee_ty, arg_exprs);
+ }
+
+ Some(CallStep::Builtin) => {
+ confirm_builtin_call(fcx, call_expr, callee_ty, arg_exprs);
+ }
+
+ Some(CallStep::Overloaded(method_callee)) => {
+ confirm_overloaded_call(fcx, call_expr, arg_exprs, method_callee);
+ }
+ }
+}
+
+enum CallStep<'tcx> {
+ Builtin,
+ Overloaded(ty::MethodCallee<'tcx>)
+}
+
+fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
+ call_expr: &ast::Expr,
+ callee_expr: &ast::Expr,
+ adjusted_ty: Ty<'tcx>,
+ autoderefref: ty::AutoDerefRef<'tcx>)
+ -> Option<CallStep<'tcx>>
+{
+ // If the callee is a bare function or a closure, then we're all set.
+ match structurally_resolved_type(fcx, callee_expr.span, adjusted_ty).sty {
+ ty::ty_bare_fn(..) => {
+ fcx.write_adjustment(callee_expr.id,
+ callee_expr.span,
+ ty::AdjustDerefRef(autoderefref));
+ return Some(CallStep::Builtin);
+ }
+
+ _ => {}
+ }
+
+ // Try the options that are least restrictive on the caller first.
+ for &(opt_trait_def_id, method_name) in [
+ (fcx.tcx().lang_items.fn_trait(), token::intern("call")),
+ (fcx.tcx().lang_items.fn_mut_trait(), token::intern("call_mut")),
+ (fcx.tcx().lang_items.fn_once_trait(), token::intern("call_once")),
+ ].iter() {
+ let trait_def_id = match opt_trait_def_id {
+ Some(def_id) => def_id,
+ None => continue,
+ };
+
+ match method::lookup_in_trait_adjusted(fcx,
+ call_expr.span,
+ Some(&*callee_expr),
+ method_name,
+ trait_def_id,
+ autoderefref.clone(),
+ adjusted_ty,
+ None) {
+ None => continue,
+ Some(method_callee) => {
+ return Some(CallStep::Overloaded(method_callee));
+ }
+ }
+ }
+
+ None
+}
+
+fn confirm_builtin_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
+ call_expr: &ast::Expr,
+ callee_ty: Ty<'tcx>,
+ arg_exprs: &[P<ast::Expr>])
+{
+ let error_fn_sig;
+
+ let fn_sig = match callee_ty.sty {
+ ty::ty_bare_fn(_, &ty::BareFnTy {ref sig, ..}) => {
+ sig
+ }
+ _ => {
+ fcx.type_error_message(call_expr.span, |actual| {
+ format!("expected function, found `{}`", actual)
+ }, callee_ty, None);
+
+ // This is the "default" function signature, used in case of error.
+ // In that case, we check each argument against "error" in order to
+ // set up all the node type bindings.
+ error_fn_sig = ty::Binder(ty::FnSig {
+ inputs: err_args(fcx.tcx(), arg_exprs.len()),
+ output: ty::FnConverging(fcx.tcx().types.err),
+ variadic: false
+ });
+
+ &error_fn_sig
+ }
+ };
+
+ // Replace any late-bound regions that appear in the function
+ // signature with region variables. We also have to
+ // renormalize the associated types at this point, since they
+ // previously appeared within a `Binder<>` and hence would not
+ // have been normalized before.
+ let fn_sig =
+ fcx.infcx().replace_late_bound_regions_with_fresh_var(call_expr.span,
+ infer::FnCall,
+ fn_sig).0;
+ let fn_sig =
+ fcx.normalize_associated_types_in(call_expr.span, &fn_sig);
+
+ // Call the generic checker.
+ let arg_exprs: Vec<_> = arg_exprs.iter().collect(); // for some weird reason we take &[&P<...>].
+ check_argument_types(fcx,
+ call_expr.span,
+ fn_sig.inputs[],
+ arg_exprs.as_slice(),
+ AutorefArgs::No,
+ fn_sig.variadic,
+ TupleArgumentsFlag::DontTupleArguments);
+
+ write_call(fcx, call_expr, fn_sig.output);
+}
+
+fn confirm_overloaded_call<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>,
+ call_expr: &ast::Expr,
+ arg_exprs: &[P<ast::Expr>],
+ method_callee: ty::MethodCallee<'tcx>)
+{
+ let arg_exprs: Vec<_> = arg_exprs.iter().collect(); // for some weird reason we take &[&P<...>].
+ let output_type = check_method_argument_types(fcx,
+ call_expr.span,
+ method_callee.ty,
+ call_expr,
+ arg_exprs.as_slice(),
+ AutorefArgs::No,
+ TupleArgumentsFlag::TupleArguments);
+ let method_call = ty::MethodCall::expr(call_expr.id);
+ fcx.inh.method_map.borrow_mut().insert(method_call, method_callee);
+ write_call(fcx, call_expr, output_type);
+}
+
use super::{check_fn, Expectation, FnCtxt};
use astconv;
-use middle::infer;
use middle::region::CodeExtent;
use middle::subst;
use middle::ty::{self, ToPolyTraitRef, Ty};
use rscope::RegionScope;
use syntax::abi;
use syntax::ast;
-use syntax::ast::CaptureClause::*;
use syntax::ast_util;
use util::ppaux::Repr;
pub fn check_expr_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
expr: &ast::Expr,
- capture: ast::CaptureClause,
+ _capture: ast::CaptureClause,
opt_kind: Option<ast::UnboxedClosureKind>,
decl: &ast::FnDecl,
body: &ast::Block,
// evidence than an unboxed closure is desired, we'll use
// that, otherwise we'll fall back to boxed closures.
match expected_sig_and_kind {
- None => { // doesn't look like an unboxed closure
- let region = astconv::opt_ast_region_to_region(fcx,
- fcx,
- expr.span,
- &None);
-
- check_boxed_closure(fcx,
- expr,
- ty::RegionTraitStore(region, ast::MutMutable),
- decl,
- body,
- expected);
-
- match capture {
- CaptureByValue => {
- fcx.ccx.tcx.sess.span_err(
- expr.span,
- "boxed closures can't capture by value, \
- if you want to use an unboxed closure, \
- explicitly annotate its kind: e.g. `move |:|`");
- },
- CaptureByRef => {}
- }
- }
+ None => { // don't have information about the kind, request explicit annotation
+ // NB We still need to typeck the body, so assume `FnMut` kind just for that
+ let kind = ty::FnMutUnboxedClosureKind;
+
+ check_unboxed_closure(fcx, expr, kind, decl, body, None);
+
+ fcx.ccx.tcx.sess.span_err(
+ expr.span,
+ "can't infer the \"kind\" of the closure, explicitly annotate it. e.g. \
+ `|&:| {}`");
+ },
Some((sig, kind)) => {
check_unboxed_closure(fcx, expr, kind, decl, body, Some(sig));
}
None
}
-
-
-fn check_boxed_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
- expr: &ast::Expr,
- store: ty::TraitStore,
- decl: &ast::FnDecl,
- body: &ast::Block,
- expected: Expectation<'tcx>) {
- let tcx = fcx.ccx.tcx;
-
- // Find the expected input/output types (if any). Substitute
- // fresh bound regions for any bound regions we find in the
- // expected types so as to avoid capture.
- let expected_cenv = expected.map_to_option(fcx, |ty| match ty.sty {
- ty::ty_closure(ref cenv) => Some(cenv),
- _ => None
- });
- let (expected_sig, expected_onceness, expected_bounds) = match expected_cenv {
- Some(cenv) => {
- let (sig, _) =
- ty::replace_late_bound_regions(
- tcx,
- &cenv.sig,
- |_, debruijn| fcx.inh.infcx.fresh_bound_region(debruijn));
- let onceness = match (&store, &cenv.store) {
- // As the closure type and onceness go, only three
- // combinations are legit:
- // once closure
- // many closure
- // once proc
- // If the actual and expected closure type disagree with
- // each other, set expected onceness to be always Once or
- // Many according to the actual type. Otherwise, it will
- // yield either an illegal "many proc" or a less known
- // "once closure" in the error message.
- (&ty::UniqTraitStore, &ty::UniqTraitStore) |
- (&ty::RegionTraitStore(..), &ty::RegionTraitStore(..)) =>
- cenv.onceness,
- (&ty::UniqTraitStore, _) => ast::Once,
- (&ty::RegionTraitStore(..), _) => ast::Many,
- };
- (Some(sig), onceness, cenv.bounds.clone())
- }
- _ => {
- // Not an error! Means we're inferring the closure type
- let region = fcx.infcx().next_region_var(
- infer::AddrOfRegion(expr.span));
- let bounds = ty::region_existential_bound(region);
- let onceness = ast::Many;
- (None, onceness, bounds)
- }
- };
-
- // construct the function type
- let fn_ty = astconv::ty_of_closure(fcx,
- ast::Unsafety::Normal,
- expected_onceness,
- expected_bounds,
- store,
- decl,
- abi::Rust,
- expected_sig);
- let fn_sig = fn_ty.sig.clone();
- let fty = ty::mk_closure(tcx, fn_ty);
- debug!("check_expr_fn fty={}", fcx.infcx().ty_to_string(fty));
-
- fcx.write_ty(expr.id, fty);
-
- // If the closure is a stack closure and hasn't had some non-standard
- // style inferred for it, then check it under its parent's style.
- // Otherwise, use its own
- let (inherited_style, inherited_style_id) = match store {
- ty::RegionTraitStore(..) => (fcx.ps.borrow().unsafety,
- fcx.ps.borrow().def),
- ty::UniqTraitStore => (ast::Unsafety::Normal, expr.id)
- };
-
- let fn_sig =
- ty::liberate_late_bound_regions(tcx, CodeExtent::from_node_id(body.id), &fn_sig);
-
- check_fn(fcx.ccx,
- inherited_style,
- inherited_style_id,
- &fn_sig,
- &*decl,
- expr.id,
- &*body,
- fcx.inh);
-}
use syntax::codemap::Span;
use util::ppaux::Repr;
-// Requires that the two types unify, and prints an error message if they
-// don't.
+// Requires that the two types unify, and prints an error message if
+// they don't.
pub fn suptype<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span,
- expected: Ty<'tcx>, actual: Ty<'tcx>) {
- suptype_with_fn(fcx, sp, false, expected, actual,
+ ty_expected: Ty<'tcx>, ty_actual: Ty<'tcx>) {
+ suptype_with_fn(fcx, sp, false, ty_expected, ty_actual,
|sp, e, a, s| { fcx.report_mismatched_types(sp, e, a, s) })
}
+/// As `suptype`, but call `handle_err` if unification for subtyping fails.
pub fn suptype_with_fn<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
sp: Span,
b_is_expected: bool,
expected: Ty<'tcx>, actual: Ty<'tcx>) {
match infer::mk_eqty(fcx.infcx(), false, infer::Misc(sp), actual, expected) {
Ok(()) => { /* ok */ }
- Err(ref err) => {
- fcx.report_mismatched_types(sp, expected, actual, err);
- }
+ Err(ref err) => { fcx.report_mismatched_types(sp, expected, actual, err); }
}
}
method_callee: &MethodCallee) {
let sig = match method_callee.ty.sty {
ty::ty_bare_fn(_, ref f) => f.sig.clone(),
- ty::ty_closure(ref f) => f.sig.clone(),
_ => return,
};
// Do a search through a list of bounds, using a callback to actually
// create the candidates.
- fn elaborate_bounds(
+ fn elaborate_bounds<F>(
&mut self,
bounds: &[ty::PolyTraitRef<'tcx>],
num_includes_types: bool,
- mk_cand: for<'b> |this: &mut ProbeContext<'b, 'tcx>,
- tr: ty::PolyTraitRef<'tcx>,
- m: Rc<ty::Method<'tcx>>,
- method_num: uint|)
+ mut mk_cand: F,
+ ) where
+ F: for<'b> FnMut(
+ &mut ProbeContext<'b, 'tcx>,
+ ty::PolyTraitRef<'tcx>,
+ Rc<ty::Method<'tcx>>,
+ uint,
+ ),
{
debug!("elaborate_bounds(bounds={})", bounds.repr(self.tcx()));
let param_env = ParameterEnvironment::for_item(ccx.tcx, it.id);
check_bare_fn(ccx, &**decl, &**body, it.id, fn_pty.ty, param_env);
}
- ast::ItemImpl(_, _, _, _, ref impl_items) => {
+ ast::ItemImpl(_, _, _, _, _, ref impl_items) => {
debug!("ItemImpl {} with id {}", token::get_ident(it.ident), it.id);
let impl_pty = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id));
span: Span,
adj: &ty::AutoAdjustment<'tcx>) {
match *adj {
- ty::AdjustAddEnv(..) |
ty::AdjustReifyFnPointer(..) => {
}
ty::AdjustDerefRef(ref d_r) => {
///
/// Note: this method does not modify the adjustments table. The caller is responsible for
/// inserting an AutoAdjustment record into the `fcx` using one of the suitable methods.
-pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>, sp: Span,
+pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>,
+ sp: Span,
base_ty: Ty<'tcx>,
expr_id: Option<ast::NodeId>,
mut lvalue_pref: LvaluePreference,
(fcx.tcx().types.err, 0, None)
}
-/// Attempts to resolve a call expression as an overloaded call.
-fn try_overloaded_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
- call_expression: &ast::Expr,
- callee: &ast::Expr,
- callee_type: Ty<'tcx>,
- args: &[&P<ast::Expr>])
- -> bool {
- // Bail out if the callee is a bare function or a closure. We check those
- // manually.
- match structurally_resolved_type(fcx, callee.span, callee_type).sty {
- ty::ty_bare_fn(..) | ty::ty_closure(_) => return false,
- _ => {}
- }
-
- // Try the options that are least restrictive on the caller first.
- for &(maybe_function_trait, method_name) in [
- (fcx.tcx().lang_items.fn_trait(), token::intern("call")),
- (fcx.tcx().lang_items.fn_mut_trait(), token::intern("call_mut")),
- (fcx.tcx().lang_items.fn_once_trait(), token::intern("call_once")),
- ].iter() {
- let function_trait = match maybe_function_trait {
- None => continue,
- Some(function_trait) => function_trait,
- };
- let method_callee =
- match method::lookup_in_trait(fcx,
- call_expression.span,
- Some(&*callee),
- method_name,
- function_trait,
- callee_type,
- None) {
- None => continue,
- Some(method_callee) => method_callee,
- };
- let method_call = MethodCall::expr(call_expression.id);
- let output_type = check_method_argument_types(fcx,
- call_expression.span,
- method_callee.ty,
- call_expression,
- args,
- AutorefArgs::No,
- TupleArguments);
- fcx.inh.method_map.borrow_mut().insert(method_call, method_callee);
- write_call(fcx, call_expression, output_type);
-
- return true
- }
-
- false
-}
-
fn try_overloaded_deref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
span: Span,
method_call: Option<MethodCall>,
check_argument_types(fcx,
sp,
err_inputs[],
- callee_expr,
args_no_rcvr,
autoref_args,
false,
check_argument_types(fcx,
sp,
fty.sig.0.inputs.slice_from(1),
- callee_expr,
args_no_rcvr,
autoref_args,
fty.sig.0.variadic,
fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
sp: Span,
fn_inputs: &[Ty<'tcx>],
- _callee_expr: &ast::Expr,
args: &[&P<ast::Expr>],
autoref_args: AutorefArgs,
variadic: bool,
debug!(">> typechecking: expr={} expected={}",
expr.repr(fcx.tcx()), expected.repr(fcx.tcx()));
- // A generic function for doing all of the checking for call expressions
- fn check_call(fcx: &FnCtxt,
- call_expr: &ast::Expr,
- f: &ast::Expr,
- args: &[&P<ast::Expr>]) {
- // Store the type of `f` as the type of the callee
- let fn_ty = fcx.expr_ty(f);
-
- // Extract the function signature from `in_fty`.
- let fn_ty = structurally_resolved_type(fcx, f.span, fn_ty);
-
- // This is the "default" function signature, used in case of error.
- // In that case, we check each argument against "error" in order to
- // set up all the node type bindings.
- let error_fn_sig = ty::Binder(FnSig {
- inputs: err_args(fcx.tcx(), args.len()),
- output: ty::FnConverging(fcx.tcx().types.err),
- variadic: false
- });
-
- let fn_sig = match fn_ty.sty {
- ty::ty_bare_fn(_, &ty::BareFnTy {ref sig, ..}) |
- ty::ty_closure(box ty::ClosureTy {ref sig, ..}) => sig,
- _ => {
- fcx.type_error_message(call_expr.span, |actual| {
- format!("expected function, found `{}`", actual)
- }, fn_ty, None);
- &error_fn_sig
- }
- };
-
- // Replace any late-bound regions that appear in the function
- // signature with region variables. We also have to
- // renormalize the associated types at this point, since they
- // previously appeared within a `Binder<>` and hence would not
- // have been normalized before.
- let fn_sig =
- fcx.infcx().replace_late_bound_regions_with_fresh_var(call_expr.span,
- infer::FnCall,
- fn_sig).0;
- let fn_sig =
- fcx.normalize_associated_types_in(call_expr.span,
- &fn_sig);
-
- // Call the generic checker.
- check_argument_types(fcx,
- call_expr.span,
- fn_sig.inputs[],
- f,
- args,
- AutorefArgs::No,
- fn_sig.variadic,
- DontTupleArguments);
-
- write_call(fcx, call_expr, fn_sig.output);
- }
-
// Checks a method call.
fn check_method_call(fcx: &FnCtxt,
expr: &ast::Expr,
check_block_with_expected(fcx, &**b, expected);
fcx.write_ty(id, fcx.node_ty(b.id));
}
- ast::ExprCall(ref f, ref args) => {
- // Index expressions need to be handled separately, to inform them
- // that they appear in call position.
- check_expr(fcx, &**f);
- let f_ty = fcx.expr_ty(&**f);
-
- let args: Vec<_> = args.iter().map(|x| x).collect();
- if !try_overloaded_call(fcx, expr, &**f, f_ty, args[]) {
- check_call(fcx, expr, &**f, args[]);
- let args_err = args.iter().fold(false,
- |rest_err, a| {
- // is this not working?
- let a_ty = fcx.expr_ty(&***a);
- rest_err || ty::type_is_error(a_ty)});
- if ty::type_is_error(f_ty) || args_err {
- fcx.write_error(id);
- }
- }
+ ast::ExprCall(ref callee, ref args) => {
+ callee::check_call(fcx, expr, &**callee, args.as_slice());
}
ast::ExprMethodCall(ident, ref tps, ref args) => {
check_method_call(fcx, expr, ident, args[], tps[], lvalue_pref);
pub fn check_decl_initializer(fcx: &FnCtxt,
nid: ast::NodeId,
init: &ast::Expr)
- {
+{
let local_ty = fcx.local_ty(init.span, nid);
check_expr_coercable_to_type(fcx, init, local_ty)
}
Some(i) => {
span_err!(ccx.tcx.sess, v.span, E0081,
"discriminant value `{}` already exists", disr_vals[i]);
- span_note!(ccx.tcx.sess, ccx.tcx().map.span(variants[i].id.node),
+ span_note!(ccx.tcx.sess, ccx.tcx.map.span(variants[i].id.node),
"conflicting discriminant here")
}
None => {}
use middle::traits;
use middle::ty::{ReScope};
use middle::ty::{self, Ty, MethodCall};
-use middle::infer;
+use middle::infer::{mod, GenericKind};
use middle::pat_util;
use util::ppaux::{ty_to_string, Repr};
pub struct Rcx<'a, 'tcx: 'a> {
fcx: &'a FnCtxt<'a, 'tcx>,
- region_param_pairs: Vec<(ty::Region, ty::ParamTy)>,
+ region_bound_pairs: Vec<(ty::Region, GenericKind<'tcx>)>,
// id of innermost fn or loop
repeating_scope: ast::NodeId,
Rcx { fcx: fcx,
repeating_scope: initial_repeating_scope,
subject: subject,
- region_param_pairs: Vec::new() }
+ region_bound_pairs: Vec::new() }
}
pub fn tcx(&self) -> &'a ty::ctxt<'tcx> {
}
};
- let len = self.region_param_pairs.len();
+ let len = self.region_bound_pairs.len();
self.relate_free_regions(fn_sig[], body.id);
link_fn_args(self, CodeExtent::from_node_id(body.id), fn_decl.inputs[]);
self.visit_block(body);
self.visit_region_obligations(body.id);
- self.region_param_pairs.truncate(len);
+ self.region_bound_pairs.truncate(len);
}
fn visit_region_obligations(&mut self, node_id: ast::NodeId)
// relationship that arises here, but
// presently we do not.)
}
- regionmanip::RegionSubParamConstraint(_, r_a, p_b) => {
- debug!("RegionSubParamConstraint: {} <= {}",
- r_a.repr(tcx), p_b.repr(tcx));
+ regionmanip::RegionSubGenericConstraint(_, r_a, ref generic_b) => {
+ debug!("RegionSubGenericConstraint: {} <= {}",
+ r_a.repr(tcx), generic_b.repr(tcx));
- self.region_param_pairs.push((r_a, p_b));
+ self.region_bound_pairs.push((r_a, generic_b.clone()));
}
}
}
let function_type = rcx.resolve_node_type(expr.id);
match function_type.sty {
- ty::ty_closure(box ty::ClosureTy{store: ty::RegionTraitStore(..),
- ref bounds,
- ..}) => {
- // For closure, ensure that the variables outlive region
- // bound, since they are captured by reference.
- ty::with_freevars(tcx, expr.id, |freevars| {
- if freevars.is_empty() {
- // No free variables means that the environment
- // will be NULL at runtime and hence the closure
- // has static lifetime.
- } else {
- // Variables being referenced must outlive closure.
- constrain_free_variables_in_by_ref_closure(
- rcx, bounds.region_bound, expr, freevars);
-
- // Closure is stack allocated and hence cannot
- // outlive the appropriate temporary scope.
- let s = rcx.repeating_scope;
- rcx.fcx.mk_subr(infer::InfStackClosure(expr.span),
- bounds.region_bound, ty::ReScope(CodeExtent::from_node_id(s)));
- }
- });
- }
ty::ty_unboxed_closure(_, region, _) => {
if tcx.capture_modes.borrow()[expr.id].clone() == ast::CaptureByRef {
ty::with_freevars(tcx, expr.id, |freevars| {
rcx.set_repeating_scope(repeating_scope);
match function_type.sty {
- ty::ty_closure(box ty::ClosureTy {ref bounds, ..}) => {
- ty::with_freevars(tcx, expr.id, |freevars| {
- ensure_free_variable_types_outlive_closure_bound(rcx, bounds, expr, freevars);
- })
- }
ty::ty_unboxed_closure(_, region, _) => {
ty::with_freevars(tcx, expr.id, |freevars| {
let bounds = ty::region_existential_bound(*region);
fn constrain_callee(rcx: &mut Rcx,
callee_id: ast::NodeId,
- call_expr: &ast::Expr,
- callee_expr: &ast::Expr) {
- let call_region = ty::ReScope(CodeExtent::from_node_id(call_expr.id));
-
+ _call_expr: &ast::Expr,
+ _callee_expr: &ast::Expr) {
let callee_ty = rcx.resolve_node_type(callee_id);
match callee_ty.sty {
ty::ty_bare_fn(..) => { }
- ty::ty_closure(ref closure_ty) => {
- let region = match closure_ty.store {
- ty::RegionTraitStore(r, _) => {
- // While we're here, link the closure's region with a unique
- // immutable borrow (gathered later in borrowck)
- let mc = mc::MemCategorizationContext::new(rcx.fcx);
- let expr_cmt = ignore_err!(mc.cat_expr(callee_expr));
- link_region(rcx, callee_expr.span, call_region,
- ty::UniqueImmBorrow, expr_cmt);
- r
- }
- ty::UniqTraitStore => ty::ReStatic
- };
- rcx.fcx.mk_subr(infer::InvokeClosure(callee_expr.span),
- call_region, region);
-
- let region = closure_ty.bounds.region_bound;
- rcx.fcx.mk_subr(infer::InvokeClosure(callee_expr.span),
- call_region, region);
- }
_ => {
// this should not happen, but it does if the program is
// erroneous
let o1 = infer::ReferenceOutlivesReferent(ty, origin.span());
rcx.fcx.mk_subr(o1, r_a, r_b);
}
- regionmanip::RegionSubParamConstraint(None, r_a, param_b) => {
- param_must_outlive(rcx, origin.clone(), r_a, param_b);
+ regionmanip::RegionSubGenericConstraint(None, r_a, ref generic_b) => {
+ generic_must_outlive(rcx, origin.clone(), r_a, generic_b);
}
- regionmanip::RegionSubParamConstraint(Some(ty), r_a, param_b) => {
+ regionmanip::RegionSubGenericConstraint(Some(ty), r_a, ref generic_b) => {
let o1 = infer::ReferenceOutlivesReferent(ty, origin.span());
- param_must_outlive(rcx, o1, r_a, param_b);
+ generic_must_outlive(rcx, o1, r_a, generic_b);
}
}
}
}
-fn param_must_outlive<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
- origin: infer::SubregionOrigin<'tcx>,
- region: ty::Region,
- param_ty: ty::ParamTy) {
+fn generic_must_outlive<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
+ origin: infer::SubregionOrigin<'tcx>,
+ region: ty::Region,
+ generic: &GenericKind<'tcx>) {
let param_env = &rcx.fcx.inh.param_env;
- debug!("param_must_outlive(region={}, param_ty={})",
+ debug!("param_must_outlive(region={}, generic={})",
region.repr(rcx.tcx()),
- param_ty.repr(rcx.tcx()));
+ generic.repr(rcx.tcx()));
// To start, collect bounds from user:
let mut param_bounds =
ty::required_region_bounds(rcx.tcx(),
- param_ty.to_ty(rcx.tcx()),
+ generic.to_ty(rcx.tcx()),
param_env.caller_bounds.predicates.as_slice().to_vec());
// Add in the default bound of fn body that applies to all in
// fn foo<'a, A>(x: &'a A) { x.bar() }
//
// The problem is that the type of `x` is `&'a A`. To be
- // well-formed, then, A must be lower-bounded by `'a`, but we
+ // well-formed, then, A must be lower-generic by `'a`, but we
// don't know that this holds from first principles.
- for &(ref r, ref p) in rcx.region_param_pairs.iter() {
- debug!("param_ty={} p={}",
- param_ty.repr(rcx.tcx()),
+ for &(ref r, ref p) in rcx.region_bound_pairs.iter() {
+ debug!("generic={} p={}",
+ generic.repr(rcx.tcx()),
p.repr(rcx.tcx()));
- if param_ty == *p {
+ if generic == p {
param_bounds.push(*r);
}
}
- // Inform region inference that this parameter type must be
- // properly bounded.
- infer::verify_param_bound(rcx.fcx.infcx(),
- origin,
- param_ty,
- region,
- param_bounds);
+ // Inform region inference that this generic must be properly
+ // bounded.
+ rcx.fcx.infcx().verify_generic_bound(origin,
+ generic.clone(),
+ region,
+ param_bounds);
}
pub use self::WfConstraint::*;
+use middle::infer::GenericKind;
use middle::subst::{ParamSpace, Subst, Substs};
use middle::ty::{self, Ty};
use middle::ty_fold::{TypeFolder};
pub enum WfConstraint<'tcx> {
RegionSubRegionConstraint(Option<Ty<'tcx>>, ty::Region, ty::Region),
- RegionSubParamConstraint(Option<Ty<'tcx>>, ty::Region, ty::ParamTy),
+ RegionSubGenericConstraint(Option<Ty<'tcx>>, ty::Region, GenericKind<'tcx>),
}
struct Wf<'a, 'tcx: 'a> {
// No borrowed content reachable here.
}
- ty::ty_closure(box ref c) => {
- self.accumulate_from_closure_ty(ty, c);
- }
-
ty::ty_unboxed_closure(_, region, _) => {
// An "unboxed closure type" is basically
// modeled here as equivalent to a struct like
ty::ty_projection(ref data) => {
// `<T as TraitRef<..>>::Name`
- // FIXME(#20303) -- gain ability to require that ty_projection : in-scope region,
- // like a type parameter
+ self.push_projection_constraint_from_top(data);
// this seems like a minimal requirement:
let trait_def = ty::lookup_trait_def(self.tcx, data.trait_ref.def_id);
self.push_param_constraint(region, opt_ty, param_ty);
}
+ /// Pushes a constraint that `projection_ty` must outlive the top region on the stack.
+ fn push_projection_constraint_from_top(&mut self,
+ projection_ty: &ty::ProjectionTy<'tcx>) {
+ let &(region, opt_ty) = self.stack.last().unwrap();
+ self.out.push(RegionSubGenericConstraint(
+ opt_ty, region, GenericKind::Projection(projection_ty.clone())));
+ }
+
/// Pushes a constraint that `region <= param_ty`, due to `opt_ty`
fn push_param_constraint(&mut self,
region: ty::Region,
opt_ty: Option<Ty<'tcx>>,
param_ty: ty::ParamTy) {
- self.out.push(RegionSubParamConstraint(opt_ty, region, param_ty));
+ self.out.push(RegionSubGenericConstraint(
+ opt_ty, region, GenericKind::Param(param_ty)));
}
fn accumulate_from_adt(&mut self,
}
}
- fn accumulate_from_closure_ty(&mut self,
- ty: Ty<'tcx>,
- c: &ty::ClosureTy<'tcx>)
- {
- match c.store {
- ty::RegionTraitStore(r_b, _) => {
- self.push_region_constraint_from_top(r_b);
- }
- ty::UniqTraitStore => { }
- }
-
- let required_region_bounds =
- ty::object_region_bounds(self.tcx, None, c.bounds.builtin_bounds);
- self.accumulate_from_object_ty(ty, c.bounds.region_bound, required_region_bounds);
- }
-
fn accumulate_from_object_ty(&mut self,
ty: Ty<'tcx>,
region_bound: ty::Region,
}
impl<'tcx> Repr<'tcx> for WfConstraint<'tcx> {
- fn repr(&self, tcx: &ty::ctxt) -> String {
+ fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
match *self {
- RegionSubRegionConstraint(_, r_a, r_b) => {
+ RegionSubRegionConstraint(_, ref r_a, ref r_b) => {
format!("RegionSubRegionConstraint({}, {})",
r_a.repr(tcx),
r_b.repr(tcx))
}
- RegionSubParamConstraint(_, r, p) => {
- format!("RegionSubParamConstraint({}, {})",
+ RegionSubGenericConstraint(_, ref r, ref p) => {
+ format!("RegionSubGenericConstraint({}, {})",
r.repr(tcx),
p.repr(tcx))
}
_body: &ast::Block)
{
let is_old_skool_closure = match self.fcx.expr_ty(expr).sty {
- ty::ty_closure(..) => true,
_ => false,
};
}
}
- fn with_fcx(&mut self,
- item: &ast::Item,
- f: for<'fcx> |&mut CheckTypeWellFormedVisitor<'ccx, 'tcx>,
- &FnCtxt<'fcx, 'tcx>|) {
+ fn with_fcx<F>(&mut self, item: &ast::Item, mut f: F) where
+ F: for<'fcx> FnMut(&mut CheckTypeWellFormedVisitor<'ccx, 'tcx>, &FnCtxt<'fcx, 'tcx>),
+ {
let ccx = self.ccx;
let item_def_id = local_def(item.id);
let polytype = ty::lookup_item_type(ccx.tcx, item_def_id);
}
/// In a type definition, we check that to ensure that the types of the fields are well-formed.
- fn check_type_defn(&mut self,
- item: &ast::Item,
- lookup_fields: for<'fcx> |&FnCtxt<'fcx, 'tcx>|
- -> Vec<AdtVariant<'tcx>>)
+ fn check_type_defn<F>(&mut self, item: &ast::Item, mut lookup_fields: F) where
+ F: for<'fcx> FnMut(&FnCtxt<'fcx, 'tcx>) -> Vec<AdtVariant<'tcx>>,
{
self.with_fcx(item, |this, fcx| {
let variants = lookup_fields(fcx);
self.fcx.tcx()
}
+ fn fold_binder<T>(&mut self, binder: &ty::Binder<T>) -> ty::Binder<T>
+ where T : TypeFoldable<'tcx> + Repr<'tcx>
+ {
+ self.binding_count += 1;
+ let value = liberate_late_bound_regions(self.fcx.tcx(), self.scope, binder);
+ debug!("BoundsChecker::fold_binder: late-bound regions replaced: {}",
+ value.repr(self.tcx()));
+ let value = value.fold_with(self);
+ self.binding_count -= 1;
+ ty::Binder(value)
+ }
+
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
debug!("BoundsChecker t={}",
t.repr(self.tcx()));
self.fold_substs(substs);
}
- ty::ty_bare_fn(_, &ty::BareFnTy{sig: ref fn_sig, ..}) |
- ty::ty_closure(box ty::ClosureTy{sig: ref fn_sig, ..}) => {
- self.binding_count += 1;
-
- let fn_sig = liberate_late_bound_regions(self.fcx.tcx(), self.scope, fn_sig);
-
- debug!("late-bound regions replaced: {}",
- fn_sig.repr(self.tcx()));
-
- self.fold_fn_sig(&fn_sig);
-
- self.binding_count -= 1;
- }
_ => {
super_fold_ty(self, t);
}
Some(adjustment) => {
let adj_object = ty::adjust_is_object(&adjustment);
let resolved_adjustment = match adjustment {
- ty::AdjustAddEnv(def_id, store) => {
- ty::AdjustAddEnv(def_id, self.resolve(&store, reason))
- }
-
ty::AdjustReifyFnPointer(def_id) => {
ty::AdjustReifyFnPointer(def_id)
}
use middle::ty::RegionEscape;
use middle::ty::{ImplContainer, ImplOrTraitItemId, MethodTraitItemId};
use middle::ty::{ParameterEnvironment, TypeTraitItemId, lookup_item_type};
-use middle::ty::{Ty, ty_bool, ty_char, ty_closure, ty_enum, ty_err};
+use middle::ty::{Ty, ty_bool, ty_char, ty_enum, ty_err};
use middle::ty::{ty_param, TypeScheme, ty_ptr};
use middle::ty::{ty_rptr, ty_struct, ty_trait, ty_tup};
use middle::ty::{ty_str, ty_vec, ty_float, ty_infer, ty_int, ty_open};
}
ty_bool | ty_char | ty_int(..) | ty_uint(..) | ty_float(..) |
- ty_str(..) | ty_vec(..) | ty_bare_fn(..) | ty_closure(..) | ty_tup(..) |
+ ty_str(..) | ty_vec(..) | ty_bare_fn(..) | ty_tup(..) |
ty_param(..) | ty_err | ty_open(..) | ty_uniq(_) |
ty_ptr(_) | ty_rptr(_, _) | ty_projection(..) => {
None
//debug!("(checking coherence) item '{}'", token::get_ident(item.ident));
match item.node {
- ItemImpl(_, _, ref opt_trait, _, _) => {
+ ItemImpl(_, _, _, ref opt_trait, _, _) => {
match opt_trait.clone() {
Some(opt_trait) => {
self.cc.check_implementation(item, &[opt_trait]);
// Converts an implementation in the AST to a vector of items.
fn create_impl_from_item(&self, item: &Item) -> Vec<ImplOrTraitItemId> {
match item.node {
- ItemImpl(_, _, ref trait_refs, _, ref ast_items) => {
+ ItemImpl(_, _, _, ref trait_refs, _, ref ast_items) => {
let mut items: Vec<ImplOrTraitItemId> =
ast_items.iter()
.map(|ast_item| {
fn visit_item(&mut self, item: &'v ast::Item) {
let def_id = ast_util::local_def(item.id);
match item.node {
- ast::ItemImpl(_, _, None, _, _) => {
+ ast::ItemImpl(_, _, _, None, _, _) => {
// For inherent impls, self type must be a nominal type
// defined in this crate.
debug!("coherence2::orphan check: inherent impl {}", item.repr(self.tcx));
}
}
}
- ast::ItemImpl(_, _, Some(_), _, _) => {
+ ast::ItemImpl(_, _, _, Some(_), _, _) => {
// "Trait" impl
debug!("coherence2::orphan check: trait impl {}", item.repr(self.tcx));
match traits::orphan_check(self.tcx, def_id) {
impl<'cx, 'tcx,'v> visit::Visitor<'v> for UnsafetyChecker<'cx, 'tcx> {
fn visit_item(&mut self, item: &'v ast::Item) {
match item.node {
- ast::ItemImpl(unsafety, _, _, _, _) => {
+ ast::ItemImpl(unsafety, _, _, _, _, _) => {
match ty::impl_trait_ref(self.tcx, ast_util::local_def(item.id)) {
None => {
// Inherent impl.
use middle::ty::{self, RegionEscape, Ty, TypeScheme};
use middle::ty_fold::{self, TypeFolder, TypeFoldable};
use middle::infer;
+use no_params;
use rscope::*;
-use {CrateCtxt, no_params, write_ty_to_tcx};
use util::nodemap::{FnvHashMap, FnvHashSet};
use util::ppaux;
use util::ppaux::{Repr,UserString};
+use write_ty_to_tcx;
use std::rc::Rc;
///////////////////////////////////////////////////////////////////////////
// Main entry point
-pub fn collect_item_types(ccx: &CrateCtxt) {
- fn collect_intrinsic_type(ccx: &CrateCtxt,
- lang_item: ast::DefId) {
- let ty::TypeScheme { ty, .. } =
- ccx.get_item_type_scheme(lang_item);
- ccx.tcx.intrinsic_defs.borrow_mut().insert(lang_item, ty);
- }
+pub fn collect_item_types(tcx: &ty::ctxt) {
+ let ccx = &CollectCtxt { tcx: tcx };
match ccx.tcx.lang_items.ty_desc() {
Some(id) => { collect_intrinsic_type(ccx, id); }
visit::walk_crate(&mut visitor, ccx.tcx.map.krate());
}
+///////////////////////////////////////////////////////////////////////////
+
+struct CollectCtxt<'a,'tcx:'a> {
+ tcx: &'a ty::ctxt<'tcx>,
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Zeroth phase: collect types of intrinsics
+
+fn collect_intrinsic_type(ccx: &CollectCtxt,
+ lang_item: ast::DefId) {
+ let ty::TypeScheme { ty, .. } =
+ ccx.get_item_type_scheme(lang_item);
+ ccx.tcx.intrinsic_defs.borrow_mut().insert(lang_item, ty);
+}
+
///////////////////////////////////////////////////////////////////////////
// First phase: just collect *trait definitions* -- basically, the set
// of type parameters and supertraits. This is information we need to
// know later when parsing field defs.
struct CollectTraitDefVisitor<'a, 'tcx: 'a> {
- ccx: &'a CrateCtxt<'a, 'tcx>
+ ccx: &'a CollectCtxt<'a, 'tcx>
}
impl<'a, 'tcx, 'v> visit::Visitor<'v> for CollectTraitDefVisitor<'a, 'tcx> {
// Second phase: collection proper.
struct CollectItemTypesVisitor<'a, 'tcx: 'a> {
- ccx: &'a CrateCtxt<'a, 'tcx>
+ ccx: &'a CollectCtxt<'a, 'tcx>
}
impl<'a, 'tcx, 'v> visit::Visitor<'v> for CollectItemTypesVisitor<'a, 'tcx> {
fn to_ty<RS:RegionScope>(&self, rs: &RS, ast_ty: &ast::Ty) -> Ty<'tcx>;
}
-impl<'a,'tcx> ToTy<'tcx> for CrateCtxt<'a,'tcx> {
+impl<'a,'tcx> ToTy<'tcx> for CollectCtxt<'a,'tcx> {
fn to_ty<RS:RegionScope>(&self, rs: &RS, ast_ty: &ast::Ty) -> Ty<'tcx> {
ast_ty_to_ty(self, rs, ast_ty)
}
}
-impl<'a, 'tcx> AstConv<'tcx> for CrateCtxt<'a, 'tcx> {
+impl<'a, 'tcx> AstConv<'tcx> for CollectCtxt<'a, 'tcx> {
fn tcx(&self) -> &ty::ctxt<'tcx> { self.tcx }
fn get_item_type_scheme(&self, id: ast::DefId) -> ty::TypeScheme<'tcx> {
}
match self.tcx.map.find(id.node) {
- Some(ast_map::NodeItem(item)) => ty_of_item(self, &*item),
+ Some(ast_map::NodeItem(item)) => {
+ ty_of_item(self, &*item)
+ }
Some(ast_map::NodeForeignItem(foreign_item)) => {
let abi = self.tcx.map.get_foreign_abi(id.node);
ty_of_foreign_item(self, &*foreign_item, abi)
}
}
-pub fn get_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn get_enum_variant_types<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
enum_ty: Ty<'tcx>,
variants: &[P<ast::Variant>],
generics: &ast::Generics) {
}
}
-fn collect_trait_methods<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn collect_trait_methods<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
trait_id: ast::NodeId,
trait_def: &ty::TraitDef<'tcx>) {
let tcx = ccx.tcx;
}
}
- fn make_method_ty<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, m: &ty::Method<'tcx>) {
+ fn make_method_ty<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, m: &ty::Method<'tcx>) {
ccx.tcx.tcache.borrow_mut().insert(
m.def_id,
TypeScheme {
ty: ty::mk_bare_fn(ccx.tcx, Some(m.def_id), ccx.tcx.mk_bare_fn(m.fty.clone())) });
}
- fn ty_method_of_trait_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+ fn ty_method_of_trait_method<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
trait_id: ast::NodeId,
trait_generics: &ty::Generics<'tcx>,
_trait_items: &[ast::TraitItem],
}
}
-pub fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn convert_field<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
struct_generics: &ty::Generics<'tcx>,
v: &ast::StructField,
origin: ast::DefId) -> ty::field_ty {
}
}
-fn convert_associated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn convert_associated_type<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
trait_def: &ty::TraitDef<'tcx>,
associated_type: &ast::AssociatedType)
{
ty::TypeTraitItem(associated_type));
}
-fn convert_methods<'a,'tcx,'i,I>(ccx: &CrateCtxt<'a, 'tcx>,
+fn convert_methods<'a,'tcx,'i,I>(ccx: &CollectCtxt<'a, 'tcx>,
container: ImplOrTraitItemContainer,
mut ms: I,
untransformed_rcvr_ty: Ty<'tcx>,
.insert(mty.def_id, ty::MethodTraitItem(mty));
}
- fn ty_of_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+ fn ty_of_method<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
container: ImplOrTraitItemContainer,
m: &ast::Method,
untransformed_rcvr_ty: Ty<'tcx>,
}
}
-pub fn ensure_no_ty_param_bounds(ccx: &CrateCtxt,
+fn ensure_no_ty_param_bounds(ccx: &CollectCtxt,
span: Span,
generics: &ast::Generics,
thing: &'static str) {
}
}
-pub fn convert(ccx: &CrateCtxt, it: &ast::Item) {
+fn convert(ccx: &CollectCtxt, it: &ast::Item) {
let tcx = ccx.tcx;
debug!("convert: item {} with id {}", token::get_ident(it.ident), it.id);
match it.node {
enum_definition.variants.as_slice(),
generics);
},
- ast::ItemImpl(_,
+ ast::ItemImpl(_, _,
ref generics,
ref opt_trait_ref,
ref selfty,
debug!("trait_def: ident={} trait_def={}",
it.ident.repr(ccx.tcx),
- trait_def.repr(ccx.tcx()));
+ trait_def.repr(ccx.tcx));
for trait_method in trait_methods.iter() {
let self_type = ty::mk_self_type(tcx);
}
}
-pub fn convert_struct<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn convert_struct<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
struct_def: &ast::StructDef,
scheme: ty::TypeScheme<'tcx>,
id: ast::NodeId) {
}
}
-pub fn convert_foreign(ccx: &CrateCtxt, i: &ast::ForeignItem) {
+fn convert_foreign(ccx: &CollectCtxt, i: &ast::ForeignItem) {
// As above, this call populates the type table with the converted
// type of the foreign item. We simply write it into the node type
// table.
ccx.tcx.tcache.borrow_mut().insert(local_def(i.id), scheme);
}
-fn get_trait_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn get_trait_def<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
trait_id: ast::DefId)
-> Rc<ty::TraitDef<'tcx>> {
if trait_id.krate != ast::LOCAL_CRATE {
}
}
-pub fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
- it: &ast::Item)
- -> Rc<ty::TraitDef<'tcx>>
+fn trait_def_of_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
+ it: &ast::Item)
+ -> Rc<ty::TraitDef<'tcx>>
{
let def_id = local_def(it.id);
let tcx = ccx.tcx;
return trait_def;
- fn mk_trait_substs<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+ fn mk_trait_substs<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
generics: &ast::Generics)
-> subst::Substs<'tcx>
{
}
}
-pub fn ty_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item)
+fn ty_of_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, it: &ast::Item)
-> ty::TypeScheme<'tcx> {
let def_id = local_def(it.id);
let tcx = ccx.tcx;
}
}
-pub fn ty_of_foreign_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn ty_of_foreign_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
it: &ast::ForeignItem,
abi: abi::Abi) -> ty::TypeScheme<'tcx>
{
}
}
-fn ty_generics_for_type_or_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn ty_generics_for_type_or_impl<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
generics: &ast::Generics)
-> ty::Generics<'tcx> {
ty_generics(ccx,
&generics.where_clause)
}
-fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn ty_generics_for_trait<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
trait_id: ast::NodeId,
substs: &'tcx subst::Substs<'tcx>,
ast_generics: &ast::Generics,
return generics;
- fn predicates_for_associated_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+ fn predicates_for_associated_types<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
self_trait_ref: &Rc<ty::TraitRef<'tcx>>,
trait_items: &[ast::TraitItem])
-> Vec<ty::Predicate<'tcx>>
}
}
-fn ty_generics_for_fn_or_method<'tcx,AC>(
- this: &AC,
- generics: &ast::Generics,
- base_generics: ty::Generics<'tcx>)
- -> ty::Generics<'tcx>
- where AC: AstConv<'tcx> {
+fn ty_generics_for_fn_or_method<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
+ generics: &ast::Generics,
+ base_generics: ty::Generics<'tcx>)
+ -> ty::Generics<'tcx>
+{
let early_lifetimes = resolve_lifetime::early_bound_lifetimes(generics);
- ty_generics(this,
+ ty_generics(ccx,
subst::FnSpace,
early_lifetimes[],
generics.ty_params[],
}
// Add the Sized bound, unless the type parameter is marked as `?Sized`.
-fn add_unsized_bound<'tcx,AC>(this: &AC,
+fn add_unsized_bound<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
bounds: &mut ty::BuiltinBounds,
ast_bounds: &[ast::TyParamBound],
span: Span)
- where AC: AstConv<'tcx> {
+{
// Try to find an unbound in bounds.
let mut unbound = None;
for ab in ast_bounds.iter() {
assert!(ptr.bound_lifetimes.is_empty());
unbound = Some(ptr.trait_ref.clone());
} else {
- this.tcx().sess.span_err(span, "type parameter has more than one relaxed default \
+ ccx.tcx.sess.span_err(span, "type parameter has more than one relaxed default \
bound, only one is supported");
}
}
}
- let kind_id = this.tcx().lang_items.require(SizedTraitLangItem);
+ let kind_id = ccx.tcx.lang_items.require(SizedTraitLangItem);
match unbound {
Some(ref tpb) => {
// FIXME(#8559) currently requires the unbound to be built-in.
- let trait_def_id = ty::trait_ref_to_def_id(this.tcx(), tpb);
+ let trait_def_id = ty::trait_ref_to_def_id(ccx.tcx, tpb);
match kind_id {
Ok(kind_id) if trait_def_id != kind_id => {
- this.tcx().sess.span_warn(span,
+ ccx.tcx.sess.span_warn(span,
"default bound relaxed for a type parameter, but \
this does nothing because the given bound is not \
a default. Only `?Sized` is supported");
- ty::try_add_builtin_trait(this.tcx(),
+ ty::try_add_builtin_trait(ccx.tcx,
kind_id,
bounds);
}
}
}
_ if kind_id.is_ok() => {
- ty::try_add_builtin_trait(this.tcx(), kind_id.unwrap(), bounds);
+ ty::try_add_builtin_trait(ccx.tcx, kind_id.unwrap(), bounds);
}
// No lang item for Sized, so we can't add it as a bound.
None => {}
}
}
-fn ty_generics<'tcx,AC>(this: &AC,
+fn ty_generics<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
space: subst::ParamSpace,
lifetime_defs: &[ast::LifetimeDef],
types: &[ast::TyParam],
base_generics: ty::Generics<'tcx>,
where_clause: &ast::WhereClause)
-> ty::Generics<'tcx>
- where AC: AstConv<'tcx>
{
let mut result = base_generics;
for (i, l) in lifetime_defs.iter().enumerate() {
let bounds = l.bounds.iter()
- .map(|l| ast_region_to_region(this.tcx(), l))
+ .map(|l| ast_region_to_region(ccx.tcx, l))
.collect();
let def = ty::RegionParameterDef { name: l.lifetime.name,
space: space,
// Now create the real type parameters.
for (i, param) in types.iter().enumerate() {
- let def = get_or_create_type_parameter_def(this,
+ let def = get_or_create_type_parameter_def(ccx,
space,
param,
i as u32);
debug!("ty_generics: def for type param: {}, {}",
- def.repr(this.tcx()),
+ def.repr(ccx.tcx),
space);
result.types.push(space, def);
}
// Just for fun, also push the bounds from the type parameters
// into the predicates list. This is currently kind of non-DRY.
- create_predicates(this.tcx(), &mut result, space);
+ create_predicates(ccx.tcx, &mut result, space);
// Add the bounds not associated with a type parameter
for predicate in where_clause.predicates.iter() {
match predicate {
&ast::WherePredicate::BoundPredicate(ref bound_pred) => {
- let ty = ast_ty_to_ty(this, &ExplicitRscope, &*bound_pred.bounded_ty);
+ let ty = ast_ty_to_ty(ccx, &ExplicitRscope, &*bound_pred.bounded_ty);
for bound in bound_pred.bounds.iter() {
match bound {
let mut projections = Vec::new();
let trait_ref = astconv::instantiate_poly_trait_ref(
- this,
+ ccx,
&ExplicitRscope,
poly_trait_ref,
Some(ty),
}
&ast::TyParamBound::RegionTyParamBound(ref lifetime) => {
- let region = ast_region_to_region(this.tcx(), lifetime);
+ let region = ast_region_to_region(ccx.tcx, lifetime);
let pred = ty::Binder(ty::OutlivesPredicate(ty, region));
result.predicates.push(space, ty::Predicate::TypeOutlives(pred))
}
}
&ast::WherePredicate::RegionPredicate(ref region_pred) => {
- let r1 = ast_region_to_region(this.tcx(), ®ion_pred.lifetime);
+ let r1 = ast_region_to_region(ccx.tcx, ®ion_pred.lifetime);
for bound in region_pred.bounds.iter() {
- let r2 = ast_region_to_region(this.tcx(), bound);
+ let r2 = ast_region_to_region(ccx.tcx, bound);
let pred = ty::Binder(ty::OutlivesPredicate(r1, r2));
result.predicates.push(space, ty::Predicate::RegionOutlives(pred))
}
&ast::WherePredicate::EqPredicate(ref eq_pred) => {
// FIXME(#20041)
- this.tcx().sess.span_bug(eq_pred.span,
+ ccx.tcx.sess.span_bug(eq_pred.span,
"Equality constraints are not yet \
implemented (#20041)")
}
}
}
-fn get_or_create_type_parameter_def<'tcx,AC>(this: &AC,
+fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
space: subst::ParamSpace,
param: &ast::TyParam,
index: u32)
-> ty::TypeParameterDef<'tcx>
- where AC: AstConv<'tcx>
{
- match this.tcx().ty_param_defs.borrow().get(¶m.id) {
+ match ccx.tcx.ty_param_defs.borrow().get(¶m.id) {
Some(d) => { return (*d).clone(); }
None => { }
}
let param_ty = ty::ParamTy::new(space, index, param.ident.name);
- let bounds = compute_bounds(this,
- param_ty.to_ty(this.tcx()),
+ let bounds = compute_bounds(ccx,
+ param_ty.to_ty(ccx.tcx),
param.bounds[],
SizedByDefault::Yes,
param.span);
let default = match param.default {
None => None,
Some(ref path) => {
- let ty = ast_ty_to_ty(this, &ExplicitRscope, &**path);
+ let ty = ast_ty_to_ty(ccx, &ExplicitRscope, &**path);
let cur_idx = index;
ty::walk_ty(ty, |t| {
match t.sty {
ty::ty_param(p) => if p.idx > cur_idx {
- span_err!(this.tcx().sess, path.span, E0128,
+ span_err!(ccx.tcx.sess, path.span, E0128,
"type parameters with a default cannot use \
forward declared identifiers");
},
default: default
};
- this.tcx().ty_param_defs.borrow_mut().insert(param.id, def.clone());
+ ccx.tcx.ty_param_defs.borrow_mut().insert(param.id, def.clone());
def
}
/// Translate the AST's notion of ty param bounds (which are an enum consisting of a newtyped Ty or
/// a region) to ty's notion of ty param bounds, which can either be user-defined traits, or the
/// built-in trait (formerly known as kind): Send.
-fn compute_bounds<'tcx,AC>(this: &AC,
+fn compute_bounds<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
param_ty: ty::Ty<'tcx>,
ast_bounds: &[ast::TyParamBound],
sized_by_default: SizedByDefault,
span: Span)
-> ty::ParamBounds<'tcx>
- where AC: AstConv<'tcx>
{
- let mut param_bounds = conv_param_bounds(this,
+ let mut param_bounds = conv_param_bounds(ccx,
span,
param_ty,
ast_bounds);
if let SizedByDefault::Yes = sized_by_default {
- add_unsized_bound(this,
+ add_unsized_bound(ccx,
&mut param_bounds.builtin_bounds,
ast_bounds,
span);
- check_bounds_compatible(this.tcx(),
+ check_bounds_compatible(ccx.tcx,
param_ty,
¶m_bounds,
span);
}
}
-fn conv_param_bounds<'tcx,AC>(this: &AC,
+fn conv_param_bounds<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
span: Span,
param_ty: ty::Ty<'tcx>,
ast_bounds: &[ast::TyParamBound])
-> ty::ParamBounds<'tcx>
- where AC: AstConv<'tcx>
{
let astconv::PartitionedBounds { builtin_bounds,
trait_bounds,
region_bounds } =
- astconv::partition_bounds(this.tcx(), span, ast_bounds.as_slice());
+ astconv::partition_bounds(ccx.tcx, span, ast_bounds.as_slice());
let mut projection_bounds = Vec::new();
let trait_bounds: Vec<ty::PolyTraitRef> =
trait_bounds.into_iter()
.map(|bound| {
- astconv::instantiate_poly_trait_ref(this,
+ astconv::instantiate_poly_trait_ref(ccx,
&ExplicitRscope,
bound,
Some(param_ty),
.collect();
let region_bounds: Vec<ty::Region> =
region_bounds.into_iter()
- .map(|r| ast_region_to_region(this.tcx(), r))
+ .map(|r| ast_region_to_region(ccx.tcx, r))
.collect();
ty::ParamBounds {
region_bounds: region_bounds,
}
}
-pub fn ty_of_foreign_fn_decl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn ty_of_foreign_fn_decl<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
decl: &ast::FnDecl,
def_id: ast::DefId,
ast_generics: &ast::Generics,
return scheme;
}
-pub fn mk_item_substs<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
- ty_generics: &ty::Generics<'tcx>)
- -> subst::Substs<'tcx>
+fn mk_item_substs<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
+ ty_generics: &ty::Generics<'tcx>)
+ -> subst::Substs<'tcx>
{
let types =
ty_generics.types.map(
/// comes back to check after the fact that explicit type the user
/// wrote actually matches what the pre-defined option said.
fn check_method_self_type<'a, 'tcx, RS:RegionScope>(
- crate_context: &CrateCtxt<'a, 'tcx>,
+ ccx: &CollectCtxt<'a, 'tcx>,
rs: &RS,
required_type: Ty<'tcx>,
explicit_self: &ast::ExplicitSelf,
body_id: ast::NodeId)
{
if let ast::SelfExplicit(ref ast_type, _) = explicit_self.node {
- let typ = crate_context.to_ty(rs, &**ast_type);
+ let typ = ccx.to_ty(rs, &**ast_type);
let base_type = match typ.sty {
ty::ty_ptr(tm) | ty::ty_rptr(_, tm) => tm.ty,
ty::ty_uniq(typ) => typ,
assert!(!base_type.has_regions_escaping_depth(1));
let required_type_free =
liberate_early_bound_regions(
- crate_context.tcx, body_scope,
+ ccx.tcx, body_scope,
&ty::liberate_late_bound_regions(
- crate_context.tcx, body_scope, &ty::Binder(required_type)));
+ ccx.tcx, body_scope, &ty::Binder(required_type)));
// The "base type" comes from the impl. It too may have late-bound
// regions from the method.
assert!(!base_type.has_regions_escaping_depth(1));
let base_type_free =
liberate_early_bound_regions(
- crate_context.tcx, body_scope,
+ ccx.tcx, body_scope,
&ty::liberate_late_bound_regions(
- crate_context.tcx, body_scope, &ty::Binder(base_type)));
+ ccx.tcx, body_scope, &ty::Binder(base_type)));
debug!("required_type={} required_type_free={} \
base_type={} base_type_free={}",
- required_type.repr(crate_context.tcx),
- required_type_free.repr(crate_context.tcx),
- base_type.repr(crate_context.tcx),
- base_type_free.repr(crate_context.tcx));
- let infcx = infer::new_infer_ctxt(crate_context.tcx);
- drop(::require_same_types(crate_context.tcx,
+ required_type.repr(ccx.tcx),
+ required_type_free.repr(ccx.tcx),
+ base_type.repr(ccx.tcx),
+ base_type_free.repr(ccx.tcx));
+ let infcx = infer::new_infer_ctxt(ccx.tcx);
+ drop(::require_same_types(ccx.tcx,
Some(&infcx),
false,
explicit_self.span,
required_type_free,
|| {
format!("mismatched self type: expected `{}`",
- ppaux::ty_to_string(crate_context.tcx, required_type))
+ ppaux::ty_to_string(ccx.tcx, required_type))
}));
infcx.resolve_regions_and_report_errors(body_id);
}
struct CrateCtxt<'a, 'tcx: 'a> {
// A mapping from method call sites to traits that have that method.
trait_map: ty::TraitMap,
- tcx: &'a ty::ctxt<'tcx>
+ tcx: &'a ty::ctxt<'tcx>,
}
// Functions that write types into the node type table
};
time(time_passes, "type collecting", (), |_|
- collect::collect_item_types(&ccx));
+ collect::collect_item_types(tcx));
// this ensures that later parts of type checking can assume that items
// have valid types and not error
}
}
- ty::ty_bare_fn(_, &ty::BareFnTy { ref sig, .. }) |
- ty::ty_closure(box ty::ClosureTy {
- ref sig,
- store: ty::UniqTraitStore,
- ..
- }) =>
- {
- self.add_constraints_from_sig(generics, sig, variance);
- }
-
- ty::ty_closure(box ty::ClosureTy { ref sig,
- store: ty::RegionTraitStore(region, _), .. }) => {
- let contra = self.contravariant(variance);
- self.add_constraints_from_region(generics, region, contra);
+ ty::ty_bare_fn(_, &ty::BareFnTy { ref sig, .. }) => {
self.add_constraints_from_sig(generics, sig, variance);
}
use std::rc::Rc;
use std::u32;
use std::str::Str as StrTrait; // Conflicts with Str variant
-use std::char::Char as CharTrait; // Conflicts with Char variant
use std::path::Path as FsPath; // Conflicts with Path struct
use core::DocContext;
}
}
}
- TyClosure(ref c) => Closure(box c.clean(cx)),
TyBareFn(ref barefn) => BareFunction(box barefn.clean(cx)),
TyParen(ref ty) => ty.clean(cx),
TyQPath(ref qp) => qp.clean(cx),
decl: (ast_util::local_def(0), &fty.sig).clean(cx),
abi: fty.abi.to_string(),
}),
- ty::ty_closure(ref fty) => {
- let decl = box ClosureDecl {
- lifetimes: Vec::new(), // FIXME: this looks wrong...
- decl: (ast_util::local_def(0), &fty.sig).clean(cx),
- onceness: fty.onceness,
- unsafety: fty.unsafety,
- bounds: fty.bounds.clean(cx),
- };
- match fty.store {
- ty::UniqTraitStore => Proc(decl),
- ty::RegionTraitStore(..) => Closure(decl),
- }
- }
ty::ty_struct(did, substs) |
ty::ty_enum(did, substs) => {
let fqn = csearch::get_item_path(cx.tcx(), did);
},
PatRange(..) => panic!("tried to get argument name from PatRange, \
which is not allowed in function arguments"),
- PatVec(..) => panic!("tried to get argument name from pat_vec, \
- which is not allowed in function arguments"),
+ PatVec(ref begin, ref mid, ref end) => {
+ let begin = begin.iter().map(|p| name_from_pat(&**p));
+ let mid = mid.as_ref().map(|p| format!("..{}", name_from_pat(&**p))).into_iter();
+ let end = end.iter().map(|p| name_from_pat(&**p));
+ format!("[{}]", begin.chain(mid).chain(end).collect::<Vec<_>>().connect(", "))
+ },
PatMac(..) => {
warn!("can't document the name of a function argument \
produced by a pattern macro");
pub struct Impl {
pub unsafety: ast::Unsafety,
+ pub polarity: ast::ImplPolarity,
pub generics: ast::Generics,
pub trait_: Option<ast::TraitRef>,
pub for_: P<ast::Ty>,
#[cfg(unix)]
mod imp {
+ use std::ffi::CString;
use libc;
- use std::c_str::ToCStr;
#[cfg(target_os = "linux")]
mod os {
impl Lock {
pub fn new(p: &Path) -> Lock {
- let fd = p.with_c_str(|s| unsafe {
- libc::open(s, libc::O_RDWR | libc::O_CREAT, libc::S_IRWXU)
- });
+ let buf = CString::from_slice(p.as_vec());
+ let fd = unsafe {
+ libc::open(buf.as_ptr(), libc::O_RDWR | libc::O_CREAT,
+ libc::S_IRWXU)
+ };
assert!(fd > 0);
let flock = os::flock {
l_start: 0,
use libc;
use std::ascii::AsciiExt;
-use std::c_str::ToCStr;
+use std::ffi::CString;
use std::cell::{RefCell, Cell};
use std::collections::HashMap;
use std::fmt;
let id = id.as_ref().map(|a| a.as_slice());
s.push_str(highlight::highlight(text.as_slice(), None, id)
.as_slice());
- let output = s.to_c_str();
+ let output = CString::from_vec(s.into_bytes());
hoedown_buffer_puts(ob, output.as_ptr());
})
}
extern fn header(ob: *mut hoedown_buffer, text: *const hoedown_buffer,
level: libc::c_int, opaque: *mut libc::c_void) {
// hoedown does this, we may as well too
- "\n".with_c_str(|p| unsafe { hoedown_buffer_puts(ob, p) });
+ unsafe { hoedown_buffer_puts(ob, "\n\0".as_ptr() as *const _); }
// Extract the text provided
let s = if text.is_null() {
"".to_string()
} else {
- unsafe {
- String::from_raw_buf_len((*text).data, (*text).size as uint)
- }
+ let s = unsafe {
+ slice::from_raw_buf(&(*text).data, (*text).size as uint)
+ };
+ str::from_utf8(s).unwrap().to_string()
};
// Transform the contents of the header into a hyphenated string
format!("{} ", sec)
});
- text.with_c_str(|p| unsafe { hoedown_buffer_puts(ob, p) });
+ let text = CString::from_vec(text.into_bytes());
+ unsafe { hoedown_buffer_puts(ob, text.as_ptr()) }
}
reset_headers();
use std::cell::RefCell;
use std::cmp::Ordering::{self, Less, Greater, Equal};
-use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::collections::{HashMap, HashSet};
use std::default::Default;
use std::fmt;
if let clean::ImplItem(ref i) = item.inner {
match i.trait_ {
Some(clean::ResolvedPath{ did, .. }) => {
- let v = match self.implementors.entry(did) {
- Vacant(entry) => entry.set(Vec::with_capacity(1)),
- Occupied(entry) => entry.into_mut(),
- };
+ let v = self.implementors.entry(&did).get().unwrap_or_else(
+ |vacant_entry| vacant_entry.insert(Vec::with_capacity(1)));
v.push(Implementor {
def_id: item.def_id,
generics: i.generics.clone(),
};
if let Some(did) = did {
- let v = match self.impls.entry(did) {
- Vacant(entry) => entry.set(Vec::with_capacity(1)),
- Occupied(entry) => entry.into_mut(),
- };
+ let v = self.impls.entry(&did).get().unwrap_or_else(
+ |vacant_entry| vacant_entry.insert(Vec::with_capacity(1)));
v.push(Impl {
impl_: i,
dox: dox,
None => continue,
Some(ref s) => s.to_string(),
};
- let v = match map.entry(short.to_string()) {
- Vacant(entry) => entry.set(Vec::with_capacity(1)),
- Occupied(entry) => entry.into_mut(),
- };
+ let short = short.to_string();
+ let v = map.entry(&short).get().unwrap_or_else(
+ |vacant_entry| vacant_entry.insert(Vec::with_capacity(1)));
v.push(myname);
}
cols += 1;
tmp /= 10;
}
- try!(write!(fmt, "<pre class='line-numbers'>"));
+ try!(write!(fmt, "<pre class=\"line-numbers\">"));
for i in range(1, lines + 1) {
- try!(write!(fmt, "<span id='{0}'>{0:1$}</span>\n", i, cols));
+ try!(write!(fmt, "<span id=\"{0}\">{0:1$}</span>\n", i, cols));
}
try!(write!(fmt, "</pre>"));
try!(write!(fmt, "{}", highlight::highlight(s.as_slice(), None, None)));
left: 0;
top: 0;
min-height: 100%;
+ z-index: -1;
}
.content, nav { max-width: 960px; }
overflow: auto;
padding-left: 0;
}
-.content pre.line-numbers { float: left; border: none; }
-.line-numbers span { color: #c67e2d; }
+.content pre.line-numbers {
+ float: left;
+ border: none;
+
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+.line-numbers span { color: #c67e2d; cursor: pointer; }
.line-numbers .line-highlighted {
- background-color: #f6fdb0;
+ background-color: #f6fdb0 !important;
}
.content .highlighted {
.summary.Unmarked { background-color: #BBBBBB; }
:target { background: #FDFFD3; }
+.line-numbers :target { background-color: transparent; }
/* Code highlighting */
pre.rust .kw { color: #8959A8; }
resizeShortBlocks();
$(window).on('resize', resizeShortBlocks);
- function highlightSourceLines() {
+ function highlightSourceLines(ev) {
var i, from, to, match = window.location.hash.match(/^#?(\d+)(?:-(\d+))?$/);
if (match) {
from = parseInt(match[1], 10);
if ($('#' + from).length === 0) {
return;
}
- $('#' + from)[0].scrollIntoView();
+ if (ev === null) $('#' + from)[0].scrollIntoView();
$('.line-numbers span').removeClass('line-highlighted');
for (i = from; i <= to; ++i) {
$('#' + i).addClass('line-highlighted');
}
}
}
- highlightSourceLines();
+ highlightSourceLines(null);
$(window).on('hashchange', highlightSourceLines);
$(document).on('keyup', function(e) {
$("#main > .docblock").before(wrapper);
});
+ $('pre.line-numbers').on('click', 'span', function() {
+ var prev_id = 0;
+
+ function set_fragment(name) {
+ if (history.replaceState) {
+ history.replaceState(null, null, '#' + name);
+ $(window).trigger('hashchange');
+ } else {
+ location.replace('#' + name);
+ }
+ }
+
+ return function(ev) {
+ var cur_id = parseInt(ev.target.id);
+
+ if (ev.shiftKey && prev_id) {
+ if (prev_id > cur_id) {
+ var tmp = prev_id;
+ prev_id = cur_id;
+ cur_id = tmp;
+ }
+
+ set_fragment(prev_id + '-' + cur_id);
+ } else {
+ prev_id = cur_id;
+
+ set_fragment(cur_id);
+ }
+ };
+ }());
+
}());
use std::cell::RefCell;
use std::collections::HashMap;
-use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::io::File;
use std::io;
use std::rc::Rc;
return Err("--extern value must be of the format `foo=bar`".to_string());
}
};
- let locs = match externs.entry(name.to_string()) {
- Vacant(entry) => entry.set(Vec::with_capacity(1)),
- Occupied(entry) => entry.into_mut(),
- };
+ let name = name.to_string();
+ let locs = externs.entry(&name).get().unwrap_or_else(
+ |vacant_entry| vacant_entry.insert(Vec::with_capacity(1)));
locs.push(location.to_string());
}
Ok(externs)
};
om.traits.push(t);
},
- ast::ItemImpl(unsafety, ref gen, ref tr, ref ty, ref items) => {
+ ast::ItemImpl(unsafety, polarity, ref gen, ref tr, ref ty, ref items) => {
let i = Impl {
unsafety: unsafety,
+ polarity: polarity,
generics: gen.clone(),
trait_: tr.clone(),
for_: ty.clone(),
use collections::enum_set::{EnumSet, CLike};
impl<
- E,
- S: Encoder<E>,
- T: Encodable<S, E>
-> Encodable<S, E> for DList<T> {
- fn encode(&self, s: &mut S) -> Result<(), E> {
+ T: Encodable
+> Encodable for DList<T> {
+ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
s.emit_seq(self.len(), |s| {
for (i, e) in self.iter().enumerate() {
try!(s.emit_seq_elt(i, |s| e.encode(s)));
}
}
-impl<E, D:Decoder<E>,T:Decodable<D, E>> Decodable<D, E> for DList<T> {
- fn decode(d: &mut D) -> Result<DList<T>, E> {
+impl<T:Decodable> Decodable for DList<T> {
+ fn decode<D: Decoder>(d: &mut D) -> Result<DList<T>, D::Error> {
d.read_seq(|d, len| {
let mut list = DList::new();
for i in range(0u, len) {
}
}
-impl<
- E,
- S: Encoder<E>,
- T: Encodable<S, E>
-> Encodable<S, E> for RingBuf<T> {
- fn encode(&self, s: &mut S) -> Result<(), E> {
+impl<T: Encodable> Encodable for RingBuf<T> {
+ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
s.emit_seq(self.len(), |s| {
for (i, e) in self.iter().enumerate() {
try!(s.emit_seq_elt(i, |s| e.encode(s)));
}
}
-impl<E, D:Decoder<E>,T:Decodable<D, E>> Decodable<D, E> for RingBuf<T> {
- fn decode(d: &mut D) -> Result<RingBuf<T>, E> {
+impl<T:Decodable> Decodable for RingBuf<T> {
+ fn decode<D: Decoder>(d: &mut D) -> Result<RingBuf<T>, D::Error> {
d.read_seq(|d, len| {
let mut deque: RingBuf<T> = RingBuf::new();
for i in range(0u, len) {
}
impl<
- E,
- S: Encoder<E>,
- K: Encodable<S, E> + PartialEq + Ord,
- V: Encodable<S, E> + PartialEq
-> Encodable<S, E> for BTreeMap<K, V> {
- fn encode(&self, e: &mut S) -> Result<(), E> {
+ K: Encodable + PartialEq + Ord,
+ V: Encodable + PartialEq
+> Encodable for BTreeMap<K, V> {
+ fn encode<S: Encoder>(&self, e: &mut S) -> Result<(), S::Error> {
e.emit_map(self.len(), |e| {
let mut i = 0;
for (key, val) in self.iter() {
}
impl<
- E,
- D: Decoder<E>,
- K: Decodable<D, E> + PartialEq + Ord,
- V: Decodable<D, E> + PartialEq
-> Decodable<D, E> for BTreeMap<K, V> {
- fn decode(d: &mut D) -> Result<BTreeMap<K, V>, E> {
+ K: Decodable + PartialEq + Ord,
+ V: Decodable + PartialEq
+> Decodable for BTreeMap<K, V> {
+ fn decode<D: Decoder>(d: &mut D) -> Result<BTreeMap<K, V>, D::Error> {
d.read_map(|d, len| {
let mut map = BTreeMap::new();
for i in range(0u, len) {
}
impl<
- E,
- S: Encoder<E>,
- T: Encodable<S, E> + PartialEq + Ord
-> Encodable<S, E> for BTreeSet<T> {
- fn encode(&self, s: &mut S) -> Result<(), E> {
+ T: Encodable + PartialEq + Ord
+> Encodable for BTreeSet<T> {
+ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
s.emit_seq(self.len(), |s| {
let mut i = 0;
for e in self.iter() {
}
impl<
- E,
- D: Decoder<E>,
- T: Decodable<D, E> + PartialEq + Ord
-> Decodable<D, E> for BTreeSet<T> {
- fn decode(d: &mut D) -> Result<BTreeSet<T>, E> {
+ T: Decodable + PartialEq + Ord
+> Decodable for BTreeSet<T> {
+ fn decode<D: Decoder>(d: &mut D) -> Result<BTreeSet<T>, D::Error> {
d.read_seq(|d, len| {
let mut set = BTreeSet::new();
for i in range(0u, len) {
}
impl<
- E,
- S: Encoder<E>,
- T: Encodable<S, E> + CLike
-> Encodable<S, E> for EnumSet<T> {
- fn encode(&self, s: &mut S) -> Result<(), E> {
+ T: Encodable + CLike
+> Encodable for EnumSet<T> {
+ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
let mut bits = 0;
for item in self.iter() {
bits |= item.to_uint();
}
impl<
- E,
- D: Decoder<E>,
- T: Decodable<D, E> + CLike
-> Decodable<D, E> for EnumSet<T> {
- fn decode(d: &mut D) -> Result<EnumSet<T>, E> {
+ T: Decodable + CLike
+> Decodable for EnumSet<T> {
+ fn decode<D: Decoder>(d: &mut D) -> Result<EnumSet<T>, D::Error> {
let bits = try!(d.read_uint());
let mut set = EnumSet::new();
for bit in range(0, uint::BITS) {
}
impl<
- E,
- S: Encoder<E>,
- K: Encodable<S, E> + Hash<X> + Eq,
- V: Encodable<S, E>,
+ K: Encodable + Hash<X> + Eq,
+ V: Encodable,
X,
H: Hasher<X>
-> Encodable<S, E> for HashMap<K, V, H> {
- fn encode(&self, e: &mut S) -> Result<(), E> {
+> Encodable for HashMap<K, V, H> {
+ fn encode<S: Encoder>(&self, e: &mut S) -> Result<(), S::Error> {
e.emit_map(self.len(), |e| {
let mut i = 0;
for (key, val) in self.iter() {
}
impl<
- E,
- D: Decoder<E>,
- K: Decodable<D, E> + Hash<S> + Eq,
- V: Decodable<D, E>,
+ K: Decodable + Hash<S> + Eq,
+ V: Decodable,
S,
H: Hasher<S> + Default
-> Decodable<D, E> for HashMap<K, V, H> {
- fn decode(d: &mut D) -> Result<HashMap<K, V, H>, E> {
+> Decodable for HashMap<K, V, H> {
+ fn decode<D: Decoder>(d: &mut D) -> Result<HashMap<K, V, H>, D::Error> {
d.read_map(|d, len| {
let hasher = Default::default();
let mut map = HashMap::with_capacity_and_hasher(len, hasher);
}
impl<
- E,
- S: Encoder<E>,
- T: Encodable<S, E> + Hash<X> + Eq,
+ T: Encodable + Hash<X> + Eq,
X,
H: Hasher<X>
-> Encodable<S, E> for HashSet<T, H> {
- fn encode(&self, s: &mut S) -> Result<(), E> {
+> Encodable for HashSet<T, H> {
+ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
s.emit_seq(self.len(), |s| {
let mut i = 0;
for e in self.iter() {
}
impl<
- E,
- D: Decoder<E>,
- T: Decodable<D, E> + Hash<S> + Eq,
+ T: Decodable + Hash<S> + Eq,
S,
H: Hasher<S> + Default
-> Decodable<D, E> for HashSet<T, H> {
- fn decode(d: &mut D) -> Result<HashSet<T, H>, E> {
+> Decodable for HashSet<T, H> {
+ fn decode<D: Decoder>(d: &mut D) -> Result<HashSet<T, H>, D::Error> {
d.read_seq(|d, len| {
let mut set = HashSet::with_capacity_and_hasher(len, Default::default());
for i in range(0u, len) {
}
}
-impl<
- E,
- S: Encoder<E>,
- V: Encodable<S, E>
-> Encodable<S, E> for VecMap<V> {
- fn encode(&self, e: &mut S) -> Result<(), E> {
+impl<V: Encodable> Encodable for VecMap<V> {
+ fn encode<S: Encoder>(&self, e: &mut S) -> Result<(), S::Error> {
e.emit_map(self.len(), |e| {
for (i, (key, val)) in self.iter().enumerate() {
try!(e.emit_map_elt_key(i, |e| key.encode(e)));
}
}
-impl<
- E,
- D: Decoder<E>,
- V: Decodable<D, E>
-> Decodable<D, E> for VecMap<V> {
- fn decode(d: &mut D) -> Result<VecMap<V>, E> {
+impl<V: Decodable> Decodable for VecMap<V> {
+ fn decode<D: Decoder>(d: &mut D) -> Result<VecMap<V>, D::Error> {
d.read_map(|d, len| {
let mut map = VecMap::new();
for i in range(0u, len) {
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Implementations of serialization for structures found in libcollections
+
+use std::uint;
+use std::default::Default;
+use std::hash::{Hash, Hasher};
+
+use {Decodable, Encodable, Decoder, Encoder};
+use std::collections::{DList, RingBuf, BTreeMap, BTreeSet, HashMap, HashSet, VecMap};
+use collections::enum_set::{EnumSet, CLike};
+
+impl<
+ E,
+ S: Encoder<E>,
+ T: Encodable<S, E>
+> Encodable<S, E> for DList<T> {
+ fn encode(&self, s: &mut S) -> Result<(), E> {
+ s.emit_seq(self.len(), |s| {
+ for (i, e) in self.iter().enumerate() {
+ try!(s.emit_seq_elt(i, |s| e.encode(s)));
+ }
+ Ok(())
+ })
+ }
+}
+
+impl<E, D:Decoder<E>,T:Decodable<D, E>> Decodable<D, E> for DList<T> {
+ fn decode(d: &mut D) -> Result<DList<T>, E> {
+ d.read_seq(|d, len| {
+ let mut list = DList::new();
+ for i in range(0u, len) {
+ list.push_back(try!(d.read_seq_elt(i, |d| Decodable::decode(d))));
+ }
+ Ok(list)
+ })
+ }
+}
+
+impl<
+ E,
+ S: Encoder<E>,
+ T: Encodable<S, E>
+> Encodable<S, E> for RingBuf<T> {
+ fn encode(&self, s: &mut S) -> Result<(), E> {
+ s.emit_seq(self.len(), |s| {
+ for (i, e) in self.iter().enumerate() {
+ try!(s.emit_seq_elt(i, |s| e.encode(s)));
+ }
+ Ok(())
+ })
+ }
+}
+
+impl<E, D:Decoder<E>,T:Decodable<D, E>> Decodable<D, E> for RingBuf<T> {
+ fn decode(d: &mut D) -> Result<RingBuf<T>, E> {
+ d.read_seq(|d, len| {
+ let mut deque: RingBuf<T> = RingBuf::new();
+ for i in range(0u, len) {
+ deque.push_back(try!(d.read_seq_elt(i, |d| Decodable::decode(d))));
+ }
+ Ok(deque)
+ })
+ }
+}
+
+impl<
+ E,
+ S: Encoder<E>,
+ K: Encodable<S, E> + PartialEq + Ord,
+ V: Encodable<S, E> + PartialEq
+> Encodable<S, E> for BTreeMap<K, V> {
+ fn encode(&self, e: &mut S) -> Result<(), E> {
+ e.emit_map(self.len(), |e| {
+ let mut i = 0;
+ for (key, val) in self.iter() {
+ try!(e.emit_map_elt_key(i, |e| key.encode(e)));
+ try!(e.emit_map_elt_val(i, |e| val.encode(e)));
+ i += 1;
+ }
+ Ok(())
+ })
+ }
+}
+
+impl<
+ E,
+ D: Decoder<E>,
+ K: Decodable<D, E> + PartialEq + Ord,
+ V: Decodable<D, E> + PartialEq
+> Decodable<D, E> for BTreeMap<K, V> {
+ fn decode(d: &mut D) -> Result<BTreeMap<K, V>, E> {
+ d.read_map(|d, len| {
+ let mut map = BTreeMap::new();
+ for i in range(0u, len) {
+ let key = try!(d.read_map_elt_key(i, |d| Decodable::decode(d)));
+ let val = try!(d.read_map_elt_val(i, |d| Decodable::decode(d)));
+ map.insert(key, val);
+ }
+ Ok(map)
+ })
+ }
+}
+
+impl<
+ E,
+ S: Encoder<E>,
+ T: Encodable<S, E> + PartialEq + Ord
+> Encodable<S, E> for BTreeSet<T> {
+ fn encode(&self, s: &mut S) -> Result<(), E> {
+ s.emit_seq(self.len(), |s| {
+ let mut i = 0;
+ for e in self.iter() {
+ try!(s.emit_seq_elt(i, |s| e.encode(s)));
+ i += 1;
+ }
+ Ok(())
+ })
+ }
+}
+
+impl<
+ E,
+ D: Decoder<E>,
+ T: Decodable<D, E> + PartialEq + Ord
+> Decodable<D, E> for BTreeSet<T> {
+ fn decode(d: &mut D) -> Result<BTreeSet<T>, E> {
+ d.read_seq(|d, len| {
+ let mut set = BTreeSet::new();
+ for i in range(0u, len) {
+ set.insert(try!(d.read_seq_elt(i, |d| Decodable::decode(d))));
+ }
+ Ok(set)
+ })
+ }
+}
+
+impl<
+ E,
+ S: Encoder<E>,
+ T: Encodable<S, E> + CLike
+> Encodable<S, E> for EnumSet<T> {
+ fn encode(&self, s: &mut S) -> Result<(), E> {
+ let mut bits = 0;
+ for item in self.iter() {
+ bits |= item.to_uint();
+ }
+ s.emit_uint(bits)
+ }
+}
+
+impl<
+ E,
+ D: Decoder<E>,
+ T: Decodable<D, E> + CLike
+> Decodable<D, E> for EnumSet<T> {
+ fn decode(d: &mut D) -> Result<EnumSet<T>, E> {
+ let bits = try!(d.read_uint());
+ let mut set = EnumSet::new();
+ for bit in range(0, uint::BITS) {
+ if bits & (1 << bit) != 0 {
+ set.insert(CLike::from_uint(1 << bit));
+ }
+ }
+ Ok(set)
+ }
+}
+
+impl<
+ E,
+ S: Encoder<E>,
+ K: Encodable<S, E> + Hash<X> + Eq,
+ V: Encodable<S, E>,
+ X,
+ H: Hasher<X>
+> Encodable<S, E> for HashMap<K, V, H> {
+ fn encode(&self, e: &mut S) -> Result<(), E> {
+ e.emit_map(self.len(), |e| {
+ let mut i = 0;
+ for (key, val) in self.iter() {
+ try!(e.emit_map_elt_key(i, |e| key.encode(e)));
+ try!(e.emit_map_elt_val(i, |e| val.encode(e)));
+ i += 1;
+ }
+ Ok(())
+ })
+ }
+}
+
+impl<
+ E,
+ D: Decoder<E>,
+ K: Decodable<D, E> + Hash<S> + Eq,
+ V: Decodable<D, E>,
+ S,
+ H: Hasher<S> + Default
+> Decodable<D, E> for HashMap<K, V, H> {
+ fn decode(d: &mut D) -> Result<HashMap<K, V, H>, E> {
+ d.read_map(|d, len| {
+ let hasher = Default::default();
+ let mut map = HashMap::with_capacity_and_hasher(len, hasher);
+ for i in range(0u, len) {
+ let key = try!(d.read_map_elt_key(i, |d| Decodable::decode(d)));
+ let val = try!(d.read_map_elt_val(i, |d| Decodable::decode(d)));
+ map.insert(key, val);
+ }
+ Ok(map)
+ })
+ }
+}
+
+impl<
+ E,
+ S: Encoder<E>,
+ T: Encodable<S, E> + Hash<X> + Eq,
+ X,
+ H: Hasher<X>
+> Encodable<S, E> for HashSet<T, H> {
+ fn encode(&self, s: &mut S) -> Result<(), E> {
+ s.emit_seq(self.len(), |s| {
+ let mut i = 0;
+ for e in self.iter() {
+ try!(s.emit_seq_elt(i, |s| e.encode(s)));
+ i += 1;
+ }
+ Ok(())
+ })
+ }
+}
+
+impl<
+ E,
+ D: Decoder<E>,
+ T: Decodable<D, E> + Hash<S> + Eq,
+ S,
+ H: Hasher<S> + Default
+> Decodable<D, E> for HashSet<T, H> {
+ fn decode(d: &mut D) -> Result<HashSet<T, H>, E> {
+ d.read_seq(|d, len| {
+ let mut set = HashSet::with_capacity_and_hasher(len, Default::default());
+ for i in range(0u, len) {
+ set.insert(try!(d.read_seq_elt(i, |d| Decodable::decode(d))));
+ }
+ Ok(set)
+ })
+ }
+}
+
+impl<
+ E,
+ S: Encoder<E>,
+ V: Encodable<S, E>
+> Encodable<S, E> for VecMap<V> {
+ fn encode(&self, e: &mut S) -> Result<(), E> {
+ e.emit_map(self.len(), |e| {
+ for (i, (key, val)) in self.iter().enumerate() {
+ try!(e.emit_map_elt_key(i, |e| key.encode(e)));
+ try!(e.emit_map_elt_val(i, |e| val.encode(e)));
+ }
+ Ok(())
+ })
+ }
+}
+
+impl<
+ E,
+ D: Decoder<E>,
+ V: Decodable<D, E>
+> Decodable<D, E> for VecMap<V> {
+ fn decode(d: &mut D) -> Result<VecMap<V>, E> {
+ d.read_map(|d, len| {
+ let mut map = VecMap::new();
+ for i in range(0u, len) {
+ let key = try!(d.read_map_elt_key(i, |d| Decodable::decode(d)));
+ let val = try!(d.read_map_elt_val(i, |d| Decodable::decode(d)));
+ map.insert(key, val);
+ }
+ Ok(map)
+ })
+ }
+}
}
/// Shortcut function to decode a JSON `&str` into an object
-pub fn decode<T: ::Decodable<Decoder, DecoderError>>(s: &str) -> DecodeResult<T> {
+pub fn decode<T: ::Decodable>(s: &str) -> DecodeResult<T> {
let json = match from_str(s) {
Ok(x) => x,
Err(e) => return Err(ParseError(e))
}
/// Shortcut function to encode a `T` into a JSON `String`
-pub fn encode<T>(object: &T) -> string::String
- where T: for<'a> Encodable<Encoder<'a>, fmt::Error>
-{
+pub fn encode<T: ::Encodable>(object: &T) -> string::String {
let mut s = String::new();
{
let mut encoder = Encoder::new(&mut s);
}
}
-impl<'a> ::Encoder<fmt::Error> for Encoder<'a> {
+impl<'a> ::Encoder for Encoder<'a> {
+ type Error = fmt::Error;
+
fn emit_nil(&mut self) -> EncodeResult { write!(self.writer, "null") }
fn emit_uint(&mut self, v: uint) -> EncodeResult { write!(self.writer, "{}", v) }
}
}
-impl<'a> ::Encoder<fmt::Error> for PrettyEncoder<'a> {
+impl<'a> ::Encoder for PrettyEncoder<'a> {
+ type Error = fmt::Error;
+
fn emit_nil(&mut self) -> EncodeResult { write!(self.writer, "null") }
fn emit_uint(&mut self, v: uint) -> EncodeResult { write!(self.writer, "{}", v) }
}
}
-impl<E: ::Encoder<S>, S> Encodable<E, S> for Json {
- fn encode(&self, e: &mut E) -> Result<(), S> {
+impl Encodable for Json {
+ fn encode<E: ::Encoder>(&self, e: &mut E) -> Result<(), E::Error> {
match *self {
Json::I64(v) => v.encode(e),
Json::U64(v) => v.encode(e),
}
}
-// NOTE(stage0): remove impl after a snapshot
-#[cfg(stage0)]
-impl<'a> ops::Index<&'a str, Json> for Json {
- fn index(&self, idx: & &str) -> &Json {
- self.find(*idx).unwrap()
- }
-}
-
-#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot
impl<'a> ops::Index<&'a str> for Json {
type Output = Json;
}
}
-// NOTE(stage0): remove impl after a snapshot
-#[cfg(stage0)]
-impl ops::Index<uint, Json> for Json {
- fn index<'a>(&'a self, idx: &uint) -> &'a Json {
- match self {
- &Json::Array(ref v) => v.index(idx),
- _ => panic!("can only index Json with uint if it is an array")
- }
- }
-}
-
-#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot
impl ops::Index<uint> for Json {
type Output = Json;
}
}
-impl ::Decoder<DecoderError> for Decoder {
+impl ::Decoder for Decoder {
+ type Error = DecoderError;
+
fn read_nil(&mut self) -> DecodeResult<()> {
expect!(self.pop(), Null)
}
}
}
-impl<'a, T> fmt::Show for AsJson<'a, T>
- where T: for<'b> Encodable<Encoder<'b>, fmt::Error>
-{
+impl<'a, T: Encodable> fmt::Show for AsJson<'a, T> {
/// Encodes a json value into a string
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut shim = FormatShim { inner: f };
}
}
-impl<'a, T> fmt::Show for AsPrettyJson<'a, T>
- where T: for<'b> Encodable<PrettyEncoder<'b>, fmt::Error>
-{
+impl<'a, T: Encodable> fmt::Show for AsPrettyJson<'a, T> {
/// Encodes a json value into a string
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut shim = FormatShim { inner: f };
A(f64),
B(string::String)
}
- fn check_err<T: Decodable<Decoder, DecoderError>>(to_parse: &'static str,
- expected: DecoderError) {
+ fn check_err<T: Decodable>(to_parse: &'static str, expected: DecoderError) {
let res: DecodeResult<T> = match from_str(to_parse) {
Err(e) => Err(ParseError(e)),
Ok(json) => Decodable::decode(&mut Decoder::new(json))
--- /dev/null
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Rust JSON serialization library
+// Copyright (c) 2011 Google Inc.
+
+#![forbid(non_camel_case_types)]
+#![allow(missing_docs)]
+
+//! JSON parsing and serialization
+//!
+//! # What is JSON?
+//!
+//! JSON (JavaScript Object Notation) is a way to write data in Javascript.
+//! Like XML, it allows to encode structured data in a text format that can be easily read by humans
+//! Its simple syntax and native compatibility with JavaScript have made it a widely used format.
+//!
+//! Data types that can be encoded are JavaScript types (see the `Json` enum for more details):
+//!
+//! * `Boolean`: equivalent to rust's `bool`
+//! * `Number`: equivalent to rust's `f64`
+//! * `String`: equivalent to rust's `String`
+//! * `Array`: equivalent to rust's `Vec<T>`, but also allowing objects of different types in the
+//! same array
+//! * `Object`: equivalent to rust's `BTreeMap<String, json::Json>`
+//! * `Null`
+//!
+//! An object is a series of string keys mapping to values, in `"key": value` format.
+//! Arrays are enclosed in square brackets ([ ... ]) and objects in curly brackets ({ ... }).
+//! A simple JSON document encoding a person, his/her age, address and phone numbers could look like
+//!
+//! ```ignore
+//! {
+//! "FirstName": "John",
+//! "LastName": "Doe",
+//! "Age": 43,
+//! "Address": {
+//! "Street": "Downing Street 10",
+//! "City": "London",
+//! "Country": "Great Britain"
+//! },
+//! "PhoneNumbers": [
+//! "+44 1234567",
+//! "+44 2345678"
+//! ]
+//! }
+//! ```
+//!
+//! # Rust Type-based Encoding and Decoding
+//!
+//! Rust provides a mechanism for low boilerplate encoding & decoding of values to and from JSON via
+//! the serialization API.
+//! To be able to encode a piece of data, it must implement the `serialize::RustcEncodable` trait.
+//! To be able to decode a piece of data, it must implement the `serialize::RustcDecodable` trait.
+//! The Rust compiler provides an annotation to automatically generate the code for these traits:
+//! `#[derive(RustcDecodable, RustcEncodable)]`
+//!
+//! The JSON API provides an enum `json::Json` and a trait `ToJson` to encode objects.
+//! The `ToJson` trait provides a `to_json` method to convert an object into a `json::Json` value.
+//! A `json::Json` value can be encoded as a string or buffer using the functions described above.
+//! You can also use the `json::Encoder` object, which implements the `Encoder` trait.
+//!
+//! When using `ToJson` the `RustcEncodable` trait implementation is not mandatory.
+//!
+//! # Examples of use
+//!
+//! ## Using Autoserialization
+//!
+//! Create a struct called `TestStruct` and serialize and deserialize it to and from JSON using the
+//! serialization API, using the derived serialization code.
+//!
+//! ```notrust
+//! // FIXME(#19470): this cannot be ```rust``` because it fails orphan checking at the moment
+//! extern crate serialize;
+//! use serialize::json;
+//!
+//! // Automatically generate `Decodable` and `Encodable` trait implementations
+//! #[derive(RustcDecodable, RustcEncodable)]
+//! pub struct TestStruct {
+//! data_int: u8,
+//! data_str: String,
+//! data_vector: Vec<u8>,
+//! }
+//!
+//! fn main() {
+//! let object = TestStruct {
+//! data_int: 1,
+//! data_str: "homura".to_string(),
+//! data_vector: vec![2,3,4,5],
+//! };
+//!
+//! // Serialize using `json::encode`
+//! let encoded = json::encode(&object);
+//!
+//! // Deserialize using `json::decode`
+//! let decoded: TestStruct = json::decode(encoded.as_slice()).unwrap();
+//! }
+//! ```
+//!
+//! ## Using the `ToJson` trait
+//!
+//! The examples above use the `ToJson` trait to generate the JSON string, which is required
+//! for custom mappings.
+//!
+//! ### Simple example of `ToJson` usage
+//!
+//! ```notrust
+//! // FIXME(#19470): this cannot be ```rust``` because it fails orphan checking at the moment
+//! extern crate serialize;
+//! use serialize::json::{mod, ToJson, Json};
+//!
+//! // A custom data structure
+//! struct ComplexNum {
+//! a: f64,
+//! b: f64,
+//! }
+//!
+//! // JSON value representation
+//! impl ToJson for ComplexNum {
+//! fn to_json(&self) -> Json {
+//! Json::String(format!("{}+{}i", self.a, self.b))
+//! }
+//! }
+//!
+//! // Only generate `RustcEncodable` trait implementation
+//! #[derive(Encodable)]
+//! pub struct ComplexNumRecord {
+//! uid: u8,
+//! dsc: String,
+//! val: Json,
+//! }
+//!
+//! fn main() {
+//! let num = ComplexNum { a: 0.0001, b: 12.539 };
+//! let data: String = json::encode(&ComplexNumRecord{
+//! uid: 1,
+//! dsc: "test".to_string(),
+//! val: num.to_json(),
+//! });
+//! println!("data: {}", data);
+//! // data: {"uid":1,"dsc":"test","val":"0.0001+12.539j"};
+//! }
+//! ```
+//!
+//! ### Verbose example of `ToJson` usage
+//!
+//! ```notrust
+//! // FIXME(#19470): this cannot be ```rust``` because it fails orphan checking at the moment
+//! extern crate serialize;
+//! use std::collections::BTreeMap;
+//! use serialize::json::{mod, Json, ToJson};
+//!
+//! // Only generate `Decodable` trait implementation
+//! #[derive(Decodable)]
+//! pub struct TestStruct {
+//! data_int: u8,
+//! data_str: String,
+//! data_vector: Vec<u8>,
+//! }
+//!
+//! // Specify encoding method manually
+//! impl ToJson for TestStruct {
+//! fn to_json(&self) -> Json {
+//! let mut d = BTreeMap::new();
+//! // All standard types implement `to_json()`, so use it
+//! d.insert("data_int".to_string(), self.data_int.to_json());
+//! d.insert("data_str".to_string(), self.data_str.to_json());
+//! d.insert("data_vector".to_string(), self.data_vector.to_json());
+//! Json::Object(d)
+//! }
+//! }
+//!
+//! fn main() {
+//! // Serialize using `ToJson`
+//! let input_data = TestStruct {
+//! data_int: 1,
+//! data_str: "madoka".to_string(),
+//! data_vector: vec![2,3,4,5],
+//! };
+//! let json_obj: Json = input_data.to_json();
+//! let json_str: String = json_obj.to_string();
+//!
+//! // Deserialize like before
+//! let decoded: TestStruct = json::decode(json_str.as_slice()).unwrap();
+//! }
+//! ```
+
+use self::JsonEvent::*;
+use self::StackElement::*;
+use self::ErrorCode::*;
+use self::ParserError::*;
+use self::DecoderError::*;
+use self::ParserState::*;
+use self::InternalStackElement::*;
+
+use std;
+use std::collections::{HashMap, BTreeMap};
+use std::{char, f64, fmt, io, num, str};
+use std::mem::{swap, transmute};
+use std::num::{Float, Int};
+use std::num::FpCategory as Fp;
+use std::str::FromStr;
+use std::string;
+use std::ops;
+use unicode::str as unicode_str;
+use unicode::str::Utf16Item;
+
+use Encodable;
+
+/// Represents a json value
+#[derive(Clone, PartialEq, PartialOrd)]
+pub enum Json {
+ I64(i64),
+ U64(u64),
+ F64(f64),
+ String(string::String),
+ Boolean(bool),
+ Array(self::Array),
+ Object(self::Object),
+ Null,
+}
+
+pub type Array = Vec<Json>;
+pub type Object = BTreeMap<string::String, Json>;
+
+pub struct PrettyJson<'a> { inner: &'a Json }
+
+pub struct AsJson<'a, T: 'a> { inner: &'a T }
+pub struct AsPrettyJson<'a, T: 'a> { inner: &'a T, indent: Option<uint> }
+
+/// The errors that can arise while parsing a JSON stream.
+#[derive(Clone, Copy, PartialEq)]
+pub enum ErrorCode {
+ InvalidSyntax,
+ InvalidNumber,
+ EOFWhileParsingObject,
+ EOFWhileParsingArray,
+ EOFWhileParsingValue,
+ EOFWhileParsingString,
+ KeyMustBeAString,
+ ExpectedColon,
+ TrailingCharacters,
+ TrailingComma,
+ InvalidEscape,
+ InvalidUnicodeCodePoint,
+ LoneLeadingSurrogateInHexEscape,
+ UnexpectedEndOfHexEscape,
+ UnrecognizedHex,
+ NotFourDigit,
+ NotUtf8,
+}
+
+#[derive(Clone, Copy, PartialEq, Show)]
+pub enum ParserError {
+ /// msg, line, col
+ SyntaxError(ErrorCode, uint, uint),
+ IoError(io::IoErrorKind, &'static str),
+}
+
+// Builder and Parser have the same errors.
+pub type BuilderError = ParserError;
+
+#[derive(Clone, PartialEq, Show)]
+pub enum DecoderError {
+ ParseError(ParserError),
+ ExpectedError(string::String, string::String),
+ MissingFieldError(string::String),
+ UnknownVariantError(string::String),
+ ApplicationError(string::String)
+}
+
+/// Returns a readable error string for a given error code.
+pub fn error_str(error: ErrorCode) -> &'static str {
+ match error {
+ InvalidSyntax => "invalid syntax",
+ InvalidNumber => "invalid number",
+ EOFWhileParsingObject => "EOF While parsing object",
+ EOFWhileParsingArray => "EOF While parsing array",
+ EOFWhileParsingValue => "EOF While parsing value",
+ EOFWhileParsingString => "EOF While parsing string",
+ KeyMustBeAString => "key must be a string",
+ ExpectedColon => "expected `:`",
+ TrailingCharacters => "trailing characters",
+ TrailingComma => "trailing comma",
+ InvalidEscape => "invalid escape",
+ UnrecognizedHex => "invalid \\u{ esc}ape (unrecognized hex)",
+ NotFourDigit => "invalid \\u{ esc}ape (not four digits)",
+ NotUtf8 => "contents not utf-8",
+ InvalidUnicodeCodePoint => "invalid Unicode code point",
+ LoneLeadingSurrogateInHexEscape => "lone leading surrogate in hex escape",
+ UnexpectedEndOfHexEscape => "unexpected end of hex escape",
+ }
+}
+
+/// Shortcut function to decode a JSON `&str` into an object
+pub fn decode<T: ::Decodable<Decoder, DecoderError>>(s: &str) -> DecodeResult<T> {
+ let json = match from_str(s) {
+ Ok(x) => x,
+ Err(e) => return Err(ParseError(e))
+ };
+
+ let mut decoder = Decoder::new(json);
+ ::Decodable::decode(&mut decoder)
+}
+
+/// Shortcut function to encode a `T` into a JSON `String`
+pub fn encode<T>(object: &T) -> string::String
+ where T: for<'a> Encodable<Encoder<'a>, fmt::Error>
+{
+ let mut s = String::new();
+ {
+ let mut encoder = Encoder::new(&mut s);
+ let _ = object.encode(&mut encoder);
+ }
+ s
+}
+
+impl fmt::Show for ErrorCode {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ error_str(*self).fmt(f)
+ }
+}
+
+fn io_error_to_error(io: io::IoError) -> ParserError {
+ IoError(io.kind, io.desc)
+}
+
+impl std::error::Error for DecoderError {
+ fn description(&self) -> &str { "decoder error" }
+ fn detail(&self) -> Option<std::string::String> { Some(self.to_string()) }
+}
+
+pub type EncodeResult = fmt::Result;
+pub type DecodeResult<T> = Result<T, DecoderError>;
+
+fn escape_str(wr: &mut fmt::Writer, v: &str) -> fmt::Result {
+ try!(wr.write_str("\""));
+
+ let mut start = 0;
+
+ for (i, byte) in v.bytes().enumerate() {
+ let escaped = match byte {
+ b'"' => "\\\"",
+ b'\\' => "\\\\",
+ b'\x00' => "\\u0000",
+ b'\x01' => "\\u0001",
+ b'\x02' => "\\u0002",
+ b'\x03' => "\\u0003",
+ b'\x04' => "\\u0004",
+ b'\x05' => "\\u0005",
+ b'\x06' => "\\u0006",
+ b'\x07' => "\\u0007",
+ b'\x08' => "\\b",
+ b'\t' => "\\t",
+ b'\n' => "\\n",
+ b'\x0b' => "\\u000b",
+ b'\x0c' => "\\f",
+ b'\r' => "\\r",
+ b'\x0e' => "\\u000e",
+ b'\x0f' => "\\u000f",
+ b'\x10' => "\\u0010",
+ b'\x11' => "\\u0011",
+ b'\x12' => "\\u0012",
+ b'\x13' => "\\u0013",
+ b'\x14' => "\\u0014",
+ b'\x15' => "\\u0015",
+ b'\x16' => "\\u0016",
+ b'\x17' => "\\u0017",
+ b'\x18' => "\\u0018",
+ b'\x19' => "\\u0019",
+ b'\x1a' => "\\u001a",
+ b'\x1b' => "\\u001b",
+ b'\x1c' => "\\u001c",
+ b'\x1d' => "\\u001d",
+ b'\x1e' => "\\u001e",
+ b'\x1f' => "\\u001f",
+ b'\x7f' => "\\u007f",
+ _ => { continue; }
+ };
+
+ if start < i {
+ try!(wr.write_str(v[start..i]));
+ }
+
+ try!(wr.write_str(escaped));
+
+ start = i + 1;
+ }
+
+ if start != v.len() {
+ try!(wr.write_str(v[start..]));
+ }
+
+ wr.write_str("\"")
+}
+
+fn escape_char(writer: &mut fmt::Writer, v: char) -> fmt::Result {
+ let mut buf = [0; 4];
+ let n = v.encode_utf8(&mut buf).unwrap();
+ let buf = unsafe { str::from_utf8_unchecked(buf[0..n]) };
+ escape_str(writer, buf)
+}
+
+fn spaces(wr: &mut fmt::Writer, mut n: uint) -> fmt::Result {
+ const BUF: &'static str = " ";
+
+ while n >= BUF.len() {
+ try!(wr.write_str(BUF));
+ n -= BUF.len();
+ }
+
+ if n > 0 {
+ wr.write_str(BUF[..n])
+ } else {
+ Ok(())
+ }
+}
+
+fn fmt_number_or_null(v: f64) -> string::String {
+ match v.classify() {
+ Fp::Nan | Fp::Infinite => string::String::from_str("null"),
+ _ if v.fract() != 0f64 => f64::to_str_digits(v, 6u),
+ _ => f64::to_str_digits(v, 6u) + ".0",
+ }
+}
+
+/// A structure for implementing serialization to JSON.
+pub struct Encoder<'a> {
+ writer: &'a mut (fmt::Writer+'a),
+}
+
+impl<'a> Encoder<'a> {
+ /// Creates a new JSON encoder whose output will be written to the writer
+ /// specified.
+ pub fn new(writer: &'a mut fmt::Writer) -> Encoder<'a> {
+ Encoder { writer: writer }
+ }
+}
+
+impl<'a> ::Encoder<fmt::Error> for Encoder<'a> {
+ fn emit_nil(&mut self) -> EncodeResult { write!(self.writer, "null") }
+
+ fn emit_uint(&mut self, v: uint) -> EncodeResult { write!(self.writer, "{}", v) }
+ fn emit_u64(&mut self, v: u64) -> EncodeResult { write!(self.writer, "{}", v) }
+ fn emit_u32(&mut self, v: u32) -> EncodeResult { write!(self.writer, "{}", v) }
+ fn emit_u16(&mut self, v: u16) -> EncodeResult { write!(self.writer, "{}", v) }
+ fn emit_u8(&mut self, v: u8) -> EncodeResult { write!(self.writer, "{}", v) }
+
+ fn emit_int(&mut self, v: int) -> EncodeResult { write!(self.writer, "{}", v) }
+ fn emit_i64(&mut self, v: i64) -> EncodeResult { write!(self.writer, "{}", v) }
+ fn emit_i32(&mut self, v: i32) -> EncodeResult { write!(self.writer, "{}", v) }
+ fn emit_i16(&mut self, v: i16) -> EncodeResult { write!(self.writer, "{}", v) }
+ fn emit_i8(&mut self, v: i8) -> EncodeResult { write!(self.writer, "{}", v) }
+
+ fn emit_bool(&mut self, v: bool) -> EncodeResult {
+ if v {
+ write!(self.writer, "true")
+ } else {
+ write!(self.writer, "false")
+ }
+ }
+
+ fn emit_f64(&mut self, v: f64) -> EncodeResult {
+ write!(self.writer, "{}", fmt_number_or_null(v))
+ }
+ fn emit_f32(&mut self, v: f32) -> EncodeResult {
+ self.emit_f64(v as f64)
+ }
+
+ fn emit_char(&mut self, v: char) -> EncodeResult {
+ escape_char(self.writer, v)
+ }
+ fn emit_str(&mut self, v: &str) -> EncodeResult {
+ escape_str(self.writer, v)
+ }
+
+ fn emit_enum<F>(&mut self, _name: &str, f: F) -> EncodeResult where
+ F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ {
+ f(self)
+ }
+
+ fn emit_enum_variant<F>(&mut self,
+ name: &str,
+ _id: uint,
+ cnt: uint,
+ f: F) -> EncodeResult where
+ F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ {
+ // enums are encoded as strings or objects
+ // Bunny => "Bunny"
+ // Kangaroo(34,"William") => {"variant": "Kangaroo", "fields": [34,"William"]}
+ if cnt == 0 {
+ escape_str(self.writer, name)
+ } else {
+ try!(write!(self.writer, "{{\"variant\":"));
+ try!(escape_str(self.writer, name));
+ try!(write!(self.writer, ",\"fields\":["));
+ try!(f(self));
+ write!(self.writer, "]}}")
+ }
+ }
+
+ fn emit_enum_variant_arg<F>(&mut self, idx: uint, f: F) -> EncodeResult where
+ F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ {
+ if idx != 0 {
+ try!(write!(self.writer, ","));
+ }
+ f(self)
+ }
+
+ fn emit_enum_struct_variant<F>(&mut self,
+ name: &str,
+ id: uint,
+ cnt: uint,
+ f: F) -> EncodeResult where
+ F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ {
+ self.emit_enum_variant(name, id, cnt, f)
+ }
+
+ fn emit_enum_struct_variant_field<F>(&mut self,
+ _: &str,
+ idx: uint,
+ f: F) -> EncodeResult where
+ F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ {
+ self.emit_enum_variant_arg(idx, f)
+ }
+
+ fn emit_struct<F>(&mut self, _: &str, _: uint, f: F) -> EncodeResult where
+ F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ {
+ try!(write!(self.writer, "{{"));
+ try!(f(self));
+ write!(self.writer, "}}")
+ }
+
+ fn emit_struct_field<F>(&mut self, name: &str, idx: uint, f: F) -> EncodeResult where
+ F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ {
+ if idx != 0 { try!(write!(self.writer, ",")); }
+ try!(escape_str(self.writer, name));
+ try!(write!(self.writer, ":"));
+ f(self)
+ }
+
+ fn emit_tuple<F>(&mut self, len: uint, f: F) -> EncodeResult where
+ F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ {
+ self.emit_seq(len, f)
+ }
+ fn emit_tuple_arg<F>(&mut self, idx: uint, f: F) -> EncodeResult where
+ F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ {
+ self.emit_seq_elt(idx, f)
+ }
+
+ fn emit_tuple_struct<F>(&mut self, _name: &str, len: uint, f: F) -> EncodeResult where
+ F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ {
+ self.emit_seq(len, f)
+ }
+ fn emit_tuple_struct_arg<F>(&mut self, idx: uint, f: F) -> EncodeResult where
+ F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ {
+ self.emit_seq_elt(idx, f)
+ }
+
+ fn emit_option<F>(&mut self, f: F) -> EncodeResult where
+ F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ {
+ f(self)
+ }
+ fn emit_option_none(&mut self) -> EncodeResult { self.emit_nil() }
+ fn emit_option_some<F>(&mut self, f: F) -> EncodeResult where
+ F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ {
+ f(self)
+ }
+
+ fn emit_seq<F>(&mut self, _len: uint, f: F) -> EncodeResult where
+ F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ {
+ try!(write!(self.writer, "["));
+ try!(f(self));
+ write!(self.writer, "]")
+ }
+
+ fn emit_seq_elt<F>(&mut self, idx: uint, f: F) -> EncodeResult where
+ F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ {
+ if idx != 0 {
+ try!(write!(self.writer, ","));
+ }
+ f(self)
+ }
+
+ fn emit_map<F>(&mut self, _len: uint, f: F) -> EncodeResult where
+ F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ {
+ try!(write!(self.writer, "{{"));
+ try!(f(self));
+ write!(self.writer, "}}")
+ }
+
+ fn emit_map_elt_key<F>(&mut self, idx: uint, mut f: F) -> EncodeResult where
+ F: FnMut(&mut Encoder<'a>) -> EncodeResult,
+ {
+ if idx != 0 { try!(write!(self.writer, ",")) }
+ // ref #12967, make sure to wrap a key in double quotes,
+ // in the event that its of a type that omits them (eg numbers)
+ let mut buf = Vec::new();
+ // FIXME(14302) remove the transmute and unsafe block.
+ unsafe {
+ let mut check_encoder = Encoder::new(&mut buf);
+ try!(f(transmute(&mut check_encoder)));
+ }
+ let out = str::from_utf8(buf[]).unwrap();
+ let needs_wrapping = out.char_at(0) != '"' && out.char_at_reverse(out.len()) != '"';
+ if needs_wrapping { try!(write!(self.writer, "\"")); }
+ try!(f(self));
+ if needs_wrapping { try!(write!(self.writer, "\"")); }
+ Ok(())
+ }
+
+ fn emit_map_elt_val<F>(&mut self, _idx: uint, f: F) -> EncodeResult where
+ F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
+ {
+ try!(write!(self.writer, ":"));
+ f(self)
+ }
+}
+
+/// Another encoder for JSON, but prints out human-readable JSON instead of
+/// compact data
+pub struct PrettyEncoder<'a> {
+ writer: &'a mut (fmt::Writer+'a),
+ curr_indent: uint,
+ indent: uint,
+}
+
+impl<'a> PrettyEncoder<'a> {
+ /// Creates a new encoder whose output will be written to the specified writer
+ pub fn new(writer: &'a mut fmt::Writer) -> PrettyEncoder<'a> {
+ PrettyEncoder { writer: writer, curr_indent: 0, indent: 2, }
+ }
+
+ /// Set the number of spaces to indent for each level.
+ /// This is safe to set during encoding.
+ pub fn set_indent(&mut self, indent: uint) {
+ // self.indent very well could be 0 so we need to use checked division.
+ let level = self.curr_indent.checked_div(self.indent).unwrap_or(0);
+ self.indent = indent;
+ self.curr_indent = level * self.indent;
+ }
+}
+
+impl<'a> ::Encoder<fmt::Error> for PrettyEncoder<'a> {
+ fn emit_nil(&mut self) -> EncodeResult { write!(self.writer, "null") }
+
+ fn emit_uint(&mut self, v: uint) -> EncodeResult { write!(self.writer, "{}", v) }
+ fn emit_u64(&mut self, v: u64) -> EncodeResult { write!(self.writer, "{}", v) }
+ fn emit_u32(&mut self, v: u32) -> EncodeResult { write!(self.writer, "{}", v) }
+ fn emit_u16(&mut self, v: u16) -> EncodeResult { write!(self.writer, "{}", v) }
+ fn emit_u8(&mut self, v: u8) -> EncodeResult { write!(self.writer, "{}", v) }
+
+ fn emit_int(&mut self, v: int) -> EncodeResult { write!(self.writer, "{}", v) }
+ fn emit_i64(&mut self, v: i64) -> EncodeResult { write!(self.writer, "{}", v) }
+ fn emit_i32(&mut self, v: i32) -> EncodeResult { write!(self.writer, "{}", v) }
+ fn emit_i16(&mut self, v: i16) -> EncodeResult { write!(self.writer, "{}", v) }
+ fn emit_i8(&mut self, v: i8) -> EncodeResult { write!(self.writer, "{}", v) }
+
+ fn emit_bool(&mut self, v: bool) -> EncodeResult {
+ if v {
+ write!(self.writer, "true")
+ } else {
+ write!(self.writer, "false")
+ }
+ }
+
+ fn emit_f64(&mut self, v: f64) -> EncodeResult {
+ write!(self.writer, "{}", fmt_number_or_null(v))
+ }
+ fn emit_f32(&mut self, v: f32) -> EncodeResult {
+ self.emit_f64(v as f64)
+ }
+
+ fn emit_char(&mut self, v: char) -> EncodeResult {
+ escape_char(self.writer, v)
+ }
+ fn emit_str(&mut self, v: &str) -> EncodeResult {
+ escape_str(self.writer, v)
+ }
+
+ fn emit_enum<F>(&mut self, _name: &str, f: F) -> EncodeResult where
+ F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
+ {
+ f(self)
+ }
+
+ fn emit_enum_variant<F>(&mut self,
+ name: &str,
+ _id: uint,
+ cnt: uint,
+ f: F)
+ -> EncodeResult where
+ F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
+ {
+ if cnt == 0 {
+ escape_str(self.writer, name)
+ } else {
+ try!(write!(self.writer, "{{\n"));
+ self.curr_indent += self.indent;
+ try!(spaces(self.writer, self.curr_indent));
+ try!(write!(self.writer, "\"variant\": "));
+ try!(escape_str(self.writer, name));
+ try!(write!(self.writer, ",\n"));
+ try!(spaces(self.writer, self.curr_indent));
+ try!(write!(self.writer, "\"fields\": [\n"));
+ self.curr_indent += self.indent;
+ try!(f(self));
+ self.curr_indent -= self.indent;
+ try!(write!(self.writer, "\n"));
+ try!(spaces(self.writer, self.curr_indent));
+ self.curr_indent -= self.indent;
+ try!(write!(self.writer, "]\n"));
+ try!(spaces(self.writer, self.curr_indent));
+ write!(self.writer, "}}")
+ }
+ }
+
+ fn emit_enum_variant_arg<F>(&mut self, idx: uint, f: F) -> EncodeResult where
+ F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
+ {
+ if idx != 0 {
+ try!(write!(self.writer, ",\n"));
+ }
+ try!(spaces(self.writer, self.curr_indent));
+ f(self)
+ }
+
+ fn emit_enum_struct_variant<F>(&mut self,
+ name: &str,
+ id: uint,
+ cnt: uint,
+ f: F) -> EncodeResult where
+ F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
+ {
+ self.emit_enum_variant(name, id, cnt, f)
+ }
+
+ fn emit_enum_struct_variant_field<F>(&mut self,
+ _: &str,
+ idx: uint,
+ f: F) -> EncodeResult where
+ F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
+ {
+ self.emit_enum_variant_arg(idx, f)
+ }
+
+
+ fn emit_struct<F>(&mut self, _: &str, len: uint, f: F) -> EncodeResult where
+ F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
+ {
+ if len == 0 {
+ write!(self.writer, "{{}}")
+ } else {
+ try!(write!(self.writer, "{{"));
+ self.curr_indent += self.indent;
+ try!(f(self));
+ self.curr_indent -= self.indent;
+ try!(write!(self.writer, "\n"));
+ try!(spaces(self.writer, self.curr_indent));
+ write!(self.writer, "}}")
+ }
+ }
+
+ fn emit_struct_field<F>(&mut self, name: &str, idx: uint, f: F) -> EncodeResult where
+ F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
+ {
+ if idx == 0 {
+ try!(write!(self.writer, "\n"));
+ } else {
+ try!(write!(self.writer, ",\n"));
+ }
+ try!(spaces(self.writer, self.curr_indent));
+ try!(escape_str(self.writer, name));
+ try!(write!(self.writer, ": "));
+ f(self)
+ }
+
+ fn emit_tuple<F>(&mut self, len: uint, f: F) -> EncodeResult where
+ F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
+ {
+ self.emit_seq(len, f)
+ }
+ fn emit_tuple_arg<F>(&mut self, idx: uint, f: F) -> EncodeResult where
+ F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
+ {
+ self.emit_seq_elt(idx, f)
+ }
+
+ fn emit_tuple_struct<F>(&mut self, _: &str, len: uint, f: F) -> EncodeResult where
+ F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
+ {
+ self.emit_seq(len, f)
+ }
+ fn emit_tuple_struct_arg<F>(&mut self, idx: uint, f: F) -> EncodeResult where
+ F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
+ {
+ self.emit_seq_elt(idx, f)
+ }
+
+ fn emit_option<F>(&mut self, f: F) -> EncodeResult where
+ F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
+ {
+ f(self)
+ }
+ fn emit_option_none(&mut self) -> EncodeResult { self.emit_nil() }
+ fn emit_option_some<F>(&mut self, f: F) -> EncodeResult where
+ F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
+ {
+ f(self)
+ }
+
+ fn emit_seq<F>(&mut self, len: uint, f: F) -> EncodeResult where
+ F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
+ {
+ if len == 0 {
+ write!(self.writer, "[]")
+ } else {
+ try!(write!(self.writer, "["));
+ self.curr_indent += self.indent;
+ try!(f(self));
+ self.curr_indent -= self.indent;
+ try!(write!(self.writer, "\n"));
+ try!(spaces(self.writer, self.curr_indent));
+ write!(self.writer, "]")
+ }
+ }
+
+ fn emit_seq_elt<F>(&mut self, idx: uint, f: F) -> EncodeResult where
+ F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
+ {
+ if idx == 0 {
+ try!(write!(self.writer, "\n"));
+ } else {
+ try!(write!(self.writer, ",\n"));
+ }
+ try!(spaces(self.writer, self.curr_indent));
+ f(self)
+ }
+
+ fn emit_map<F>(&mut self, len: uint, f: F) -> EncodeResult where
+ F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
+ {
+ if len == 0 {
+ write!(self.writer, "{{}}")
+ } else {
+ try!(write!(self.writer, "{{"));
+ self.curr_indent += self.indent;
+ try!(f(self));
+ self.curr_indent -= self.indent;
+ try!(write!(self.writer, "\n"));
+ try!(spaces(self.writer, self.curr_indent));
+ write!(self.writer, "}}")
+ }
+ }
+
+ fn emit_map_elt_key<F>(&mut self, idx: uint, mut f: F) -> EncodeResult where
+ F: FnMut(&mut PrettyEncoder<'a>) -> EncodeResult,
+ {
+ if idx == 0 {
+ try!(write!(self.writer, "\n"));
+ } else {
+ try!(write!(self.writer, ",\n"));
+ }
+ try!(spaces(self.writer, self.curr_indent));
+ // ref #12967, make sure to wrap a key in double quotes,
+ // in the event that its of a type that omits them (eg numbers)
+ let mut buf = Vec::new();
+ // FIXME(14302) remove the transmute and unsafe block.
+ unsafe {
+ let mut check_encoder = PrettyEncoder::new(&mut buf);
+ try!(f(transmute(&mut check_encoder)));
+ }
+ let out = str::from_utf8(buf[]).unwrap();
+ let needs_wrapping = out.char_at(0) != '"' && out.char_at_reverse(out.len()) != '"';
+ if needs_wrapping { try!(write!(self.writer, "\"")); }
+ try!(f(self));
+ if needs_wrapping { try!(write!(self.writer, "\"")); }
+ Ok(())
+ }
+
+ fn emit_map_elt_val<F>(&mut self, _idx: uint, f: F) -> EncodeResult where
+ F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
+ {
+ try!(write!(self.writer, ": "));
+ f(self)
+ }
+}
+
+impl<E: ::Encoder<S>, S> Encodable<E, S> for Json {
+ fn encode(&self, e: &mut E) -> Result<(), S> {
+ match *self {
+ Json::I64(v) => v.encode(e),
+ Json::U64(v) => v.encode(e),
+ Json::F64(v) => v.encode(e),
+ Json::String(ref v) => v.encode(e),
+ Json::Boolean(v) => v.encode(e),
+ Json::Array(ref v) => v.encode(e),
+ Json::Object(ref v) => v.encode(e),
+ Json::Null => e.emit_nil(),
+ }
+ }
+}
+
+/// Create an `AsJson` wrapper which can be used to print a value as JSON
+/// on-the-fly via `write!`
+pub fn as_json<T>(t: &T) -> AsJson<T> {
+ AsJson { inner: t }
+}
+
+/// Create an `AsPrettyJson` wrapper which can be used to print a value as JSON
+/// on-the-fly via `write!`
+pub fn as_pretty_json<T>(t: &T) -> AsPrettyJson<T> {
+ AsPrettyJson { inner: t, indent: None }
+}
+
+impl Json {
+ /// Borrow this json object as a pretty object to generate a pretty
+ /// representation for it via `Show`.
+ pub fn pretty(&self) -> PrettyJson {
+ PrettyJson { inner: self }
+ }
+
+ /// If the Json value is an Object, returns the value associated with the provided key.
+ /// Otherwise, returns None.
+ pub fn find<'a>(&'a self, key: &str) -> Option<&'a Json>{
+ match self {
+ &Json::Object(ref map) => map.get(key),
+ _ => None
+ }
+ }
+
+ /// Attempts to get a nested Json Object for each key in `keys`.
+ /// If any key is found not to exist, find_path will return None.
+ /// Otherwise, it will return the Json value associated with the final key.
+ pub fn find_path<'a>(&'a self, keys: &[&str]) -> Option<&'a Json>{
+ let mut target = self;
+ for key in keys.iter() {
+ match target.find(*key) {
+ Some(t) => { target = t; },
+ None => return None
+ }
+ }
+ Some(target)
+ }
+
+ /// If the Json value is an Object, performs a depth-first search until
+ /// a value associated with the provided key is found. If no value is found
+ /// or the Json value is not an Object, returns None.
+ pub fn search<'a>(&'a self, key: &str) -> Option<&'a Json> {
+ match self {
+ &Json::Object(ref map) => {
+ match map.get(key) {
+ Some(json_value) => Some(json_value),
+ None => {
+ for (_, v) in map.iter() {
+ match v.search(key) {
+ x if x.is_some() => return x,
+ _ => ()
+ }
+ }
+ None
+ }
+ }
+ },
+ _ => None
+ }
+ }
+
+ /// Returns true if the Json value is an Object. Returns false otherwise.
+ pub fn is_object<'a>(&'a self) -> bool {
+ self.as_object().is_some()
+ }
+
+ /// If the Json value is an Object, returns the associated BTreeMap.
+ /// Returns None otherwise.
+ pub fn as_object<'a>(&'a self) -> Option<&'a Object> {
+ match self {
+ &Json::Object(ref map) => Some(map),
+ _ => None
+ }
+ }
+
+ /// Returns true if the Json value is an Array. Returns false otherwise.
+ pub fn is_array<'a>(&'a self) -> bool {
+ self.as_array().is_some()
+ }
+
+ /// If the Json value is an Array, returns the associated vector.
+ /// Returns None otherwise.
+ pub fn as_array<'a>(&'a self) -> Option<&'a Array> {
+ match self {
+ &Json::Array(ref array) => Some(&*array),
+ _ => None
+ }
+ }
+
+ /// Returns true if the Json value is a String. Returns false otherwise.
+ pub fn is_string<'a>(&'a self) -> bool {
+ self.as_string().is_some()
+ }
+
+ /// If the Json value is a String, returns the associated str.
+ /// Returns None otherwise.
+ pub fn as_string<'a>(&'a self) -> Option<&'a str> {
+ match *self {
+ Json::String(ref s) => Some(s[]),
+ _ => None
+ }
+ }
+
+ /// Returns true if the Json value is a Number. Returns false otherwise.
+ pub fn is_number(&self) -> bool {
+ match *self {
+ Json::I64(_) | Json::U64(_) | Json::F64(_) => true,
+ _ => false,
+ }
+ }
+
+ /// Returns true if the Json value is a i64. Returns false otherwise.
+ pub fn is_i64(&self) -> bool {
+ match *self {
+ Json::I64(_) => true,
+ _ => false,
+ }
+ }
+
+ /// Returns true if the Json value is a u64. Returns false otherwise.
+ pub fn is_u64(&self) -> bool {
+ match *self {
+ Json::U64(_) => true,
+ _ => false,
+ }
+ }
+
+ /// Returns true if the Json value is a f64. Returns false otherwise.
+ pub fn is_f64(&self) -> bool {
+ match *self {
+ Json::F64(_) => true,
+ _ => false,
+ }
+ }
+
+ /// If the Json value is a number, return or cast it to a i64.
+ /// Returns None otherwise.
+ pub fn as_i64(&self) -> Option<i64> {
+ match *self {
+ Json::I64(n) => Some(n),
+ Json::U64(n) => num::cast(n),
+ _ => None
+ }
+ }
+
+ /// If the Json value is a number, return or cast it to a u64.
+ /// Returns None otherwise.
+ pub fn as_u64(&self) -> Option<u64> {
+ match *self {
+ Json::I64(n) => num::cast(n),
+ Json::U64(n) => Some(n),
+ _ => None
+ }
+ }
+
+ /// If the Json value is a number, return or cast it to a f64.
+ /// Returns None otherwise.
+ pub fn as_f64(&self) -> Option<f64> {
+ match *self {
+ Json::I64(n) => num::cast(n),
+ Json::U64(n) => num::cast(n),
+ Json::F64(n) => Some(n),
+ _ => None
+ }
+ }
+
+ /// Returns true if the Json value is a Boolean. Returns false otherwise.
+ pub fn is_boolean(&self) -> bool {
+ self.as_boolean().is_some()
+ }
+
+ /// If the Json value is a Boolean, returns the associated bool.
+ /// Returns None otherwise.
+ pub fn as_boolean(&self) -> Option<bool> {
+ match self {
+ &Json::Boolean(b) => Some(b),
+ _ => None
+ }
+ }
+
+ /// Returns true if the Json value is a Null. Returns false otherwise.
+ pub fn is_null(&self) -> bool {
+ self.as_null().is_some()
+ }
+
+ /// If the Json value is a Null, returns ().
+ /// Returns None otherwise.
+ pub fn as_null(&self) -> Option<()> {
+ match self {
+ &Json::Null => Some(()),
+ _ => None
+ }
+ }
+}
+
+impl<'a> ops::Index<&'a str> for Json {
+ type Output = Json;
+
+ fn index(&self, idx: & &str) -> &Json {
+ self.find(*idx).unwrap()
+ }
+}
+
+impl ops::Index<uint> for Json {
+ type Output = Json;
+
+ fn index<'a>(&'a self, idx: &uint) -> &'a Json {
+ match self {
+ &Json::Array(ref v) => v.index(idx),
+ _ => panic!("can only index Json with uint if it is an array")
+ }
+ }
+}
+
+/// The output of the streaming parser.
+#[derive(PartialEq, Clone, Show)]
+pub enum JsonEvent {
+ ObjectStart,
+ ObjectEnd,
+ ArrayStart,
+ ArrayEnd,
+ BooleanValue(bool),
+ I64Value(i64),
+ U64Value(u64),
+ F64Value(f64),
+ StringValue(string::String),
+ NullValue,
+ Error(ParserError),
+}
+
+#[derive(PartialEq, Show)]
+enum ParserState {
+ // Parse a value in an array, true means first element.
+ ParseArray(bool),
+ // Parse ',' or ']' after an element in an array.
+ ParseArrayComma,
+ // Parse a key:value in an object, true means first element.
+ ParseObject(bool),
+ // Parse ',' or ']' after an element in an object.
+ ParseObjectComma,
+ // Initial state.
+ ParseStart,
+ // Expecting the stream to end.
+ ParseBeforeFinish,
+ // Parsing can't continue.
+ ParseFinished,
+}
+
+/// A Stack represents the current position of the parser in the logical
+/// structure of the JSON stream.
+/// For example foo.bar[3].x
+pub struct Stack {
+ stack: Vec<InternalStackElement>,
+ str_buffer: Vec<u8>,
+}
+
+/// StackElements compose a Stack.
+/// For example, Key("foo"), Key("bar"), Index(3) and Key("x") are the
+/// StackElements compositing the stack that represents foo.bar[3].x
+#[derive(PartialEq, Clone, Show)]
+pub enum StackElement<'l> {
+ Index(u32),
+ Key(&'l str),
+}
+
+// Internally, Key elements are stored as indices in a buffer to avoid
+// allocating a string for every member of an object.
+#[derive(PartialEq, Clone, Show)]
+enum InternalStackElement {
+ InternalIndex(u32),
+ InternalKey(u16, u16), // start, size
+}
+
+impl Stack {
+ pub fn new() -> Stack {
+ Stack { stack: Vec::new(), str_buffer: Vec::new() }
+ }
+
+ /// Returns The number of elements in the Stack.
+ pub fn len(&self) -> uint { self.stack.len() }
+
+ /// Returns true if the stack is empty.
+ pub fn is_empty(&self) -> bool { self.stack.is_empty() }
+
+ /// Provides access to the StackElement at a given index.
+ /// lower indices are at the bottom of the stack while higher indices are
+ /// at the top.
+ pub fn get<'l>(&'l self, idx: uint) -> StackElement<'l> {
+ match self.stack[idx] {
+ InternalIndex(i) => Index(i),
+ InternalKey(start, size) => {
+ Key(str::from_utf8(
+ self.str_buffer[start as uint .. start as uint + size as uint]).unwrap())
+ }
+ }
+ }
+
+ /// Compares this stack with an array of StackElements.
+ pub fn is_equal_to(&self, rhs: &[StackElement]) -> bool {
+ if self.stack.len() != rhs.len() { return false; }
+ for i in range(0, rhs.len()) {
+ if self.get(i) != rhs[i] { return false; }
+ }
+ return true;
+ }
+
+ /// Returns true if the bottom-most elements of this stack are the same as
+ /// the ones passed as parameter.
+ pub fn starts_with(&self, rhs: &[StackElement]) -> bool {
+ if self.stack.len() < rhs.len() { return false; }
+ for i in range(0, rhs.len()) {
+ if self.get(i) != rhs[i] { return false; }
+ }
+ return true;
+ }
+
+ /// Returns true if the top-most elements of this stack are the same as
+ /// the ones passed as parameter.
+ pub fn ends_with(&self, rhs: &[StackElement]) -> bool {
+ if self.stack.len() < rhs.len() { return false; }
+ let offset = self.stack.len() - rhs.len();
+ for i in range(0, rhs.len()) {
+ if self.get(i + offset) != rhs[i] { return false; }
+ }
+ return true;
+ }
+
+ /// Returns the top-most element (if any).
+ pub fn top<'l>(&'l self) -> Option<StackElement<'l>> {
+ return match self.stack.last() {
+ None => None,
+ Some(&InternalIndex(i)) => Some(Index(i)),
+ Some(&InternalKey(start, size)) => {
+ Some(Key(str::from_utf8(
+ self.str_buffer[start as uint .. (start+size) as uint]
+ ).unwrap()))
+ }
+ }
+ }
+
+ // Used by Parser to insert Key elements at the top of the stack.
+ fn push_key(&mut self, key: string::String) {
+ self.stack.push(InternalKey(self.str_buffer.len() as u16, key.len() as u16));
+ for c in key.as_bytes().iter() {
+ self.str_buffer.push(*c);
+ }
+ }
+
+ // Used by Parser to insert Index elements at the top of the stack.
+ fn push_index(&mut self, index: u32) {
+ self.stack.push(InternalIndex(index));
+ }
+
+ // Used by Parser to remove the top-most element of the stack.
+ fn pop(&mut self) {
+ assert!(!self.is_empty());
+ match *self.stack.last().unwrap() {
+ InternalKey(_, sz) => {
+ let new_size = self.str_buffer.len() - sz as uint;
+ self.str_buffer.truncate(new_size);
+ }
+ InternalIndex(_) => {}
+ }
+ self.stack.pop();
+ }
+
+ // Used by Parser to test whether the top-most element is an index.
+ fn last_is_index(&self) -> bool {
+ if self.is_empty() { return false; }
+ return match *self.stack.last().unwrap() {
+ InternalIndex(_) => true,
+ _ => false,
+ }
+ }
+
+ // Used by Parser to increment the index of the top-most element.
+ fn bump_index(&mut self) {
+ let len = self.stack.len();
+ let idx = match *self.stack.last().unwrap() {
+ InternalIndex(i) => { i + 1 }
+ _ => { panic!(); }
+ };
+ self.stack[len - 1] = InternalIndex(idx);
+ }
+}
+
+/// A streaming JSON parser implemented as an iterator of JsonEvent, consuming
+/// an iterator of char.
+pub struct Parser<T> {
+ rdr: T,
+ ch: Option<char>,
+ line: uint,
+ col: uint,
+ // We maintain a stack representing where we are in the logical structure
+ // of the JSON stream.
+ stack: Stack,
+ // A state machine is kept to make it possible to interrupt and resume parsing.
+ state: ParserState,
+}
+
+impl<T: Iterator<Item=char>> Iterator for Parser<T> {
+ type Item = JsonEvent;
+
+ fn next(&mut self) -> Option<JsonEvent> {
+ if self.state == ParseFinished {
+ return None;
+ }
+
+ if self.state == ParseBeforeFinish {
+ self.parse_whitespace();
+ // Make sure there is no trailing characters.
+ if self.eof() {
+ self.state = ParseFinished;
+ return None;
+ } else {
+ return Some(self.error_event(TrailingCharacters));
+ }
+ }
+
+ return Some(self.parse());
+ }
+}
+
+impl<T: Iterator<Item=char>> Parser<T> {
+ /// Creates the JSON parser.
+ pub fn new(rdr: T) -> Parser<T> {
+ let mut p = Parser {
+ rdr: rdr,
+ ch: Some('\x00'),
+ line: 1,
+ col: 0,
+ stack: Stack::new(),
+ state: ParseStart,
+ };
+ p.bump();
+ return p;
+ }
+
+ /// Provides access to the current position in the logical structure of the
+ /// JSON stream.
+ pub fn stack<'l>(&'l self) -> &'l Stack {
+ return &self.stack;
+ }
+
+ fn eof(&self) -> bool { self.ch.is_none() }
+ fn ch_or_null(&self) -> char { self.ch.unwrap_or('\x00') }
+ fn bump(&mut self) {
+ self.ch = self.rdr.next();
+
+ if self.ch_is('\n') {
+ self.line += 1u;
+ self.col = 1u;
+ } else {
+ self.col += 1u;
+ }
+ }
+
+ fn next_char(&mut self) -> Option<char> {
+ self.bump();
+ self.ch
+ }
+ fn ch_is(&self, c: char) -> bool {
+ self.ch == Some(c)
+ }
+
+ fn error<T>(&self, reason: ErrorCode) -> Result<T, ParserError> {
+ Err(SyntaxError(reason, self.line, self.col))
+ }
+
+ fn parse_whitespace(&mut self) {
+ while self.ch_is(' ') ||
+ self.ch_is('\n') ||
+ self.ch_is('\t') ||
+ self.ch_is('\r') { self.bump(); }
+ }
+
+ fn parse_number(&mut self) -> JsonEvent {
+ let mut neg = false;
+
+ if self.ch_is('-') {
+ self.bump();
+ neg = true;
+ }
+
+ let res = match self.parse_u64() {
+ Ok(res) => res,
+ Err(e) => { return Error(e); }
+ };
+
+ if self.ch_is('.') || self.ch_is('e') || self.ch_is('E') {
+ let mut res = res as f64;
+
+ if self.ch_is('.') {
+ res = match self.parse_decimal(res) {
+ Ok(res) => res,
+ Err(e) => { return Error(e); }
+ };
+ }
+
+ if self.ch_is('e') || self.ch_is('E') {
+ res = match self.parse_exponent(res) {
+ Ok(res) => res,
+ Err(e) => { return Error(e); }
+ };
+ }
+
+ if neg {
+ res *= -1.0;
+ }
+
+ F64Value(res)
+ } else {
+ if neg {
+ let res = -(res as i64);
+
+ // Make sure we didn't underflow.
+ if res > 0 {
+ Error(SyntaxError(InvalidNumber, self.line, self.col))
+ } else {
+ I64Value(res)
+ }
+ } else {
+ U64Value(res)
+ }
+ }
+ }
+
+ fn parse_u64(&mut self) -> Result<u64, ParserError> {
+ let mut accum = 0;
+ let last_accum = 0; // necessary to detect overflow.
+
+ match self.ch_or_null() {
+ '0' => {
+ self.bump();
+
+ // A leading '0' must be the only digit before the decimal point.
+ match self.ch_or_null() {
+ '0' ... '9' => return self.error(InvalidNumber),
+ _ => ()
+ }
+ },
+ '1' ... '9' => {
+ while !self.eof() {
+ match self.ch_or_null() {
+ c @ '0' ... '9' => {
+ accum *= 10;
+ accum += (c as u64) - ('0' as u64);
+
+ // Detect overflow by comparing to the last value.
+ if accum <= last_accum { return self.error(InvalidNumber); }
+
+ self.bump();
+ }
+ _ => break,
+ }
+ }
+ }
+ _ => return self.error(InvalidNumber),
+ }
+
+ Ok(accum)
+ }
+
+ fn parse_decimal(&mut self, mut res: f64) -> Result<f64, ParserError> {
+ self.bump();
+
+ // Make sure a digit follows the decimal place.
+ match self.ch_or_null() {
+ '0' ... '9' => (),
+ _ => return self.error(InvalidNumber)
+ }
+
+ let mut dec = 1.0;
+ while !self.eof() {
+ match self.ch_or_null() {
+ c @ '0' ... '9' => {
+ dec /= 10.0;
+ res += (((c as int) - ('0' as int)) as f64) * dec;
+ self.bump();
+ }
+ _ => break,
+ }
+ }
+
+ Ok(res)
+ }
+
+ fn parse_exponent(&mut self, mut res: f64) -> Result<f64, ParserError> {
+ self.bump();
+
+ let mut exp = 0u;
+ let mut neg_exp = false;
+
+ if self.ch_is('+') {
+ self.bump();
+ } else if self.ch_is('-') {
+ self.bump();
+ neg_exp = true;
+ }
+
+ // Make sure a digit follows the exponent place.
+ match self.ch_or_null() {
+ '0' ... '9' => (),
+ _ => return self.error(InvalidNumber)
+ }
+ while !self.eof() {
+ match self.ch_or_null() {
+ c @ '0' ... '9' => {
+ exp *= 10;
+ exp += (c as uint) - ('0' as uint);
+
+ self.bump();
+ }
+ _ => break
+ }
+ }
+
+ let exp = 10_f64.powi(exp as i32);
+ if neg_exp {
+ res /= exp;
+ } else {
+ res *= exp;
+ }
+
+ Ok(res)
+ }
+
+ fn decode_hex_escape(&mut self) -> Result<u16, ParserError> {
+ let mut i = 0u;
+ let mut n = 0u16;
+ while i < 4 && !self.eof() {
+ self.bump();
+ n = match self.ch_or_null() {
+ c @ '0' ... '9' => n * 16 + ((c as u16) - ('0' as u16)),
+ 'a' | 'A' => n * 16 + 10,
+ 'b' | 'B' => n * 16 + 11,
+ 'c' | 'C' => n * 16 + 12,
+ 'd' | 'D' => n * 16 + 13,
+ 'e' | 'E' => n * 16 + 14,
+ 'f' | 'F' => n * 16 + 15,
+ _ => return self.error(InvalidEscape)
+ };
+
+ i += 1u;
+ }
+
+ // Error out if we didn't parse 4 digits.
+ if i != 4 {
+ return self.error(InvalidEscape);
+ }
+
+ Ok(n)
+ }
+
+ fn parse_str(&mut self) -> Result<string::String, ParserError> {
+ let mut escape = false;
+ let mut res = string::String::new();
+
+ loop {
+ self.bump();
+ if self.eof() {
+ return self.error(EOFWhileParsingString);
+ }
+
+ if escape {
+ match self.ch_or_null() {
+ '"' => res.push('"'),
+ '\\' => res.push('\\'),
+ '/' => res.push('/'),
+ 'b' => res.push('\x08'),
+ 'f' => res.push('\x0c'),
+ 'n' => res.push('\n'),
+ 'r' => res.push('\r'),
+ 't' => res.push('\t'),
+ 'u' => match try!(self.decode_hex_escape()) {
+ 0xDC00 ... 0xDFFF => {
+ return self.error(LoneLeadingSurrogateInHexEscape)
+ }
+
+ // Non-BMP characters are encoded as a sequence of
+ // two hex escapes, representing UTF-16 surrogates.
+ n1 @ 0xD800 ... 0xDBFF => {
+ match (self.next_char(), self.next_char()) {
+ (Some('\\'), Some('u')) => (),
+ _ => return self.error(UnexpectedEndOfHexEscape),
+ }
+
+ let buf = [n1, try!(self.decode_hex_escape())];
+ match unicode_str::utf16_items(&buf).next() {
+ Some(Utf16Item::ScalarValue(c)) => res.push(c),
+ _ => return self.error(LoneLeadingSurrogateInHexEscape),
+ }
+ }
+
+ n => match char::from_u32(n as u32) {
+ Some(c) => res.push(c),
+ None => return self.error(InvalidUnicodeCodePoint),
+ },
+ },
+ _ => return self.error(InvalidEscape),
+ }
+ escape = false;
+ } else if self.ch_is('\\') {
+ escape = true;
+ } else {
+ match self.ch {
+ Some('"') => {
+ self.bump();
+ return Ok(res);
+ },
+ Some(c) => res.push(c),
+ None => unreachable!()
+ }
+ }
+ }
+ }
+
+ // Invoked at each iteration, consumes the stream until it has enough
+ // information to return a JsonEvent.
+ // Manages an internal state so that parsing can be interrupted and resumed.
+ // Also keeps track of the position in the logical structure of the json
+ // stream int the form of a stack that can be queried by the user using the
+ // stack() method.
+ fn parse(&mut self) -> JsonEvent {
+ loop {
+ // The only paths where the loop can spin a new iteration
+ // are in the cases ParseArrayComma and ParseObjectComma if ','
+ // is parsed. In these cases the state is set to (respectively)
+ // ParseArray(false) and ParseObject(false), which always return,
+ // so there is no risk of getting stuck in an infinite loop.
+ // All other paths return before the end of the loop's iteration.
+ self.parse_whitespace();
+
+ match self.state {
+ ParseStart => {
+ return self.parse_start();
+ }
+ ParseArray(first) => {
+ return self.parse_array(first);
+ }
+ ParseArrayComma => {
+ match self.parse_array_comma_or_end() {
+ Some(evt) => { return evt; }
+ None => {}
+ }
+ }
+ ParseObject(first) => {
+ return self.parse_object(first);
+ }
+ ParseObjectComma => {
+ self.stack.pop();
+ if self.ch_is(',') {
+ self.state = ParseObject(false);
+ self.bump();
+ } else {
+ return self.parse_object_end();
+ }
+ }
+ _ => {
+ return self.error_event(InvalidSyntax);
+ }
+ }
+ }
+ }
+
+ fn parse_start(&mut self) -> JsonEvent {
+ let val = self.parse_value();
+ self.state = match val {
+ Error(_) => ParseFinished,
+ ArrayStart => ParseArray(true),
+ ObjectStart => ParseObject(true),
+ _ => ParseBeforeFinish,
+ };
+ return val;
+ }
+
+ fn parse_array(&mut self, first: bool) -> JsonEvent {
+ if self.ch_is(']') {
+ if !first {
+ self.error_event(InvalidSyntax)
+ } else {
+ self.state = if self.stack.is_empty() {
+ ParseBeforeFinish
+ } else if self.stack.last_is_index() {
+ ParseArrayComma
+ } else {
+ ParseObjectComma
+ };
+ self.bump();
+ ArrayEnd
+ }
+ } else {
+ if first {
+ self.stack.push_index(0);
+ }
+ let val = self.parse_value();
+ self.state = match val {
+ Error(_) => ParseFinished,
+ ArrayStart => ParseArray(true),
+ ObjectStart => ParseObject(true),
+ _ => ParseArrayComma,
+ };
+ val
+ }
+ }
+
+ fn parse_array_comma_or_end(&mut self) -> Option<JsonEvent> {
+ if self.ch_is(',') {
+ self.stack.bump_index();
+ self.state = ParseArray(false);
+ self.bump();
+ None
+ } else if self.ch_is(']') {
+ self.stack.pop();
+ self.state = if self.stack.is_empty() {
+ ParseBeforeFinish
+ } else if self.stack.last_is_index() {
+ ParseArrayComma
+ } else {
+ ParseObjectComma
+ };
+ self.bump();
+ Some(ArrayEnd)
+ } else if self.eof() {
+ Some(self.error_event(EOFWhileParsingArray))
+ } else {
+ Some(self.error_event(InvalidSyntax))
+ }
+ }
+
+ fn parse_object(&mut self, first: bool) -> JsonEvent {
+ if self.ch_is('}') {
+ if !first {
+ if self.stack.is_empty() {
+ return self.error_event(TrailingComma);
+ } else {
+ self.stack.pop();
+ }
+ }
+ self.state = if self.stack.is_empty() {
+ ParseBeforeFinish
+ } else if self.stack.last_is_index() {
+ ParseArrayComma
+ } else {
+ ParseObjectComma
+ };
+ self.bump();
+ return ObjectEnd;
+ }
+ if self.eof() {
+ return self.error_event(EOFWhileParsingObject);
+ }
+ if !self.ch_is('"') {
+ return self.error_event(KeyMustBeAString);
+ }
+ let s = match self.parse_str() {
+ Ok(s) => s,
+ Err(e) => {
+ self.state = ParseFinished;
+ return Error(e);
+ }
+ };
+ self.parse_whitespace();
+ if self.eof() {
+ return self.error_event(EOFWhileParsingObject);
+ } else if self.ch_or_null() != ':' {
+ return self.error_event(ExpectedColon);
+ }
+ self.stack.push_key(s);
+ self.bump();
+ self.parse_whitespace();
+
+ let val = self.parse_value();
+
+ self.state = match val {
+ Error(_) => ParseFinished,
+ ArrayStart => ParseArray(true),
+ ObjectStart => ParseObject(true),
+ _ => ParseObjectComma,
+ };
+ return val;
+ }
+
+ fn parse_object_end(&mut self) -> JsonEvent {
+ if self.ch_is('}') {
+ self.state = if self.stack.is_empty() {
+ ParseBeforeFinish
+ } else if self.stack.last_is_index() {
+ ParseArrayComma
+ } else {
+ ParseObjectComma
+ };
+ self.bump();
+ ObjectEnd
+ } else if self.eof() {
+ self.error_event(EOFWhileParsingObject)
+ } else {
+ self.error_event(InvalidSyntax)
+ }
+ }
+
+ fn parse_value(&mut self) -> JsonEvent {
+ if self.eof() { return self.error_event(EOFWhileParsingValue); }
+ match self.ch_or_null() {
+ 'n' => { self.parse_ident("ull", NullValue) }
+ 't' => { self.parse_ident("rue", BooleanValue(true)) }
+ 'f' => { self.parse_ident("alse", BooleanValue(false)) }
+ '0' ... '9' | '-' => self.parse_number(),
+ '"' => match self.parse_str() {
+ Ok(s) => StringValue(s),
+ Err(e) => Error(e),
+ },
+ '[' => {
+ self.bump();
+ ArrayStart
+ }
+ '{' => {
+ self.bump();
+ ObjectStart
+ }
+ _ => { self.error_event(InvalidSyntax) }
+ }
+ }
+
+ fn parse_ident(&mut self, ident: &str, value: JsonEvent) -> JsonEvent {
+ if ident.chars().all(|c| Some(c) == self.next_char()) {
+ self.bump();
+ value
+ } else {
+ Error(SyntaxError(InvalidSyntax, self.line, self.col))
+ }
+ }
+
+ fn error_event(&mut self, reason: ErrorCode) -> JsonEvent {
+ self.state = ParseFinished;
+ Error(SyntaxError(reason, self.line, self.col))
+ }
+}
+
+/// A Builder consumes a json::Parser to create a generic Json structure.
+pub struct Builder<T> {
+ parser: Parser<T>,
+ token: Option<JsonEvent>,
+}
+
+impl<T: Iterator<Item=char>> Builder<T> {
+ /// Create a JSON Builder.
+ pub fn new(src: T) -> Builder<T> {
+ Builder { parser: Parser::new(src), token: None, }
+ }
+
+ // Decode a Json value from a Parser.
+ pub fn build(&mut self) -> Result<Json, BuilderError> {
+ self.bump();
+ let result = self.build_value();
+ self.bump();
+ match self.token {
+ None => {}
+ Some(Error(e)) => { return Err(e); }
+ ref tok => { panic!("unexpected token {}", tok.clone()); }
+ }
+ result
+ }
+
+ fn bump(&mut self) {
+ self.token = self.parser.next();
+ }
+
+ fn build_value(&mut self) -> Result<Json, BuilderError> {
+ return match self.token {
+ Some(NullValue) => Ok(Json::Null),
+ Some(I64Value(n)) => Ok(Json::I64(n)),
+ Some(U64Value(n)) => Ok(Json::U64(n)),
+ Some(F64Value(n)) => Ok(Json::F64(n)),
+ Some(BooleanValue(b)) => Ok(Json::Boolean(b)),
+ Some(StringValue(ref mut s)) => {
+ let mut temp = string::String::new();
+ swap(s, &mut temp);
+ Ok(Json::String(temp))
+ }
+ Some(Error(e)) => Err(e),
+ Some(ArrayStart) => self.build_array(),
+ Some(ObjectStart) => self.build_object(),
+ Some(ObjectEnd) => self.parser.error(InvalidSyntax),
+ Some(ArrayEnd) => self.parser.error(InvalidSyntax),
+ None => self.parser.error(EOFWhileParsingValue),
+ }
+ }
+
+ fn build_array(&mut self) -> Result<Json, BuilderError> {
+ self.bump();
+ let mut values = Vec::new();
+
+ loop {
+ if self.token == Some(ArrayEnd) {
+ return Ok(Json::Array(values.into_iter().collect()));
+ }
+ match self.build_value() {
+ Ok(v) => values.push(v),
+ Err(e) => { return Err(e) }
+ }
+ self.bump();
+ }
+ }
+
+ fn build_object(&mut self) -> Result<Json, BuilderError> {
+ self.bump();
+
+ let mut values = BTreeMap::new();
+
+ loop {
+ match self.token {
+ Some(ObjectEnd) => { return Ok(Json::Object(values)); }
+ Some(Error(e)) => { return Err(e); }
+ None => { break; }
+ _ => {}
+ }
+ let key = match self.parser.stack().top() {
+ Some(Key(k)) => { k.to_string() }
+ _ => { panic!("invalid state"); }
+ };
+ match self.build_value() {
+ Ok(value) => { values.insert(key, value); }
+ Err(e) => { return Err(e); }
+ }
+ self.bump();
+ }
+ return self.parser.error(EOFWhileParsingObject);
+ }
+}
+
+/// Decodes a json value from an `&mut io::Reader`
+pub fn from_reader(rdr: &mut io::Reader) -> Result<Json, BuilderError> {
+ let contents = match rdr.read_to_end() {
+ Ok(c) => c,
+ Err(e) => return Err(io_error_to_error(e))
+ };
+ let s = match str::from_utf8(contents.as_slice()).ok() {
+ Some(s) => s,
+ _ => return Err(SyntaxError(NotUtf8, 0, 0))
+ };
+ let mut builder = Builder::new(s.chars());
+ builder.build()
+}
+
+/// Decodes a json value from a string
+pub fn from_str(s: &str) -> Result<Json, BuilderError> {
+ let mut builder = Builder::new(s.chars());
+ builder.build()
+}
+
+/// A structure to decode JSON to values in rust.
+pub struct Decoder {
+ stack: Vec<Json>,
+}
+
+impl Decoder {
+ /// Creates a new decoder instance for decoding the specified JSON value.
+ pub fn new(json: Json) -> Decoder {
+ Decoder { stack: vec![json] }
+ }
+}
+
+impl Decoder {
+ fn pop(&mut self) -> Json {
+ self.stack.pop().unwrap()
+ }
+}
+
+macro_rules! expect {
+ ($e:expr, Null) => ({
+ match $e {
+ Json::Null => Ok(()),
+ other => Err(ExpectedError("Null".to_string(),
+ format!("{}", other)))
+ }
+ });
+ ($e:expr, $t:ident) => ({
+ match $e {
+ Json::$t(v) => Ok(v),
+ other => {
+ Err(ExpectedError(stringify!($t).to_string(),
+ format!("{}", other)))
+ }
+ }
+ })
+}
+
+macro_rules! read_primitive {
+ ($name:ident, $ty:ty) => {
+ fn $name(&mut self) -> DecodeResult<$ty> {
+ match self.pop() {
+ Json::I64(f) => match num::cast(f) {
+ Some(f) => Ok(f),
+ None => Err(ExpectedError("Number".to_string(), format!("{}", f))),
+ },
+ Json::U64(f) => match num::cast(f) {
+ Some(f) => Ok(f),
+ None => Err(ExpectedError("Number".to_string(), format!("{}", f))),
+ },
+ Json::F64(f) => Err(ExpectedError("Integer".to_string(), format!("{}", f))),
+ // re: #12967.. a type w/ numeric keys (ie HashMap<uint, V> etc)
+ // is going to have a string here, as per JSON spec.
+ Json::String(s) => match s.parse() {
+ Some(f) => Ok(f),
+ None => Err(ExpectedError("Number".to_string(), s)),
+ },
+ value => Err(ExpectedError("Number".to_string(), format!("{}", value))),
+ }
+ }
+ }
+}
+
+impl ::Decoder<DecoderError> for Decoder {
+ fn read_nil(&mut self) -> DecodeResult<()> {
+ expect!(self.pop(), Null)
+ }
+
+ read_primitive! { read_uint, uint }
+ read_primitive! { read_u8, u8 }
+ read_primitive! { read_u16, u16 }
+ read_primitive! { read_u32, u32 }
+ read_primitive! { read_u64, u64 }
+ read_primitive! { read_int, int }
+ read_primitive! { read_i8, i8 }
+ read_primitive! { read_i16, i16 }
+ read_primitive! { read_i32, i32 }
+ read_primitive! { read_i64, i64 }
+
+ fn read_f32(&mut self) -> DecodeResult<f32> { self.read_f64().map(|x| x as f32) }
+
+ fn read_f64(&mut self) -> DecodeResult<f64> {
+ match self.pop() {
+ Json::I64(f) => Ok(f as f64),
+ Json::U64(f) => Ok(f as f64),
+ Json::F64(f) => Ok(f),
+ Json::String(s) => {
+ // re: #12967.. a type w/ numeric keys (ie HashMap<uint, V> etc)
+ // is going to have a string here, as per JSON spec.
+ match s.parse() {
+ Some(f) => Ok(f),
+ None => Err(ExpectedError("Number".to_string(), s)),
+ }
+ },
+ Json::Null => Ok(f64::NAN),
+ value => Err(ExpectedError("Number".to_string(), format!("{}", value)))
+ }
+ }
+
+ fn read_bool(&mut self) -> DecodeResult<bool> {
+ expect!(self.pop(), Boolean)
+ }
+
+ fn read_char(&mut self) -> DecodeResult<char> {
+ let s = try!(self.read_str());
+ {
+ let mut it = s.chars();
+ match (it.next(), it.next()) {
+ // exactly one character
+ (Some(c), None) => return Ok(c),
+ _ => ()
+ }
+ }
+ Err(ExpectedError("single character string".to_string(), format!("{}", s)))
+ }
+
+ fn read_str(&mut self) -> DecodeResult<string::String> {
+ expect!(self.pop(), String)
+ }
+
+ fn read_enum<T, F>(&mut self, _name: &str, f: F) -> DecodeResult<T> where
+ F: FnOnce(&mut Decoder) -> DecodeResult<T>,
+ {
+ f(self)
+ }
+
+ fn read_enum_variant<T, F>(&mut self, names: &[&str],
+ mut f: F) -> DecodeResult<T>
+ where F: FnMut(&mut Decoder, uint) -> DecodeResult<T>,
+ {
+ let name = match self.pop() {
+ Json::String(s) => s,
+ Json::Object(mut o) => {
+ let n = match o.remove(&"variant".to_string()) {
+ Some(Json::String(s)) => s,
+ Some(val) => {
+ return Err(ExpectedError("String".to_string(), format!("{}", val)))
+ }
+ None => {
+ return Err(MissingFieldError("variant".to_string()))
+ }
+ };
+ match o.remove(&"fields".to_string()) {
+ Some(Json::Array(l)) => {
+ for field in l.into_iter().rev() {
+ self.stack.push(field);
+ }
+ },
+ Some(val) => {
+ return Err(ExpectedError("Array".to_string(), format!("{}", val)))
+ }
+ None => {
+ return Err(MissingFieldError("fields".to_string()))
+ }
+ }
+ n
+ }
+ json => {
+ return Err(ExpectedError("String or Object".to_string(), format!("{}", json)))
+ }
+ };
+ let idx = match names.iter().position(|n| *n == name[]) {
+ Some(idx) => idx,
+ None => return Err(UnknownVariantError(name))
+ };
+ f(self, idx)
+ }
+
+ fn read_enum_variant_arg<T, F>(&mut self, _idx: uint, f: F) -> DecodeResult<T> where
+ F: FnOnce(&mut Decoder) -> DecodeResult<T>,
+ {
+ f(self)
+ }
+
+ fn read_enum_struct_variant<T, F>(&mut self, names: &[&str], f: F) -> DecodeResult<T> where
+ F: FnMut(&mut Decoder, uint) -> DecodeResult<T>,
+ {
+ self.read_enum_variant(names, f)
+ }
+
+
+ fn read_enum_struct_variant_field<T, F>(&mut self,
+ _name: &str,
+ idx: uint,
+ f: F)
+ -> DecodeResult<T> where
+ F: FnOnce(&mut Decoder) -> DecodeResult<T>,
+ {
+ self.read_enum_variant_arg(idx, f)
+ }
+
+ fn read_struct<T, F>(&mut self, _name: &str, _len: uint, f: F) -> DecodeResult<T> where
+ F: FnOnce(&mut Decoder) -> DecodeResult<T>,
+ {
+ let value = try!(f(self));
+ self.pop();
+ Ok(value)
+ }
+
+ fn read_struct_field<T, F>(&mut self,
+ name: &str,
+ _idx: uint,
+ f: F)
+ -> DecodeResult<T> where
+ F: FnOnce(&mut Decoder) -> DecodeResult<T>,
+ {
+ let mut obj = try!(expect!(self.pop(), Object));
+
+ let value = match obj.remove(&name.to_string()) {
+ None => {
+ // Add a Null and try to parse it as an Option<_>
+ // to get None as a default value.
+ self.stack.push(Json::Null);
+ match f(self) {
+ Ok(x) => x,
+ Err(_) => return Err(MissingFieldError(name.to_string())),
+ }
+ },
+ Some(json) => {
+ self.stack.push(json);
+ try!(f(self))
+ }
+ };
+ self.stack.push(Json::Object(obj));
+ Ok(value)
+ }
+
+ fn read_tuple<T, F>(&mut self, tuple_len: uint, f: F) -> DecodeResult<T> where
+ F: FnOnce(&mut Decoder) -> DecodeResult<T>,
+ {
+ self.read_seq(move |d, len| {
+ if len == tuple_len {
+ f(d)
+ } else {
+ Err(ExpectedError(format!("Tuple{}", tuple_len), format!("Tuple{}", len)))
+ }
+ })
+ }
+
+ fn read_tuple_arg<T, F>(&mut self, idx: uint, f: F) -> DecodeResult<T> where
+ F: FnOnce(&mut Decoder) -> DecodeResult<T>,
+ {
+ self.read_seq_elt(idx, f)
+ }
+
+ fn read_tuple_struct<T, F>(&mut self,
+ _name: &str,
+ len: uint,
+ f: F)
+ -> DecodeResult<T> where
+ F: FnOnce(&mut Decoder) -> DecodeResult<T>,
+ {
+ self.read_tuple(len, f)
+ }
+
+ fn read_tuple_struct_arg<T, F>(&mut self,
+ idx: uint,
+ f: F)
+ -> DecodeResult<T> where
+ F: FnOnce(&mut Decoder) -> DecodeResult<T>,
+ {
+ self.read_tuple_arg(idx, f)
+ }
+
+ fn read_option<T, F>(&mut self, mut f: F) -> DecodeResult<T> where
+ F: FnMut(&mut Decoder, bool) -> DecodeResult<T>,
+ {
+ match self.pop() {
+ Json::Null => f(self, false),
+ value => { self.stack.push(value); f(self, true) }
+ }
+ }
+
+ fn read_seq<T, F>(&mut self, f: F) -> DecodeResult<T> where
+ F: FnOnce(&mut Decoder, uint) -> DecodeResult<T>,
+ {
+ let array = try!(expect!(self.pop(), Array));
+ let len = array.len();
+ for v in array.into_iter().rev() {
+ self.stack.push(v);
+ }
+ f(self, len)
+ }
+
+ fn read_seq_elt<T, F>(&mut self, _idx: uint, f: F) -> DecodeResult<T> where
+ F: FnOnce(&mut Decoder) -> DecodeResult<T>,
+ {
+ f(self)
+ }
+
+ fn read_map<T, F>(&mut self, f: F) -> DecodeResult<T> where
+ F: FnOnce(&mut Decoder, uint) -> DecodeResult<T>,
+ {
+ let obj = try!(expect!(self.pop(), Object));
+ let len = obj.len();
+ for (key, value) in obj.into_iter() {
+ self.stack.push(value);
+ self.stack.push(Json::String(key));
+ }
+ f(self, len)
+ }
+
+ fn read_map_elt_key<T, F>(&mut self, _idx: uint, f: F) -> DecodeResult<T> where
+ F: FnOnce(&mut Decoder) -> DecodeResult<T>,
+ {
+ f(self)
+ }
+
+ fn read_map_elt_val<T, F>(&mut self, _idx: uint, f: F) -> DecodeResult<T> where
+ F: FnOnce(&mut Decoder) -> DecodeResult<T>,
+ {
+ f(self)
+ }
+
+ fn error(&mut self, err: &str) -> DecoderError {
+ ApplicationError(err.to_string())
+ }
+}
+
+/// A trait for converting values to JSON
+pub trait ToJson for Sized? {
+ /// Converts the value of `self` to an instance of JSON
+ fn to_json(&self) -> Json;
+}
+
+macro_rules! to_json_impl_i64 {
+ ($($t:ty), +) => (
+ $(impl ToJson for $t {
+ fn to_json(&self) -> Json { Json::I64(*self as i64) }
+ })+
+ )
+}
+
+to_json_impl_i64! { int, i8, i16, i32, i64 }
+
+macro_rules! to_json_impl_u64 {
+ ($($t:ty), +) => (
+ $(impl ToJson for $t {
+ fn to_json(&self) -> Json { Json::U64(*self as u64) }
+ })+
+ )
+}
+
+to_json_impl_u64! { uint, u8, u16, u32, u64 }
+
+impl ToJson for Json {
+ fn to_json(&self) -> Json { self.clone() }
+}
+
+impl ToJson for f32 {
+ fn to_json(&self) -> Json { (*self as f64).to_json() }
+}
+
+impl ToJson for f64 {
+ fn to_json(&self) -> Json {
+ match self.classify() {
+ Fp::Nan | Fp::Infinite => Json::Null,
+ _ => Json::F64(*self)
+ }
+ }
+}
+
+impl ToJson for () {
+ fn to_json(&self) -> Json { Json::Null }
+}
+
+impl ToJson for bool {
+ fn to_json(&self) -> Json { Json::Boolean(*self) }
+}
+
+impl ToJson for str {
+ fn to_json(&self) -> Json { Json::String(self.to_string()) }
+}
+
+impl ToJson for string::String {
+ fn to_json(&self) -> Json { Json::String((*self).clone()) }
+}
+
+macro_rules! tuple_impl {
+ // use variables to indicate the arity of the tuple
+ ($($tyvar:ident),* ) => {
+ // the trailing commas are for the 1 tuple
+ impl<
+ $( $tyvar : ToJson ),*
+ > ToJson for ( $( $tyvar ),* , ) {
+
+ #[inline]
+ #[allow(non_snake_case)]
+ fn to_json(&self) -> Json {
+ match *self {
+ ($(ref $tyvar),*,) => Json::Array(vec![$($tyvar.to_json()),*])
+ }
+ }
+ }
+ }
+}
+
+tuple_impl!{A}
+tuple_impl!{A, B}
+tuple_impl!{A, B, C}
+tuple_impl!{A, B, C, D}
+tuple_impl!{A, B, C, D, E}
+tuple_impl!{A, B, C, D, E, F}
+tuple_impl!{A, B, C, D, E, F, G}
+tuple_impl!{A, B, C, D, E, F, G, H}
+tuple_impl!{A, B, C, D, E, F, G, H, I}
+tuple_impl!{A, B, C, D, E, F, G, H, I, J}
+tuple_impl!{A, B, C, D, E, F, G, H, I, J, K}
+tuple_impl!{A, B, C, D, E, F, G, H, I, J, K, L}
+
+impl<A: ToJson> ToJson for [A] {
+ fn to_json(&self) -> Json { Json::Array(self.iter().map(|elt| elt.to_json()).collect()) }
+}
+
+impl<A: ToJson> ToJson for Vec<A> {
+ fn to_json(&self) -> Json { Json::Array(self.iter().map(|elt| elt.to_json()).collect()) }
+}
+
+impl<A: ToJson> ToJson for BTreeMap<string::String, A> {
+ fn to_json(&self) -> Json {
+ let mut d = BTreeMap::new();
+ for (key, value) in self.iter() {
+ d.insert((*key).clone(), value.to_json());
+ }
+ Json::Object(d)
+ }
+}
+
+impl<A: ToJson> ToJson for HashMap<string::String, A> {
+ fn to_json(&self) -> Json {
+ let mut d = BTreeMap::new();
+ for (key, value) in self.iter() {
+ d.insert((*key).clone(), value.to_json());
+ }
+ Json::Object(d)
+ }
+}
+
+impl<A:ToJson> ToJson for Option<A> {
+ fn to_json(&self) -> Json {
+ match *self {
+ None => Json::Null,
+ Some(ref value) => value.to_json()
+ }
+ }
+}
+
+struct FormatShim<'a, 'b: 'a> {
+ inner: &'a mut fmt::Formatter<'b>,
+}
+
+impl<'a, 'b> fmt::Writer for FormatShim<'a, 'b> {
+ fn write_str(&mut self, s: &str) -> fmt::Result {
+ self.inner.write_str(s)
+ }
+}
+
+impl fmt::Show for Json {
+ /// Encodes a json value into a string
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let mut shim = FormatShim { inner: f };
+ let mut encoder = Encoder::new(&mut shim);
+ self.encode(&mut encoder)
+ }
+}
+
+impl<'a> fmt::Show for PrettyJson<'a> {
+ /// Encodes a json value into a string
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let mut shim = FormatShim { inner: f };
+ let mut encoder = PrettyEncoder::new(&mut shim);
+ self.inner.encode(&mut encoder)
+ }
+}
+
+impl<'a, T> fmt::Show for AsJson<'a, T>
+ where T: for<'b> Encodable<Encoder<'b>, fmt::Error>
+{
+ /// Encodes a json value into a string
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let mut shim = FormatShim { inner: f };
+ let mut encoder = Encoder::new(&mut shim);
+ self.inner.encode(&mut encoder)
+ }
+}
+
+impl<'a, T> AsPrettyJson<'a, T> {
+ /// Set the indentation level for the emitted JSON
+ pub fn indent(mut self, indent: uint) -> AsPrettyJson<'a, T> {
+ self.indent = Some(indent);
+ self
+ }
+}
+
+impl<'a, T> fmt::Show for AsPrettyJson<'a, T>
+ where T: for<'b> Encodable<PrettyEncoder<'b>, fmt::Error>
+{
+ /// Encodes a json value into a string
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let mut shim = FormatShim { inner: f };
+ let mut encoder = PrettyEncoder::new(&mut shim);
+ match self.indent {
+ Some(n) => encoder.set_indent(n),
+ None => {}
+ }
+ self.inner.encode(&mut encoder)
+ }
+}
+
+impl FromStr for Json {
+ fn from_str(s: &str) -> Option<Json> {
+ from_str(s).ok()
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ extern crate test;
+ use self::Animal::*;
+ use self::DecodeEnum::*;
+ use self::test::Bencher;
+ use {Encodable, Decodable};
+ use super::Json::*;
+ use super::ErrorCode::*;
+ use super::ParserError::*;
+ use super::DecoderError::*;
+ use super::JsonEvent::*;
+ use super::StackElement::*;
+ use super::{Json, from_str, DecodeResult, DecoderError, JsonEvent, Parser,
+ StackElement, Stack, Decoder};
+ use std::{i64, u64, f32, f64};
+ use std::collections::BTreeMap;
+ use std::num::Float;
+ use std::string;
+
+ #[derive(RustcDecodable, Eq, PartialEq, Show)]
+ struct OptionData {
+ opt: Option<uint>,
+ }
+
+ #[test]
+ fn test_decode_option_none() {
+ let s ="{}";
+ let obj: OptionData = super::decode(s).unwrap();
+ assert_eq!(obj, OptionData { opt: None });
+ }
+
+ #[test]
+ fn test_decode_option_some() {
+ let s = "{ \"opt\": 10 }";
+ let obj: OptionData = super::decode(s).unwrap();
+ assert_eq!(obj, OptionData { opt: Some(10u) });
+ }
+
+ #[test]
+ fn test_decode_option_malformed() {
+ check_err::<OptionData>("{ \"opt\": [] }",
+ ExpectedError("Number".to_string(), "[]".to_string()));
+ check_err::<OptionData>("{ \"opt\": false }",
+ ExpectedError("Number".to_string(), "false".to_string()));
+ }
+
+ #[derive(PartialEq, RustcEncodable, RustcDecodable, Show)]
+ enum Animal {
+ Dog,
+ Frog(string::String, int)
+ }
+
+ #[derive(PartialEq, RustcEncodable, RustcDecodable, Show)]
+ struct Inner {
+ a: (),
+ b: uint,
+ c: Vec<string::String>,
+ }
+
+ #[derive(PartialEq, RustcEncodable, RustcDecodable, Show)]
+ struct Outer {
+ inner: Vec<Inner>,
+ }
+
+ fn mk_object(items: &[(string::String, Json)]) -> Json {
+ let mut d = BTreeMap::new();
+
+ for item in items.iter() {
+ match *item {
+ (ref key, ref value) => { d.insert((*key).clone(), (*value).clone()); },
+ }
+ };
+
+ Object(d)
+ }
+
+ #[test]
+ fn test_from_str_trait() {
+ let s = "null";
+ assert!(s.parse::<Json>().unwrap() == s.parse().unwrap());
+ }
+
+ #[test]
+ fn test_write_null() {
+ assert_eq!(Null.to_string(), "null");
+ assert_eq!(Null.pretty().to_string(), "null");
+ }
+
+ #[test]
+ fn test_write_i64() {
+ assert_eq!(U64(0).to_string(), "0");
+ assert_eq!(U64(0).pretty().to_string(), "0");
+
+ assert_eq!(U64(1234).to_string(), "1234");
+ assert_eq!(U64(1234).pretty().to_string(), "1234");
+
+ assert_eq!(I64(-5678).to_string(), "-5678");
+ assert_eq!(I64(-5678).pretty().to_string(), "-5678");
+
+ assert_eq!(U64(7650007200025252000).to_string(), "7650007200025252000");
+ assert_eq!(U64(7650007200025252000).pretty().to_string(), "7650007200025252000");
+ }
+
+ #[test]
+ fn test_write_f64() {
+ assert_eq!(F64(3.0).to_string(), "3.0");
+ assert_eq!(F64(3.0).pretty().to_string(), "3.0");
+
+ assert_eq!(F64(3.1).to_string(), "3.1");
+ assert_eq!(F64(3.1).pretty().to_string(), "3.1");
+
+ assert_eq!(F64(-1.5).to_string(), "-1.5");
+ assert_eq!(F64(-1.5).pretty().to_string(), "-1.5");
+
+ assert_eq!(F64(0.5).to_string(), "0.5");
+ assert_eq!(F64(0.5).pretty().to_string(), "0.5");
+
+ assert_eq!(F64(f64::NAN).to_string(), "null");
+ assert_eq!(F64(f64::NAN).pretty().to_string(), "null");
+
+ assert_eq!(F64(f64::INFINITY).to_string(), "null");
+ assert_eq!(F64(f64::INFINITY).pretty().to_string(), "null");
+
+ assert_eq!(F64(f64::NEG_INFINITY).to_string(), "null");
+ assert_eq!(F64(f64::NEG_INFINITY).pretty().to_string(), "null");
+ }
+
+ #[test]
+ fn test_write_str() {
+ assert_eq!(String("".to_string()).to_string(), "\"\"");
+ assert_eq!(String("".to_string()).pretty().to_string(), "\"\"");
+
+ assert_eq!(String("homura".to_string()).to_string(), "\"homura\"");
+ assert_eq!(String("madoka".to_string()).pretty().to_string(), "\"madoka\"");
+ }
+
+ #[test]
+ fn test_write_bool() {
+ assert_eq!(Boolean(true).to_string(), "true");
+ assert_eq!(Boolean(true).pretty().to_string(), "true");
+
+ assert_eq!(Boolean(false).to_string(), "false");
+ assert_eq!(Boolean(false).pretty().to_string(), "false");
+ }
+
+ #[test]
+ fn test_write_array() {
+ assert_eq!(Array(vec![]).to_string(), "[]");
+ assert_eq!(Array(vec![]).pretty().to_string(), "[]");
+
+ assert_eq!(Array(vec![Boolean(true)]).to_string(), "[true]");
+ assert_eq!(
+ Array(vec![Boolean(true)]).pretty().to_string(),
+ "\
+ [\n \
+ true\n\
+ ]"
+ );
+
+ let long_test_array = Array(vec![
+ Boolean(false),
+ Null,
+ Array(vec![String("foo\nbar".to_string()), F64(3.5)])]);
+
+ assert_eq!(long_test_array.to_string(),
+ "[false,null,[\"foo\\nbar\",3.5]]");
+ assert_eq!(
+ long_test_array.pretty().to_string(),
+ "\
+ [\n \
+ false,\n \
+ null,\n \
+ [\n \
+ \"foo\\nbar\",\n \
+ 3.5\n \
+ ]\n\
+ ]"
+ );
+ }
+
+ #[test]
+ fn test_write_object() {
+ assert_eq!(mk_object(&[]).to_string(), "{}");
+ assert_eq!(mk_object(&[]).pretty().to_string(), "{}");
+
+ assert_eq!(
+ mk_object(&[
+ ("a".to_string(), Boolean(true))
+ ]).to_string(),
+ "{\"a\":true}"
+ );
+ assert_eq!(
+ mk_object(&[("a".to_string(), Boolean(true))]).pretty().to_string(),
+ "\
+ {\n \
+ \"a\": true\n\
+ }"
+ );
+
+ let complex_obj = mk_object(&[
+ ("b".to_string(), Array(vec![
+ mk_object(&[("c".to_string(), String("\x0c\r".to_string()))]),
+ mk_object(&[("d".to_string(), String("".to_string()))])
+ ]))
+ ]);
+
+ assert_eq!(
+ complex_obj.to_string(),
+ "{\
+ \"b\":[\
+ {\"c\":\"\\f\\r\"},\
+ {\"d\":\"\"}\
+ ]\
+ }"
+ );
+ assert_eq!(
+ complex_obj.pretty().to_string(),
+ "\
+ {\n \
+ \"b\": [\n \
+ {\n \
+ \"c\": \"\\f\\r\"\n \
+ },\n \
+ {\n \
+ \"d\": \"\"\n \
+ }\n \
+ ]\n\
+ }"
+ );
+
+ let a = mk_object(&[
+ ("a".to_string(), Boolean(true)),
+ ("b".to_string(), Array(vec![
+ mk_object(&[("c".to_string(), String("\x0c\r".to_string()))]),
+ mk_object(&[("d".to_string(), String("".to_string()))])
+ ]))
+ ]);
+
+ // We can't compare the strings directly because the object fields be
+ // printed in a different order.
+ assert_eq!(a.clone(), a.to_string().parse().unwrap());
+ assert_eq!(a.clone(), a.pretty().to_string().parse().unwrap());
+ }
+
+ #[test]
+ fn test_write_enum() {
+ let animal = Dog;
+ assert_eq!(
+ format!("{}", super::as_json(&animal)),
+ "\"Dog\""
+ );
+ assert_eq!(
+ format!("{}", super::as_pretty_json(&animal)),
+ "\"Dog\""
+ );
+
+ let animal = Frog("Henry".to_string(), 349);
+ assert_eq!(
+ format!("{}", super::as_json(&animal)),
+ "{\"variant\":\"Frog\",\"fields\":[\"Henry\",349]}"
+ );
+ assert_eq!(
+ format!("{}", super::as_pretty_json(&animal)),
+ "{\n \
+ \"variant\": \"Frog\",\n \
+ \"fields\": [\n \
+ \"Henry\",\n \
+ 349\n \
+ ]\n\
+ }"
+ );
+ }
+
+ macro_rules! check_encoder_for_simple {
+ ($value:expr, $expected:expr) => ({
+ let s = format!("{}", super::as_json(&$value));
+ assert_eq!(s, $expected);
+
+ let s = format!("{}", super::as_pretty_json(&$value));
+ assert_eq!(s, $expected);
+ })
+ }
+
+ #[test]
+ fn test_write_some() {
+ check_encoder_for_simple!(Some("jodhpurs".to_string()), "\"jodhpurs\"");
+ }
+
+ #[test]
+ fn test_write_none() {
+ check_encoder_for_simple!(None::<string::String>, "null");
+ }
+
+ #[test]
+ fn test_write_char() {
+ check_encoder_for_simple!('a', "\"a\"");
+ check_encoder_for_simple!('\t', "\"\\t\"");
+ check_encoder_for_simple!('\u{0000}', "\"\\u0000\"");
+ check_encoder_for_simple!('\u{001b}', "\"\\u001b\"");
+ check_encoder_for_simple!('\u{007f}', "\"\\u007f\"");
+ check_encoder_for_simple!('\u{00a0}', "\"\u{00a0}\"");
+ check_encoder_for_simple!('\u{abcd}', "\"\u{abcd}\"");
+ check_encoder_for_simple!('\u{10ffff}', "\"\u{10ffff}\"");
+ }
+
+ #[test]
+ fn test_trailing_characters() {
+ assert_eq!(from_str("nulla"), Err(SyntaxError(TrailingCharacters, 1, 5)));
+ assert_eq!(from_str("truea"), Err(SyntaxError(TrailingCharacters, 1, 5)));
+ assert_eq!(from_str("falsea"), Err(SyntaxError(TrailingCharacters, 1, 6)));
+ assert_eq!(from_str("1a"), Err(SyntaxError(TrailingCharacters, 1, 2)));
+ assert_eq!(from_str("[]a"), Err(SyntaxError(TrailingCharacters, 1, 3)));
+ assert_eq!(from_str("{}a"), Err(SyntaxError(TrailingCharacters, 1, 3)));
+ }
+
+ #[test]
+ fn test_read_identifiers() {
+ assert_eq!(from_str("n"), Err(SyntaxError(InvalidSyntax, 1, 2)));
+ assert_eq!(from_str("nul"), Err(SyntaxError(InvalidSyntax, 1, 4)));
+ assert_eq!(from_str("t"), Err(SyntaxError(InvalidSyntax, 1, 2)));
+ assert_eq!(from_str("truz"), Err(SyntaxError(InvalidSyntax, 1, 4)));
+ assert_eq!(from_str("f"), Err(SyntaxError(InvalidSyntax, 1, 2)));
+ assert_eq!(from_str("faz"), Err(SyntaxError(InvalidSyntax, 1, 3)));
+
+ assert_eq!(from_str("null"), Ok(Null));
+ assert_eq!(from_str("true"), Ok(Boolean(true)));
+ assert_eq!(from_str("false"), Ok(Boolean(false)));
+ assert_eq!(from_str(" null "), Ok(Null));
+ assert_eq!(from_str(" true "), Ok(Boolean(true)));
+ assert_eq!(from_str(" false "), Ok(Boolean(false)));
+ }
+
+ #[test]
+ fn test_decode_identifiers() {
+ let v: () = super::decode("null").unwrap();
+ assert_eq!(v, ());
+
+ let v: bool = super::decode("true").unwrap();
+ assert_eq!(v, true);
+
+ let v: bool = super::decode("false").unwrap();
+ assert_eq!(v, false);
+ }
+
+ #[test]
+ fn test_read_number() {
+ assert_eq!(from_str("+"), Err(SyntaxError(InvalidSyntax, 1, 1)));
+ assert_eq!(from_str("."), Err(SyntaxError(InvalidSyntax, 1, 1)));
+ assert_eq!(from_str("NaN"), Err(SyntaxError(InvalidSyntax, 1, 1)));
+ assert_eq!(from_str("-"), Err(SyntaxError(InvalidNumber, 1, 2)));
+ assert_eq!(from_str("00"), Err(SyntaxError(InvalidNumber, 1, 2)));
+ assert_eq!(from_str("1."), Err(SyntaxError(InvalidNumber, 1, 3)));
+ assert_eq!(from_str("1e"), Err(SyntaxError(InvalidNumber, 1, 3)));
+ assert_eq!(from_str("1e+"), Err(SyntaxError(InvalidNumber, 1, 4)));
+
+ assert_eq!(from_str("18446744073709551616"), Err(SyntaxError(InvalidNumber, 1, 20)));
+ assert_eq!(from_str("-9223372036854775809"), Err(SyntaxError(InvalidNumber, 1, 21)));
+
+ assert_eq!(from_str("3"), Ok(U64(3)));
+ assert_eq!(from_str("3.1"), Ok(F64(3.1)));
+ assert_eq!(from_str("-1.2"), Ok(F64(-1.2)));
+ assert_eq!(from_str("0.4"), Ok(F64(0.4)));
+ assert_eq!(from_str("0.4e5"), Ok(F64(0.4e5)));
+ assert_eq!(from_str("0.4e+15"), Ok(F64(0.4e15)));
+ assert_eq!(from_str("0.4e-01"), Ok(F64(0.4e-01)));
+ assert_eq!(from_str(" 3 "), Ok(U64(3)));
+
+ assert_eq!(from_str("-9223372036854775808"), Ok(I64(i64::MIN)));
+ assert_eq!(from_str("9223372036854775807"), Ok(U64(i64::MAX as u64)));
+ assert_eq!(from_str("18446744073709551615"), Ok(U64(u64::MAX)));
+ }
+
+ #[test]
+ fn test_decode_numbers() {
+ let v: f64 = super::decode("3").unwrap();
+ assert_eq!(v, 3.0);
+
+ let v: f64 = super::decode("3.1").unwrap();
+ assert_eq!(v, 3.1);
+
+ let v: f64 = super::decode("-1.2").unwrap();
+ assert_eq!(v, -1.2);
+
+ let v: f64 = super::decode("0.4").unwrap();
+ assert_eq!(v, 0.4);
+
+ let v: f64 = super::decode("0.4e5").unwrap();
+ assert_eq!(v, 0.4e5);
+
+ let v: f64 = super::decode("0.4e15").unwrap();
+ assert_eq!(v, 0.4e15);
+
+ let v: f64 = super::decode("0.4e-01").unwrap();
+ assert_eq!(v, 0.4e-01);
+
+ let v: u64 = super::decode("0").unwrap();
+ assert_eq!(v, 0);
+
+ let v: u64 = super::decode("18446744073709551615").unwrap();
+ assert_eq!(v, u64::MAX);
+
+ let v: i64 = super::decode("-9223372036854775808").unwrap();
+ assert_eq!(v, i64::MIN);
+
+ let v: i64 = super::decode("9223372036854775807").unwrap();
+ assert_eq!(v, i64::MAX);
+
+ let res: DecodeResult<i64> = super::decode("765.25252");
+ assert_eq!(res, Err(ExpectedError("Integer".to_string(), "765.25252".to_string())));
+ }
+
+ #[test]
+ fn test_read_str() {
+ assert_eq!(from_str("\""), Err(SyntaxError(EOFWhileParsingString, 1, 2)));
+ assert_eq!(from_str("\"lol"), Err(SyntaxError(EOFWhileParsingString, 1, 5)));
+
+ assert_eq!(from_str("\"\""), Ok(String("".to_string())));
+ assert_eq!(from_str("\"foo\""), Ok(String("foo".to_string())));
+ assert_eq!(from_str("\"\\\"\""), Ok(String("\"".to_string())));
+ assert_eq!(from_str("\"\\b\""), Ok(String("\x08".to_string())));
+ assert_eq!(from_str("\"\\n\""), Ok(String("\n".to_string())));
+ assert_eq!(from_str("\"\\r\""), Ok(String("\r".to_string())));
+ assert_eq!(from_str("\"\\t\""), Ok(String("\t".to_string())));
+ assert_eq!(from_str(" \"foo\" "), Ok(String("foo".to_string())));
+ assert_eq!(from_str("\"\\u12ab\""), Ok(String("\u{12ab}".to_string())));
+ assert_eq!(from_str("\"\\uAB12\""), Ok(String("\u{AB12}".to_string())));
+ }
+
+ #[test]
+ fn test_decode_str() {
+ let s = [("\"\"", ""),
+ ("\"foo\"", "foo"),
+ ("\"\\\"\"", "\""),
+ ("\"\\b\"", "\x08"),
+ ("\"\\n\"", "\n"),
+ ("\"\\r\"", "\r"),
+ ("\"\\t\"", "\t"),
+ ("\"\\u12ab\"", "\u{12ab}"),
+ ("\"\\uAB12\"", "\u{AB12}")];
+
+ for &(i, o) in s.iter() {
+ let v: string::String = super::decode(i).unwrap();
+ assert_eq!(v, o);
+ }
+ }
+
+ #[test]
+ fn test_read_array() {
+ assert_eq!(from_str("["), Err(SyntaxError(EOFWhileParsingValue, 1, 2)));
+ assert_eq!(from_str("[1"), Err(SyntaxError(EOFWhileParsingArray, 1, 3)));
+ assert_eq!(from_str("[1,"), Err(SyntaxError(EOFWhileParsingValue, 1, 4)));
+ assert_eq!(from_str("[1,]"), Err(SyntaxError(InvalidSyntax, 1, 4)));
+ assert_eq!(from_str("[6 7]"), Err(SyntaxError(InvalidSyntax, 1, 4)));
+
+ assert_eq!(from_str("[]"), Ok(Array(vec![])));
+ assert_eq!(from_str("[ ]"), Ok(Array(vec![])));
+ assert_eq!(from_str("[true]"), Ok(Array(vec![Boolean(true)])));
+ assert_eq!(from_str("[ false ]"), Ok(Array(vec![Boolean(false)])));
+ assert_eq!(from_str("[null]"), Ok(Array(vec![Null])));
+ assert_eq!(from_str("[3, 1]"),
+ Ok(Array(vec![U64(3), U64(1)])));
+ assert_eq!(from_str("\n[3, 2]\n"),
+ Ok(Array(vec![U64(3), U64(2)])));
+ assert_eq!(from_str("[2, [4, 1]]"),
+ Ok(Array(vec![U64(2), Array(vec![U64(4), U64(1)])])));
+ }
+
+ #[test]
+ fn test_decode_array() {
+ let v: Vec<()> = super::decode("[]").unwrap();
+ assert_eq!(v, vec![]);
+
+ let v: Vec<()> = super::decode("[null]").unwrap();
+ assert_eq!(v, vec![()]);
+
+ let v: Vec<bool> = super::decode("[true]").unwrap();
+ assert_eq!(v, vec![true]);
+
+ let v: Vec<int> = super::decode("[3, 1]").unwrap();
+ assert_eq!(v, vec![3, 1]);
+
+ let v: Vec<Vec<uint>> = super::decode("[[3], [1, 2]]").unwrap();
+ assert_eq!(v, vec![vec![3], vec![1, 2]]);
+ }
+
+ #[test]
+ fn test_decode_tuple() {
+ let t: (uint, uint, uint) = super::decode("[1, 2, 3]").unwrap();
+ assert_eq!(t, (1u, 2, 3));
+
+ let t: (uint, string::String) = super::decode("[1, \"two\"]").unwrap();
+ assert_eq!(t, (1u, "two".to_string()));
+ }
+
+ #[test]
+ fn test_decode_tuple_malformed_types() {
+ assert!(super::decode::<(uint, string::String)>("[1, 2]").is_err());
+ }
+
+ #[test]
+ fn test_decode_tuple_malformed_length() {
+ assert!(super::decode::<(uint, uint)>("[1, 2, 3]").is_err());
+ }
+
+ #[test]
+ fn test_read_object() {
+ assert_eq!(from_str("{"), Err(SyntaxError(EOFWhileParsingObject, 1, 2)));
+ assert_eq!(from_str("{ "), Err(SyntaxError(EOFWhileParsingObject, 1, 3)));
+ assert_eq!(from_str("{1"), Err(SyntaxError(KeyMustBeAString, 1, 2)));
+ assert_eq!(from_str("{ \"a\""), Err(SyntaxError(EOFWhileParsingObject, 1, 6)));
+ assert_eq!(from_str("{\"a\""), Err(SyntaxError(EOFWhileParsingObject, 1, 5)));
+ assert_eq!(from_str("{\"a\" "), Err(SyntaxError(EOFWhileParsingObject, 1, 6)));
+
+ assert_eq!(from_str("{\"a\" 1"), Err(SyntaxError(ExpectedColon, 1, 6)));
+ assert_eq!(from_str("{\"a\":"), Err(SyntaxError(EOFWhileParsingValue, 1, 6)));
+ assert_eq!(from_str("{\"a\":1"), Err(SyntaxError(EOFWhileParsingObject, 1, 7)));
+ assert_eq!(from_str("{\"a\":1 1"), Err(SyntaxError(InvalidSyntax, 1, 8)));
+ assert_eq!(from_str("{\"a\":1,"), Err(SyntaxError(EOFWhileParsingObject, 1, 8)));
+
+ assert_eq!(from_str("{}").unwrap(), mk_object(&[]));
+ assert_eq!(from_str("{\"a\": 3}").unwrap(),
+ mk_object(&[("a".to_string(), U64(3))]));
+
+ assert_eq!(from_str(
+ "{ \"a\": null, \"b\" : true }").unwrap(),
+ mk_object(&[
+ ("a".to_string(), Null),
+ ("b".to_string(), Boolean(true))]));
+ assert_eq!(from_str("\n{ \"a\": null, \"b\" : true }\n").unwrap(),
+ mk_object(&[
+ ("a".to_string(), Null),
+ ("b".to_string(), Boolean(true))]));
+ assert_eq!(from_str(
+ "{\"a\" : 1.0 ,\"b\": [ true ]}").unwrap(),
+ mk_object(&[
+ ("a".to_string(), F64(1.0)),
+ ("b".to_string(), Array(vec![Boolean(true)]))
+ ]));
+ assert_eq!(from_str(
+ "{\
+ \"a\": 1.0, \
+ \"b\": [\
+ true,\
+ \"foo\\nbar\", \
+ { \"c\": {\"d\": null} } \
+ ]\
+ }").unwrap(),
+ mk_object(&[
+ ("a".to_string(), F64(1.0)),
+ ("b".to_string(), Array(vec![
+ Boolean(true),
+ String("foo\nbar".to_string()),
+ mk_object(&[
+ ("c".to_string(), mk_object(&[("d".to_string(), Null)]))
+ ])
+ ]))
+ ]));
+ }
+
+ #[test]
+ fn test_decode_struct() {
+ let s = "{
+ \"inner\": [
+ { \"a\": null, \"b\": 2, \"c\": [\"abc\", \"xyz\"] }
+ ]
+ }";
+
+ let v: Outer = super::decode(s).unwrap();
+ assert_eq!(
+ v,
+ Outer {
+ inner: vec![
+ Inner { a: (), b: 2, c: vec!["abc".to_string(), "xyz".to_string()] }
+ ]
+ }
+ );
+ }
+
+ #[derive(RustcDecodable)]
+ struct FloatStruct {
+ f: f64,
+ a: Vec<f64>
+ }
+ #[test]
+ fn test_decode_struct_with_nan() {
+ let s = "{\"f\":null,\"a\":[null,123]}";
+ let obj: FloatStruct = super::decode(s).unwrap();
+ assert!(obj.f.is_nan());
+ assert!(obj.a[0].is_nan());
+ assert_eq!(obj.a[1], 123f64);
+ }
+
+ #[test]
+ fn test_decode_option() {
+ let value: Option<string::String> = super::decode("null").unwrap();
+ assert_eq!(value, None);
+
+ let value: Option<string::String> = super::decode("\"jodhpurs\"").unwrap();
+ assert_eq!(value, Some("jodhpurs".to_string()));
+ }
+
+ #[test]
+ fn test_decode_enum() {
+ let value: Animal = super::decode("\"Dog\"").unwrap();
+ assert_eq!(value, Dog);
+
+ let s = "{\"variant\":\"Frog\",\"fields\":[\"Henry\",349]}";
+ let value: Animal = super::decode(s).unwrap();
+ assert_eq!(value, Frog("Henry".to_string(), 349));
+ }
+
+ #[test]
+ fn test_decode_map() {
+ let s = "{\"a\": \"Dog\", \"b\": {\"variant\":\"Frog\",\
+ \"fields\":[\"Henry\", 349]}}";
+ let mut map: BTreeMap<string::String, Animal> = super::decode(s).unwrap();
+
+ assert_eq!(map.remove(&"a".to_string()), Some(Dog));
+ assert_eq!(map.remove(&"b".to_string()), Some(Frog("Henry".to_string(), 349)));
+ }
+
+ #[test]
+ fn test_multiline_errors() {
+ assert_eq!(from_str("{\n \"foo\":\n \"bar\""),
+ Err(SyntaxError(EOFWhileParsingObject, 3u, 8u)));
+ }
+
+ #[derive(RustcDecodable)]
+ #[allow(dead_code)]
+ struct DecodeStruct {
+ x: f64,
+ y: bool,
+ z: string::String,
+ w: Vec<DecodeStruct>
+ }
+ #[derive(RustcDecodable)]
+ enum DecodeEnum {
+ A(f64),
+ B(string::String)
+ }
+ fn check_err<T: Decodable<Decoder, DecoderError>>(to_parse: &'static str,
+ expected: DecoderError) {
+ let res: DecodeResult<T> = match from_str(to_parse) {
+ Err(e) => Err(ParseError(e)),
+ Ok(json) => Decodable::decode(&mut Decoder::new(json))
+ };
+ match res {
+ Ok(_) => panic!("`{}` parsed & decoded ok, expecting error `{}`",
+ to_parse, expected),
+ Err(ParseError(e)) => panic!("`{}` is not valid json: {}",
+ to_parse, e),
+ Err(e) => {
+ assert_eq!(e, expected);
+ }
+ }
+ }
+ #[test]
+ fn test_decode_errors_struct() {
+ check_err::<DecodeStruct>("[]", ExpectedError("Object".to_string(), "[]".to_string()));
+ check_err::<DecodeStruct>("{\"x\": true, \"y\": true, \"z\": \"\", \"w\": []}",
+ ExpectedError("Number".to_string(), "true".to_string()));
+ check_err::<DecodeStruct>("{\"x\": 1, \"y\": [], \"z\": \"\", \"w\": []}",
+ ExpectedError("Boolean".to_string(), "[]".to_string()));
+ check_err::<DecodeStruct>("{\"x\": 1, \"y\": true, \"z\": {}, \"w\": []}",
+ ExpectedError("String".to_string(), "{}".to_string()));
+ check_err::<DecodeStruct>("{\"x\": 1, \"y\": true, \"z\": \"\", \"w\": null}",
+ ExpectedError("Array".to_string(), "null".to_string()));
+ check_err::<DecodeStruct>("{\"x\": 1, \"y\": true, \"z\": \"\"}",
+ MissingFieldError("w".to_string()));
+ }
+ #[test]
+ fn test_decode_errors_enum() {
+ check_err::<DecodeEnum>("{}",
+ MissingFieldError("variant".to_string()));
+ check_err::<DecodeEnum>("{\"variant\": 1}",
+ ExpectedError("String".to_string(), "1".to_string()));
+ check_err::<DecodeEnum>("{\"variant\": \"A\"}",
+ MissingFieldError("fields".to_string()));
+ check_err::<DecodeEnum>("{\"variant\": \"A\", \"fields\": null}",
+ ExpectedError("Array".to_string(), "null".to_string()));
+ check_err::<DecodeEnum>("{\"variant\": \"C\", \"fields\": []}",
+ UnknownVariantError("C".to_string()));
+ }
+
+ #[test]
+ fn test_find(){
+ let json_value = from_str("{\"dog\" : \"cat\"}").unwrap();
+ let found_str = json_value.find("dog");
+ assert!(found_str.unwrap().as_string().unwrap() == "cat");
+ }
+
+ #[test]
+ fn test_find_path(){
+ let json_value = from_str("{\"dog\":{\"cat\": {\"mouse\" : \"cheese\"}}}").unwrap();
+ let found_str = json_value.find_path(&["dog", "cat", "mouse"]);
+ assert!(found_str.unwrap().as_string().unwrap() == "cheese");
+ }
+
+ #[test]
+ fn test_search(){
+ let json_value = from_str("{\"dog\":{\"cat\": {\"mouse\" : \"cheese\"}}}").unwrap();
+ let found_str = json_value.search("mouse").and_then(|j| j.as_string());
+ assert!(found_str.unwrap() == "cheese");
+ }
+
+ #[test]
+ fn test_index(){
+ let json_value = from_str("{\"animals\":[\"dog\",\"cat\",\"mouse\"]}").unwrap();
+ let ref array = json_value["animals"];
+ assert_eq!(array[0].as_string().unwrap(), "dog");
+ assert_eq!(array[1].as_string().unwrap(), "cat");
+ assert_eq!(array[2].as_string().unwrap(), "mouse");
+ }
+
+ #[test]
+ fn test_is_object(){
+ let json_value = from_str("{}").unwrap();
+ assert!(json_value.is_object());
+ }
+
+ #[test]
+ fn test_as_object(){
+ let json_value = from_str("{}").unwrap();
+ let json_object = json_value.as_object();
+ assert!(json_object.is_some());
+ }
+
+ #[test]
+ fn test_is_array(){
+ let json_value = from_str("[1, 2, 3]").unwrap();
+ assert!(json_value.is_array());
+ }
+
+ #[test]
+ fn test_as_array(){
+ let json_value = from_str("[1, 2, 3]").unwrap();
+ let json_array = json_value.as_array();
+ let expected_length = 3;
+ assert!(json_array.is_some() && json_array.unwrap().len() == expected_length);
+ }
+
+ #[test]
+ fn test_is_string(){
+ let json_value = from_str("\"dog\"").unwrap();
+ assert!(json_value.is_string());
+ }
+
+ #[test]
+ fn test_as_string(){
+ let json_value = from_str("\"dog\"").unwrap();
+ let json_str = json_value.as_string();
+ let expected_str = "dog";
+ assert_eq!(json_str, Some(expected_str));
+ }
+
+ #[test]
+ fn test_is_number(){
+ let json_value = from_str("12").unwrap();
+ assert!(json_value.is_number());
+ }
+
+ #[test]
+ fn test_is_i64(){
+ let json_value = from_str("-12").unwrap();
+ assert!(json_value.is_i64());
+
+ let json_value = from_str("12").unwrap();
+ assert!(!json_value.is_i64());
+
+ let json_value = from_str("12.0").unwrap();
+ assert!(!json_value.is_i64());
+ }
+
+ #[test]
+ fn test_is_u64(){
+ let json_value = from_str("12").unwrap();
+ assert!(json_value.is_u64());
+
+ let json_value = from_str("-12").unwrap();
+ assert!(!json_value.is_u64());
+
+ let json_value = from_str("12.0").unwrap();
+ assert!(!json_value.is_u64());
+ }
+
+ #[test]
+ fn test_is_f64(){
+ let json_value = from_str("12").unwrap();
+ assert!(!json_value.is_f64());
+
+ let json_value = from_str("-12").unwrap();
+ assert!(!json_value.is_f64());
+
+ let json_value = from_str("12.0").unwrap();
+ assert!(json_value.is_f64());
+
+ let json_value = from_str("-12.0").unwrap();
+ assert!(json_value.is_f64());
+ }
+
+ #[test]
+ fn test_as_i64(){
+ let json_value = from_str("-12").unwrap();
+ let json_num = json_value.as_i64();
+ assert_eq!(json_num, Some(-12));
+ }
+
+ #[test]
+ fn test_as_u64(){
+ let json_value = from_str("12").unwrap();
+ let json_num = json_value.as_u64();
+ assert_eq!(json_num, Some(12));
+ }
+
+ #[test]
+ fn test_as_f64(){
+ let json_value = from_str("12.0").unwrap();
+ let json_num = json_value.as_f64();
+ assert_eq!(json_num, Some(12f64));
+ }
+
+ #[test]
+ fn test_is_boolean(){
+ let json_value = from_str("false").unwrap();
+ assert!(json_value.is_boolean());
+ }
+
+ #[test]
+ fn test_as_boolean(){
+ let json_value = from_str("false").unwrap();
+ let json_bool = json_value.as_boolean();
+ let expected_bool = false;
+ assert!(json_bool.is_some() && json_bool.unwrap() == expected_bool);
+ }
+
+ #[test]
+ fn test_is_null(){
+ let json_value = from_str("null").unwrap();
+ assert!(json_value.is_null());
+ }
+
+ #[test]
+ fn test_as_null(){
+ let json_value = from_str("null").unwrap();
+ let json_null = json_value.as_null();
+ let expected_null = ();
+ assert!(json_null.is_some() && json_null.unwrap() == expected_null);
+ }
+
+ #[test]
+ fn test_encode_hashmap_with_numeric_key() {
+ use std::str::from_utf8;
+ use std::io::Writer;
+ use std::collections::HashMap;
+ let mut hm: HashMap<uint, bool> = HashMap::new();
+ hm.insert(1, true);
+ let mut mem_buf = Vec::new();
+ write!(&mut mem_buf, "{}", super::as_pretty_json(&hm)).unwrap();
+ let json_str = from_utf8(mem_buf[]).unwrap();
+ match from_str(json_str) {
+ Err(_) => panic!("Unable to parse json_str: {}", json_str),
+ _ => {} // it parsed and we are good to go
+ }
+ }
+
+ #[test]
+ fn test_prettyencode_hashmap_with_numeric_key() {
+ use std::str::from_utf8;
+ use std::io::Writer;
+ use std::collections::HashMap;
+ let mut hm: HashMap<uint, bool> = HashMap::new();
+ hm.insert(1, true);
+ let mut mem_buf = Vec::new();
+ write!(&mut mem_buf, "{}", super::as_pretty_json(&hm)).unwrap();
+ let json_str = from_utf8(mem_buf[]).unwrap();
+ match from_str(json_str) {
+ Err(_) => panic!("Unable to parse json_str: {}", json_str),
+ _ => {} // it parsed and we are good to go
+ }
+ }
+
+ #[test]
+ fn test_prettyencoder_indent_level_param() {
+ use std::str::from_utf8;
+ use std::collections::BTreeMap;
+
+ let mut tree = BTreeMap::new();
+
+ tree.insert("hello".to_string(), String("guten tag".to_string()));
+ tree.insert("goodbye".to_string(), String("sayonara".to_string()));
+
+ let json = Array(
+ // The following layout below should look a lot like
+ // the pretty-printed JSON (indent * x)
+ vec!
+ ( // 0x
+ String("greetings".to_string()), // 1x
+ Object(tree), // 1x + 2x + 2x + 1x
+ ) // 0x
+ // End JSON array (7 lines)
+ );
+
+ // Helper function for counting indents
+ fn indents(source: &str) -> uint {
+ let trimmed = source.trim_left_matches(' ');
+ source.len() - trimmed.len()
+ }
+
+ // Test up to 4 spaces of indents (more?)
+ for i in range(0, 4u) {
+ let mut writer = Vec::new();
+ write!(&mut writer, "{}",
+ super::as_pretty_json(&json).indent(i)).unwrap();
+
+ let printed = from_utf8(writer[]).unwrap();
+
+ // Check for indents at each line
+ let lines: Vec<&str> = printed.lines().collect();
+ assert_eq!(lines.len(), 7); // JSON should be 7 lines
+
+ assert_eq!(indents(lines[0]), 0 * i); // [
+ assert_eq!(indents(lines[1]), 1 * i); // "greetings",
+ assert_eq!(indents(lines[2]), 1 * i); // {
+ assert_eq!(indents(lines[3]), 2 * i); // "hello": "guten tag",
+ assert_eq!(indents(lines[4]), 2 * i); // "goodbye": "sayonara"
+ assert_eq!(indents(lines[5]), 1 * i); // },
+ assert_eq!(indents(lines[6]), 0 * i); // ]
+
+ // Finally, test that the pretty-printed JSON is valid
+ from_str(printed).ok().expect("Pretty-printed JSON is invalid!");
+ }
+ }
+
+ #[test]
+ fn test_hashmap_with_numeric_key_can_handle_double_quote_delimited_key() {
+ use std::collections::HashMap;
+ use Decodable;
+ let json_str = "{\"1\":true}";
+ let json_obj = match from_str(json_str) {
+ Err(_) => panic!("Unable to parse json_str: {}", json_str),
+ Ok(o) => o
+ };
+ let mut decoder = Decoder::new(json_obj);
+ let _hm: HashMap<uint, bool> = Decodable::decode(&mut decoder).unwrap();
+ }
+
+ #[test]
+ fn test_hashmap_with_numeric_key_will_error_with_string_keys() {
+ use std::collections::HashMap;
+ use Decodable;
+ let json_str = "{\"a\":true}";
+ let json_obj = match from_str(json_str) {
+ Err(_) => panic!("Unable to parse json_str: {}", json_str),
+ Ok(o) => o
+ };
+ let mut decoder = Decoder::new(json_obj);
+ let result: Result<HashMap<uint, bool>, DecoderError> = Decodable::decode(&mut decoder);
+ assert_eq!(result, Err(ExpectedError("Number".to_string(), "a".to_string())));
+ }
+
+ fn assert_stream_equal(src: &str,
+ expected: Vec<(JsonEvent, Vec<StackElement>)>) {
+ let mut parser = Parser::new(src.chars());
+ let mut i = 0;
+ loop {
+ let evt = match parser.next() {
+ Some(e) => e,
+ None => { break; }
+ };
+ let (ref expected_evt, ref expected_stack) = expected[i];
+ if !parser.stack().is_equal_to(expected_stack.as_slice()) {
+ panic!("Parser stack is not equal to {}", expected_stack);
+ }
+ assert_eq!(&evt, expected_evt);
+ i+=1;
+ }
+ }
+ #[test]
+ #[cfg_attr(target_word_size = "32", ignore)] // FIXME(#14064)
+ fn test_streaming_parser() {
+ assert_stream_equal(
+ r#"{ "foo":"bar", "array" : [0, 1, 2, 3, 4, 5], "idents":[null,true,false]}"#,
+ vec![
+ (ObjectStart, vec![]),
+ (StringValue("bar".to_string()), vec![Key("foo")]),
+ (ArrayStart, vec![Key("array")]),
+ (U64Value(0), vec![Key("array"), Index(0)]),
+ (U64Value(1), vec![Key("array"), Index(1)]),
+ (U64Value(2), vec![Key("array"), Index(2)]),
+ (U64Value(3), vec![Key("array"), Index(3)]),
+ (U64Value(4), vec![Key("array"), Index(4)]),
+ (U64Value(5), vec![Key("array"), Index(5)]),
+ (ArrayEnd, vec![Key("array")]),
+ (ArrayStart, vec![Key("idents")]),
+ (NullValue, vec![Key("idents"), Index(0)]),
+ (BooleanValue(true), vec![Key("idents"), Index(1)]),
+ (BooleanValue(false), vec![Key("idents"), Index(2)]),
+ (ArrayEnd, vec![Key("idents")]),
+ (ObjectEnd, vec![]),
+ ]
+ );
+ }
+ fn last_event(src: &str) -> JsonEvent {
+ let mut parser = Parser::new(src.chars());
+ let mut evt = NullValue;
+ loop {
+ evt = match parser.next() {
+ Some(e) => e,
+ None => return evt,
+ }
+ }
+ }
+
+ #[test]
+ #[cfg_attr(target_word_size = "32", ignore)] // FIXME(#14064)
+ fn test_read_object_streaming() {
+ assert_eq!(last_event("{ "), Error(SyntaxError(EOFWhileParsingObject, 1, 3)));
+ assert_eq!(last_event("{1"), Error(SyntaxError(KeyMustBeAString, 1, 2)));
+ assert_eq!(last_event("{ \"a\""), Error(SyntaxError(EOFWhileParsingObject, 1, 6)));
+ assert_eq!(last_event("{\"a\""), Error(SyntaxError(EOFWhileParsingObject, 1, 5)));
+ assert_eq!(last_event("{\"a\" "), Error(SyntaxError(EOFWhileParsingObject, 1, 6)));
+
+ assert_eq!(last_event("{\"a\" 1"), Error(SyntaxError(ExpectedColon, 1, 6)));
+ assert_eq!(last_event("{\"a\":"), Error(SyntaxError(EOFWhileParsingValue, 1, 6)));
+ assert_eq!(last_event("{\"a\":1"), Error(SyntaxError(EOFWhileParsingObject, 1, 7)));
+ assert_eq!(last_event("{\"a\":1 1"), Error(SyntaxError(InvalidSyntax, 1, 8)));
+ assert_eq!(last_event("{\"a\":1,"), Error(SyntaxError(EOFWhileParsingObject, 1, 8)));
+ assert_eq!(last_event("{\"a\":1,}"), Error(SyntaxError(TrailingComma, 1, 8)));
+
+ assert_stream_equal(
+ "{}",
+ vec![(ObjectStart, vec![]), (ObjectEnd, vec![])]
+ );
+ assert_stream_equal(
+ "{\"a\": 3}",
+ vec![
+ (ObjectStart, vec![]),
+ (U64Value(3), vec![Key("a")]),
+ (ObjectEnd, vec![]),
+ ]
+ );
+ assert_stream_equal(
+ "{ \"a\": null, \"b\" : true }",
+ vec![
+ (ObjectStart, vec![]),
+ (NullValue, vec![Key("a")]),
+ (BooleanValue(true), vec![Key("b")]),
+ (ObjectEnd, vec![]),
+ ]
+ );
+ assert_stream_equal(
+ "{\"a\" : 1.0 ,\"b\": [ true ]}",
+ vec![
+ (ObjectStart, vec![]),
+ (F64Value(1.0), vec![Key("a")]),
+ (ArrayStart, vec![Key("b")]),
+ (BooleanValue(true),vec![Key("b"), Index(0)]),
+ (ArrayEnd, vec![Key("b")]),
+ (ObjectEnd, vec![]),
+ ]
+ );
+ assert_stream_equal(
+ r#"{
+ "a": 1.0,
+ "b": [
+ true,
+ "foo\nbar",
+ { "c": {"d": null} }
+ ]
+ }"#,
+ vec![
+ (ObjectStart, vec![]),
+ (F64Value(1.0), vec![Key("a")]),
+ (ArrayStart, vec![Key("b")]),
+ (BooleanValue(true), vec![Key("b"), Index(0)]),
+ (StringValue("foo\nbar".to_string()), vec![Key("b"), Index(1)]),
+ (ObjectStart, vec![Key("b"), Index(2)]),
+ (ObjectStart, vec![Key("b"), Index(2), Key("c")]),
+ (NullValue, vec![Key("b"), Index(2), Key("c"), Key("d")]),
+ (ObjectEnd, vec![Key("b"), Index(2), Key("c")]),
+ (ObjectEnd, vec![Key("b"), Index(2)]),
+ (ArrayEnd, vec![Key("b")]),
+ (ObjectEnd, vec![]),
+ ]
+ );
+ }
+ #[test]
+ #[cfg_attr(target_word_size = "32", ignore)] // FIXME(#14064)
+ fn test_read_array_streaming() {
+ assert_stream_equal(
+ "[]",
+ vec![
+ (ArrayStart, vec![]),
+ (ArrayEnd, vec![]),
+ ]
+ );
+ assert_stream_equal(
+ "[ ]",
+ vec![
+ (ArrayStart, vec![]),
+ (ArrayEnd, vec![]),
+ ]
+ );
+ assert_stream_equal(
+ "[true]",
+ vec![
+ (ArrayStart, vec![]),
+ (BooleanValue(true), vec![Index(0)]),
+ (ArrayEnd, vec![]),
+ ]
+ );
+ assert_stream_equal(
+ "[ false ]",
+ vec![
+ (ArrayStart, vec![]),
+ (BooleanValue(false), vec![Index(0)]),
+ (ArrayEnd, vec![]),
+ ]
+ );
+ assert_stream_equal(
+ "[null]",
+ vec![
+ (ArrayStart, vec![]),
+ (NullValue, vec![Index(0)]),
+ (ArrayEnd, vec![]),
+ ]
+ );
+ assert_stream_equal(
+ "[3, 1]",
+ vec![
+ (ArrayStart, vec![]),
+ (U64Value(3), vec![Index(0)]),
+ (U64Value(1), vec![Index(1)]),
+ (ArrayEnd, vec![]),
+ ]
+ );
+ assert_stream_equal(
+ "\n[3, 2]\n",
+ vec![
+ (ArrayStart, vec![]),
+ (U64Value(3), vec![Index(0)]),
+ (U64Value(2), vec![Index(1)]),
+ (ArrayEnd, vec![]),
+ ]
+ );
+ assert_stream_equal(
+ "[2, [4, 1]]",
+ vec![
+ (ArrayStart, vec![]),
+ (U64Value(2), vec![Index(0)]),
+ (ArrayStart, vec![Index(1)]),
+ (U64Value(4), vec![Index(1), Index(0)]),
+ (U64Value(1), vec![Index(1), Index(1)]),
+ (ArrayEnd, vec![Index(1)]),
+ (ArrayEnd, vec![]),
+ ]
+ );
+
+ assert_eq!(last_event("["), Error(SyntaxError(EOFWhileParsingValue, 1, 2)));
+
+ assert_eq!(from_str("["), Err(SyntaxError(EOFWhileParsingValue, 1, 2)));
+ assert_eq!(from_str("[1"), Err(SyntaxError(EOFWhileParsingArray, 1, 3)));
+ assert_eq!(from_str("[1,"), Err(SyntaxError(EOFWhileParsingValue, 1, 4)));
+ assert_eq!(from_str("[1,]"), Err(SyntaxError(InvalidSyntax, 1, 4)));
+ assert_eq!(from_str("[6 7]"), Err(SyntaxError(InvalidSyntax, 1, 4)));
+
+ }
+ #[test]
+ fn test_trailing_characters_streaming() {
+ assert_eq!(last_event("nulla"), Error(SyntaxError(TrailingCharacters, 1, 5)));
+ assert_eq!(last_event("truea"), Error(SyntaxError(TrailingCharacters, 1, 5)));
+ assert_eq!(last_event("falsea"), Error(SyntaxError(TrailingCharacters, 1, 6)));
+ assert_eq!(last_event("1a"), Error(SyntaxError(TrailingCharacters, 1, 2)));
+ assert_eq!(last_event("[]a"), Error(SyntaxError(TrailingCharacters, 1, 3)));
+ assert_eq!(last_event("{}a"), Error(SyntaxError(TrailingCharacters, 1, 3)));
+ }
+ #[test]
+ fn test_read_identifiers_streaming() {
+ assert_eq!(Parser::new("null".chars()).next(), Some(NullValue));
+ assert_eq!(Parser::new("true".chars()).next(), Some(BooleanValue(true)));
+ assert_eq!(Parser::new("false".chars()).next(), Some(BooleanValue(false)));
+
+ assert_eq!(last_event("n"), Error(SyntaxError(InvalidSyntax, 1, 2)));
+ assert_eq!(last_event("nul"), Error(SyntaxError(InvalidSyntax, 1, 4)));
+ assert_eq!(last_event("t"), Error(SyntaxError(InvalidSyntax, 1, 2)));
+ assert_eq!(last_event("truz"), Error(SyntaxError(InvalidSyntax, 1, 4)));
+ assert_eq!(last_event("f"), Error(SyntaxError(InvalidSyntax, 1, 2)));
+ assert_eq!(last_event("faz"), Error(SyntaxError(InvalidSyntax, 1, 3)));
+ }
+
+ #[test]
+ fn test_stack() {
+ let mut stack = Stack::new();
+
+ assert!(stack.is_empty());
+ assert!(stack.len() == 0);
+ assert!(!stack.last_is_index());
+
+ stack.push_index(0);
+ stack.bump_index();
+
+ assert!(stack.len() == 1);
+ assert!(stack.is_equal_to(&[Index(1)]));
+ assert!(stack.starts_with(&[Index(1)]));
+ assert!(stack.ends_with(&[Index(1)]));
+ assert!(stack.last_is_index());
+ assert!(stack.get(0) == Index(1));
+
+ stack.push_key("foo".to_string());
+
+ assert!(stack.len() == 2);
+ assert!(stack.is_equal_to(&[Index(1), Key("foo")]));
+ assert!(stack.starts_with(&[Index(1), Key("foo")]));
+ assert!(stack.starts_with(&[Index(1)]));
+ assert!(stack.ends_with(&[Index(1), Key("foo")]));
+ assert!(stack.ends_with(&[Key("foo")]));
+ assert!(!stack.last_is_index());
+ assert!(stack.get(0) == Index(1));
+ assert!(stack.get(1) == Key("foo"));
+
+ stack.push_key("bar".to_string());
+
+ assert!(stack.len() == 3);
+ assert!(stack.is_equal_to(&[Index(1), Key("foo"), Key("bar")]));
+ assert!(stack.starts_with(&[Index(1)]));
+ assert!(stack.starts_with(&[Index(1), Key("foo")]));
+ assert!(stack.starts_with(&[Index(1), Key("foo"), Key("bar")]));
+ assert!(stack.ends_with(&[Key("bar")]));
+ assert!(stack.ends_with(&[Key("foo"), Key("bar")]));
+ assert!(stack.ends_with(&[Index(1), Key("foo"), Key("bar")]));
+ assert!(!stack.last_is_index());
+ assert!(stack.get(0) == Index(1));
+ assert!(stack.get(1) == Key("foo"));
+ assert!(stack.get(2) == Key("bar"));
+
+ stack.pop();
+
+ assert!(stack.len() == 2);
+ assert!(stack.is_equal_to(&[Index(1), Key("foo")]));
+ assert!(stack.starts_with(&[Index(1), Key("foo")]));
+ assert!(stack.starts_with(&[Index(1)]));
+ assert!(stack.ends_with(&[Index(1), Key("foo")]));
+ assert!(stack.ends_with(&[Key("foo")]));
+ assert!(!stack.last_is_index());
+ assert!(stack.get(0) == Index(1));
+ assert!(stack.get(1) == Key("foo"));
+ }
+
+ #[test]
+ fn test_to_json() {
+ use std::collections::{HashMap,BTreeMap};
+ use super::ToJson;
+
+ let array2 = Array(vec!(U64(1), U64(2)));
+ let array3 = Array(vec!(U64(1), U64(2), U64(3)));
+ let object = {
+ let mut tree_map = BTreeMap::new();
+ tree_map.insert("a".to_string(), U64(1));
+ tree_map.insert("b".to_string(), U64(2));
+ Object(tree_map)
+ };
+
+ assert_eq!(array2.to_json(), array2);
+ assert_eq!(object.to_json(), object);
+ assert_eq!(3_i.to_json(), I64(3));
+ assert_eq!(4_i8.to_json(), I64(4));
+ assert_eq!(5_i16.to_json(), I64(5));
+ assert_eq!(6_i32.to_json(), I64(6));
+ assert_eq!(7_i64.to_json(), I64(7));
+ assert_eq!(8_u.to_json(), U64(8));
+ assert_eq!(9_u8.to_json(), U64(9));
+ assert_eq!(10_u16.to_json(), U64(10));
+ assert_eq!(11_u32.to_json(), U64(11));
+ assert_eq!(12_u64.to_json(), U64(12));
+ assert_eq!(13.0_f32.to_json(), F64(13.0_f64));
+ assert_eq!(14.0_f64.to_json(), F64(14.0_f64));
+ assert_eq!(().to_json(), Null);
+ assert_eq!(f32::INFINITY.to_json(), Null);
+ assert_eq!(f64::NAN.to_json(), Null);
+ assert_eq!(true.to_json(), Boolean(true));
+ assert_eq!(false.to_json(), Boolean(false));
+ assert_eq!("abc".to_json(), String("abc".to_string()));
+ assert_eq!("abc".to_string().to_json(), String("abc".to_string()));
+ assert_eq!((1u, 2u).to_json(), array2);
+ assert_eq!((1u, 2u, 3u).to_json(), array3);
+ assert_eq!([1u, 2].to_json(), array2);
+ assert_eq!((&[1u, 2, 3]).to_json(), array3);
+ assert_eq!((vec![1u, 2]).to_json(), array2);
+ assert_eq!(vec!(1u, 2, 3).to_json(), array3);
+ let mut tree_map = BTreeMap::new();
+ tree_map.insert("a".to_string(), 1u);
+ tree_map.insert("b".to_string(), 2);
+ assert_eq!(tree_map.to_json(), object);
+ let mut hash_map = HashMap::new();
+ hash_map.insert("a".to_string(), 1u);
+ hash_map.insert("b".to_string(), 2);
+ assert_eq!(hash_map.to_json(), object);
+ assert_eq!(Some(15i).to_json(), I64(15));
+ assert_eq!(Some(15u).to_json(), U64(15));
+ assert_eq!(None::<int>.to_json(), Null);
+ }
+
+ #[bench]
+ fn bench_streaming_small(b: &mut Bencher) {
+ b.iter( || {
+ let mut parser = Parser::new(
+ r#"{
+ "a": 1.0,
+ "b": [
+ true,
+ "foo\nbar",
+ { "c": {"d": null} }
+ ]
+ }"#.chars()
+ );
+ loop {
+ match parser.next() {
+ None => return,
+ _ => {}
+ }
+ }
+ });
+ }
+ #[bench]
+ fn bench_small(b: &mut Bencher) {
+ b.iter( || {
+ let _ = from_str(r#"{
+ "a": 1.0,
+ "b": [
+ true,
+ "foo\nbar",
+ { "c": {"d": null} }
+ ]
+ }"#);
+ });
+ }
+
+ fn big_json() -> string::String {
+ let mut src = "[\n".to_string();
+ for _ in range(0i, 500) {
+ src.push_str(r#"{ "a": true, "b": null, "c":3.1415, "d": "Hello world", "e": \
+ [1,2,3]},"#);
+ }
+ src.push_str("{}]");
+ return src;
+ }
+
+ #[bench]
+ fn bench_streaming_large(b: &mut Bencher) {
+ let src = big_json();
+ b.iter( || {
+ let mut parser = Parser::new(src.chars());
+ loop {
+ match parser.next() {
+ None => return,
+ _ => {}
+ }
+ }
+ });
+ }
+ #[bench]
+ fn bench_large(b: &mut Bencher) {
+ let src = big_json();
+ b.iter( || { let _ = from_str(src.as_slice()); });
+ }
+}
pub use self::serialize::{Decoder, Encoder, Decodable, Encodable,
DecoderHelpers, EncoderHelpers};
+#[cfg(stage0)]
+#[path = "serialize_stage0.rs"]
mod serialize;
+#[cfg(not(stage0))]
+mod serialize;
+
+#[cfg(stage0)]
+#[path = "collection_impls_stage0.rs"]
+mod collection_impls;
+#[cfg(not(stage0))]
mod collection_impls;
pub mod base64;
pub mod hex;
+
+#[cfg(stage0)]
+#[path = "json_stage0.rs"]
+pub mod json;
+#[cfg(not(stage0))]
pub mod json;
mod rustc_serialize {
use std::cell::{Cell, RefCell};
use std::sync::Arc;
-pub trait Encoder<E> {
+pub trait Encoder {
+ type Error;
+
// Primitive types:
- fn emit_nil(&mut self) -> Result<(), E>;
- fn emit_uint(&mut self, v: uint) -> Result<(), E>;
- fn emit_u64(&mut self, v: u64) -> Result<(), E>;
- fn emit_u32(&mut self, v: u32) -> Result<(), E>;
- fn emit_u16(&mut self, v: u16) -> Result<(), E>;
- fn emit_u8(&mut self, v: u8) -> Result<(), E>;
- fn emit_int(&mut self, v: int) -> Result<(), E>;
- fn emit_i64(&mut self, v: i64) -> Result<(), E>;
- fn emit_i32(&mut self, v: i32) -> Result<(), E>;
- fn emit_i16(&mut self, v: i16) -> Result<(), E>;
- fn emit_i8(&mut self, v: i8) -> Result<(), E>;
- fn emit_bool(&mut self, v: bool) -> Result<(), E>;
- fn emit_f64(&mut self, v: f64) -> Result<(), E>;
- fn emit_f32(&mut self, v: f32) -> Result<(), E>;
- fn emit_char(&mut self, v: char) -> Result<(), E>;
- fn emit_str(&mut self, v: &str) -> Result<(), E>;
+ fn emit_nil(&mut self) -> Result<(), Self::Error>;
+ fn emit_uint(&mut self, v: uint) -> Result<(), Self::Error>;
+ fn emit_u64(&mut self, v: u64) -> Result<(), Self::Error>;
+ fn emit_u32(&mut self, v: u32) -> Result<(), Self::Error>;
+ fn emit_u16(&mut self, v: u16) -> Result<(), Self::Error>;
+ fn emit_u8(&mut self, v: u8) -> Result<(), Self::Error>;
+ fn emit_int(&mut self, v: int) -> Result<(), Self::Error>;
+ fn emit_i64(&mut self, v: i64) -> Result<(), Self::Error>;
+ fn emit_i32(&mut self, v: i32) -> Result<(), Self::Error>;
+ fn emit_i16(&mut self, v: i16) -> Result<(), Self::Error>;
+ fn emit_i8(&mut self, v: i8) -> Result<(), Self::Error>;
+ fn emit_bool(&mut self, v: bool) -> Result<(), Self::Error>;
+ fn emit_f64(&mut self, v: f64) -> Result<(), Self::Error>;
+ fn emit_f32(&mut self, v: f32) -> Result<(), Self::Error>;
+ fn emit_char(&mut self, v: char) -> Result<(), Self::Error>;
+ fn emit_str(&mut self, v: &str) -> Result<(), Self::Error>;
// Compound types:
- fn emit_enum<F>(&mut self, name: &str, f: F) -> Result<(), E> where
- F: FnOnce(&mut Self) -> Result<(), E>;
+ fn emit_enum<F>(&mut self, name: &str, f: F) -> Result<(), Self::Error>
+ where F: FnOnce(&mut Self) -> Result<(), Self::Error>;
fn emit_enum_variant<F>(&mut self, v_name: &str,
v_id: uint,
len: uint,
- f: F) -> Result<(), E> where
- F: FnOnce(&mut Self) -> Result<(), E>;
- fn emit_enum_variant_arg<F>(&mut self, a_idx: uint, f: F) -> Result<(), E> where
- F: FnOnce(&mut Self) -> Result<(), E>;
+ f: F) -> Result<(), Self::Error>
+ where F: FnOnce(&mut Self) -> Result<(), Self::Error>;
+ fn emit_enum_variant_arg<F>(&mut self, a_idx: uint, f: F)
+ -> Result<(), Self::Error>
+ where F: FnOnce(&mut Self) -> Result<(), Self::Error>;
fn emit_enum_struct_variant<F>(&mut self, v_name: &str,
v_id: uint,
len: uint,
- f: F) -> Result<(), E> where
- F: FnOnce(&mut Self) -> Result<(), E>;
+ f: F) -> Result<(), Self::Error>
+ where F: FnOnce(&mut Self) -> Result<(), Self::Error>;
fn emit_enum_struct_variant_field<F>(&mut self,
f_name: &str,
f_idx: uint,
- f: F) -> Result<(), E> where
- F: FnOnce(&mut Self) -> Result<(), E>;
+ f: F) -> Result<(), Self::Error>
+ where F: FnOnce(&mut Self) -> Result<(), Self::Error>;
+
+ fn emit_struct<F>(&mut self, name: &str, len: uint, f: F)
+ -> Result<(), Self::Error>
+ where F: FnOnce(&mut Self) -> Result<(), Self::Error>;
+ fn emit_struct_field<F>(&mut self, f_name: &str, f_idx: uint, f: F)
+ -> Result<(), Self::Error>
+ where F: FnOnce(&mut Self) -> Result<(), Self::Error>;
+
+ fn emit_tuple<F>(&mut self, len: uint, f: F) -> Result<(), Self::Error>
+ where F: FnOnce(&mut Self) -> Result<(), Self::Error>;
+ fn emit_tuple_arg<F>(&mut self, idx: uint, f: F) -> Result<(), Self::Error>
+ where F: FnOnce(&mut Self) -> Result<(), Self::Error>;
+
+ fn emit_tuple_struct<F>(&mut self, name: &str, len: uint, f: F)
+ -> Result<(), Self::Error>
+ where F: FnOnce(&mut Self) -> Result<(), Self::Error>;
+ fn emit_tuple_struct_arg<F>(&mut self, f_idx: uint, f: F)
+ -> Result<(), Self::Error>
+ where F: FnOnce(&mut Self) -> Result<(), Self::Error>;
+
+ // Specialized types:
+ fn emit_option<F>(&mut self, f: F) -> Result<(), Self::Error>
+ where F: FnOnce(&mut Self) -> Result<(), Self::Error>;
+ fn emit_option_none(&mut self) -> Result<(), Self::Error>;
+ fn emit_option_some<F>(&mut self, f: F) -> Result<(), Self::Error>
+ where F: FnOnce(&mut Self) -> Result<(), Self::Error>;
- fn emit_struct<F>(&mut self, name: &str, len: uint, f: F) -> Result<(), E> where
- F: FnOnce(&mut Self) -> Result<(), E>;
- fn emit_struct_field<F>(&mut self, f_name: &str, f_idx: uint, f: F) -> Result<(), E> where
- F: FnOnce(&mut Self) -> Result<(), E>;
+ fn emit_seq<F>(&mut self, len: uint, f: F) -> Result<(), Self::Error>
+ where F: FnOnce(&mut Self) -> Result<(), Self::Error>;
+ fn emit_seq_elt<F>(&mut self, idx: uint, f: F) -> Result<(), Self::Error>
+ where F: FnOnce(&mut Self) -> Result<(), Self::Error>;
- fn emit_tuple<F>(&mut self, len: uint, f: F) -> Result<(), E> where
- F: FnOnce(&mut Self) -> Result<(), E>;
- fn emit_tuple_arg<F>(&mut self, idx: uint, f: F) -> Result<(), E> where
- F: FnOnce(&mut Self) -> Result<(), E>;
+ fn emit_map<F>(&mut self, len: uint, f: F) -> Result<(), Self::Error>
+ where F: FnOnce(&mut Self) -> Result<(), Self::Error>;
+ fn emit_map_elt_key<F>(&mut self, idx: uint, f: F) -> Result<(), Self::Error>
+ where F: FnMut(&mut Self) -> Result<(), Self::Error>;
+ fn emit_map_elt_val<F>(&mut self, idx: uint, f: F) -> Result<(), Self::Error>
+ where F: FnOnce(&mut Self) -> Result<(), Self::Error>;
+}
- fn emit_tuple_struct<F>(&mut self, name: &str, len: uint, f: F) -> Result<(), E> where
- F: FnOnce(&mut Self) -> Result<(), E>;
- fn emit_tuple_struct_arg<F>(&mut self, f_idx: uint, f: F) -> Result<(), E> where
- F: FnOnce(&mut Self) -> Result<(), E>;
+pub trait Decoder {
+ type Error;
- // Specialized types:
- fn emit_option<F>(&mut self, f: F) -> Result<(), E> where
- F: FnOnce(&mut Self) -> Result<(), E>;
- fn emit_option_none(&mut self) -> Result<(), E>;
- fn emit_option_some<F>(&mut self, f: F) -> Result<(), E> where
- F: FnOnce(&mut Self) -> Result<(), E>;
-
- fn emit_seq<F>(&mut self, len: uint, f: F) -> Result<(), E> where
- F: FnOnce(&mut Self) -> Result<(), E>;
- fn emit_seq_elt<F>(&mut self, idx: uint, f: F) -> Result<(), E> where
- F: FnOnce(&mut Self) -> Result<(), E>;
-
- fn emit_map<F>(&mut self, len: uint, f: F) -> Result<(), E> where
- F: FnOnce(&mut Self) -> Result<(), E>;
- fn emit_map_elt_key<F>(&mut self, idx: uint, f: F) -> Result<(), E> where
- F: FnMut(&mut Self) -> Result<(), E>;
- fn emit_map_elt_val<F>(&mut self, idx: uint, f: F) -> Result<(), E> where
- F: FnOnce(&mut Self) -> Result<(), E>;
-}
-
-pub trait Decoder<E> {
// Primitive types:
- fn read_nil(&mut self) -> Result<(), E>;
- fn read_uint(&mut self) -> Result<uint, E>;
- fn read_u64(&mut self) -> Result<u64, E>;
- fn read_u32(&mut self) -> Result<u32, E>;
- fn read_u16(&mut self) -> Result<u16, E>;
- fn read_u8(&mut self) -> Result<u8, E>;
- fn read_int(&mut self) -> Result<int, E>;
- fn read_i64(&mut self) -> Result<i64, E>;
- fn read_i32(&mut self) -> Result<i32, E>;
- fn read_i16(&mut self) -> Result<i16, E>;
- fn read_i8(&mut self) -> Result<i8, E>;
- fn read_bool(&mut self) -> Result<bool, E>;
- fn read_f64(&mut self) -> Result<f64, E>;
- fn read_f32(&mut self) -> Result<f32, E>;
- fn read_char(&mut self) -> Result<char, E>;
- fn read_str(&mut self) -> Result<String, E>;
+ fn read_nil(&mut self) -> Result<(), Self::Error>;
+ fn read_uint(&mut self) -> Result<uint, Self::Error>;
+ fn read_u64(&mut self) -> Result<u64, Self::Error>;
+ fn read_u32(&mut self) -> Result<u32, Self::Error>;
+ fn read_u16(&mut self) -> Result<u16, Self::Error>;
+ fn read_u8(&mut self) -> Result<u8, Self::Error>;
+ fn read_int(&mut self) -> Result<int, Self::Error>;
+ fn read_i64(&mut self) -> Result<i64, Self::Error>;
+ fn read_i32(&mut self) -> Result<i32, Self::Error>;
+ fn read_i16(&mut self) -> Result<i16, Self::Error>;
+ fn read_i8(&mut self) -> Result<i8, Self::Error>;
+ fn read_bool(&mut self) -> Result<bool, Self::Error>;
+ fn read_f64(&mut self) -> Result<f64, Self::Error>;
+ fn read_f32(&mut self) -> Result<f32, Self::Error>;
+ fn read_char(&mut self) -> Result<char, Self::Error>;
+ fn read_str(&mut self) -> Result<String, Self::Error>;
// Compound types:
- fn read_enum<T, F>(&mut self, name: &str, f: F) -> Result<T, E> where
- F: FnOnce(&mut Self) -> Result<T, E>;
-
- fn read_enum_variant<T, F>(&mut self, names: &[&str], f: F) -> Result<T, E> where
- F: FnMut(&mut Self, uint) -> Result<T, E>;
- fn read_enum_variant_arg<T, F>(&mut self, a_idx: uint, f: F) -> Result<T, E> where
- F: FnOnce(&mut Self) -> Result<T, E>;
-
- fn read_enum_struct_variant<T, F>(&mut self, names: &[&str], f: F) -> Result<T, E> where
- F: FnMut(&mut Self, uint) -> Result<T, E>;
+ fn read_enum<T, F>(&mut self, name: &str, f: F) -> Result<T, Self::Error>
+ where F: FnOnce(&mut Self) -> Result<T, Self::Error>;
+
+ fn read_enum_variant<T, F>(&mut self, names: &[&str], f: F)
+ -> Result<T, Self::Error>
+ where F: FnMut(&mut Self, uint) -> Result<T, Self::Error>;
+ fn read_enum_variant_arg<T, F>(&mut self, a_idx: uint, f: F)
+ -> Result<T, Self::Error>
+ where F: FnOnce(&mut Self) -> Result<T, Self::Error>;
+
+ fn read_enum_struct_variant<T, F>(&mut self, names: &[&str], f: F)
+ -> Result<T, Self::Error>
+ where F: FnMut(&mut Self, uint) -> Result<T, Self::Error>;
fn read_enum_struct_variant_field<T, F>(&mut self,
&f_name: &str,
f_idx: uint,
f: F)
- -> Result<T, E> where
- F: FnOnce(&mut Self) -> Result<T, E>;
+ -> Result<T, Self::Error>
+ where F: FnOnce(&mut Self) -> Result<T, Self::Error>;
- fn read_struct<T, F>(&mut self, s_name: &str, len: uint, f: F) -> Result<T, E> where
- F: FnOnce(&mut Self) -> Result<T, E>;
+ fn read_struct<T, F>(&mut self, s_name: &str, len: uint, f: F)
+ -> Result<T, Self::Error>
+ where F: FnOnce(&mut Self) -> Result<T, Self::Error>;
fn read_struct_field<T, F>(&mut self,
f_name: &str,
f_idx: uint,
f: F)
- -> Result<T, E> where
- F: FnOnce(&mut Self) -> Result<T, E>;
-
- fn read_tuple<T, F>(&mut self, len: uint, f: F) -> Result<T, E> where
- F: FnOnce(&mut Self) -> Result<T, E>;
- fn read_tuple_arg<T, F>(&mut self, a_idx: uint, f: F) -> Result<T, E> where
- F: FnOnce(&mut Self) -> Result<T, E>;
-
- fn read_tuple_struct<T, F>(&mut self, s_name: &str, len: uint, f: F) -> Result<T, E> where
- F: FnOnce(&mut Self) -> Result<T, E>;
- fn read_tuple_struct_arg<T, F>(&mut self, a_idx: uint, f: F) -> Result<T, E> where
- F: FnOnce(&mut Self) -> Result<T, E>;
+ -> Result<T, Self::Error>
+ where F: FnOnce(&mut Self) -> Result<T, Self::Error>;
+
+ fn read_tuple<T, F>(&mut self, len: uint, f: F) -> Result<T, Self::Error>
+ where F: FnOnce(&mut Self) -> Result<T, Self::Error>;
+ fn read_tuple_arg<T, F>(&mut self, a_idx: uint, f: F)
+ -> Result<T, Self::Error>
+ where F: FnOnce(&mut Self) -> Result<T, Self::Error>;
+
+ fn read_tuple_struct<T, F>(&mut self, s_name: &str, len: uint, f: F)
+ -> Result<T, Self::Error>
+ where F: FnOnce(&mut Self) -> Result<T, Self::Error>;
+ fn read_tuple_struct_arg<T, F>(&mut self, a_idx: uint, f: F)
+ -> Result<T, Self::Error>
+ where F: FnOnce(&mut Self) -> Result<T, Self::Error>;
// Specialized types:
- fn read_option<T, F>(&mut self, f: F) -> Result<T, E> where
- F: FnMut(&mut Self, bool) -> Result<T, E>;
-
- fn read_seq<T, F>(&mut self, f: F) -> Result<T, E> where
- F: FnOnce(&mut Self, uint) -> Result<T, E>;
- fn read_seq_elt<T, F>(&mut self, idx: uint, f: F) -> Result<T, E> where
- F: FnOnce(&mut Self) -> Result<T, E>;
-
- fn read_map<T, F>(&mut self, f: F) -> Result<T, E> where
- F: FnOnce(&mut Self, uint) -> Result<T, E>;
- fn read_map_elt_key<T, F>(&mut self, idx: uint, f: F) -> Result<T, E> where
- F: FnOnce(&mut Self) -> Result<T, E>;
- fn read_map_elt_val<T, F>(&mut self, idx: uint, f: F) -> Result<T, E> where
- F: FnOnce(&mut Self) -> Result<T, E>;
+ fn read_option<T, F>(&mut self, f: F) -> Result<T, Self::Error>
+ where F: FnMut(&mut Self, bool) -> Result<T, Self::Error>;
+
+ fn read_seq<T, F>(&mut self, f: F) -> Result<T, Self::Error>
+ where F: FnOnce(&mut Self, uint) -> Result<T, Self::Error>;
+ fn read_seq_elt<T, F>(&mut self, idx: uint, f: F) -> Result<T, Self::Error>
+ where F: FnOnce(&mut Self) -> Result<T, Self::Error>;
+
+ fn read_map<T, F>(&mut self, f: F) -> Result<T, Self::Error>
+ where F: FnOnce(&mut Self, uint) -> Result<T, Self::Error>;
+ fn read_map_elt_key<T, F>(&mut self, idx: uint, f: F)
+ -> Result<T, Self::Error>
+ where F: FnOnce(&mut Self) -> Result<T, Self::Error>;
+ fn read_map_elt_val<T, F>(&mut self, idx: uint, f: F)
+ -> Result<T, Self::Error>
+ where F: FnOnce(&mut Self) -> Result<T, Self::Error>;
// Failure
- fn error(&mut self, err: &str) -> E;
+ fn error(&mut self, err: &str) -> Self::Error;
}
-pub trait Encodable<S:Encoder<E>, E> for Sized? {
- fn encode(&self, s: &mut S) -> Result<(), E>;
+pub trait Encodable for Sized? {
+ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error>;
}
-pub trait Decodable<D:Decoder<E>, E> {
- fn decode(d: &mut D) -> Result<Self, E>;
+pub trait Decodable {
+ fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error>;
}
-impl<E, S:Encoder<E>> Encodable<S, E> for uint {
- fn encode(&self, s: &mut S) -> Result<(), E> {
+impl Encodable for uint {
+ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
s.emit_uint(*self)
}
}
-impl<E, D:Decoder<E>> Decodable<D, E> for uint {
- fn decode(d: &mut D) -> Result<uint, E> {
+impl Decodable for uint {
+ fn decode<D: Decoder>(d: &mut D) -> Result<uint, D::Error> {
d.read_uint()
}
}
-impl<E, S:Encoder<E>> Encodable<S, E> for u8 {
- fn encode(&self, s: &mut S) -> Result<(), E> {
+impl Encodable for u8 {
+ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
s.emit_u8(*self)
}
}
-impl<E, D:Decoder<E>> Decodable<D, E> for u8 {
- fn decode(d: &mut D) -> Result<u8, E> {
+impl Decodable for u8 {
+ fn decode<D: Decoder>(d: &mut D) -> Result<u8, D::Error> {
d.read_u8()
}
}
-impl<E, S:Encoder<E>> Encodable<S, E> for u16 {
- fn encode(&self, s: &mut S) -> Result<(), E> {
+impl Encodable for u16 {
+ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
s.emit_u16(*self)
}
}
-impl<E, D:Decoder<E>> Decodable<D, E> for u16 {
- fn decode(d: &mut D) -> Result<u16, E> {
+impl Decodable for u16 {
+ fn decode<D: Decoder>(d: &mut D) -> Result<u16, D::Error> {
d.read_u16()
}
}
-impl<E, S:Encoder<E>> Encodable<S, E> for u32 {
- fn encode(&self, s: &mut S) -> Result<(), E> {
+impl Encodable for u32 {
+ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
s.emit_u32(*self)
}
}
-impl<E, D:Decoder<E>> Decodable<D, E> for u32 {
- fn decode(d: &mut D) -> Result<u32, E> {
+impl Decodable for u32 {
+ fn decode<D: Decoder>(d: &mut D) -> Result<u32, D::Error> {
d.read_u32()
}
}
-impl<E, S:Encoder<E>> Encodable<S, E> for u64 {
- fn encode(&self, s: &mut S) -> Result<(), E> {
+impl Encodable for u64 {
+ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
s.emit_u64(*self)
}
}
-impl<E, D:Decoder<E>> Decodable<D, E> for u64 {
- fn decode(d: &mut D) -> Result<u64, E> {
+impl Decodable for u64 {
+ fn decode<D: Decoder>(d: &mut D) -> Result<u64, D::Error> {
d.read_u64()
}
}
-impl<E, S:Encoder<E>> Encodable<S, E> for int {
- fn encode(&self, s: &mut S) -> Result<(), E> {
+impl Encodable for int {
+ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
s.emit_int(*self)
}
}
-impl<E, D:Decoder<E>> Decodable<D, E> for int {
- fn decode(d: &mut D) -> Result<int, E> {
+impl Decodable for int {
+ fn decode<D: Decoder>(d: &mut D) -> Result<int, D::Error> {
d.read_int()
}
}
-impl<E, S:Encoder<E>> Encodable<S, E> for i8 {
- fn encode(&self, s: &mut S) -> Result<(), E> {
+impl Encodable for i8 {
+ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
s.emit_i8(*self)
}
}
-impl<E, D:Decoder<E>> Decodable<D, E> for i8 {
- fn decode(d: &mut D) -> Result<i8, E> {
+impl Decodable for i8 {
+ fn decode<D: Decoder>(d: &mut D) -> Result<i8, D::Error> {
d.read_i8()
}
}
-impl<E, S:Encoder<E>> Encodable<S, E> for i16 {
- fn encode(&self, s: &mut S) -> Result<(), E> {
+impl Encodable for i16 {
+ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
s.emit_i16(*self)
}
}
-impl<E, D:Decoder<E>> Decodable<D, E> for i16 {
- fn decode(d: &mut D) -> Result<i16, E> {
+impl Decodable for i16 {
+ fn decode<D: Decoder>(d: &mut D) -> Result<i16, D::Error> {
d.read_i16()
}
}
-impl<E, S:Encoder<E>> Encodable<S, E> for i32 {
- fn encode(&self, s: &mut S) -> Result<(), E> {
+impl Encodable for i32 {
+ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
s.emit_i32(*self)
}
}
-impl<E, D:Decoder<E>> Decodable<D, E> for i32 {
- fn decode(d: &mut D) -> Result<i32, E> {
+impl Decodable for i32 {
+ fn decode<D: Decoder>(d: &mut D) -> Result<i32, D::Error> {
d.read_i32()
}
}
-impl<E, S:Encoder<E>> Encodable<S, E> for i64 {
- fn encode(&self, s: &mut S) -> Result<(), E> {
+impl Encodable for i64 {
+ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
s.emit_i64(*self)
}
}
-impl<E, D:Decoder<E>> Decodable<D, E> for i64 {
- fn decode(d: &mut D) -> Result<i64, E> {
+impl Decodable for i64 {
+ fn decode<D: Decoder>(d: &mut D) -> Result<i64, D::Error> {
d.read_i64()
}
}
-impl<E, S:Encoder<E>> Encodable<S, E> for str {
- fn encode(&self, s: &mut S) -> Result<(), E> {
+impl Encodable for str {
+ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
s.emit_str(self)
}
}
-impl<E, S:Encoder<E>> Encodable<S, E> for String {
- fn encode(&self, s: &mut S) -> Result<(), E> {
+impl Encodable for String {
+ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
s.emit_str(self[])
}
}
-impl<E, D:Decoder<E>> Decodable<D, E> for String {
- fn decode(d: &mut D) -> Result<String, E> {
+impl Decodable for String {
+ fn decode<D: Decoder>(d: &mut D) -> Result<String, D::Error> {
d.read_str()
}
}
-impl<E, S:Encoder<E>> Encodable<S, E> for f32 {
- fn encode(&self, s: &mut S) -> Result<(), E> {
+impl Encodable for f32 {
+ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
s.emit_f32(*self)
}
}
-impl<E, D:Decoder<E>> Decodable<D, E> for f32 {
- fn decode(d: &mut D) -> Result<f32, E> {
+impl Decodable for f32 {
+ fn decode<D: Decoder>(d: &mut D) -> Result<f32, D::Error> {
d.read_f32()
}
}
-impl<E, S:Encoder<E>> Encodable<S, E> for f64 {
- fn encode(&self, s: &mut S) -> Result<(), E> {
+impl Encodable for f64 {
+ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
s.emit_f64(*self)
}
}
-impl<E, D:Decoder<E>> Decodable<D, E> for f64 {
- fn decode(d: &mut D) -> Result<f64, E> {
+impl Decodable for f64 {
+ fn decode<D: Decoder>(d: &mut D) -> Result<f64, D::Error> {
d.read_f64()
}
}
-impl<E, S:Encoder<E>> Encodable<S, E> for bool {
- fn encode(&self, s: &mut S) -> Result<(), E> {
+impl Encodable for bool {
+ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
s.emit_bool(*self)
}
}
-impl<E, D:Decoder<E>> Decodable<D, E> for bool {
- fn decode(d: &mut D) -> Result<bool, E> {
+impl Decodable for bool {
+ fn decode<D: Decoder>(d: &mut D) -> Result<bool, D::Error> {
d.read_bool()
}
}
-impl<E, S:Encoder<E>> Encodable<S, E> for char {
- fn encode(&self, s: &mut S) -> Result<(), E> {
+impl Encodable for char {
+ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
s.emit_char(*self)
}
}
-impl<E, D:Decoder<E>> Decodable<D, E> for char {
- fn decode(d: &mut D) -> Result<char, E> {
+impl Decodable for char {
+ fn decode<D: Decoder>(d: &mut D) -> Result<char, D::Error> {
d.read_char()
}
}
-impl<E, S:Encoder<E>> Encodable<S, E> for () {
- fn encode(&self, s: &mut S) -> Result<(), E> {
+impl Encodable for () {
+ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
s.emit_nil()
}
}
-impl<E, D:Decoder<E>> Decodable<D, E> for () {
- fn decode(d: &mut D) -> Result<(), E> {
+impl Decodable for () {
+ fn decode<D: Decoder>(d: &mut D) -> Result<(), D::Error> {
d.read_nil()
}
}
-impl<'a, E, S: Encoder<E>, Sized? T: Encodable<S, E>> Encodable<S, E> for &'a T {
- fn encode(&self, s: &mut S) -> Result<(), E> {
+impl<'a, Sized? T: Encodable> Encodable for &'a T {
+ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
(**self).encode(s)
}
}
-impl<E, S: Encoder<E>, Sized? T: Encodable<S, E>> Encodable<S, E> for Box<T> {
- fn encode(&self, s: &mut S) -> Result<(), E> {
+impl<Sized? T: Encodable> Encodable for Box<T> {
+ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
(**self).encode(s)
}
}
-impl<E, D:Decoder<E>, T: Decodable<D, E>> Decodable<D, E> for Box<T> {
- fn decode(d: &mut D) -> Result<Box<T>, E> {
+impl< T: Decodable> Decodable for Box<T> {
+ fn decode<D: Decoder>(d: &mut D) -> Result<Box<T>, D::Error> {
Ok(box try!(Decodable::decode(d)))
}
}
-impl<E, D:Decoder<E>, T: Decodable<D, E>> Decodable<D, E> for Box<[T]> {
- fn decode(d: &mut D) -> Result<Box<[T]>, E> {
+impl< T: Decodable> Decodable for Box<[T]> {
+ fn decode<D: Decoder>(d: &mut D) -> Result<Box<[T]>, D::Error> {
let v: Vec<T> = try!(Decodable::decode(d));
Ok(v.into_boxed_slice())
}
}
-impl<E, S:Encoder<E>,T:Encodable<S, E>> Encodable<S, E> for Rc<T> {
+impl<T:Encodable> Encodable for Rc<T> {
#[inline]
- fn encode(&self, s: &mut S) -> Result<(), E> {
+ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
(**self).encode(s)
}
}
-impl<E, D:Decoder<E>,T:Decodable<D, E>> Decodable<D, E> for Rc<T> {
+impl<T:Decodable> Decodable for Rc<T> {
#[inline]
- fn decode(d: &mut D) -> Result<Rc<T>, E> {
+ fn decode<D: Decoder>(d: &mut D) -> Result<Rc<T>, D::Error> {
Ok(Rc::new(try!(Decodable::decode(d))))
}
}
-impl<E, S:Encoder<E>,T:Encodable<S, E>> Encodable<S, E> for [T] {
- fn encode(&self, s: &mut S) -> Result<(), E> {
+impl<T:Encodable> Encodable for [T] {
+ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
s.emit_seq(self.len(), |s| {
for (i, e) in self.iter().enumerate() {
try!(s.emit_seq_elt(i, |s| e.encode(s)))
}
}
-impl<E, S:Encoder<E>,T:Encodable<S, E>> Encodable<S, E> for Vec<T> {
- fn encode(&self, s: &mut S) -> Result<(), E> {
+impl<T:Encodable> Encodable for Vec<T> {
+ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
s.emit_seq(self.len(), |s| {
for (i, e) in self.iter().enumerate() {
try!(s.emit_seq_elt(i, |s| e.encode(s)))
}
}
-impl<E, D:Decoder<E>,T:Decodable<D, E>> Decodable<D, E> for Vec<T> {
- fn decode(d: &mut D) -> Result<Vec<T>, E> {
+impl<T:Decodable> Decodable for Vec<T> {
+ fn decode<D: Decoder>(d: &mut D) -> Result<Vec<T>, D::Error> {
d.read_seq(|d, len| {
let mut v = Vec::with_capacity(len);
for i in range(0, len) {
}
}
-impl<E, S:Encoder<E>,T:Encodable<S, E>> Encodable<S, E> for Option<T> {
- fn encode(&self, s: &mut S) -> Result<(), E> {
+impl<T:Encodable> Encodable for Option<T> {
+ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
s.emit_option(|s| {
match *self {
None => s.emit_option_none(),
}
}
-impl<E, D:Decoder<E>,T:Decodable<D, E>> Decodable<D, E> for Option<T> {
- fn decode(d: &mut D) -> Result<Option<T>, E> {
+impl<T:Decodable> Decodable for Option<T> {
+ fn decode<D: Decoder>(d: &mut D) -> Result<Option<T>, D::Error> {
d.read_option(|d, b| {
if b {
Ok(Some(try!(Decodable::decode(d))))
macro_rules! tuple {
() => ();
( $($name:ident,)+ ) => (
- impl<E, D:Decoder<E>,$($name:Decodable<D, E>),*> Decodable<D,E> for ($($name,)*) {
+ impl<$($name:Decodable),*> Decodable for ($($name,)*) {
#[allow(non_snake_case)]
- fn decode(d: &mut D) -> Result<($($name,)*), E> {
+ fn decode<D: Decoder>(d: &mut D) -> Result<($($name,)*), D::Error> {
let len: uint = count_idents!($($name),*);
d.read_tuple(len, |d| {
let mut i = 0;
- let ret = ($(try!(d.read_tuple_arg({ i+=1; i-1 }, |d| -> Result<$name,E> {
+ let ret = ($(try!(d.read_tuple_arg({ i+=1; i-1 },
+ |d| -> Result<$name,D::Error> {
Decodable::decode(d)
})),)*);
return Ok(ret);
})
}
}
- impl<E, S:Encoder<E>,$($name:Encodable<S, E>),*> Encodable<S, E> for ($($name,)*) {
+ impl<$($name:Encodable),*> Encodable for ($($name,)*) {
#[allow(non_snake_case)]
- fn encode(&self, s: &mut S) -> Result<(), E> {
+ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
let ($(ref $name,)*) = *self;
let mut n = 0;
$(let $name = $name; n += 1;)*
tuple! { T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, }
-impl<E, S: Encoder<E>> Encodable<S, E> for path::posix::Path {
- fn encode(&self, e: &mut S) -> Result<(), E> {
+impl Encodable for path::posix::Path {
+ fn encode<S: Encoder>(&self, e: &mut S) -> Result<(), S::Error> {
self.as_vec().encode(e)
}
}
-impl<E, D: Decoder<E>> Decodable<D, E> for path::posix::Path {
- fn decode(d: &mut D) -> Result<path::posix::Path, E> {
+impl Decodable for path::posix::Path {
+ fn decode<D: Decoder>(d: &mut D) -> Result<path::posix::Path, D::Error> {
let bytes: Vec<u8> = try!(Decodable::decode(d));
Ok(path::posix::Path::new(bytes))
}
}
-impl<E, S: Encoder<E>> Encodable<S, E> for path::windows::Path {
- fn encode(&self, e: &mut S) -> Result<(), E> {
+impl Encodable for path::windows::Path {
+ fn encode<S: Encoder>(&self, e: &mut S) -> Result<(), S::Error> {
self.as_vec().encode(e)
}
}
-impl<E, D: Decoder<E>> Decodable<D, E> for path::windows::Path {
- fn decode(d: &mut D) -> Result<path::windows::Path, E> {
+impl Decodable for path::windows::Path {
+ fn decode<D: Decoder>(d: &mut D) -> Result<path::windows::Path, D::Error> {
let bytes: Vec<u8> = try!(Decodable::decode(d));
Ok(path::windows::Path::new(bytes))
}
}
-impl<E, S: Encoder<E>, T: Encodable<S, E> + Copy> Encodable<S, E> for Cell<T> {
- fn encode(&self, s: &mut S) -> Result<(), E> {
+impl<T: Encodable + Copy> Encodable for Cell<T> {
+ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
self.get().encode(s)
}
}
-impl<E, D: Decoder<E>, T: Decodable<D, E> + Copy> Decodable<D, E> for Cell<T> {
- fn decode(d: &mut D) -> Result<Cell<T>, E> {
+impl<T: Decodable + Copy> Decodable for Cell<T> {
+ fn decode<D: Decoder>(d: &mut D) -> Result<Cell<T>, D::Error> {
Ok(Cell::new(try!(Decodable::decode(d))))
}
}
// `encoder.error("attempting to Encode borrowed RefCell")`
// from `encode` when `try_borrow` returns `None`.
-impl<E, S: Encoder<E>, T: Encodable<S, E>> Encodable<S, E> for RefCell<T> {
- fn encode(&self, s: &mut S) -> Result<(), E> {
+impl<T: Encodable> Encodable for RefCell<T> {
+ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
self.borrow().encode(s)
}
}
-impl<E, D: Decoder<E>, T: Decodable<D, E>> Decodable<D, E> for RefCell<T> {
- fn decode(d: &mut D) -> Result<RefCell<T>, E> {
+impl<T: Decodable> Decodable for RefCell<T> {
+ fn decode<D: Decoder>(d: &mut D) -> Result<RefCell<T>, D::Error> {
Ok(RefCell::new(try!(Decodable::decode(d))))
}
}
-impl<E, S:Encoder<E>, T:Encodable<S, E>> Encodable<S, E> for Arc<T> {
- fn encode(&self, s: &mut S) -> Result<(), E> {
+impl<T:Encodable> Encodable for Arc<T> {
+ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
(**self).encode(s)
}
}
-impl<E, D:Decoder<E>,T:Decodable<D, E>+Send+Sync> Decodable<D, E> for Arc<T> {
- fn decode(d: &mut D) -> Result<Arc<T>, E> {
+impl<T:Decodable+Send+Sync> Decodable for Arc<T> {
+ fn decode<D: Decoder>(d: &mut D) -> Result<Arc<T>, D::Error> {
Ok(Arc::new(try!(Decodable::decode(d))))
}
}
// ___________________________________________________________________________
// Helper routines
-pub trait EncoderHelpers<E> {
- fn emit_from_vec<T, F>(&mut self, v: &[T], f: F) -> Result<(), E> where
- F: FnMut(&mut Self, &T) -> Result<(), E>;
+pub trait EncoderHelpers: Encoder {
+ fn emit_from_vec<T, F>(&mut self, v: &[T], f: F)
+ -> Result<(), <Self as Encoder>::Error>
+ where F: FnMut(&mut Self, &T) -> Result<(), <Self as Encoder>::Error>;
}
-impl<E, S:Encoder<E>> EncoderHelpers<E> for S {
- fn emit_from_vec<T, F>(&mut self, v: &[T], mut f: F) -> Result<(), E> where
- F: FnMut(&mut S, &T) -> Result<(), E>,
+impl<S:Encoder> EncoderHelpers for S {
+ fn emit_from_vec<T, F>(&mut self, v: &[T], mut f: F) -> Result<(), S::Error> where
+ F: FnMut(&mut S, &T) -> Result<(), S::Error>,
{
self.emit_seq(v.len(), |this| {
for (i, e) in v.iter().enumerate() {
}
}
-pub trait DecoderHelpers<E> {
- fn read_to_vec<T, F>(&mut self, f: F) -> Result<Vec<T>, E> where
- F: FnMut(&mut Self) -> Result<T, E>;
+pub trait DecoderHelpers: Decoder {
+ fn read_to_vec<T, F>(&mut self, f: F)
+ -> Result<Vec<T>, <Self as Decoder>::Error> where
+ F: FnMut(&mut Self) -> Result<T, <Self as Decoder>::Error>;
}
-impl<E, D:Decoder<E>> DecoderHelpers<E> for D {
- fn read_to_vec<T, F>(&mut self, mut f: F) -> Result<Vec<T>, E> where F:
- FnMut(&mut D) -> Result<T, E>,
+impl<D: Decoder> DecoderHelpers for D {
+ fn read_to_vec<T, F>(&mut self, mut f: F) -> Result<Vec<T>, D::Error> where F:
+ FnMut(&mut D) -> Result<T, D::Error>,
{
self.read_seq(|this, len| {
let mut v = Vec::with_capacity(len);
--- /dev/null
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Support code for encoding and decoding types.
+
+/*
+Core encoding and decoding interfaces.
+*/
+
+use std::path;
+use std::rc::Rc;
+use std::cell::{Cell, RefCell};
+use std::sync::Arc;
+
+pub trait Encoder<E> {
+ // Primitive types:
+ fn emit_nil(&mut self) -> Result<(), E>;
+ fn emit_uint(&mut self, v: uint) -> Result<(), E>;
+ fn emit_u64(&mut self, v: u64) -> Result<(), E>;
+ fn emit_u32(&mut self, v: u32) -> Result<(), E>;
+ fn emit_u16(&mut self, v: u16) -> Result<(), E>;
+ fn emit_u8(&mut self, v: u8) -> Result<(), E>;
+ fn emit_int(&mut self, v: int) -> Result<(), E>;
+ fn emit_i64(&mut self, v: i64) -> Result<(), E>;
+ fn emit_i32(&mut self, v: i32) -> Result<(), E>;
+ fn emit_i16(&mut self, v: i16) -> Result<(), E>;
+ fn emit_i8(&mut self, v: i8) -> Result<(), E>;
+ fn emit_bool(&mut self, v: bool) -> Result<(), E>;
+ fn emit_f64(&mut self, v: f64) -> Result<(), E>;
+ fn emit_f32(&mut self, v: f32) -> Result<(), E>;
+ fn emit_char(&mut self, v: char) -> Result<(), E>;
+ fn emit_str(&mut self, v: &str) -> Result<(), E>;
+
+ // Compound types:
+ fn emit_enum<F>(&mut self, name: &str, f: F) -> Result<(), E> where
+ F: FnOnce(&mut Self) -> Result<(), E>;
+
+ fn emit_enum_variant<F>(&mut self, v_name: &str,
+ v_id: uint,
+ len: uint,
+ f: F) -> Result<(), E> where
+ F: FnOnce(&mut Self) -> Result<(), E>;
+ fn emit_enum_variant_arg<F>(&mut self, a_idx: uint, f: F) -> Result<(), E> where
+ F: FnOnce(&mut Self) -> Result<(), E>;
+
+ fn emit_enum_struct_variant<F>(&mut self, v_name: &str,
+ v_id: uint,
+ len: uint,
+ f: F) -> Result<(), E> where
+ F: FnOnce(&mut Self) -> Result<(), E>;
+ fn emit_enum_struct_variant_field<F>(&mut self,
+ f_name: &str,
+ f_idx: uint,
+ f: F) -> Result<(), E> where
+ F: FnOnce(&mut Self) -> Result<(), E>;
+
+ fn emit_struct<F>(&mut self, name: &str, len: uint, f: F) -> Result<(), E> where
+ F: FnOnce(&mut Self) -> Result<(), E>;
+ fn emit_struct_field<F>(&mut self, f_name: &str, f_idx: uint, f: F) -> Result<(), E> where
+ F: FnOnce(&mut Self) -> Result<(), E>;
+
+ fn emit_tuple<F>(&mut self, len: uint, f: F) -> Result<(), E> where
+ F: FnOnce(&mut Self) -> Result<(), E>;
+ fn emit_tuple_arg<F>(&mut self, idx: uint, f: F) -> Result<(), E> where
+ F: FnOnce(&mut Self) -> Result<(), E>;
+
+ fn emit_tuple_struct<F>(&mut self, name: &str, len: uint, f: F) -> Result<(), E> where
+ F: FnOnce(&mut Self) -> Result<(), E>;
+ fn emit_tuple_struct_arg<F>(&mut self, f_idx: uint, f: F) -> Result<(), E> where
+ F: FnOnce(&mut Self) -> Result<(), E>;
+
+ // Specialized types:
+ fn emit_option<F>(&mut self, f: F) -> Result<(), E> where
+ F: FnOnce(&mut Self) -> Result<(), E>;
+ fn emit_option_none(&mut self) -> Result<(), E>;
+ fn emit_option_some<F>(&mut self, f: F) -> Result<(), E> where
+ F: FnOnce(&mut Self) -> Result<(), E>;
+
+ fn emit_seq<F>(&mut self, len: uint, f: F) -> Result<(), E> where
+ F: FnOnce(&mut Self) -> Result<(), E>;
+ fn emit_seq_elt<F>(&mut self, idx: uint, f: F) -> Result<(), E> where
+ F: FnOnce(&mut Self) -> Result<(), E>;
+
+ fn emit_map<F>(&mut self, len: uint, f: F) -> Result<(), E> where
+ F: FnOnce(&mut Self) -> Result<(), E>;
+ fn emit_map_elt_key<F>(&mut self, idx: uint, f: F) -> Result<(), E> where
+ F: FnMut(&mut Self) -> Result<(), E>;
+ fn emit_map_elt_val<F>(&mut self, idx: uint, f: F) -> Result<(), E> where
+ F: FnOnce(&mut Self) -> Result<(), E>;
+}
+
+pub trait Decoder<E> {
+ // Primitive types:
+ fn read_nil(&mut self) -> Result<(), E>;
+ fn read_uint(&mut self) -> Result<uint, E>;
+ fn read_u64(&mut self) -> Result<u64, E>;
+ fn read_u32(&mut self) -> Result<u32, E>;
+ fn read_u16(&mut self) -> Result<u16, E>;
+ fn read_u8(&mut self) -> Result<u8, E>;
+ fn read_int(&mut self) -> Result<int, E>;
+ fn read_i64(&mut self) -> Result<i64, E>;
+ fn read_i32(&mut self) -> Result<i32, E>;
+ fn read_i16(&mut self) -> Result<i16, E>;
+ fn read_i8(&mut self) -> Result<i8, E>;
+ fn read_bool(&mut self) -> Result<bool, E>;
+ fn read_f64(&mut self) -> Result<f64, E>;
+ fn read_f32(&mut self) -> Result<f32, E>;
+ fn read_char(&mut self) -> Result<char, E>;
+ fn read_str(&mut self) -> Result<String, E>;
+
+ // Compound types:
+ fn read_enum<T, F>(&mut self, name: &str, f: F) -> Result<T, E> where
+ F: FnOnce(&mut Self) -> Result<T, E>;
+
+ fn read_enum_variant<T, F>(&mut self, names: &[&str], f: F) -> Result<T, E> where
+ F: FnMut(&mut Self, uint) -> Result<T, E>;
+ fn read_enum_variant_arg<T, F>(&mut self, a_idx: uint, f: F) -> Result<T, E> where
+ F: FnOnce(&mut Self) -> Result<T, E>;
+
+ fn read_enum_struct_variant<T, F>(&mut self, names: &[&str], f: F) -> Result<T, E> where
+ F: FnMut(&mut Self, uint) -> Result<T, E>;
+ fn read_enum_struct_variant_field<T, F>(&mut self,
+ &f_name: &str,
+ f_idx: uint,
+ f: F)
+ -> Result<T, E> where
+ F: FnOnce(&mut Self) -> Result<T, E>;
+
+ fn read_struct<T, F>(&mut self, s_name: &str, len: uint, f: F) -> Result<T, E> where
+ F: FnOnce(&mut Self) -> Result<T, E>;
+ fn read_struct_field<T, F>(&mut self,
+ f_name: &str,
+ f_idx: uint,
+ f: F)
+ -> Result<T, E> where
+ F: FnOnce(&mut Self) -> Result<T, E>;
+
+ fn read_tuple<T, F>(&mut self, len: uint, f: F) -> Result<T, E> where
+ F: FnOnce(&mut Self) -> Result<T, E>;
+ fn read_tuple_arg<T, F>(&mut self, a_idx: uint, f: F) -> Result<T, E> where
+ F: FnOnce(&mut Self) -> Result<T, E>;
+
+ fn read_tuple_struct<T, F>(&mut self, s_name: &str, len: uint, f: F) -> Result<T, E> where
+ F: FnOnce(&mut Self) -> Result<T, E>;
+ fn read_tuple_struct_arg<T, F>(&mut self, a_idx: uint, f: F) -> Result<T, E> where
+ F: FnOnce(&mut Self) -> Result<T, E>;
+
+ // Specialized types:
+ fn read_option<T, F>(&mut self, f: F) -> Result<T, E> where
+ F: FnMut(&mut Self, bool) -> Result<T, E>;
+
+ fn read_seq<T, F>(&mut self, f: F) -> Result<T, E> where
+ F: FnOnce(&mut Self, uint) -> Result<T, E>;
+ fn read_seq_elt<T, F>(&mut self, idx: uint, f: F) -> Result<T, E> where
+ F: FnOnce(&mut Self) -> Result<T, E>;
+
+ fn read_map<T, F>(&mut self, f: F) -> Result<T, E> where
+ F: FnOnce(&mut Self, uint) -> Result<T, E>;
+ fn read_map_elt_key<T, F>(&mut self, idx: uint, f: F) -> Result<T, E> where
+ F: FnOnce(&mut Self) -> Result<T, E>;
+ fn read_map_elt_val<T, F>(&mut self, idx: uint, f: F) -> Result<T, E> where
+ F: FnOnce(&mut Self) -> Result<T, E>;
+
+ // Failure
+ fn error(&mut self, err: &str) -> E;
+}
+
+pub trait Encodable<S:Encoder<E>, E> for Sized? {
+ fn encode(&self, s: &mut S) -> Result<(), E>;
+}
+
+pub trait Decodable<D:Decoder<E>, E> {
+ fn decode(d: &mut D) -> Result<Self, E>;
+}
+
+impl<E, S:Encoder<E>> Encodable<S, E> for uint {
+ fn encode(&self, s: &mut S) -> Result<(), E> {
+ s.emit_uint(*self)
+ }
+}
+
+impl<E, D:Decoder<E>> Decodable<D, E> for uint {
+ fn decode(d: &mut D) -> Result<uint, E> {
+ d.read_uint()
+ }
+}
+
+impl<E, S:Encoder<E>> Encodable<S, E> for u8 {
+ fn encode(&self, s: &mut S) -> Result<(), E> {
+ s.emit_u8(*self)
+ }
+}
+
+impl<E, D:Decoder<E>> Decodable<D, E> for u8 {
+ fn decode(d: &mut D) -> Result<u8, E> {
+ d.read_u8()
+ }
+}
+
+impl<E, S:Encoder<E>> Encodable<S, E> for u16 {
+ fn encode(&self, s: &mut S) -> Result<(), E> {
+ s.emit_u16(*self)
+ }
+}
+
+impl<E, D:Decoder<E>> Decodable<D, E> for u16 {
+ fn decode(d: &mut D) -> Result<u16, E> {
+ d.read_u16()
+ }
+}
+
+impl<E, S:Encoder<E>> Encodable<S, E> for u32 {
+ fn encode(&self, s: &mut S) -> Result<(), E> {
+ s.emit_u32(*self)
+ }
+}
+
+impl<E, D:Decoder<E>> Decodable<D, E> for u32 {
+ fn decode(d: &mut D) -> Result<u32, E> {
+ d.read_u32()
+ }
+}
+
+impl<E, S:Encoder<E>> Encodable<S, E> for u64 {
+ fn encode(&self, s: &mut S) -> Result<(), E> {
+ s.emit_u64(*self)
+ }
+}
+
+impl<E, D:Decoder<E>> Decodable<D, E> for u64 {
+ fn decode(d: &mut D) -> Result<u64, E> {
+ d.read_u64()
+ }
+}
+
+impl<E, S:Encoder<E>> Encodable<S, E> for int {
+ fn encode(&self, s: &mut S) -> Result<(), E> {
+ s.emit_int(*self)
+ }
+}
+
+impl<E, D:Decoder<E>> Decodable<D, E> for int {
+ fn decode(d: &mut D) -> Result<int, E> {
+ d.read_int()
+ }
+}
+
+impl<E, S:Encoder<E>> Encodable<S, E> for i8 {
+ fn encode(&self, s: &mut S) -> Result<(), E> {
+ s.emit_i8(*self)
+ }
+}
+
+impl<E, D:Decoder<E>> Decodable<D, E> for i8 {
+ fn decode(d: &mut D) -> Result<i8, E> {
+ d.read_i8()
+ }
+}
+
+impl<E, S:Encoder<E>> Encodable<S, E> for i16 {
+ fn encode(&self, s: &mut S) -> Result<(), E> {
+ s.emit_i16(*self)
+ }
+}
+
+impl<E, D:Decoder<E>> Decodable<D, E> for i16 {
+ fn decode(d: &mut D) -> Result<i16, E> {
+ d.read_i16()
+ }
+}
+
+impl<E, S:Encoder<E>> Encodable<S, E> for i32 {
+ fn encode(&self, s: &mut S) -> Result<(), E> {
+ s.emit_i32(*self)
+ }
+}
+
+impl<E, D:Decoder<E>> Decodable<D, E> for i32 {
+ fn decode(d: &mut D) -> Result<i32, E> {
+ d.read_i32()
+ }
+}
+
+impl<E, S:Encoder<E>> Encodable<S, E> for i64 {
+ fn encode(&self, s: &mut S) -> Result<(), E> {
+ s.emit_i64(*self)
+ }
+}
+
+impl<E, D:Decoder<E>> Decodable<D, E> for i64 {
+ fn decode(d: &mut D) -> Result<i64, E> {
+ d.read_i64()
+ }
+}
+
+impl<E, S:Encoder<E>> Encodable<S, E> for str {
+ fn encode(&self, s: &mut S) -> Result<(), E> {
+ s.emit_str(self)
+ }
+}
+
+impl<E, S:Encoder<E>> Encodable<S, E> for String {
+ fn encode(&self, s: &mut S) -> Result<(), E> {
+ s.emit_str(self[])
+ }
+}
+
+impl<E, D:Decoder<E>> Decodable<D, E> for String {
+ fn decode(d: &mut D) -> Result<String, E> {
+ d.read_str()
+ }
+}
+
+impl<E, S:Encoder<E>> Encodable<S, E> for f32 {
+ fn encode(&self, s: &mut S) -> Result<(), E> {
+ s.emit_f32(*self)
+ }
+}
+
+impl<E, D:Decoder<E>> Decodable<D, E> for f32 {
+ fn decode(d: &mut D) -> Result<f32, E> {
+ d.read_f32()
+ }
+}
+
+impl<E, S:Encoder<E>> Encodable<S, E> for f64 {
+ fn encode(&self, s: &mut S) -> Result<(), E> {
+ s.emit_f64(*self)
+ }
+}
+
+impl<E, D:Decoder<E>> Decodable<D, E> for f64 {
+ fn decode(d: &mut D) -> Result<f64, E> {
+ d.read_f64()
+ }
+}
+
+impl<E, S:Encoder<E>> Encodable<S, E> for bool {
+ fn encode(&self, s: &mut S) -> Result<(), E> {
+ s.emit_bool(*self)
+ }
+}
+
+impl<E, D:Decoder<E>> Decodable<D, E> for bool {
+ fn decode(d: &mut D) -> Result<bool, E> {
+ d.read_bool()
+ }
+}
+
+impl<E, S:Encoder<E>> Encodable<S, E> for char {
+ fn encode(&self, s: &mut S) -> Result<(), E> {
+ s.emit_char(*self)
+ }
+}
+
+impl<E, D:Decoder<E>> Decodable<D, E> for char {
+ fn decode(d: &mut D) -> Result<char, E> {
+ d.read_char()
+ }
+}
+
+impl<E, S:Encoder<E>> Encodable<S, E> for () {
+ fn encode(&self, s: &mut S) -> Result<(), E> {
+ s.emit_nil()
+ }
+}
+
+impl<E, D:Decoder<E>> Decodable<D, E> for () {
+ fn decode(d: &mut D) -> Result<(), E> {
+ d.read_nil()
+ }
+}
+
+impl<'a, E, S: Encoder<E>, Sized? T: Encodable<S, E>> Encodable<S, E> for &'a T {
+ fn encode(&self, s: &mut S) -> Result<(), E> {
+ (**self).encode(s)
+ }
+}
+
+impl<E, S: Encoder<E>, Sized? T: Encodable<S, E>> Encodable<S, E> for Box<T> {
+ fn encode(&self, s: &mut S) -> Result<(), E> {
+ (**self).encode(s)
+ }
+}
+
+impl<E, D:Decoder<E>, T: Decodable<D, E>> Decodable<D, E> for Box<T> {
+ fn decode(d: &mut D) -> Result<Box<T>, E> {
+ Ok(box try!(Decodable::decode(d)))
+ }
+}
+
+impl<E, D:Decoder<E>, T: Decodable<D, E>> Decodable<D, E> for Box<[T]> {
+ fn decode(d: &mut D) -> Result<Box<[T]>, E> {
+ let v: Vec<T> = try!(Decodable::decode(d));
+ Ok(v.into_boxed_slice())
+ }
+}
+
+impl<E, S:Encoder<E>,T:Encodable<S, E>> Encodable<S, E> for Rc<T> {
+ #[inline]
+ fn encode(&self, s: &mut S) -> Result<(), E> {
+ (**self).encode(s)
+ }
+}
+
+impl<E, D:Decoder<E>,T:Decodable<D, E>> Decodable<D, E> for Rc<T> {
+ #[inline]
+ fn decode(d: &mut D) -> Result<Rc<T>, E> {
+ Ok(Rc::new(try!(Decodable::decode(d))))
+ }
+}
+
+impl<E, S:Encoder<E>,T:Encodable<S, E>> Encodable<S, E> for [T] {
+ fn encode(&self, s: &mut S) -> Result<(), E> {
+ s.emit_seq(self.len(), |s| {
+ for (i, e) in self.iter().enumerate() {
+ try!(s.emit_seq_elt(i, |s| e.encode(s)))
+ }
+ Ok(())
+ })
+ }
+}
+
+impl<E, S:Encoder<E>,T:Encodable<S, E>> Encodable<S, E> for Vec<T> {
+ fn encode(&self, s: &mut S) -> Result<(), E> {
+ s.emit_seq(self.len(), |s| {
+ for (i, e) in self.iter().enumerate() {
+ try!(s.emit_seq_elt(i, |s| e.encode(s)))
+ }
+ Ok(())
+ })
+ }
+}
+
+impl<E, D:Decoder<E>,T:Decodable<D, E>> Decodable<D, E> for Vec<T> {
+ fn decode(d: &mut D) -> Result<Vec<T>, E> {
+ d.read_seq(|d, len| {
+ let mut v = Vec::with_capacity(len);
+ for i in range(0, len) {
+ v.push(try!(d.read_seq_elt(i, |d| Decodable::decode(d))));
+ }
+ Ok(v)
+ })
+ }
+}
+
+impl<E, S:Encoder<E>,T:Encodable<S, E>> Encodable<S, E> for Option<T> {
+ fn encode(&self, s: &mut S) -> Result<(), E> {
+ s.emit_option(|s| {
+ match *self {
+ None => s.emit_option_none(),
+ Some(ref v) => s.emit_option_some(|s| v.encode(s)),
+ }
+ })
+ }
+}
+
+impl<E, D:Decoder<E>,T:Decodable<D, E>> Decodable<D, E> for Option<T> {
+ fn decode(d: &mut D) -> Result<Option<T>, E> {
+ d.read_option(|d, b| {
+ if b {
+ Ok(Some(try!(Decodable::decode(d))))
+ } else {
+ Ok(None)
+ }
+ })
+ }
+}
+
+macro_rules! peel {
+ ($name:ident, $($other:ident,)*) => (tuple! { $($other,)* })
+}
+
+/// Evaluates to the number of identifiers passed to it, for example: `count_idents!(a, b, c) == 3
+macro_rules! count_idents {
+ () => { 0u };
+ ($_i:ident $(, $rest:ident)*) => { 1 + count_idents!($($rest),*) }
+}
+
+macro_rules! tuple {
+ () => ();
+ ( $($name:ident,)+ ) => (
+ impl<E, D:Decoder<E>,$($name:Decodable<D, E>),*> Decodable<D,E> for ($($name,)*) {
+ #[allow(non_snake_case)]
+ fn decode(d: &mut D) -> Result<($($name,)*), E> {
+ let len: uint = count_idents!($($name),*);
+ d.read_tuple(len, |d| {
+ let mut i = 0;
+ let ret = ($(try!(d.read_tuple_arg({ i+=1; i-1 }, |d| -> Result<$name,E> {
+ Decodable::decode(d)
+ })),)*);
+ return Ok(ret);
+ })
+ }
+ }
+ impl<E, S:Encoder<E>,$($name:Encodable<S, E>),*> Encodable<S, E> for ($($name,)*) {
+ #[allow(non_snake_case)]
+ fn encode(&self, s: &mut S) -> Result<(), E> {
+ let ($(ref $name,)*) = *self;
+ let mut n = 0;
+ $(let $name = $name; n += 1;)*
+ s.emit_tuple(n, |s| {
+ let mut i = 0;
+ $(try!(s.emit_tuple_arg({ i+=1; i-1 }, |s| $name.encode(s)));)*
+ Ok(())
+ })
+ }
+ }
+ peel! { $($name,)* }
+ )
+}
+
+tuple! { T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, }
+
+impl<E, S: Encoder<E>> Encodable<S, E> for path::posix::Path {
+ fn encode(&self, e: &mut S) -> Result<(), E> {
+ self.as_vec().encode(e)
+ }
+}
+
+impl<E, D: Decoder<E>> Decodable<D, E> for path::posix::Path {
+ fn decode(d: &mut D) -> Result<path::posix::Path, E> {
+ let bytes: Vec<u8> = try!(Decodable::decode(d));
+ Ok(path::posix::Path::new(bytes))
+ }
+}
+
+impl<E, S: Encoder<E>> Encodable<S, E> for path::windows::Path {
+ fn encode(&self, e: &mut S) -> Result<(), E> {
+ self.as_vec().encode(e)
+ }
+}
+
+impl<E, D: Decoder<E>> Decodable<D, E> for path::windows::Path {
+ fn decode(d: &mut D) -> Result<path::windows::Path, E> {
+ let bytes: Vec<u8> = try!(Decodable::decode(d));
+ Ok(path::windows::Path::new(bytes))
+ }
+}
+
+impl<E, S: Encoder<E>, T: Encodable<S, E> + Copy> Encodable<S, E> for Cell<T> {
+ fn encode(&self, s: &mut S) -> Result<(), E> {
+ self.get().encode(s)
+ }
+}
+
+impl<E, D: Decoder<E>, T: Decodable<D, E> + Copy> Decodable<D, E> for Cell<T> {
+ fn decode(d: &mut D) -> Result<Cell<T>, E> {
+ Ok(Cell::new(try!(Decodable::decode(d))))
+ }
+}
+
+// FIXME: #15036
+// Should use `try_borrow`, returning a
+// `encoder.error("attempting to Encode borrowed RefCell")`
+// from `encode` when `try_borrow` returns `None`.
+
+impl<E, S: Encoder<E>, T: Encodable<S, E>> Encodable<S, E> for RefCell<T> {
+ fn encode(&self, s: &mut S) -> Result<(), E> {
+ self.borrow().encode(s)
+ }
+}
+
+impl<E, D: Decoder<E>, T: Decodable<D, E>> Decodable<D, E> for RefCell<T> {
+ fn decode(d: &mut D) -> Result<RefCell<T>, E> {
+ Ok(RefCell::new(try!(Decodable::decode(d))))
+ }
+}
+
+impl<E, S:Encoder<E>, T:Encodable<S, E>> Encodable<S, E> for Arc<T> {
+ fn encode(&self, s: &mut S) -> Result<(), E> {
+ (**self).encode(s)
+ }
+}
+
+impl<E, D:Decoder<E>,T:Decodable<D, E>+Send+Sync> Decodable<D, E> for Arc<T> {
+ fn decode(d: &mut D) -> Result<Arc<T>, E> {
+ Ok(Arc::new(try!(Decodable::decode(d))))
+ }
+}
+
+// ___________________________________________________________________________
+// Helper routines
+
+pub trait EncoderHelpers<E> {
+ fn emit_from_vec<T, F>(&mut self, v: &[T], f: F) -> Result<(), E> where
+ F: FnMut(&mut Self, &T) -> Result<(), E>;
+}
+
+impl<E, S:Encoder<E>> EncoderHelpers<E> for S {
+ fn emit_from_vec<T, F>(&mut self, v: &[T], mut f: F) -> Result<(), E> where
+ F: FnMut(&mut S, &T) -> Result<(), E>,
+ {
+ self.emit_seq(v.len(), |this| {
+ for (i, e) in v.iter().enumerate() {
+ try!(this.emit_seq_elt(i, |this| {
+ f(this, e)
+ }));
+ }
+ Ok(())
+ })
+ }
+}
+
+pub trait DecoderHelpers<E> {
+ fn read_to_vec<T, F>(&mut self, f: F) -> Result<Vec<T>, E> where
+ F: FnMut(&mut Self) -> Result<T, E>;
+}
+
+impl<E, D:Decoder<E>> DecoderHelpers<E> for D {
+ fn read_to_vec<T, F>(&mut self, mut f: F) -> Result<Vec<T>, E> where F:
+ FnMut(&mut D) -> Result<T, E>,
+ {
+ self.read_seq(|this, len| {
+ let mut v = Vec::with_capacity(len);
+ for i in range(0, len) {
+ v.push(try!(this.read_seq_elt(i, |this| f(this))));
+ }
+ Ok(v)
+ })
+ }
+}
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! C-string manipulation and management
-//!
-//! This modules provides the basic methods for creating and manipulating
-//! null-terminated strings for use with FFI calls (back to C). Most C APIs require
-//! that the string being passed to them is null-terminated, and by default rust's
-//! string types are *not* null terminated.
-//!
-//! The other problem with translating Rust strings to C strings is that Rust
-//! strings can validly contain a null-byte in the middle of the string (0 is a
-//! valid Unicode codepoint). This means that not all Rust strings can actually be
-//! translated to C strings.
-//!
-//! # Creation of a C string
-//!
-//! A C string is managed through the `CString` type defined in this module. It
-//! "owns" the internal buffer of characters and will automatically deallocate the
-//! buffer when the string is dropped. The `ToCStr` trait is implemented for `&str`
-//! and `&[u8]`, but the conversions can fail due to some of the limitations
-//! explained above.
-//!
-//! This also means that currently whenever a C string is created, an allocation
-//! must be performed to place the data elsewhere (the lifetime of the C string is
-//! not tied to the lifetime of the original string/data buffer). If C strings are
-//! heavily used in applications, then caching may be advisable to prevent
-//! unnecessary amounts of allocations.
-//!
-//! Be carefull to remember that the memory is managed by C allocator API and not
-//! by Rust allocator API.
-//! That means that the CString pointers should be freed with C allocator API
-//! if you intend to do that on your own, as the behaviour if you free them with
-//! Rust's allocator API is not well defined
-//!
-//! An example of creating and using a C string would be:
-//!
-//! ```rust
-//! extern crate libc;
-//!
-//! use std::c_str::ToCStr;
-//!
-//! extern {
-//! fn puts(s: *const libc::c_char);
-//! }
-//!
-//! fn main() {
-//! let my_string = "Hello, world!";
-//!
-//! // Allocate the C string with an explicit local that owns the string. The
-//! // `c_buffer` pointer will be deallocated when `my_c_string` goes out of scope.
-//! let my_c_string = my_string.to_c_str();
-//! unsafe {
-//! puts(my_c_string.as_ptr());
-//! }
-//!
-//! // Don't save/return the pointer to the C string, the `c_buffer` will be
-//! // deallocated when this block returns!
-//! my_string.with_c_str(|c_buffer| {
-//! unsafe { puts(c_buffer); }
-//! });
-//! }
-//! ```
-
-use core::prelude::*;
-use libc;
-
-use cmp::Ordering;
-use fmt;
-use hash;
-use mem;
-use ptr;
-use slice::{self, IntSliceExt};
-use str;
-use string::String;
-use core::kinds::marker;
-
-/// The representation of a C String.
-///
-/// This structure wraps a `*libc::c_char`, and will automatically free the
-/// memory it is pointing to when it goes out of scope.
-#[allow(missing_copy_implementations)]
-pub struct CString {
- buf: *const libc::c_char,
- owns_buffer_: bool,
-}
-
-unsafe impl Send for CString { }
-unsafe impl Sync for CString { }
-
-impl Clone for CString {
- /// Clone this CString into a new, uniquely owned CString. For safety
- /// reasons, this is always a deep clone with the memory allocated
- /// with C's allocator API, rather than the usual shallow clone.
- fn clone(&self) -> CString {
- let len = self.len() + 1;
- let buf = unsafe { libc::malloc(len as libc::size_t) } as *mut libc::c_char;
- if buf.is_null() { ::alloc::oom() }
- unsafe { ptr::copy_nonoverlapping_memory(buf, self.buf, len); }
- CString { buf: buf as *const libc::c_char, owns_buffer_: true }
- }
-}
-
-impl PartialEq for CString {
- fn eq(&self, other: &CString) -> bool {
- // Check if the two strings share the same buffer
- if self.buf as uint == other.buf as uint {
- true
- } else {
- unsafe {
- libc::strcmp(self.buf, other.buf) == 0
- }
- }
- }
-}
-
-impl PartialOrd for CString {
- #[inline]
- fn partial_cmp(&self, other: &CString) -> Option<Ordering> {
- self.as_bytes().partial_cmp(other.as_bytes())
- }
-}
-
-impl Eq for CString {}
-
-impl<S: hash::Writer> hash::Hash<S> for CString {
- #[inline]
- fn hash(&self, state: &mut S) {
- self.as_bytes().hash(state)
- }
-}
-
-impl CString {
- /// Create a C String from a pointer, with memory managed by C's allocator
- /// API, so avoid calling it with a pointer to memory managed by Rust's
- /// allocator API, as the behaviour would not be well defined.
- ///
- ///# Panics
- ///
- /// Panics if `buf` is null
- pub unsafe fn new(buf: *const libc::c_char, owns_buffer: bool) -> CString {
- assert!(!buf.is_null());
- CString { buf: buf, owns_buffer_: owns_buffer }
- }
-
- /// Return a pointer to the NUL-terminated string data.
- ///
- /// `.as_ptr` returns an internal pointer into the `CString`, and
- /// may be invalidated when the `CString` falls out of scope (the
- /// destructor will run, freeing the allocation if there is
- /// one).
- ///
- /// ```rust
- /// use std::c_str::ToCStr;
- ///
- /// let foo = "some string";
- ///
- /// // right
- /// let x = foo.to_c_str();
- /// let p = x.as_ptr();
- ///
- /// // wrong (the CString will be freed, invalidating `p`)
- /// let p = foo.to_c_str().as_ptr();
- /// ```
- ///
- /// # Example
- ///
- /// ```rust
- /// extern crate libc;
- ///
- /// use std::c_str::ToCStr;
- ///
- /// fn main() {
- /// let c_str = "foo bar".to_c_str();
- /// unsafe {
- /// libc::puts(c_str.as_ptr());
- /// }
- /// }
- /// ```
- pub fn as_ptr(&self) -> *const libc::c_char {
- self.buf
- }
-
- /// Return a mutable pointer to the NUL-terminated string data.
- ///
- /// `.as_mut_ptr` returns an internal pointer into the `CString`, and
- /// may be invalidated when the `CString` falls out of scope (the
- /// destructor will run, freeing the allocation if there is
- /// one).
- ///
- /// ```rust
- /// use std::c_str::ToCStr;
- ///
- /// let foo = "some string";
- ///
- /// // right
- /// let mut x = foo.to_c_str();
- /// let p = x.as_mut_ptr();
- ///
- /// // wrong (the CString will be freed, invalidating `p`)
- /// let p = foo.to_c_str().as_mut_ptr();
- /// ```
- pub fn as_mut_ptr(&mut self) -> *mut libc::c_char {
- self.buf as *mut _
- }
-
- /// Returns whether or not the `CString` owns the buffer.
- pub fn owns_buffer(&self) -> bool {
- self.owns_buffer_
- }
-
- /// Converts the CString into a `&[u8]` without copying.
- /// Includes the terminating NUL byte.
- #[inline]
- pub fn as_bytes<'a>(&'a self) -> &'a [u8] {
- unsafe {
- slice::from_raw_buf(&self.buf, self.len() + 1).as_unsigned()
- }
- }
-
- /// Converts the CString into a `&[u8]` without copying.
- /// Does not include the terminating NUL byte.
- #[inline]
- pub fn as_bytes_no_nul<'a>(&'a self) -> &'a [u8] {
- unsafe {
- slice::from_raw_buf(&self.buf, self.len()).as_unsigned()
- }
- }
-
- /// Converts the CString into a `&str` without copying.
- /// Returns None if the CString is not UTF-8.
- #[inline]
- pub fn as_str<'a>(&'a self) -> Option<&'a str> {
- let buf = self.as_bytes_no_nul();
- str::from_utf8(buf).ok()
- }
-
- /// Return a CString iterator.
- pub fn iter<'a>(&'a self) -> CChars<'a> {
- CChars {
- ptr: self.buf,
- marker: marker::ContravariantLifetime,
- }
- }
-
- /// Unwraps the wrapped `*libc::c_char` from the `CString` wrapper.
- ///
- /// Any ownership of the buffer by the `CString` wrapper is
- /// forgotten, meaning that the backing allocation of this
- /// `CString` is not automatically freed if it owns the
- /// allocation. In this case, a user of `.unwrap()` should ensure
- /// the allocation is freed, to avoid leaking memory. You should
- /// use libc's memory allocator in this case.
- ///
- /// Prefer `.as_ptr()` when just retrieving a pointer to the
- /// string data, as that does not relinquish ownership.
- pub unsafe fn into_inner(mut self) -> *const libc::c_char {
- self.owns_buffer_ = false;
- self.buf
- }
-
- /// Return the number of bytes in the CString (not including the NUL
- /// terminator).
- #[inline]
- pub fn len(&self) -> uint {
- unsafe { libc::strlen(self.buf) as uint }
- }
-
- /// Returns if there are no bytes in this string
- #[inline]
- pub fn is_empty(&self) -> bool { self.len() == 0 }
-}
-
-impl Drop for CString {
- fn drop(&mut self) {
- if self.owns_buffer_ {
- unsafe {
- libc::free(self.buf as *mut libc::c_void)
- }
- }
- }
-}
-
-impl fmt::Show for CString {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- String::from_utf8_lossy(self.as_bytes_no_nul()).fmt(f)
- }
-}
-
-/// A generic trait for converting a value to a CString.
-pub trait ToCStr for Sized? {
- /// Copy the receiver into a CString.
- ///
- /// # Panics
- ///
- /// Panics the task if the receiver has an interior null.
- fn to_c_str(&self) -> CString;
-
- /// Unsafe variant of `to_c_str()` that doesn't check for nulls.
- unsafe fn to_c_str_unchecked(&self) -> CString;
-
- /// Work with a temporary CString constructed from the receiver.
- /// The provided `*libc::c_char` will be freed immediately upon return.
- ///
- /// # Example
- ///
- /// ```rust
- /// extern crate libc;
- ///
- /// use std::c_str::ToCStr;
- ///
- /// fn main() {
- /// let s = "PATH".with_c_str(|path| unsafe {
- /// libc::getenv(path)
- /// });
- /// }
- /// ```
- ///
- /// # Panics
- ///
- /// Panics the task if the receiver has an interior null.
- #[inline]
- fn with_c_str<T, F>(&self, f: F) -> T where
- F: FnOnce(*const libc::c_char) -> T,
- {
- let c_str = self.to_c_str();
- f(c_str.as_ptr())
- }
-
- /// Unsafe variant of `with_c_str()` that doesn't check for nulls.
- #[inline]
- unsafe fn with_c_str_unchecked<T, F>(&self, f: F) -> T where
- F: FnOnce(*const libc::c_char) -> T,
- {
- let c_str = self.to_c_str_unchecked();
- f(c_str.as_ptr())
- }
-}
-
-impl ToCStr for str {
- #[inline]
- fn to_c_str(&self) -> CString {
- self.as_bytes().to_c_str()
- }
-
- #[inline]
- unsafe fn to_c_str_unchecked(&self) -> CString {
- self.as_bytes().to_c_str_unchecked()
- }
-
- #[inline]
- fn with_c_str<T, F>(&self, f: F) -> T where
- F: FnOnce(*const libc::c_char) -> T,
- {
- self.as_bytes().with_c_str(f)
- }
-
- #[inline]
- unsafe fn with_c_str_unchecked<T, F>(&self, f: F) -> T where
- F: FnOnce(*const libc::c_char) -> T,
- {
- self.as_bytes().with_c_str_unchecked(f)
- }
-}
-
-impl ToCStr for String {
- #[inline]
- fn to_c_str(&self) -> CString {
- self.as_bytes().to_c_str()
- }
-
- #[inline]
- unsafe fn to_c_str_unchecked(&self) -> CString {
- self.as_bytes().to_c_str_unchecked()
- }
-
- #[inline]
- fn with_c_str<T, F>(&self, f: F) -> T where
- F: FnOnce(*const libc::c_char) -> T,
- {
- self.as_bytes().with_c_str(f)
- }
-
- #[inline]
- unsafe fn with_c_str_unchecked<T, F>(&self, f: F) -> T where
- F: FnOnce(*const libc::c_char) -> T,
- {
- self.as_bytes().with_c_str_unchecked(f)
- }
-}
-
-// The length of the stack allocated buffer for `vec.with_c_str()`
-const BUF_LEN: uint = 128;
-
-impl ToCStr for [u8] {
- fn to_c_str(&self) -> CString {
- let mut cs = unsafe { self.to_c_str_unchecked() };
- check_for_null(self, cs.as_mut_ptr());
- cs
- }
-
- unsafe fn to_c_str_unchecked(&self) -> CString {
- let self_len = self.len();
- let buf = libc::malloc(self_len as libc::size_t + 1) as *mut u8;
- if buf.is_null() { ::alloc::oom() }
-
- ptr::copy_memory(buf, self.as_ptr(), self_len);
- *buf.offset(self_len as int) = 0;
-
- CString::new(buf as *const libc::c_char, true)
- }
-
- fn with_c_str<T, F>(&self, f: F) -> T where
- F: FnOnce(*const libc::c_char) -> T,
- {
- unsafe { with_c_str(self, true, f) }
- }
-
- unsafe fn with_c_str_unchecked<T, F>(&self, f: F) -> T where
- F: FnOnce(*const libc::c_char) -> T,
- {
- with_c_str(self, false, f)
- }
-}
-
-impl<'a, Sized? T: ToCStr> ToCStr for &'a T {
- #[inline]
- fn to_c_str(&self) -> CString {
- (**self).to_c_str()
- }
-
- #[inline]
- unsafe fn to_c_str_unchecked(&self) -> CString {
- (**self).to_c_str_unchecked()
- }
-
- #[inline]
- fn with_c_str<T, F>(&self, f: F) -> T where
- F: FnOnce(*const libc::c_char) -> T,
- {
- (**self).with_c_str(f)
- }
-
- #[inline]
- unsafe fn with_c_str_unchecked<T, F>(&self, f: F) -> T where
- F: FnOnce(*const libc::c_char) -> T,
- {
- (**self).with_c_str_unchecked(f)
- }
-}
-
-// Unsafe function that handles possibly copying the &[u8] into a stack array.
-unsafe fn with_c_str<T, F>(v: &[u8], checked: bool, f: F) -> T where
- F: FnOnce(*const libc::c_char) -> T,
-{
- let c_str = if v.len() < BUF_LEN {
- let mut buf: [u8; BUF_LEN] = mem::uninitialized();
- slice::bytes::copy_memory(&mut buf, v);
- buf[v.len()] = 0;
-
- let buf = buf.as_mut_ptr();
- if checked {
- check_for_null(v, buf as *mut libc::c_char);
- }
-
- return f(buf as *const libc::c_char)
- } else if checked {
- v.to_c_str()
- } else {
- v.to_c_str_unchecked()
- };
-
- f(c_str.as_ptr())
-}
-
-#[inline]
-fn check_for_null(v: &[u8], buf: *mut libc::c_char) {
- for i in range(0, v.len()) {
- unsafe {
- let p = buf.offset(i as int);
- assert!(*p != 0);
- }
- }
-}
-
-/// External iterator for a CString's bytes.
-///
-/// Use with the `std::iter` module.
-#[allow(raw_pointer_deriving)]
-#[derive(Clone)]
-pub struct CChars<'a> {
- ptr: *const libc::c_char,
- marker: marker::ContravariantLifetime<'a>,
-}
-
-impl<'a> Iterator for CChars<'a> {
- type Item = libc::c_char;
-
- fn next(&mut self) -> Option<libc::c_char> {
- let ch = unsafe { *self.ptr };
- if ch == 0 {
- None
- } else {
- self.ptr = unsafe { self.ptr.offset(1) };
- Some(ch)
- }
- }
-}
-
-/// Parses a C "multistring", eg windows env values or
-/// the req->ptr result in a uv_fs_readdir() call.
-///
-/// Optionally, a `count` can be passed in, limiting the
-/// parsing to only being done `count`-times.
-///
-/// The specified closure is invoked with each string that
-/// is found, and the number of strings found is returned.
-pub unsafe fn from_c_multistring<F>(buf: *const libc::c_char,
- count: Option<uint>,
- mut f: F)
- -> uint where
- F: FnMut(&CString),
-{
-
- let mut curr_ptr: uint = buf as uint;
- let mut ctr = 0;
- let (limited_count, limit) = match count {
- Some(limit) => (true, limit),
- None => (false, 0)
- };
- while ((limited_count && ctr < limit) || !limited_count)
- && *(curr_ptr as *const libc::c_char) != 0 as libc::c_char {
- let cstr = CString::new(curr_ptr as *const libc::c_char, false);
- f(&cstr);
- curr_ptr += cstr.len() + 1;
- ctr += 1;
- }
- return ctr;
-}
-
-#[cfg(test)]
-mod tests {
- use prelude::v1::*;
- use super::*;
- use ptr;
- use thread::Thread;
- use libc;
-
- #[test]
- fn test_str_multistring_parsing() {
- unsafe {
- let input = b"zero\0one\0\0";
- let ptr = input.as_ptr();
- let expected = ["zero", "one"];
- let mut it = expected.iter();
- let result = from_c_multistring(ptr as *const libc::c_char, None, |c| {
- let cbytes = c.as_bytes_no_nul();
- assert_eq!(cbytes, it.next().unwrap().as_bytes());
- });
- assert_eq!(result, 2);
- assert!(it.next().is_none());
- }
- }
-
- #[test]
- fn test_str_to_c_str() {
- let c_str = "".to_c_str();
- unsafe {
- assert_eq!(*c_str.as_ptr().offset(0), 0);
- }
-
- let c_str = "hello".to_c_str();
- let buf = c_str.as_ptr();
- unsafe {
- assert_eq!(*buf.offset(0), 'h' as libc::c_char);
- assert_eq!(*buf.offset(1), 'e' as libc::c_char);
- assert_eq!(*buf.offset(2), 'l' as libc::c_char);
- assert_eq!(*buf.offset(3), 'l' as libc::c_char);
- assert_eq!(*buf.offset(4), 'o' as libc::c_char);
- assert_eq!(*buf.offset(5), 0);
- }
- }
-
- #[test]
- fn test_vec_to_c_str() {
- let b: &[u8] = &[];
- let c_str = b.to_c_str();
- unsafe {
- assert_eq!(*c_str.as_ptr().offset(0), 0);
- }
-
- let c_str = b"hello".to_c_str();
- let buf = c_str.as_ptr();
- unsafe {
- assert_eq!(*buf.offset(0), 'h' as libc::c_char);
- assert_eq!(*buf.offset(1), 'e' as libc::c_char);
- assert_eq!(*buf.offset(2), 'l' as libc::c_char);
- assert_eq!(*buf.offset(3), 'l' as libc::c_char);
- assert_eq!(*buf.offset(4), 'o' as libc::c_char);
- assert_eq!(*buf.offset(5), 0);
- }
-
- let c_str = b"foo\xFF".to_c_str();
- let buf = c_str.as_ptr();
- unsafe {
- assert_eq!(*buf.offset(0), 'f' as libc::c_char);
- assert_eq!(*buf.offset(1), 'o' as libc::c_char);
- assert_eq!(*buf.offset(2), 'o' as libc::c_char);
- assert_eq!(*buf.offset(3), 0xffu8 as libc::c_char);
- assert_eq!(*buf.offset(4), 0);
- }
- }
-
- #[test]
- fn test_unwrap() {
- let c_str = "hello".to_c_str();
- unsafe { libc::free(c_str.into_inner() as *mut libc::c_void) }
- }
-
- #[test]
- fn test_as_ptr() {
- let c_str = "hello".to_c_str();
- let len = unsafe { libc::strlen(c_str.as_ptr()) };
- assert_eq!(len, 5);
- }
-
- #[test]
- fn test_iterator() {
- let c_str = "".to_c_str();
- let mut iter = c_str.iter();
- assert_eq!(iter.next(), None);
-
- let c_str = "hello".to_c_str();
- let mut iter = c_str.iter();
- assert_eq!(iter.next(), Some('h' as libc::c_char));
- assert_eq!(iter.next(), Some('e' as libc::c_char));
- assert_eq!(iter.next(), Some('l' as libc::c_char));
- assert_eq!(iter.next(), Some('l' as libc::c_char));
- assert_eq!(iter.next(), Some('o' as libc::c_char));
- assert_eq!(iter.next(), None);
- }
-
- #[test]
- fn test_to_c_str_fail() {
- assert!(Thread::spawn(move|| { "he\x00llo".to_c_str() }).join().is_err());
- }
-
- #[test]
- fn test_to_c_str_unchecked() {
- unsafe {
- let c_string = "he\x00llo".to_c_str_unchecked();
- let buf = c_string.as_ptr();
- assert_eq!(*buf.offset(0), 'h' as libc::c_char);
- assert_eq!(*buf.offset(1), 'e' as libc::c_char);
- assert_eq!(*buf.offset(2), 0);
- assert_eq!(*buf.offset(3), 'l' as libc::c_char);
- assert_eq!(*buf.offset(4), 'l' as libc::c_char);
- assert_eq!(*buf.offset(5), 'o' as libc::c_char);
- assert_eq!(*buf.offset(6), 0);
- }
- }
-
- #[test]
- fn test_as_bytes() {
- let c_str = "hello".to_c_str();
- assert_eq!(c_str.as_bytes(), b"hello\0");
- let c_str = "".to_c_str();
- assert_eq!(c_str.as_bytes(), b"\0");
- let c_str = b"foo\xFF".to_c_str();
- assert_eq!(c_str.as_bytes(), b"foo\xFF\0");
- }
-
- #[test]
- fn test_as_bytes_no_nul() {
- let c_str = "hello".to_c_str();
- assert_eq!(c_str.as_bytes_no_nul(), b"hello");
- let c_str = "".to_c_str();
- let exp: &[u8] = &[];
- assert_eq!(c_str.as_bytes_no_nul(), exp);
- let c_str = b"foo\xFF".to_c_str();
- assert_eq!(c_str.as_bytes_no_nul(), b"foo\xFF");
- }
-
- #[test]
- fn test_as_str() {
- let c_str = "hello".to_c_str();
- assert_eq!(c_str.as_str(), Some("hello"));
- let c_str = "".to_c_str();
- assert_eq!(c_str.as_str(), Some(""));
- let c_str = b"foo\xFF".to_c_str();
- assert_eq!(c_str.as_str(), None);
- }
-
- #[test]
- #[should_fail]
- fn test_new_fail() {
- let _c_str = unsafe { CString::new(ptr::null(), false) };
- }
-
- #[test]
- fn test_clone() {
- let a = "hello".to_c_str();
- let b = a.clone();
- assert!(a == b);
- }
-
- #[test]
- fn test_clone_noleak() {
- fn foo<F>(f: F) where F: FnOnce(&CString) {
- let s = "test".to_string();
- let c = s.to_c_str();
- // give the closure a non-owned CString
- let mut c_ = unsafe { CString::new(c.as_ptr(), false) };
- f(&c_);
- // muck with the buffer for later printing
- unsafe { *c_.as_mut_ptr() = 'X' as libc::c_char }
- }
-
- let mut c_: Option<CString> = None;
- foo(|c| {
- c_ = Some(c.clone());
- c.clone();
- // force a copy, reading the memory
- c.as_bytes().to_vec();
- });
- let c_ = c_.unwrap();
- // force a copy, reading the memory
- c_.as_bytes().to_vec();
- }
-}
-
-#[cfg(test)]
-mod bench {
- extern crate test;
-
- use prelude::v1::*;
- use self::test::Bencher;
- use libc;
- use c_str::ToCStr;
-
- #[inline]
- fn check(s: &str, c_str: *const libc::c_char) {
- let s_buf = s.as_ptr();
- for i in range(0, s.len()) {
- unsafe {
- assert_eq!(
- *s_buf.offset(i as int) as libc::c_char,
- *c_str.offset(i as int));
- }
- }
- }
-
- static S_SHORT: &'static str = "Mary";
- static S_MEDIUM: &'static str = "Mary had a little lamb";
- static S_LONG: &'static str = "\
- Mary had a little lamb, Little lamb
- Mary had a little lamb, Little lamb
- Mary had a little lamb, Little lamb
- Mary had a little lamb, Little lamb
- Mary had a little lamb, Little lamb
- Mary had a little lamb, Little lamb";
-
- fn bench_to_string(b: &mut Bencher, s: &str) {
- b.iter(|| {
- let c_str = s.to_c_str();
- check(s, c_str.as_ptr());
- })
- }
-
- #[bench]
- fn bench_to_c_str_short(b: &mut Bencher) {
- bench_to_string(b, S_SHORT)
- }
-
- #[bench]
- fn bench_to_c_str_medium(b: &mut Bencher) {
- bench_to_string(b, S_MEDIUM)
- }
-
- #[bench]
- fn bench_to_c_str_long(b: &mut Bencher) {
- bench_to_string(b, S_LONG)
- }
-
- fn bench_to_c_str_unchecked(b: &mut Bencher, s: &str) {
- b.iter(|| {
- let c_str = unsafe { s.to_c_str_unchecked() };
- check(s, c_str.as_ptr())
- })
- }
-
- #[bench]
- fn bench_to_c_str_unchecked_short(b: &mut Bencher) {
- bench_to_c_str_unchecked(b, S_SHORT)
- }
-
- #[bench]
- fn bench_to_c_str_unchecked_medium(b: &mut Bencher) {
- bench_to_c_str_unchecked(b, S_MEDIUM)
- }
-
- #[bench]
- fn bench_to_c_str_unchecked_long(b: &mut Bencher) {
- bench_to_c_str_unchecked(b, S_LONG)
- }
-
- fn bench_with_c_str(b: &mut Bencher, s: &str) {
- b.iter(|| {
- s.with_c_str(|c_str_buf| check(s, c_str_buf))
- })
- }
-
- #[bench]
- fn bench_with_c_str_short(b: &mut Bencher) {
- bench_with_c_str(b, S_SHORT)
- }
-
- #[bench]
- fn bench_with_c_str_medium(b: &mut Bencher) {
- bench_with_c_str(b, S_MEDIUM)
- }
-
- #[bench]
- fn bench_with_c_str_long(b: &mut Bencher) {
- bench_with_c_str(b, S_LONG)
- }
-
- fn bench_with_c_str_unchecked(b: &mut Bencher, s: &str) {
- b.iter(|| {
- unsafe {
- s.with_c_str_unchecked(|c_str_buf| check(s, c_str_buf))
- }
- })
- }
-
- #[bench]
- fn bench_with_c_str_unchecked_short(b: &mut Bencher) {
- bench_with_c_str_unchecked(b, S_SHORT)
- }
-
- #[bench]
- fn bench_with_c_str_unchecked_medium(b: &mut Bencher) {
- bench_with_c_str_unchecked(b, S_MEDIUM)
- }
-
- #[bench]
- fn bench_with_c_str_unchecked_long(b: &mut Bencher) {
- bench_with_c_str_unchecked(b, S_LONG)
- }
-}
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Library to interface with chunks of memory allocated in C.
-//!
-//! It is often desirable to safely interface with memory allocated from C,
-//! encapsulating the unsafety into allocation and destruction time. Indeed,
-//! allocating memory externally is currently the only way to give Rust shared
-//! mut state with C programs that keep their own references; vectors are
-//! unsuitable because they could be reallocated or moved at any time, and
-//! importing C memory into a vector takes a one-time snapshot of the memory.
-//!
-//! This module simplifies the usage of such external blocks of memory. Memory
-//! is encapsulated into an opaque object after creation; the lifecycle of the
-//! memory can be optionally managed by Rust, if an appropriate destructor
-//! closure is provided. Safety is ensured by bounds-checking accesses, which
-//! are marshalled through get and set functions.
-//!
-//! There are three unsafe functions: the two constructors, and the
-//! unwrap method. The constructors are unsafe for the
-//! obvious reason (they act on a pointer that cannot be checked inside the
-//! method), but `unwrap()` is somewhat more subtle in its unsafety.
-//! It returns the contained pointer, but at the same time destroys the CVec
-//! without running its destructor. This can be used to pass memory back to
-//! C, but care must be taken that the ownership of underlying resources are
-//! handled correctly, i.e. that allocated memory is eventually freed
-//! if necessary.
-
-#![experimental]
-
-use kinds::Send;
-use mem;
-use ops::{Drop, FnOnce};
-use option::Option;
-use option::Option::{Some, None};
-use ptr::PtrExt;
-use ptr;
-use raw;
-use slice::AsSlice;
-use thunk::{Thunk};
-
-/// The type representing a foreign chunk of memory
-pub struct CVec<T> {
- base: *mut T,
- len: uint,
- dtor: Option<Thunk>,
-}
-
-#[unsafe_destructor]
-impl<T> Drop for CVec<T> {
- fn drop(&mut self) {
- match self.dtor.take() {
- None => (),
- Some(f) => f.invoke(())
- }
- }
-}
-
-impl<T> CVec<T> {
- /// Create a `CVec` from a raw pointer to a buffer with a given length.
- ///
- /// Panics if the given pointer is null. The returned vector will not attempt
- /// to deallocate the vector when dropped.
- ///
- /// # Arguments
- ///
- /// * base - A raw pointer to a buffer
- /// * len - The number of elements in the buffer
- pub unsafe fn new(base: *mut T, len: uint) -> CVec<T> {
- assert!(base != ptr::null_mut());
- CVec {
- base: base,
- len: len,
- dtor: None,
- }
- }
-
- /// Create a `CVec` from a foreign buffer, with a given length,
- /// and a function to run upon destruction.
- ///
- /// Panics if the given pointer is null.
- ///
- /// # Arguments
- ///
- /// * base - A foreign pointer to a buffer
- /// * len - The number of elements in the buffer
- /// * dtor - A fn to run when the value is destructed, useful
- /// for freeing the buffer, etc.
- pub unsafe fn new_with_dtor<F>(base: *mut T,
- len: uint,
- dtor: F)
- -> CVec<T>
- where F : FnOnce(), F : Send
- {
- assert!(base != ptr::null_mut());
- let dtor: Thunk = Thunk::new(dtor);
- CVec {
- base: base,
- len: len,
- dtor: Some(dtor)
- }
- }
-
- /// View the stored data as a mutable slice.
- pub fn as_mut_slice<'a>(&'a mut self) -> &'a mut [T] {
- unsafe {
- mem::transmute(raw::Slice { data: self.base as *const T, len: self.len })
- }
- }
-
- /// Retrieves an element at a given index, returning `None` if the requested
- /// index is greater than the length of the vector.
- pub fn get<'a>(&'a self, ofs: uint) -> Option<&'a T> {
- if ofs < self.len {
- Some(unsafe { &*self.base.offset(ofs as int) })
- } else {
- None
- }
- }
-
- /// Retrieves a mutable element at a given index, returning `None` if the
- /// requested index is greater than the length of the vector.
- pub fn get_mut<'a>(&'a mut self, ofs: uint) -> Option<&'a mut T> {
- if ofs < self.len {
- Some(unsafe { &mut *self.base.offset(ofs as int) })
- } else {
- None
- }
- }
-
- /// Unwrap the pointer without running the destructor
- ///
- /// This method retrieves the underlying pointer, and in the process
- /// destroys the CVec but without running the destructor. A use case
- /// would be transferring ownership of the buffer to a C function, as
- /// in this case you would not want to run the destructor.
- ///
- /// Note that if you want to access the underlying pointer without
- /// cancelling the destructor, you can simply call `transmute` on the return
- /// value of `get(0)`.
- pub unsafe fn into_inner(mut self) -> *mut T {
- self.dtor = None;
- self.base
- }
-
- /// Returns the number of items in this vector.
- pub fn len(&self) -> uint { self.len }
-
- /// Returns whether this vector is empty.
- pub fn is_empty(&self) -> bool { self.len() == 0 }
-}
-
-impl<T> AsSlice<T> for CVec<T> {
- /// View the stored data as a slice.
- fn as_slice<'a>(&'a self) -> &'a [T] {
- unsafe {
- mem::transmute(raw::Slice { data: self.base as *const T, len: self.len })
- }
- }
-}
-
-#[cfg(test)]
-mod tests {
- use prelude::v1::*;
-
- use super::CVec;
- use libc;
- use ptr;
-
- fn malloc(n: uint) -> CVec<u8> {
- unsafe {
- let mem = ptr::Unique(libc::malloc(n as libc::size_t));
- if mem.0.is_null() { ::alloc::oom() }
-
- CVec::new_with_dtor(mem.0 as *mut u8,
- n,
- move|| { libc::free(mem.0 as *mut libc::c_void); })
- }
- }
-
- #[test]
- fn test_basic() {
- let mut cv = malloc(16);
-
- *cv.get_mut(3).unwrap() = 8;
- *cv.get_mut(4).unwrap() = 9;
- assert_eq!(*cv.get(3).unwrap(), 8);
- assert_eq!(*cv.get(4).unwrap(), 9);
- assert_eq!(cv.len(), 16);
- }
-
- #[test]
- #[should_fail]
- fn test_panic_at_null() {
- unsafe {
- CVec::new(ptr::null_mut::<u8>(), 9);
- }
- }
-
- #[test]
- fn test_overrun_get() {
- let cv = malloc(16);
-
- assert!(cv.get(17).is_none());
- }
-
- #[test]
- fn test_overrun_set() {
- let mut cv = malloc(16);
-
- assert!(cv.get_mut(17).is_none());
- }
-
- #[test]
- fn test_unwrap() {
- unsafe {
- let cv = CVec::new_with_dtor(1 as *mut int,
- 0,
- move|:| panic!("Don't run this destructor!"));
- let p = cv.into_inner();
- assert_eq!(p, 1 as *mut int);
- }
- }
-
-}
use self::SearchResult::*;
use self::VacantEntryState::*;
-use borrow::BorrowFrom;
+use borrow::{BorrowFrom, ToOwned};
use clone::Clone;
use cmp::{max, Eq, PartialEq};
use default::Default;
}
}
- /// Gets the given key's corresponding entry in the map for in-place manipulation
- pub fn entry<'a>(&'a mut self, key: K) -> Entry<'a, K, V> {
+ #[stable]
+ /// Gets the given key's corresponding entry in the map for in-place manipulation.
+ /// Regardless of whether or not `to_owned()` has been called, the key must hash the same way.
+ pub fn entry<'a, Sized? Q>(&'a mut self, key: &'a Q) -> Entry<'a, Q, K, V>
+ where Q: Eq + Hash<S> + ToOwned<K>
+ {
// Gotta resize now.
self.reserve(1);
- let hash = self.make_hash(&key);
+ let hash = self.make_hash(key);
search_entry_hashed(&mut self.table, hash, key)
}
}
}
-fn search_entry_hashed<'a, K: Eq, V>(table: &'a mut RawTable<K,V>, hash: SafeHash, k: K)
- -> Entry<'a, K, V> {
+fn search_entry_hashed<'a, K, V, Sized? Q>(table: &'a mut RawTable<K,V>, hash: SafeHash, k: &'a Q)
+ -> Entry<'a, Q, K, V>
+ where Q: Eq + ToOwned<K>
+{
// Worst case, we'll find one empty bucket among `size + 1` buckets.
let size = table.size();
let mut probe = Bucket::new(table, hash);
// hash matches?
if bucket.hash() == hash {
// key matches?
- if k == *bucket.read().0 {
+ if *k == *BorrowFrom::borrow_from(bucket.read().0) {
return Occupied(OccupiedEntry{
elem: bucket,
});
}
}
-// NOTE(stage0): remove impl after a snapshot
-#[cfg(stage0)]
-#[stable]
-impl<K: Hash<S> + Eq, Sized? Q, V, S, H: Hasher<S>> Index<Q, V> for HashMap<K, V, H>
- where Q: BorrowFrom<K> + Hash<S> + Eq
-{
- #[inline]
- fn index<'a>(&'a self, index: &Q) -> &'a V {
- self.get(index).expect("no entry found for key")
- }
-}
-
-#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot
#[stable]
impl<K: Hash<S> + Eq, Sized? Q, V, S, H: Hasher<S>> Index<Q> for HashMap<K, V, H>
where Q: BorrowFrom<K> + Hash<S> + Eq
}
}
-// NOTE(stage0): remove impl after a snapshot
-#[cfg(stage0)]
-#[stable]
-impl<K: Hash<S> + Eq, Sized? Q, V, S, H: Hasher<S>> IndexMut<Q, V> for HashMap<K, V, H>
- where Q: BorrowFrom<K> + Hash<S> + Eq
-{
- #[inline]
- fn index_mut<'a>(&'a mut self, index: &Q) -> &'a mut V {
- self.get_mut(index).expect("no entry found for key")
- }
-}
-
-#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot
#[stable]
impl<K: Hash<S> + Eq, Sized? Q, V, S, H: Hasher<S>> IndexMut<Q> for HashMap<K, V, H>
where Q: BorrowFrom<K> + Hash<S> + Eq
>
}
+#[stable]
/// A view into a single occupied location in a HashMap
-pub struct OccupiedEntry<'a, K:'a, V:'a> {
+pub struct OccupiedEntry<'a, K: 'a, V: 'a> {
elem: FullBucket<K, V, &'a mut RawTable<K, V>>,
}
+#[stable]
/// A view into a single empty location in a HashMap
-pub struct VacantEntry<'a, K:'a, V:'a> {
+pub struct VacantEntry<'a, Sized? Q: 'a, K: 'a, V: 'a> {
hash: SafeHash,
- key: K,
- elem: VacantEntryState<K,V, &'a mut RawTable<K, V>>,
+ key: &'a Q,
+ elem: VacantEntryState<K, V, &'a mut RawTable<K, V>>,
}
+#[stable]
/// A view into a single location in a map, which may be vacant or occupied
-pub enum Entry<'a, K:'a, V:'a> {
+pub enum Entry<'a, Sized? Q: 'a, K: 'a, V: 'a> {
/// An occupied Entry
Occupied(OccupiedEntry<'a, K, V>),
/// A vacant Entry
- Vacant(VacantEntry<'a, K, V>),
+ Vacant(VacantEntry<'a, Q, K, V>),
}
/// Possible states of a VacantEntry
}
}
+impl<'a, Sized? Q, K, V> Entry<'a, Q, K, V> {
+ #[unstable = "matches collection reform v2 specification, waiting for dust to settle"]
+ /// Returns a mutable reference to the entry if occupied, or the VacantEntry if vacant
+ pub fn get(self) -> Result<&'a mut V, VacantEntry<'a, Q, K, V>> {
+ match self {
+ Occupied(entry) => Ok(entry.into_mut()),
+ Vacant(entry) => Err(entry),
+ }
+ }
+}
+
impl<'a, K, V> OccupiedEntry<'a, K, V> {
+ #[stable]
/// Gets a reference to the value in the entry
pub fn get(&self) -> &V {
self.elem.read().1
}
+ #[stable]
/// Gets a mutable reference to the value in the entry
pub fn get_mut(&mut self) -> &mut V {
self.elem.read_mut().1
}
+ #[stable]
/// Converts the OccupiedEntry into a mutable reference to the value in the entry
/// with a lifetime bound to the map itself
pub fn into_mut(self) -> &'a mut V {
self.elem.into_mut_refs().1
}
+ #[stable]
/// Sets the value of the entry, and returns the entry's old value
- pub fn set(&mut self, mut value: V) -> V {
+ pub fn insert(&mut self, mut value: V) -> V {
let old_value = self.get_mut();
mem::swap(&mut value, old_value);
value
}
+ #[stable]
/// Takes the value out of the entry, and returns it
- pub fn take(self) -> V {
+ pub fn remove(self) -> V {
pop_internal(self.elem).1
}
}
-impl<'a, K, V> VacantEntry<'a, K, V> {
+impl<'a, Sized? Q: 'a + ToOwned<K>, K: 'a, V: 'a> VacantEntry<'a, Q, K, V> {
+ #[stable]
/// Sets the value of the entry with the VacantEntry's key,
/// and returns a mutable reference to it
- pub fn set(self, value: V) -> &'a mut V {
+ pub fn insert(self, value: V) -> &'a mut V {
match self.elem {
NeqElem(bucket, ib) => {
- robin_hood(bucket, ib, self.hash, self.key, value)
+ robin_hood(bucket, ib, self.hash, self.key.to_owned(), value)
}
NoElem(bucket) => {
- bucket.put(self.hash, self.key, value).into_mut_refs().1
+ bucket.put(self.hash, self.key.to_owned(), value).into_mut_refs().1
}
}
}
use super::HashMap;
use super::Entry::{Occupied, Vacant};
use iter::{range_inclusive, range_step_inclusive, repeat};
+ use borrow::ToOwned;
+ use hash;
use cell::RefCell;
use rand::{weak_rng, Rng};
let mut map: HashMap<int, int> = xs.iter().map(|&x| x).collect();
// Existing key (insert)
- match map.entry(1) {
+ match map.entry(&1) {
Vacant(_) => unreachable!(),
Occupied(mut view) => {
assert_eq!(view.get(), &10);
- assert_eq!(view.set(100), 10);
+ assert_eq!(view.insert(100), 10);
}
}
assert_eq!(map.get(&1).unwrap(), &100);
// Existing key (update)
- match map.entry(2) {
+ match map.entry(&2) {
Vacant(_) => unreachable!(),
Occupied(mut view) => {
let v = view.get_mut();
assert_eq!(map.len(), 6);
// Existing key (take)
- match map.entry(3) {
+ match map.entry(&3) {
Vacant(_) => unreachable!(),
Occupied(view) => {
- assert_eq!(view.take(), 30);
+ assert_eq!(view.remove(), 30);
}
}
assert_eq!(map.get(&3), None);
// Inexistent key (insert)
- match map.entry(10) {
+ match map.entry(&10) {
Occupied(_) => unreachable!(),
Vacant(view) => {
- assert_eq!(*view.set(1000), 1000);
+ assert_eq!(*view.insert(1000), 1000);
}
}
assert_eq!(map.get(&10).unwrap(), &1000);
for i in range(0u, 1000) {
let x = rng.gen_range(-10, 10);
- match m.entry(x) {
+ match m.entry(&x) {
Vacant(_) => {},
Occupied(e) => {
println!("{}: remove {}", i, x);
- e.take();
+ e.remove();
},
}
///
/// let h = SipHasher::new();
/// let mut set = HashSet::with_capacity_and_hasher(10u, h);
- /// set.insert(1i);
+ /// set.insert(1);
/// ```
#[inline]
#[unstable = "hasher stuff is unclear"]
///
/// ```
/// use std::collections::HashSet;
- /// let a: HashSet<int> = [1i, 2, 3].iter().map(|&x| x).collect();
- /// let b: HashSet<int> = [4i, 2, 3, 4].iter().map(|&x| x).collect();
+ /// let a: HashSet<int> = [1, 2, 3].iter().map(|&x| x).collect();
+ /// let b: HashSet<int> = [4, 2, 3, 4].iter().map(|&x| x).collect();
///
/// // Can be seen as `a - b`.
/// for x in a.difference(&b) {
/// }
///
/// let diff: HashSet<int> = a.difference(&b).map(|&x| x).collect();
- /// assert_eq!(diff, [1i].iter().map(|&x| x).collect());
+ /// assert_eq!(diff, [1].iter().map(|&x| x).collect());
///
/// // Note that difference is not symmetric,
/// // and `b - a` means something else:
/// let diff: HashSet<int> = b.difference(&a).map(|&x| x).collect();
- /// assert_eq!(diff, [4i].iter().map(|&x| x).collect());
+ /// assert_eq!(diff, [4].iter().map(|&x| x).collect());
/// ```
#[stable]
pub fn difference<'a>(&'a self, other: &'a HashSet<T, H>) -> Difference<'a, T, H> {
///
/// ```
/// use std::collections::HashSet;
- /// let a: HashSet<int> = [1i, 2, 3].iter().map(|&x| x).collect();
- /// let b: HashSet<int> = [4i, 2, 3, 4].iter().map(|&x| x).collect();
+ /// let a: HashSet<int> = [1, 2, 3].iter().map(|&x| x).collect();
+ /// let b: HashSet<int> = [4, 2, 3, 4].iter().map(|&x| x).collect();
///
/// // Print 1, 4 in arbitrary order.
/// for x in a.symmetric_difference(&b) {
/// let diff2: HashSet<int> = b.symmetric_difference(&a).map(|&x| x).collect();
///
/// assert_eq!(diff1, diff2);
- /// assert_eq!(diff1, [1i, 4].iter().map(|&x| x).collect());
+ /// assert_eq!(diff1, [1, 4].iter().map(|&x| x).collect());
/// ```
#[stable]
pub fn symmetric_difference<'a>(&'a self, other: &'a HashSet<T, H>)
///
/// ```
/// use std::collections::HashSet;
- /// let a: HashSet<int> = [1i, 2, 3].iter().map(|&x| x).collect();
- /// let b: HashSet<int> = [4i, 2, 3, 4].iter().map(|&x| x).collect();
+ /// let a: HashSet<int> = [1, 2, 3].iter().map(|&x| x).collect();
+ /// let b: HashSet<int> = [4, 2, 3, 4].iter().map(|&x| x).collect();
///
/// // Print 2, 3 in arbitrary order.
/// for x in a.intersection(&b) {
/// }
///
/// let diff: HashSet<int> = a.intersection(&b).map(|&x| x).collect();
- /// assert_eq!(diff, [2i, 3].iter().map(|&x| x).collect());
+ /// assert_eq!(diff, [2, 3].iter().map(|&x| x).collect());
/// ```
#[stable]
pub fn intersection<'a>(&'a self, other: &'a HashSet<T, H>) -> Intersection<'a, T, H> {
///
/// ```
/// use std::collections::HashSet;
- /// let a: HashSet<int> = [1i, 2, 3].iter().map(|&x| x).collect();
- /// let b: HashSet<int> = [4i, 2, 3, 4].iter().map(|&x| x).collect();
+ /// let a: HashSet<int> = [1, 2, 3].iter().map(|&x| x).collect();
+ /// let b: HashSet<int> = [4, 2, 3, 4].iter().map(|&x| x).collect();
///
/// // Print 1, 2, 3, 4 in arbitrary order.
/// for x in a.union(&b) {
/// }
///
/// let diff: HashSet<int> = a.union(&b).map(|&x| x).collect();
- /// assert_eq!(diff, [1i, 2, 3, 4].iter().map(|&x| x).collect());
+ /// assert_eq!(diff, [1, 2, 3, 4].iter().map(|&x| x).collect());
/// ```
#[stable]
pub fn union<'a>(&'a self, other: &'a HashSet<T, H>) -> Union<'a, T, H> {
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
/// This function wraps up `hash_keyed` to be the only way outside this
/// module to generate a SafeHash.
pub fn make_hash<Sized? T: Hash<S>, S, H: Hasher<S>>(hasher: &H, t: &T) -> SafeHash {
- match hasher.hash(t) {
- // This constant is exceedingly likely to hash to the same
- // bucket, but it won't be counted as empty! Just so we can maintain
- // our precious uniform distribution of initial indexes.
- EMPTY_BUCKET => SafeHash { hash: 0x8000_0000_0000_0000 },
- h => SafeHash { hash: h },
- }
+ // We need to avoid 0u64 in order to prevent collisions with
+ // EMPTY_HASH. We can maintain our precious uniform distribution
+ // of initial indexes by unconditionally setting the MSB,
+ // effectively reducing 64-bits hashes to 63 bits.
+ SafeHash { hash: 0x8000_0000_0000_0000 | hasher.hash(t) }
}
// `replace` casts a `*u64` to a `*SafeHash`. Since we statically
//! the key has been seen or not. Normally, this would require a `find` followed by an
//! `insert`, effectively duplicating the search effort on each insertion.
//!
-//! When a user calls `map.entry(key)`, the map will search for the key and then yield
+//! When a user calls `map.entry(&key)`, the map will search for the key and then yield
//! a variant of the `Entry` enum.
//!
//! If a `Vacant(entry)` is yielded, then the key *was not* found. In this case the
//! let message = "she sells sea shells by the sea shore";
//!
//! for c in message.chars() {
-//! match count.entry(c) {
-//! Vacant(entry) => { entry.set(1u); },
+//! match count.entry(&c) {
+//! Vacant(entry) => { entry.insert(1u); },
//! Occupied(mut entry) => *entry.get_mut() += 1,
//! }
//! }
//! for id in orders.into_iter() {
//! // If this is the first time we've seen this customer, initialize them
//! // with no blood alcohol. Otherwise, just retrieve them.
-//! let person = match blood_alcohol.entry(id) {
-//! Vacant(entry) => entry.set(Person{id: id, blood_alcohol: 0.0}),
+//! let person = match blood_alcohol.entry(&id) {
+//! Vacant(entry) => entry.insert(Person{id: id, blood_alcohol: 0.0}),
//! Occupied(entry) => entry.into_mut(),
//! };
//!
use prelude::v1::*;
-use c_str::ToCStr;
+use ffi::CString;
use mem;
use os;
use str;
/// Lazily open a dynamic library. When passed None it gives a
/// handle to the calling process
- pub fn open<T: ToCStr>(filename: Option<T>)
- -> Result<DynamicLibrary, String> {
+ pub fn open(filename: Option<&Path>) -> Result<DynamicLibrary, String> {
unsafe {
- let mut filename = filename;
let maybe_library = dl::check_for_errors_in(|| {
- match filename.take() {
- Some(name) => dl::open_external(name),
+ match filename {
+ Some(name) => dl::open_external(name.as_vec()),
None => dl::open_internal()
}
});
// T but that feature is still unimplemented
let maybe_symbol_value = dl::check_for_errors_in(|| {
- symbol.with_c_str(|raw_string| {
- dl::symbol(self.handle, raw_string)
- })
+ let raw_string = CString::from_slice(symbol.as_bytes());
+ dl::symbol(self.handle, raw_string.as_ptr())
});
// The value must not be constructed if there is an error so
fn test_loading_cosine() {
// The math library does not need to be loaded since it is already
// statically linked in
- let none: Option<Path> = None; // appease the typechecker
+ let none: Option<&Path> = None; // appease the typechecker
let libm = match DynamicLibrary::open(none) {
Err(error) => panic!("Could not load self as module: {}", error),
Ok(libm) => libm
target_os = "freebsd",
target_os = "dragonfly"))]
pub mod dl {
- use self::Rtld::*;
-
+ pub use self::Rtld::*;
use prelude::v1::*;
- use c_str::{CString, ToCStr};
+
+ use ffi::{self, CString};
+ use str;
use libc;
use ptr;
- pub unsafe fn open_external<T: ToCStr>(filename: T) -> *mut u8 {
- filename.with_c_str(|raw_name| {
- dlopen(raw_name, Lazy as libc::c_int) as *mut u8
- })
+ pub unsafe fn open_external(filename: &[u8]) -> *mut u8 {
+ let s = CString::from_slice(filename);
+ dlopen(s.as_ptr(), Lazy as libc::c_int) as *mut u8
}
pub unsafe fn open_internal() -> *mut u8 {
let ret = if ptr::null() == last_error {
Ok(result)
} else {
- Err(String::from_str(CString::new(last_error, false).as_str()
- .unwrap()))
+ let s = ffi::c_str_to_bytes(&last_error);
+ Err(str::from_utf8(s).unwrap().to_string())
};
ret
#[cfg(target_os = "windows")]
pub mod dl {
- use c_str::ToCStr;
use iter::IteratorExt;
use libc;
use ops::FnOnce;
use string::String;
use vec::Vec;
- pub unsafe fn open_external<T: ToCStr>(filename: T) -> *mut u8 {
+ pub unsafe fn open_external(filename: &[u8]) -> *mut u8 {
// Windows expects Unicode data
- let filename_cstr = filename.to_c_str();
- let filename_str = str::from_utf8(filename_cstr.as_bytes_no_nul()).unwrap();
+ let filename_str = str::from_utf8(filename).unwrap();
let mut filename_str: Vec<u16> = filename_str.utf16_units().collect();
filename_str.push(0);
LoadLibraryW(filename_str.as_ptr() as *const libc::c_void) as *mut u8
use prelude::v1::*;
-use any::{Any, AnyRefExt};
+use any::Any;
use cell::RefCell;
use io::IoResult;
use rt::{backtrace, unwind};
--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use fmt;
+use iter::IteratorExt;
+use libc;
+use mem;
+use ops::Deref;
+use slice::{self, SliceExt, AsSlice};
+use string::String;
+use vec::Vec;
+
+/// A type representing a C-compatible string
+///
+/// This type serves the primary purpose of being able to generate a
+/// C-compatible string from a Rust byte slice or vector. An instance of this
+/// type is a static guarantee that the underlying bytes contain no interior 0
+/// bytes and the final byte is 0.
+///
+/// A `CString` is created from either a byte slice or a byte vector. After
+/// being created, a `CString` predominately inherits all of its methods from
+/// the `Deref` implementation to `[libc::c_char]`. Note that the underlying
+/// array is represented as an array of `libc::c_char` as opposed to `u8`. A
+/// `u8` slice can be obtained with the `as_bytes` method. Slices produced from
+/// a `CString` do *not* contain the trailing nul terminator unless otherwise
+/// specified.
+///
+/// # Example
+///
+/// ```no_run
+/// # extern crate libc;
+/// # fn main() {
+/// use std::ffi::CString;
+/// use libc;
+///
+/// extern {
+/// fn my_printer(s: *const libc::c_char);
+/// }
+///
+/// let to_print = "Hello, world!";
+/// let c_to_print = CString::from_slice(to_print.as_bytes());
+/// unsafe {
+/// my_printer(c_to_print.as_ptr());
+/// }
+/// # }
+/// ```
+#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+pub struct CString {
+ inner: Vec<libc::c_char>,
+}
+
+impl CString {
+ /// Create a new C-compatible string from a byte slice.
+ ///
+ /// This method will copy the data of the slice provided into a new
+ /// allocation, ensuring that there is a trailing 0 byte.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic if there are any 0 bytes already in the slice
+ /// provided.
+ pub fn from_slice(v: &[u8]) -> CString {
+ CString::from_vec(v.to_vec())
+ }
+
+ /// Create a C-compatible string from a byte vector.
+ ///
+ /// This method will consume ownership of the provided vector, appending a 0
+ /// byte to the end after verifying that there are no interior 0 bytes.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic if there are any 0 bytes already in the vector
+ /// provided.
+ pub fn from_vec(v: Vec<u8>) -> CString {
+ assert!(!v.iter().any(|&x| x == 0));
+ unsafe { CString::from_vec_unchecked(v) }
+ }
+
+ /// Create a C-compatibel string from a byte vector without checking for
+ /// interior 0 bytes.
+ ///
+ /// This method is equivalent to `from_vec` except that no runtime assertion
+ /// is made that `v` contains no 0 bytes.
+ pub unsafe fn from_vec_unchecked(mut v: Vec<u8>) -> CString {
+ v.push(0);
+ CString { inner: mem::transmute(v) }
+ }
+
+ /// Create a view into this C string which includes the trailing nul
+ /// terminator at the end of the string.
+ pub fn as_slice_with_nul(&self) -> &[libc::c_char] { self.inner.as_slice() }
+
+ /// Similar to the `as_slice` method, but returns a `u8` slice instead of a
+ /// `libc::c_char` slice.
+ pub fn as_bytes(&self) -> &[u8] {
+ unsafe { mem::transmute(self.as_slice()) }
+ }
+
+ /// Equivalend to `as_slice_with_nul` except that the type returned is a
+ /// `u8` slice instead of a `libc::c_char` slice.
+ pub fn as_bytes_with_nul(&self) -> &[u8] {
+ unsafe { mem::transmute(self.as_slice_with_nul()) }
+ }
+}
+
+impl Deref for CString {
+ type Target = [libc::c_char];
+
+ fn deref(&self) -> &[libc::c_char] {
+ self.inner.slice_to(self.inner.len() - 1)
+ }
+}
+
+impl fmt::Show for CString {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ String::from_utf8_lossy(self.as_bytes()).fmt(f)
+ }
+}
+
+/// Interpret a C string as a byte slice.
+///
+/// This function will calculate the length of the C string provided, and it
+/// will then return a corresponding slice for the contents of the C string not
+/// including the nul terminator.
+///
+/// This function will tie the lifetime of the returned slice to the lifetime of
+/// the pointer provided. This is done to help prevent the slice from escaping
+/// the lifetime of the pointer itself. If a longer lifetime is needed, then
+/// `mem::copy_lifetime` should be used.
+///
+/// This function is unsafe because there is no guarantee of the validity of the
+/// pointer `raw` or a guarantee that a nul terminator will be found.
+///
+/// # Example
+///
+/// ```no_run
+/// # extern crate libc;
+/// # fn main() {
+/// use std::ffi;
+/// use std::str;
+/// use libc;
+///
+/// extern {
+/// fn my_string() -> *const libc::c_char;
+/// }
+///
+/// unsafe {
+/// let to_print = my_string();
+/// let slice = ffi::c_str_to_bytes(&to_print);
+/// println!("string returned: {}", str::from_utf8(slice).unwrap());
+/// }
+/// # }
+/// ```
+pub unsafe fn c_str_to_bytes<'a>(raw: &'a *const libc::c_char) -> &'a [u8] {
+ let len = libc::strlen(*raw);
+ slice::from_raw_buf(&*(raw as *const _ as *const *const u8), len as uint)
+}
+
+/// Interpret a C string as a byte slice with the nul terminator.
+///
+/// This function is identical to `from_raw_buf` except that the returned slice
+/// will include the nul terminator of the string.
+pub unsafe fn c_str_to_bytes_with_nul<'a>(raw: &'a *const libc::c_char) -> &'a [u8] {
+ let len = libc::strlen(*raw) + 1;
+ slice::from_raw_buf(&*(raw as *const _ as *const *const u8), len as uint)
+}
+
+#[cfg(test)]
+mod tests {
+ use prelude::v1::*;
+ use super::*;
+ use libc;
+ use mem;
+
+ #[test]
+ fn c_to_rust() {
+ let data = b"123\0";
+ let ptr = data.as_ptr() as *const libc::c_char;
+ unsafe {
+ assert_eq!(c_str_to_bytes(&ptr), b"123");
+ assert_eq!(c_str_to_bytes_with_nul(&ptr), b"123\0");
+ }
+ }
+
+ #[test]
+ fn simple() {
+ let s = CString::from_slice(b"1234");
+ assert_eq!(s.as_bytes(), b"1234");
+ assert_eq!(s.as_bytes_with_nul(), b"1234\0");
+ unsafe {
+ assert_eq!(s.as_slice(),
+ mem::transmute::<_, &[libc::c_char]>(b"1234"));
+ assert_eq!(s.as_slice_with_nul(),
+ mem::transmute::<_, &[libc::c_char]>(b"1234\0"));
+ }
+ }
+
+ #[should_fail] #[test]
+ fn build_with_zero1() { CString::from_slice(b"\0"); }
+ #[should_fail] #[test]
+ fn build_with_zero2() { CString::from_vec(vec![0]); }
+
+ #[test]
+ fn build_with_zero3() {
+ unsafe {
+ let s = CString::from_vec_unchecked(vec![0]);
+ assert_eq!(s.as_bytes(), b"\0");
+ }
+ }
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Utilities related to FFI bindings.
+
+#![unstable = "module just underwent fairly large reorganization and the dust \
+ still needs to settle"]
+
+pub use self::c_str::CString;
+pub use self::c_str::c_str_to_bytes;
+pub use self::c_str::c_str_to_bytes_with_nul;
+
+mod c_str;
/// use std::io;
///
/// // one possible implementation of fs::walk_dir only visiting files
-/// fn visit_dirs(dir: &Path, cb: |&Path|) -> io::IoResult<()> {
+/// fn visit_dirs<F>(dir: &Path, cb: &mut F) -> io::IoResult<()> where
+/// F: FnMut(&Path),
+/// {
/// if dir.is_dir() {
/// let contents = try!(fs::readdir(dir));
/// for entry in contents.iter() {
/// if entry.is_dir() {
-/// try!(visit_dirs(entry, |p| cb(p)));
+/// try!(visit_dirs(entry, cb));
/// } else {
-/// cb(entry);
+/// (*cb)(entry);
/// }
/// }
/// Ok(())
pub use self::FileAccess::*;
pub use self::IoErrorKind::*;
-use char::Char;
+use char::CharExt;
use clone::Clone;
use default::Default;
use error::{FromError, Error};
use string::String;
use uint;
use unicode;
-use unicode::char::UnicodeChar;
use vec::Vec;
// Reexports
pub use self::IpAddr::*;
+use boxed::Box;
use fmt;
use io::{self, IoResult, IoError};
use io::net;
use iter::{Iterator, IteratorExt};
-use ops::FnOnce;
+use ops::{FnOnce, FnMut};
use option::Option;
use option::Option::{None, Some};
use result::Result::{Ok, Err};
}
// Return result of first successful parser
- fn read_or<T>(&mut self, parsers: &mut [|&mut Parser| -> Option<T>])
+ fn read_or<T>(&mut self, parsers: &mut [Box<FnMut(&mut Parser) -> Option<T>>])
-> Option<T> {
for pf in parsers.iter_mut() {
- match self.read_atomically(|p: &mut Parser| (*pf)(p)) {
+ match self.read_atomically(|p: &mut Parser| pf.call_mut((p,))) {
Some(r) => return Some(r),
None => {}
}
}
fn read_ip_addr(&mut self) -> Option<IpAddr> {
- let ipv4_addr = |p: &mut Parser| p.read_ipv4_addr();
- let ipv6_addr = |p: &mut Parser| p.read_ipv6_addr();
- self.read_or(&mut [ipv4_addr, ipv6_addr])
+ let ipv4_addr = |&mut: p: &mut Parser| p.read_ipv4_addr();
+ let ipv6_addr = |&mut: p: &mut Parser| p.read_ipv6_addr();
+ self.read_or(&mut [box ipv4_addr, box ipv6_addr])
}
fn read_socket_addr(&mut self) -> Option<SocketAddr> {
let ip_addr = |&: p: &mut Parser| {
- let ipv4_p = |p: &mut Parser| p.read_ip_addr();
- let ipv6_p = |p: &mut Parser| {
+ let ipv4_p = |&mut: p: &mut Parser| p.read_ip_addr();
+ let ipv6_p = |&mut: p: &mut Parser| {
let open_br = |&: p: &mut Parser| p.read_given_char('[');
let ip_addr = |&: p: &mut Parser| p.read_ipv6_addr();
let clos_br = |&: p: &mut Parser| p.read_given_char(']');
p.read_seq_3::<char, IpAddr, char, _, _, _>(open_br, ip_addr, clos_br)
.map(|t| match t { (_, ip, _) => ip })
};
- p.read_or(&mut [ipv4_p, ipv6_p])
+ p.read_or(&mut [box ipv4_p, box ipv6_p])
};
let colon = |&: p: &mut Parser| p.read_given_char(':');
let port = |&: p: &mut Parser| p.read_number(10, 5, 0x10000).map(|n| n as u16);
use prelude::v1::*;
-use c_str::ToCStr;
+use ffi::CString;
+use path::BytesContainer;
use io::{Listener, Acceptor, IoResult, TimedOut, standard_error};
use sys::pipe::UnixAcceptor as UnixAcceptorImp;
use sys::pipe::UnixListener as UnixListenerImp;
/// let mut stream = UnixStream::connect(&server);
/// stream.write(&[1, 2, 3]);
/// ```
- pub fn connect<P: ToCStr>(path: &P) -> IoResult<UnixStream> {
- UnixStreamImp::connect(&path.to_c_str(), None)
+ pub fn connect<P: BytesContainer>(path: P) -> IoResult<UnixStream> {
+ let path = CString::from_slice(path.container_as_bytes());
+ UnixStreamImp::connect(&path, None)
.map(|inner| UnixStream { inner: inner })
}
/// If a `timeout` with zero or negative duration is specified then
/// the function returns `Err`, with the error kind set to `TimedOut`.
#[experimental = "the timeout argument is likely to change types"]
- pub fn connect_timeout<P: ToCStr>(path: &P,
- timeout: Duration) -> IoResult<UnixStream> {
+ pub fn connect_timeout<P>(path: P, timeout: Duration)
+ -> IoResult<UnixStream>
+ where P: BytesContainer {
if timeout <= Duration::milliseconds(0) {
return Err(standard_error(TimedOut));
}
- UnixStreamImp::connect(&path.to_c_str(), Some(timeout.num_milliseconds() as u64))
+ let path = CString::from_slice(path.container_as_bytes());
+ UnixStreamImp::connect(&path, Some(timeout.num_milliseconds() as u64))
.map(|inner| UnixStream { inner: inner })
}
/// }
/// # }
/// ```
- pub fn bind<P: ToCStr>(path: &P) -> IoResult<UnixListener> {
- UnixListenerImp::bind(&path.to_c_str())
+ pub fn bind<P: BytesContainer>(path: P) -> IoResult<UnixListener> {
+ let path = CString::from_slice(path.container_as_bytes());
+ UnixListenerImp::bind(&path)
.map(|inner| UnixListener { inner: inner })
}
}
use prelude::v1::*;
-use c_str::{CString, ToCStr};
use collections::HashMap;
+use ffi::CString;
use fmt;
use hash::Hash;
use io::pipe::{PipeStream, PipePair};
use thread::Thread;
#[cfg(windows)] use std::hash::sip::SipState;
+#[cfg(windows)] use str;
/// Signal a process to exit, without forcibly killing it. Corresponds to
/// SIGTERM on unix platforms.
impl Hash for EnvKey {
fn hash(&self, state: &mut SipState) {
let &EnvKey(ref x) = self;
- match x.as_str() {
- Some(s) => for ch in s.chars() {
+ match str::from_utf8(x.as_bytes()) {
+ Ok(s) => for ch in s.chars() {
(ch as u8 as char).to_lowercase().hash(state);
},
- None => x.hash(state)
+ Err(..) => x.hash(state)
}
}
}
fn eq(&self, other: &EnvKey) -> bool {
let &EnvKey(ref x) = self;
let &EnvKey(ref y) = other;
- match (x.as_str(), y.as_str()) {
- (Some(xs), Some(ys)) => {
+ match (str::from_utf8(x.as_bytes()), str::from_utf8(y.as_bytes())) {
+ (Ok(xs), Ok(ys)) => {
if xs.len() != ys.len() {
return false
} else {
}
// FIXME (#12938): Until DST lands, we cannot decompose &str into & and str, so
-// we cannot usefully take ToCStr arguments by reference (without forcing an
+// we cannot usefully take BytesContainer arguments by reference (without forcing an
// additional & around &str). So we are instead temporarily adding an instance
-// for &Path, so that we can take ToCStr as owned. When DST lands, the &Path
-// instance should be removed, and arguments bound by ToCStr should be passed by
+// for &Path, so that we can take BytesContainer as owned. When DST lands, the &Path
+// instance should be removed, and arguments bound by BytesContainer should be passed by
// reference. (Here: {new, arg, args, env}.)
impl Command {
///
/// Builder methods are provided to change these defaults and
/// otherwise configure the process.
- pub fn new<T:ToCStr>(program: T) -> Command {
+ pub fn new<T: BytesContainer>(program: T) -> Command {
Command {
- program: program.to_c_str(),
+ program: CString::from_slice(program.container_as_bytes()),
args: Vec::new(),
env: None,
cwd: None,
}
/// Add an argument to pass to the program.
- pub fn arg<'a, T: ToCStr>(&'a mut self, arg: T) -> &'a mut Command {
- self.args.push(arg.to_c_str());
+ pub fn arg<'a, T: BytesContainer>(&'a mut self, arg: T) -> &'a mut Command {
+ self.args.push(CString::from_slice(arg.container_as_bytes()));
self
}
/// Add multiple arguments to pass to the program.
- pub fn args<'a, T: ToCStr>(&'a mut self, args: &[T]) -> &'a mut Command {
- self.args.extend(args.iter().map(|arg| arg.to_c_str()));;
+ pub fn args<'a, T: BytesContainer>(&'a mut self, args: &[T]) -> &'a mut Command {
+ self.args.extend(args.iter().map(|arg| {
+ CString::from_slice(arg.container_as_bytes())
+ }));
self
}
// Get a mutable borrow of the environment variable map for this `Command`.
- fn get_env_map<'a>(&'a mut self) -> &'a mut EnvMap {
+ fn get_env_map<'a>(&'a mut self) -> &'a mut EnvMap {
match self.env {
Some(ref mut map) => map,
None => {
// if the env is currently just inheriting from the parent's,
// materialize the parent's env into a hashtable.
- self.env = Some(os::env_as_bytes().into_iter()
- .map(|(k, v)| (EnvKey(k.to_c_str()),
- v.to_c_str()))
- .collect());
+ self.env = Some(os::env_as_bytes().into_iter().map(|(k, v)| {
+ (EnvKey(CString::from_slice(k.as_slice())),
+ CString::from_slice(v.as_slice()))
+ }).collect());
self.env.as_mut().unwrap()
}
}
///
/// Note that environment variable names are case-insensitive (but case-preserving) on Windows,
/// and case-sensitive on all other platforms.
- pub fn env<'a, T: ToCStr, U: ToCStr>(&'a mut self, key: T, val: U)
- -> &'a mut Command {
- self.get_env_map().insert(EnvKey(key.to_c_str()), val.to_c_str());
+ pub fn env<'a, T, U>(&'a mut self, key: T, val: U)
+ -> &'a mut Command
+ where T: BytesContainer, U: BytesContainer {
+ let key = EnvKey(CString::from_slice(key.container_as_bytes()));
+ let val = CString::from_slice(val.container_as_bytes());
+ self.get_env_map().insert(key, val);
self
}
/// Removes an environment variable mapping.
- pub fn env_remove<'a, T: ToCStr>(&'a mut self, key: T) -> &'a mut Command {
- self.get_env_map().remove(&EnvKey(key.to_c_str()));
+ pub fn env_remove<'a, T>(&'a mut self, key: T) -> &'a mut Command
+ where T: BytesContainer {
+ let key = EnvKey(CString::from_slice(key.container_as_bytes()));
+ self.get_env_map().remove(&key);
self
}
///
/// If the given slice contains multiple instances of an environment
/// variable, the *rightmost* instance will determine the value.
- pub fn env_set_all<'a, T: ToCStr, U: ToCStr>(&'a mut self, env: &[(T,U)])
- -> &'a mut Command {
- self.env = Some(env.iter().map(|&(ref k, ref v)| (EnvKey(k.to_c_str()), v.to_c_str()))
- .collect());
+ pub fn env_set_all<'a, T, U>(&'a mut self, env: &[(T,U)])
+ -> &'a mut Command
+ where T: BytesContainer, U: BytesContainer {
+ self.env = Some(env.iter().map(|&(ref k, ref v)| {
+ (EnvKey(CString::from_slice(k.container_as_bytes())),
+ CString::from_slice(v.container_as_bytes()))
+ }).collect());
self
}
/// Set the working directory for the child process.
pub fn cwd<'a>(&'a mut self, dir: &Path) -> &'a mut Command {
- self.cwd = Some(dir.to_c_str());
+ self.cwd = Some(CString::from_slice(dir.as_vec()));
self
}
/// non-utf8 data is lossily converted using the utf8 replacement
/// character.
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- try!(write!(f, "{}", String::from_utf8_lossy(self.program.as_bytes_no_nul())));
+ try!(write!(f, "{}", String::from_utf8_lossy(self.program.as_bytes())));
for arg in self.args.iter() {
- try!(write!(f, " '{}'", String::from_utf8_lossy(arg.as_bytes_no_nul())));
+ try!(write!(f, " '{}'", String::from_utf8_lossy(arg.as_bytes())));
}
Ok(())
}
#[test]
#[cfg(windows)]
fn env_map_keys_ci() {
- use c_str::ToCStr;
+ use ffi::CString;
use super::EnvKey;
let mut cmd = Command::new("");
cmd.env("path", "foo");
cmd.env("Path", "bar");
let env = &cmd.env.unwrap();
- let val = env.get(&EnvKey("PATH".to_c_str()));
- assert!(val.unwrap() == &"bar".to_c_str());
+ let val = env.get(&EnvKey(CString::from_slice(b"PATH")));
+ assert!(val.unwrap() == &CString::from_slice(b"bar"));
}
}
//! Temporary files and directories
-use io::{fs, IoResult};
+use io::{fs, IoError, IoErrorKind, IoResult};
use io;
-use libc;
+use iter::{IteratorExt, range};
use ops::Drop;
use option::Option;
use option::Option::{None, Some};
use os;
use path::{Path, GenericPath};
+use rand::{Rng, thread_rng};
use result::Result::{Ok, Err};
-use sync::atomic::{AtomicUint, ATOMIC_UINT_INIT, Ordering};
+use str::StrExt;
+use string::String;
/// A wrapper for a path to temporary directory implementing automatic
/// scope-based deletion.
///
/// {
/// // create a temporary directory
-/// let tmpdir = match TempDir::new("mysuffix") {
+/// let tmpdir = match TempDir::new("myprefix") {
/// Ok(dir) => dir,
/// Err(e) => panic!("couldn't create temporary directory: {}", e)
/// };
/// }
/// {
/// // create a temporary directory, this time using a custom path
-/// let tmpdir = match TempDir::new_in(&Path::new("/tmp/best/custom/path"), "mysuffix") {
+/// let tmpdir = match TempDir::new_in(&Path::new("/tmp/best/custom/path"), "myprefix") {
/// Ok(dir) => dir,
/// Err(e) => panic!("couldn't create temporary directory: {}", e)
/// };
/// }
/// {
/// // create a temporary directory
-/// let tmpdir = match TempDir::new("mysuffix") {
+/// let tmpdir = match TempDir::new("myprefix") {
/// Ok(dir) => dir,
/// Err(e) => panic!("couldn't create temporary directory: {}", e)
/// };
disarmed: bool
}
+// How many times should we (re)try finding an unused random name? It should be
+// enough that an attacker will run out of luck before we run out of patience.
+const NUM_RETRIES: u32 = 1 << 31;
+// How many characters should we include in a random file name? It needs to
+// be enough to dissuade an attacker from trying to preemptively create names
+// of that length, but not so huge that we unnecessarily drain the random number
+// generator of entropy.
+const NUM_RAND_CHARS: uint = 12;
+
impl TempDir {
/// Attempts to make a temporary directory inside of `tmpdir` whose name
- /// will have the suffix `suffix`. The directory will be automatically
+ /// will have the prefix `prefix`. The directory will be automatically
/// deleted once the returned wrapper is destroyed.
///
/// If no directory can be created, `Err` is returned.
- pub fn new_in(tmpdir: &Path, suffix: &str) -> IoResult<TempDir> {
+ pub fn new_in(tmpdir: &Path, prefix: &str) -> IoResult<TempDir> {
if !tmpdir.is_absolute() {
let abs_tmpdir = try!(os::make_absolute(tmpdir));
- return TempDir::new_in(&abs_tmpdir, suffix);
+ return TempDir::new_in(&abs_tmpdir, prefix);
}
- static CNT: AtomicUint = ATOMIC_UINT_INIT;
-
- let mut attempts = 0u;
- loop {
- let filename =
- format!("rs-{}-{}-{}",
- unsafe { libc::getpid() },
- CNT.fetch_add(1, Ordering::SeqCst),
- suffix);
- let p = tmpdir.join(filename);
- match fs::mkdir(&p, io::USER_RWX) {
- Err(error) => {
- if attempts >= 1000 {
- return Err(error)
- }
- attempts += 1;
- }
- Ok(()) => return Ok(TempDir { path: Some(p), disarmed: false })
+ let mut rng = thread_rng();
+ for _ in range(0, NUM_RETRIES) {
+ let suffix: String = rng.gen_ascii_chars().take(NUM_RAND_CHARS).collect();
+ let leaf = if prefix.len() > 0 {
+ format!("{}.{}", prefix, suffix)
+ } else {
+ // If we're given an empty string for a prefix, then creating a
+ // directory starting with "." would lead to it being
+ // semi-invisible on some systems.
+ suffix
+ };
+ let path = tmpdir.join(leaf);
+ match fs::mkdir(&path, io::USER_RWX) {
+ Ok(_) => return Ok(TempDir { path: Some(path), disarmed: false }),
+ Err(IoError{kind:IoErrorKind::PathAlreadyExists,..}) => (),
+ Err(e) => return Err(e)
}
}
+
+ return Err(IoError{
+ kind: IoErrorKind::PathAlreadyExists,
+ desc:"Exhausted",
+ detail: None});
}
/// Attempts to make a temporary directory inside of `os::tmpdir()` whose
- /// name will have the suffix `suffix`. The directory will be automatically
+ /// name will have the prefix `prefix`. The directory will be automatically
/// deleted once the returned wrapper is destroyed.
///
/// If no directory can be created, `Err` is returned.
- pub fn new(suffix: &str) -> IoResult<TempDir> {
- TempDir::new_in(&os::tmpdir(), suffix)
+ pub fn new(prefix: &str) -> IoResult<TempDir> {
+ TempDir::new_in(&os::tmpdir(), prefix)
}
/// Unwrap the wrapped `std::path::Path` from the `TempDir` wrapper.
/* Runtime and platform support */
-pub mod thread_local;
-pub mod c_str;
-pub mod c_vec;
+pub mod thread_local; // first for macros
+
pub mod dynamic_lib;
+pub mod ffi;
pub mod fmt;
pub mod io;
pub mod os;
/// # #![allow(unreachable_code)]
/// panic!();
/// panic!("this is a terrible mistake!");
-/// panic!(4i); // panic with the value of 4 to be collected elsewhere
+/// panic!(4); // panic with the value of 4 to be collected elsewhere
/// panic!("this is a {} {message}", "fancy", message = "message");
/// ```
#[macro_export]
/// // assert with a custom message
/// # let x = true;
/// assert!(x, "x wasn't true!");
-/// # let a = 3i; let b = 27i;
+/// # let a = 3; let b = 27;
/// assert!(a + b == 30, "a = {}, b = {}", a, b);
/// ```
#[macro_export]
/// # Example
///
/// ```
-/// let a = 3i;
-/// let b = 1i + 2i;
+/// let a = 3;
+/// let b = 1 + 2;
/// assert_eq!(a, b);
/// ```
#[macro_export]
/// // assert with a custom message
/// # let x = true;
/// debug_assert!(x, "x wasn't true!");
-/// # let a = 3i; let b = 27i;
+/// # let a = 3; let b = 27;
/// debug_assert!(a + b == 30, "a = {}, b = {}", a, b);
/// ```
#[macro_export]
/// # Example
///
/// ```
-/// let a = 3i;
-/// let b = 1i + 2i;
+/// let a = 3;
+/// let b = 1 + 2;
/// debug_assert_eq!(a, b);
/// ```
#[macro_export]
/// ```
/// format!("test");
/// format!("hello {}", "world!");
-/// format!("x = {}, y = {y}", 10i, y = 30i);
+/// format!("x = {}, y = {y}", 10, y = 30);
/// ```
#[macro_export]
#[stable]
/// let (tx1, rx1) = channel();
/// let (tx2, rx2) = channel();
/// # fn long_running_task() {}
-/// # fn calculate_the_answer() -> int { 42i }
+/// # fn calculate_the_answer() -> int { 42 }
///
/// Thread::spawn(move|| { long_running_task(); tx1.send(()) }).detach();
/// Thread::spawn(move|| { tx2.send(calculate_the_answer()) }).detach();
/// # Example
///
/// ```
- /// let s = concat!("test", 10i, 'b', true);
+ /// let s = concat!("test", 10, 'b', true);
/// assert_eq!(s, "test10btrue");
/// ```
#[macro_export]
use self::SignificantDigits::*;
use self::SignFormat::*;
-use char::{self, Char};
+use char::{self, CharExt};
use num::{self, Int, Float, ToPrimitive};
use num::FpCategory as Fp;
use ops::FnMut;
use sync::atomic::{AtomicInt, ATOMIC_INT_INIT, Ordering};
use vec::Vec;
-#[cfg(unix)] use c_str::ToCStr;
+#[cfg(unix)] use ffi::{self, CString};
-#[cfg(unix)]
-pub use sys::ext as unix;
-#[cfg(windows)]
-pub use sys::ext as windows;
+#[cfg(unix)] pub use sys::ext as unix;
+#[cfg(windows)] pub use sys::ext as windows;
/// Get the number of cores available
pub fn num_cpus() -> uint {
///
/// Panics if `n` has any interior NULs.
pub fn getenv_as_bytes(n: &str) -> Option<Vec<u8>> {
- use c_str::CString;
-
unsafe {
with_env_lock(|| {
- let s = n.with_c_str(|buf| libc::getenv(buf));
+ let s = CString::from_slice(n.as_bytes());
+ let s = libc::getenv(s.as_ptr()) as *const _;
if s.is_null() {
None
} else {
- Some(CString::new(s as *const libc::c_char, false).as_bytes_no_nul().to_vec())
+ Some(ffi::c_str_to_bytes(&s).to_vec())
}
})
}
fn _setenv(n: &str, v: &[u8]) {
unsafe {
with_env_lock(|| {
- n.with_c_str(|nbuf| {
- v.with_c_str(|vbuf| {
- if libc::funcs::posix01::unistd::setenv(nbuf, vbuf, 1) != 0 {
- panic!(IoError::last_error());
- }
- })
- })
+ let k = CString::from_slice(n.as_bytes());
+ let v = CString::from_slice(v);
+ if libc::funcs::posix01::unistd::setenv(k.as_ptr(),
+ v.as_ptr(), 1) != 0 {
+ panic!(IoError::last_error());
+ }
})
}
}
fn _unsetenv(n: &str) {
unsafe {
with_env_lock(|| {
- n.with_c_str(|nbuf| {
- if libc::funcs::posix01::unistd::unsetenv(nbuf) != 0 {
- panic!(IoError::last_error());
- }
- })
+ let nbuf = CString::from_slice(n.as_bytes());
+ if libc::funcs::posix01::unistd::unsetenv(nbuf.as_ptr()) != 0 {
+ panic!(IoError::last_error());
+ }
})
}
}
#[cfg(target_os = "macos")]
unsafe fn load_argc_and_argv(argc: int,
argv: *const *const c_char) -> Vec<Vec<u8>> {
- use c_str::CString;
use iter::range;
range(0, argc as uint).map(|i| {
- CString::new(*argv.offset(i as int), false).as_bytes_no_nul().to_vec()
+ ffi::c_str_to_bytes(&*argv.offset(i as int)).to_vec()
}).collect()
}
// res
#[cfg(target_os = "ios")]
fn real_args_as_bytes() -> Vec<Vec<u8>> {
- use c_str::CString;
use iter::range;
use mem;
#![experimental]
use core::kinds::Sized;
-use c_str::CString;
+use ffi::CString;
use clone::Clone;
use fmt;
use iter::IteratorExt;
impl BytesContainer for CString {
#[inline]
fn container_as_bytes<'a>(&'a self) -> &'a [u8] {
- self.as_bytes_no_nul()
+ self.as_bytes()
}
}
fn contains_nul<T: BytesContainer>(v: &T) -> bool {
v.container_as_bytes().iter().any(|&x| x == 0)
}
-
-#[cfg(test)]
-mod tests {
- use prelude::v1::*;
- use c_str::ToCStr;
- use path::{WindowsPath, PosixPath};
-
- #[test]
- fn test_cstring() {
- let input = "/foo/bar/baz";
- let path: PosixPath = PosixPath::new(input.to_c_str());
- assert_eq!(path.as_vec(), input.as_bytes());
-
- let input = r"\foo\bar\baz";
- let path: WindowsPath = WindowsPath::new(input.to_c_str());
- assert_eq!(path.as_str().unwrap(), input);
- }
-}
//! POSIX file path handling
-use c_str::{CString, ToCStr};
use clone::Clone;
-use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering};
+use cmp::{Ordering, Eq, Ord, PartialEq, PartialOrd};
use hash;
use io::Writer;
use iter::{AdditiveIterator, Extend};
use iter::{Iterator, IteratorExt, Map};
-use option::Option;
-use option::Option::{None, Some};
use kinds::Sized;
-use str::{FromStr, Str};
-use str;
-use slice::{Split, AsSlice, SliceConcatExt, SliceExt};
+use option::Option::{self, Some, None};
+use slice::{AsSlice, Split, SliceExt, SliceConcatExt};
+use str::{self, FromStr, StrExt};
use vec::Vec;
use super::{BytesContainer, GenericPath, GenericPathUnsafe};
}
}
-// FIXME (#12938): Until DST lands, we cannot decompose &str into & and str, so
-// we cannot usefully take ToCStr arguments by reference (without forcing an
-// additional & around &str). So we are instead temporarily adding an instance
-// for &Path, so that we can take ToCStr as owned. When DST lands, the &Path
-// instance should be removed, and arguments bound by ToCStr should be passed by
-// reference.
-
-impl ToCStr for Path {
- #[inline]
- fn to_c_str(&self) -> CString {
- // The Path impl guarantees no internal NUL
- unsafe { self.to_c_str_unchecked() }
- }
-
- #[inline]
- unsafe fn to_c_str_unchecked(&self) -> CString {
- self.as_vec().to_c_str_unchecked()
- }
-}
-
impl<S: hash::Writer> hash::Hash<S> for Path {
#[inline]
fn hash(&self, state: &mut S) {
use self::PathPrefix::*;
use ascii::AsciiExt;
-use c_str::{CString, ToCStr};
+use char::CharExt;
use clone::Clone;
-use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering};
+use cmp::{Ordering, Eq, Ord, PartialEq, PartialOrd};
use hash;
use io::Writer;
use iter::{AdditiveIterator, Extend};
use iter::{Iterator, IteratorExt, Map, repeat};
use mem;
-use option::Option;
-use option::Option::{Some, None};
+use option::Option::{self, Some, None};
use slice::{SliceExt, SliceConcatExt};
use str::{SplitTerminator, FromStr, StrExt};
use string::{String, ToString};
-use unicode::char::UnicodeChar;
use vec::Vec;
use super::{contains_nul, BytesContainer, GenericPath, GenericPathUnsafe};
}
}
-// FIXME (#12938): Until DST lands, we cannot decompose &str into & and str, so
-// we cannot usefully take ToCStr arguments by reference (without forcing an
-// additional & around &str). So we are instead temporarily adding an instance
-// for &Path, so that we can take ToCStr as owned. When DST lands, the &Path
-// instance should be removed, and arguments bound by ToCStr should be passed by
-// reference.
-
-impl ToCStr for Path {
- #[inline]
- fn to_c_str(&self) -> CString {
- // The Path impl guarantees no internal NUL
- unsafe { self.to_c_str_unchecked() }
- }
-
- #[inline]
- unsafe fn to_c_str_unchecked(&self) -> CString {
- self.as_vec().to_c_str_unchecked()
- }
-}
-
impl<S: hash::Writer> hash::Hash<S> for Path {
#[cfg(not(test))]
#[inline]
// Reexported types and traits
#[stable] #[doc(no_inline)] pub use boxed::Box;
-#[stable] #[doc(no_inline)] pub use char::{Char, UnicodeChar};
+#[stable] #[doc(no_inline)] pub use char::CharExt;
#[stable] #[doc(no_inline)] pub use clone::Clone;
#[stable] #[doc(no_inline)] pub use cmp::{PartialEq, PartialOrd, Eq, Ord};
#[stable] #[doc(no_inline)] pub use iter::CloneIteratorExt;
/// The standard RNG. This is designed to be efficient on the current
/// platform.
-#[derive(Copy)]
+#[deriving(Copy, Clone)]
pub struct StdRng {
rng: IsaacWordRng,
}
type ThreadRngInner = reseeding::ReseedingRng<StdRng, ThreadRngReseeder>;
/// The thread-local RNG.
+#[deriving(Clone)]
pub struct ThreadRng {
rng: Rc<RefCell<ThreadRngInner>>,
}
mod imp {
use prelude::v1::*;
+ use libc;
use mem;
- use slice;
+ use ffi;
use sync::{StaticMutex, MUTEX_INIT};
}
unsafe fn load_argc_and_argv(argc: int, argv: *const *const u8) -> Vec<Vec<u8>> {
+ let argv = argv as *const *const libc::c_char;
range(0, argc as uint).map(|i| {
- let arg = *argv.offset(i as int);
- let mut len = 0u;
- while *arg.offset(len as int) != 0 {
- len += 1u;
- }
- slice::from_raw_buf(&arg, len).to_vec()
+ ffi::c_str_to_bytes(&*argv.offset(i as int)).to_vec()
}).collect()
}
use prelude::v1::*;
use os;
-use sync::atomic::{mod, Ordering};
+use sync::atomic::{self, Ordering};
pub use sys::backtrace::write;
use intrinsics;
use libc::c_void;
use mem;
-use sync::atomic::{mod, Ordering};
+use sync::atomic::{self, Ordering};
use sync::{Once, ONCE_INIT};
use rt::libunwind as uw;
use os;
use slice;
use str;
-use sync::atomic::{mod, Ordering};
+use sync::atomic::{self, Ordering};
/// Dynamically inquire about whether we're running under V.
/// You should usually not use this unless your test definitely
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//! Multi-producer, single-consumer communication primitives threads
+//! Communication primitives for concurrent tasks
+//!
+//! Rust makes it very difficult to share data among tasks to prevent race
+//! conditions and to improve parallelism, but there is often a need for
+//! communication between concurrent tasks. The primitives defined in this
+//! module are the building blocks for synchronization in rust.
//!
//! This module provides message-based communication over channels, concretely
//! defined among three types:
//! * `Receiver`
//!
//! A `Sender` or `SyncSender` is used to send data to a `Receiver`. Both
-//! senders are clone-able (multi-producer) such that many threads can send
-//! simultaneously to one receiver (single-consumer). These channels are
+//! senders are clone-able such that many tasks can send simultaneously to one
+//! receiver. These channels are *task blocking*, not *thread blocking*. This
+//! means that if one task is blocked on a channel, other tasks can continue to
+//! make progress.
//!
-//! These channels come in two flavors:
+//! Rust channels come in one of two flavors:
//!
//! 1. An asynchronous, infinitely buffered channel. The `channel()` function
//! will return a `(Sender, Receiver)` tuple where all sends will be
//! "rendezvous" channel where each sender atomically hands off a message to
//! a receiver.
//!
-//! ## Disconnection
+//! ## Panic Propagation
//!
-//! The send and receive operations on channels will all return a `Result`
-//! indicating whether the operation succeeded or not. An unsuccessful operation
-//! is normally indicative of the other half of a channel having "hung up" by
-//! being dropped in its corresponding thread.
+//! In addition to being a core primitive for communicating in rust, channels
+//! are the points at which panics are propagated among tasks. Whenever the one
+//! half of channel is closed, the other half will have its next operation
+//! `panic!`. The purpose of this is to allow propagation of panics among tasks
+//! that are linked to one another via channels.
//!
-//! Once half of a channel has been deallocated, most operations can no longer
-//! continue to make progress, so `Err` will be returned. Many applications will
-//! continue to `unwrap()` the results returned from this module, instigating a
-//! propagation of failure among threads if one unexpectedly dies.
+//! There are methods on both of senders and receivers to perform their
+//! respective operations without panicking, however.
//!
-//! # Examples
+//! # Example
//!
//! Simple usage:
//!
//! ```
//! use std::thread::Thread;
-//! use std::sync::mpsc::channel;
//!
//! // Create a simple streaming channel
//! let (tx, rx) = channel();
//! Thread::spawn(move|| {
-//! tx.send(10i).unwrap();
+//! tx.send(10);
//! }).detach();
-//! assert_eq!(rx.recv().unwrap(), 10i);
+//! assert_eq!(rx.recv(), 10);
//! ```
//!
//! Shared usage:
//!
//! ```
//! use std::thread::Thread;
-//! use std::sync::mpsc::channel;
//!
//! // Create a shared channel that can be sent along from many threads
//! // where tx is the sending half (tx for transmission), and rx is the receiving
//! for i in range(0i, 10i) {
//! let tx = tx.clone();
//! Thread::spawn(move|| {
-//! tx.send(i).unwrap();
+//! tx.send(i);
//! }).detach()
//! }
//!
//! for _ in range(0i, 10i) {
-//! let j = rx.recv().unwrap();
+//! let j = rx.recv();
//! assert!(0 <= j && j < 10);
//! }
//! ```
//!
//! Propagating panics:
//!
-//! ```
-//! use std::sync::mpsc::channel;
-//!
-//! // The call to recv() will return an error because the channel has already
-//! // hung up (or been deallocated)
+//! ```should_fail
+//! // The call to recv() will panic!() because the channel has already hung
+//! // up (or been deallocated)
//! let (tx, rx) = channel::<int>();
//! drop(tx);
-//! assert!(rx.recv().is_err());
+//! rx.recv();
//! ```
//!
//! Synchronous channels:
//!
//! ```
//! use std::thread::Thread;
-//! use std::sync::mpsc::sync_channel;
//!
//! let (tx, rx) = sync_channel::<int>(0);
//! Thread::spawn(move|| {
//! // This will wait for the parent task to start receiving
-//! tx.send(53).unwrap();
+//! tx.send(53);
//! }).detach();
-//! rx.recv().unwrap();
+//! rx.recv();
//! ```
//!
//! Reading from a channel with a timeout requires to use a Timer together
//! after 10 seconds no matter what:
//!
//! ```no_run
-//! use std::sync::mpsc::channel;
//! use std::io::timer::Timer;
//! use std::time::Duration;
//!
//!
//! loop {
//! select! {
-//! val = rx.recv() => println!("Received {}", val.unwrap()),
-//! _ = timeout.recv() => {
+//! val = rx.recv() => println!("Received {}", val),
+//! () = timeout.recv() => {
//! println!("timed out, total time was more than 10 seconds");
//! break;
//! }
//! has been inactive for 5 seconds:
//!
//! ```no_run
-//! use std::sync::mpsc::channel;
//! use std::io::timer::Timer;
//! use std::time::Duration;
//!
//! let timeout = timer.oneshot(Duration::seconds(5));
//!
//! select! {
-//! val = rx.recv() => println!("Received {}", val.unwrap()),
-//! _ = timeout.recv() => {
+//! val = rx.recv() => println!("Received {}", val),
+//! () = timeout.recv() => {
//! println!("timed out, no message received in 5 seconds");
//! break;
//! }
// And now that you've seen all the races that I found and attempted to fix,
// here's the code for you to find some more!
-use prelude::v1::*;
+use core::prelude::*;
-use sync::Arc;
-use fmt;
-use kinds::marker;
-use mem;
-use cell::UnsafeCell;
+pub use self::TryRecvError::*;
+pub use self::TrySendError::*;
+
+use alloc::arc::Arc;
+use core::kinds;
+use core::kinds::marker;
+use core::mem;
+use core::cell::UnsafeCell;
pub use self::select::{Select, Handle};
use self::select::StartResult;
use self::select::StartResult::*;
use self::blocking::SignalToken;
+macro_rules! test {
+ { fn $name:ident() $b:block $(#[$a:meta])*} => (
+ mod $name {
+ #![allow(unused_imports)]
+
+ use super::*;
+ use comm::*;
+ use thread::Thread;
+ use prelude::{Ok, Err, spawn, range, drop, Box, Some, None, Option};
+ use prelude::{Vec, Buffer, from_str, Clone};
+
+ $(#[$a])* #[test] fn f() { $b }
+ }
+ )
+}
+
mod blocking;
mod oneshot;
mod select;
/// The receiving-half of Rust's channel type. This half can only be owned by
/// one task
-#[stable]
+#[unstable]
pub struct Receiver<T> {
inner: UnsafeCell<Flavor<T>>,
}
/// An iterator over messages on a receiver, this iterator will block
/// whenever `next` is called, waiting for a new message, and `None` will be
/// returned when the corresponding channel has hung up.
-#[stable]
-pub struct Iter<'a, T:'a> {
+#[unstable]
+pub struct Messages<'a, T:'a> {
rx: &'a Receiver<T>
}
/// The sending-half of Rust's asynchronous channel type. This half can only be
/// owned by one task, but it can be cloned to send to other tasks.
-#[stable]
+#[unstable]
pub struct Sender<T> {
inner: UnsafeCell<Flavor<T>>,
}
/// The sending-half of Rust's synchronous channel type. This half can only be
/// owned by one task, but it can be cloned to send to other tasks.
-#[stable]
+#[unstable = "this type may be renamed, but it will always exist"]
pub struct SyncSender<T> {
inner: Arc<RacyCell<sync::Packet<T>>>,
// can't share in an arc
_marker: marker::NoSync,
}
-/// An error returned from the `send` function on channels.
-///
-/// A `send` operation can only fail if the receiving end of a channel is
-/// disconnected, implying that the data could never be received. The error
-/// contains the data being sent as a payload so it can be recovered.
-#[derive(PartialEq, Eq)]
-#[stable]
-pub struct SendError<T>(pub T);
-
-/// An error returned from the `recv` function on a `Receiver`.
-///
-/// The `recv` operation can only fail if the sending half of a channel is
-/// disconnected, implying that no further messages will ever be received.
-#[derive(PartialEq, Eq, Clone, Copy)]
-#[stable]
-pub struct RecvError;
-
/// This enumeration is the list of the possible reasons that try_recv could not
/// return data when called.
-#[derive(PartialEq, Clone, Copy)]
-#[stable]
+#[deriving(PartialEq, Clone, Copy, Show)]
+#[experimental = "this is likely to be removed in changing try_recv()"]
pub enum TryRecvError {
/// This channel is currently empty, but the sender(s) have not yet
/// disconnected, so data may yet become available.
- #[stable]
Empty,
-
/// This channel's sending half has become disconnected, and there will
/// never be any more data received on this channel
- #[stable]
Disconnected,
}
/// This enumeration is the list of the possible error outcomes for the
/// `SyncSender::try_send` method.
-#[derive(PartialEq, Clone)]
-#[stable]
+#[deriving(PartialEq, Clone, Show)]
+#[experimental = "this is likely to be removed in changing try_send()"]
pub enum TrySendError<T> {
/// The data could not be sent on the channel because it would require that
/// the callee block to send the data.
/// If this is a buffered channel, then the buffer is full at this time. If
/// this is not a buffered channel, then there is no receiver available to
/// acquire the data.
- #[stable]
Full(T),
-
/// This channel's receiving half has disconnected, so the data could not be
/// sent. The data is returned back to the callee in this case.
- #[stable]
- Disconnected(T),
+ RecvDisconnected(T),
}
enum Flavor<T> {
/// # Example
///
/// ```
-/// use std::sync::mpsc::channel;
/// use std::thread::Thread;
///
/// // tx is is the sending half (tx for transmission), and rx is the receiving
/// // Spawn off an expensive computation
/// Thread::spawn(move|| {
/// # fn expensive_computation() {}
-/// tx.send(expensive_computation()).unwrap();
+/// tx.send(expensive_computation());
/// }).detach();
///
/// // Do some useful work for awhile
///
/// // Let's see what that answer was
-/// println!("{}", rx.recv().unwrap());
+/// println!("{}", rx.recv());
/// ```
-#[stable]
+#[unstable]
pub fn channel<T: Send>() -> (Sender<T>, Receiver<T>) {
let a = Arc::new(RacyCell::new(oneshot::Packet::new()));
(Sender::new(Flavor::Oneshot(a.clone())), Receiver::new(Flavor::Oneshot(a)))
/// # Example
///
/// ```
-/// use std::sync::mpsc::sync_channel;
/// use std::thread::Thread;
///
/// let (tx, rx) = sync_channel(1);
///
/// // this returns immediately
-/// tx.send(1i).unwrap();
+/// tx.send(1);
///
/// Thread::spawn(move|| {
/// // this will block until the previous message has been received
-/// tx.send(2i).unwrap();
+/// tx.send(2);
/// }).detach();
///
-/// assert_eq!(rx.recv().unwrap(), 1i);
-/// assert_eq!(rx.recv().unwrap(), 2i);
+/// assert_eq!(rx.recv(), 1);
+/// assert_eq!(rx.recv(), 2);
/// ```
-#[stable]
+#[unstable = "this function may be renamed to more accurately reflect the type \
+ of channel that is is creating"]
pub fn sync_channel<T: Send>(bound: uint) -> (SyncSender<T>, Receiver<T>) {
let a = Arc::new(RacyCell::new(sync::Packet::new(bound)));
(SyncSender::new(a.clone()), Receiver::new(Flavor::Sync(a)))
}
}
+ /// Sends a value along this channel to be received by the corresponding
+ /// receiver.
+ ///
+ /// Rust channels are infinitely buffered so this method will never block.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic if the other end of the channel has hung up.
+ /// This means that if the corresponding receiver has fallen out of scope,
+ /// this function will trigger a panic message saying that a message is
+ /// being sent on a closed channel.
+ ///
+ /// Note that if this function does *not* panic, it does not mean that the
+ /// data will be successfully received. All sends are placed into a queue,
+ /// so it is possible for a send to succeed (the other end is alive), but
+ /// then the other end could immediately disconnect.
+ ///
+ /// The purpose of this functionality is to propagate panics among tasks.
+ /// If a panic is not desired, then consider using the `send_opt` method
+ #[experimental = "this function is being considered candidate for removal \
+ to adhere to the general guidelines of rust"]
+ pub fn send(&self, t: T) {
+ if self.send_opt(t).is_err() {
+ panic!("sending on a closed channel");
+ }
+ }
+
/// Attempts to send a value on this channel, returning it back if it could
/// not be sent.
///
/// will be received. It is possible for the corresponding receiver to
/// hang up immediately after this function returns `Ok`.
///
- /// This method will never block the current thread.
+ /// Like `send`, this method will never block.
+ ///
+ /// # Panics
+ ///
+ /// This method will never panic, it will return the message back to the
+ /// caller if the other end is disconnected
///
/// # Example
///
/// ```
- /// use std::sync::mpsc::channel;
- ///
/// let (tx, rx) = channel();
///
/// // This send is always successful
- /// tx.send(1i).unwrap();
+ /// assert_eq!(tx.send_opt(1), Ok(()));
///
/// // This send will fail because the receiver is gone
/// drop(rx);
- /// assert_eq!(tx.send(1i).err().unwrap().0, 1);
+ /// assert_eq!(tx.send_opt(1), Err(1));
/// ```
- pub fn send(&self, t: T) -> Result<(), SendError<T>> {
+ #[unstable = "this function may be renamed to send() in the future"]
+ pub fn send_opt(&self, t: T) -> Result<(), T> {
let (new_inner, ret) = match *unsafe { self.inner() } {
Flavor::Oneshot(ref p) => {
unsafe {
let p = p.get();
if !(*p).sent() {
- return (*p).send(t).map_err(SendError);
+ return (*p).send(t);
} else {
let a =
Arc::new(RacyCell::new(stream::Packet::new()));
- let rx = Receiver::new(Flavor::Stream(a.clone()));
- match (*p).upgrade(rx) {
+ match (*p).upgrade(Receiver::new(Flavor::Stream(a.clone()))) {
oneshot::UpSuccess => {
let ret = (*a.get()).send(t);
(a, ret)
}
}
}
- Flavor::Stream(ref p) => return unsafe {
- (*p.get()).send(t).map_err(SendError)
- },
- Flavor::Shared(ref p) => return unsafe {
- (*p.get()).send(t).map_err(SendError)
- },
+ Flavor::Stream(ref p) => return unsafe { (*p.get()).send(t) },
+ Flavor::Shared(ref p) => return unsafe { (*p.get()).send(t) },
Flavor::Sync(..) => unreachable!(),
};
let tmp = Sender::new(Flavor::Stream(new_inner));
mem::swap(self.inner_mut(), tmp.inner_mut());
}
- ret.map_err(SendError)
+ return ret;
}
}
let a = Arc::new(RacyCell::new(shared::Packet::new()));
unsafe {
let guard = (*a.get()).postinit_lock();
- let rx = Receiver::new(Flavor::Shared(a.clone()));
- match (*p.get()).upgrade(rx) {
+ match (*p.get()).upgrade(Receiver::new(Flavor::Shared(a.clone()))) {
oneshot::UpSuccess |
oneshot::UpDisconnected => (a, None, guard),
oneshot::UpWoke(task) => (a, Some(task), guard)
let a = Arc::new(RacyCell::new(shared::Packet::new()));
unsafe {
let guard = (*a.get()).postinit_lock();
- let rx = Receiver::new(Flavor::Shared(a.clone()));
- match (*p.get()).upgrade(rx) {
+ match (*p.get()).upgrade(Receiver::new(Flavor::Shared(a.clone()))) {
stream::UpSuccess |
stream::UpDisconnected => (a, None, guard),
stream::UpWoke(task) => (a, Some(task), guard),
/// available or a receiver is available to hand off the message to.
///
/// Note that a successful send does *not* guarantee that the receiver will
- /// ever see the data if there is a buffer on this channel. Items may be
+ /// ever see the data if there is a buffer on this channel. Messages may be
/// enqueued in the internal buffer for the receiver to receive at a later
/// time. If the buffer size is 0, however, it can be guaranteed that the
/// receiver has indeed received the data if this function returns success.
///
- /// This function will never panic, but it may return `Err` if the
- /// `Receiver` has disconnected and is no longer able to receive
- /// information.
- #[stable]
- pub fn send(&self, t: T) -> Result<(), SendError<T>> {
- unsafe { (*self.inner.get()).send(t).map_err(SendError) }
+ /// # Panics
+ ///
+ /// Similarly to `Sender::send`, this function will panic if the
+ /// corresponding `Receiver` for this channel has disconnected. This
+ /// behavior is used to propagate panics among tasks.
+ ///
+ /// If a panic is not desired, you can achieve the same semantics with the
+ /// `SyncSender::send_opt` method which will not panic if the receiver
+ /// disconnects.
+ #[experimental = "this function is being considered candidate for removal \
+ to adhere to the general guidelines of rust"]
+ pub fn send(&self, t: T) {
+ if self.send_opt(t).is_err() {
+ panic!("sending on a closed channel");
+ }
+ }
+
+ /// Send a value on a channel, returning it back if the receiver
+ /// disconnected
+ ///
+ /// This method will *block* to send the value `t` on the channel, but if
+ /// the value could not be sent due to the receiver disconnecting, the value
+ /// is returned back to the callee. This function is similar to `try_send`,
+ /// except that it will block if the channel is currently full.
+ ///
+ /// # Panics
+ ///
+ /// This function cannot panic.
+ #[unstable = "this function may be renamed to send() in the future"]
+ pub fn send_opt(&self, t: T) -> Result<(), T> {
+ unsafe { (*self.inner.get()).send(t) }
}
/// Attempts to send a value on this channel without blocking.
///
- /// This method differs from `send` by returning immediately if the
+ /// This method differs from `send_opt` by returning immediately if the
/// channel's buffer is full or no receiver is waiting to acquire some
- /// data. Compared with `send`, this function has two failure cases
+ /// data. Compared with `send_opt`, this function has two failure cases
/// instead of one (one for disconnection, one for a full buffer).
///
/// See `SyncSender::send` for notes about guarantees of whether the
/// receiver has received the data or not if this function is successful.
- #[stable]
+ ///
+ /// # Panics
+ ///
+ /// This function cannot panic
+ #[unstable = "the return type of this function is candidate for \
+ modification"]
pub fn try_send(&self, t: T) -> Result<(), TrySendError<T>> {
unsafe { (*self.inner.get()).try_send(t) }
}
Receiver { inner: UnsafeCell::new(inner) }
}
+ /// Blocks waiting for a value on this receiver
+ ///
+ /// This function will block if necessary to wait for a corresponding send
+ /// on the channel from its paired `Sender` structure. This receiver will
+ /// be woken up when data is ready, and the data will be returned.
+ ///
+ /// # Panics
+ ///
+ /// Similar to channels, this method will trigger a task panic if the
+ /// other end of the channel has hung up (been deallocated). The purpose of
+ /// this is to propagate panics among tasks.
+ ///
+ /// If a panic is not desired, then there are two options:
+ ///
+ /// * If blocking is still desired, the `recv_opt` method will return `None`
+ /// when the other end hangs up
+ ///
+ /// * If blocking is not desired, then the `try_recv` method will attempt to
+ /// peek at a value on this receiver.
+ #[experimental = "this function is being considered candidate for removal \
+ to adhere to the general guidelines of rust"]
+ pub fn recv(&self) -> T {
+ match self.recv_opt() {
+ Ok(t) => t,
+ Err(()) => panic!("receiving on a closed channel"),
+ }
+ }
+
/// Attempts to return a pending value on this receiver without blocking
///
/// This method will never block the caller in order to wait for data to
///
/// This is useful for a flavor of "optimistic check" before deciding to
/// block on a receiver.
- #[stable]
+ ///
+ /// # Panics
+ ///
+ /// This function cannot panic.
+ #[unstable = "the return type of this function may be altered"]
pub fn try_recv(&self) -> Result<T, TryRecvError> {
loop {
let new_port = match *unsafe { self.inner() } {
Flavor::Oneshot(ref p) => {
match unsafe { (*p.get()).try_recv() } {
Ok(t) => return Ok(t),
- Err(oneshot::Empty) => return Err(TryRecvError::Empty),
- Err(oneshot::Disconnected) => {
- return Err(TryRecvError::Disconnected)
- }
+ Err(oneshot::Empty) => return Err(Empty),
+ Err(oneshot::Disconnected) => return Err(Disconnected),
Err(oneshot::Upgraded(rx)) => rx,
}
}
Flavor::Stream(ref p) => {
match unsafe { (*p.get()).try_recv() } {
Ok(t) => return Ok(t),
- Err(stream::Empty) => return Err(TryRecvError::Empty),
- Err(stream::Disconnected) => {
- return Err(TryRecvError::Disconnected)
- }
+ Err(stream::Empty) => return Err(Empty),
+ Err(stream::Disconnected) => return Err(Disconnected),
Err(stream::Upgraded(rx)) => rx,
}
}
Flavor::Shared(ref p) => {
match unsafe { (*p.get()).try_recv() } {
Ok(t) => return Ok(t),
- Err(shared::Empty) => return Err(TryRecvError::Empty),
- Err(shared::Disconnected) => {
- return Err(TryRecvError::Disconnected)
- }
+ Err(shared::Empty) => return Err(Empty),
+ Err(shared::Disconnected) => return Err(Disconnected),
}
}
Flavor::Sync(ref p) => {
match unsafe { (*p.get()).try_recv() } {
Ok(t) => return Ok(t),
- Err(sync::Empty) => return Err(TryRecvError::Empty),
- Err(sync::Disconnected) => {
- return Err(TryRecvError::Disconnected)
- }
+ Err(sync::Empty) => return Err(Empty),
+ Err(sync::Disconnected) => return Err(Disconnected),
}
}
};
}
}
- /// Attempt to wait for a value on this receiver, returning an error if the
+ /// Attempt to wait for a value on this receiver, but does not panic if the
/// corresponding channel has hung up.
///
- /// This function will always block the current thread if there is no data
- /// available and it's possible for more data to be sent. Once a message is
- /// sent to the corresponding `Sender`, then this receiver will wake up and
- /// return that message.
+ /// This implementation of iterators for ports will always block if there is
+ /// not data available on the receiver, but it will not panic in the case
+ /// that the channel has been deallocated.
///
- /// If the corresponding `Sender` has disconnected, or it disconnects while
- /// this call is blocking, this call will wake up and return `Err` to
- /// indicate that no more messages can ever be received on this channel.
- #[stable]
- pub fn recv(&self) -> Result<T, RecvError> {
+ /// In other words, this function has the same semantics as the `recv`
+ /// method except for the panic aspect.
+ ///
+ /// If the channel has hung up, then `Err` is returned. Otherwise `Ok` of
+ /// the value found on the receiver is returned.
+ #[unstable = "this function may be renamed to recv()"]
+ pub fn recv_opt(&self) -> Result<T, ()> {
loop {
let new_port = match *unsafe { self.inner() } {
Flavor::Oneshot(ref p) => {
match unsafe { (*p.get()).recv() } {
Ok(t) => return Ok(t),
Err(oneshot::Empty) => return unreachable!(),
- Err(oneshot::Disconnected) => return Err(RecvError),
+ Err(oneshot::Disconnected) => return Err(()),
Err(oneshot::Upgraded(rx)) => rx,
}
}
match unsafe { (*p.get()).recv() } {
Ok(t) => return Ok(t),
Err(stream::Empty) => return unreachable!(),
- Err(stream::Disconnected) => return Err(RecvError),
+ Err(stream::Disconnected) => return Err(()),
Err(stream::Upgraded(rx)) => rx,
}
}
match unsafe { (*p.get()).recv() } {
Ok(t) => return Ok(t),
Err(shared::Empty) => return unreachable!(),
- Err(shared::Disconnected) => return Err(RecvError),
+ Err(shared::Disconnected) => return Err(()),
}
}
- Flavor::Sync(ref p) => return unsafe {
- (*p.get()).recv().map_err(|()| RecvError)
- }
+ Flavor::Sync(ref p) => return unsafe { (*p.get()).recv() }
};
unsafe {
mem::swap(self.inner_mut(), new_port.inner_mut());
/// Returns an iterator that will block waiting for messages, but never
/// `panic!`. It will return `None` when the channel has hung up.
- #[stable]
- pub fn iter(&self) -> Iter<T> {
- Iter { rx: self }
+ #[unstable]
+ pub fn iter<'a>(&'a self) -> Messages<'a, T> {
+ Messages { rx: self }
}
}
}
#[unstable]
-impl<'a, T: Send> Iterator for Iter<'a, T> {
- type Item = T;
-
- fn next(&mut self) -> Option<T> { self.rx.recv().ok() }
+impl<'a, T: Send> Iterator<T> for Messages<'a, T> {
+ fn next(&mut self) -> Option<T> { self.rx.recv_opt().ok() }
}
#[unsafe_destructor]
unsafe impl<T:Send> Send for RacyCell<T> { }
-unsafe impl<T> Sync for RacyCell<T> { } // Oh dear
-
-impl<T> fmt::Show for SendError<T> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- "sending on a closed channel".fmt(f)
- }
-}
-
-impl<T> fmt::Show for TrySendError<T> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match *self {
- TrySendError::Full(..) => {
- "sending on a full channel".fmt(f)
- }
- TrySendError::Disconnected(..) => {
- "sending on a closed channel".fmt(f)
- }
- }
- }
-}
-
-impl fmt::Show for RecvError {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- "receiving on a closed channel".fmt(f)
- }
-}
+unsafe impl<T> kinds::Sync for RacyCell<T> { } // Oh dear
-impl fmt::Show for TryRecvError {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match *self {
- TryRecvError::Empty => {
- "receiving on an empty channel".fmt(f)
- }
- TryRecvError::Disconnected => {
- "receiving on a closed channel".fmt(f)
- }
- }
- }
-}
#[cfg(test)]
mod test {
- use prelude::v1::*;
-
- use os;
use super::*;
- use thread::Thread;
+ use prelude::{spawn, range, Some, None, from_str, Clone, Str};
+ use os;
pub fn stress_factor() -> uint {
match os::getenv("RUST_TEST_STRESS") {
- Some(val) => val.parse().unwrap(),
+ Some(val) => from_str::<uint>(val.as_slice()).unwrap(),
None => 1,
}
}
- #[test]
- fn smoke() {
+ test! { fn smoke() {
let (tx, rx) = channel::<int>();
- tx.send(1).unwrap();
- assert_eq!(rx.recv().unwrap(), 1);
- }
+ tx.send(1);
+ assert_eq!(rx.recv(), 1);
+ } }
- #[test]
- fn drop_full() {
+ test! { fn drop_full() {
let (tx, _rx) = channel();
- tx.send(box 1i).unwrap();
- }
+ tx.send(box 1i);
+ } }
- #[test]
- fn drop_full_shared() {
+ test! { fn drop_full_shared() {
let (tx, _rx) = channel();
drop(tx.clone());
drop(tx.clone());
- tx.send(box 1i).unwrap();
- }
+ tx.send(box 1i);
+ } }
- #[test]
- fn smoke_shared() {
+ test! { fn smoke_shared() {
let (tx, rx) = channel::<int>();
- tx.send(1).unwrap();
- assert_eq!(rx.recv().unwrap(), 1);
+ tx.send(1);
+ assert_eq!(rx.recv(), 1);
let tx = tx.clone();
- tx.send(1).unwrap();
- assert_eq!(rx.recv().unwrap(), 1);
- }
+ tx.send(1);
+ assert_eq!(rx.recv(), 1);
+ } }
- #[test]
- fn smoke_threads() {
+ test! { fn smoke_threads() {
let (tx, rx) = channel::<int>();
- let _t = Thread::spawn(move|| {
- tx.send(1).unwrap();
+ spawn(move|| {
+ tx.send(1);
});
- assert_eq!(rx.recv().unwrap(), 1);
- }
+ assert_eq!(rx.recv(), 1);
+ } }
- #[test]
- fn smoke_port_gone() {
+ test! { fn smoke_port_gone() {
let (tx, rx) = channel::<int>();
drop(rx);
- assert!(tx.send(1).is_err());
- }
+ tx.send(1);
+ } #[should_fail] }
- #[test]
- fn smoke_shared_port_gone() {
+ test! { fn smoke_shared_port_gone() {
let (tx, rx) = channel::<int>();
drop(rx);
- assert!(tx.send(1).is_err())
- }
+ tx.send(1);
+ } #[should_fail] }
- #[test]
- fn smoke_shared_port_gone2() {
+ test! { fn smoke_shared_port_gone2() {
let (tx, rx) = channel::<int>();
drop(rx);
let tx2 = tx.clone();
drop(tx);
- assert!(tx2.send(1).is_err());
- }
+ tx2.send(1);
+ } #[should_fail] }
- #[test]
- fn port_gone_concurrent() {
+ test! { fn port_gone_concurrent() {
let (tx, rx) = channel::<int>();
- let _t = Thread::spawn(move|| {
- rx.recv().unwrap();
+ spawn(move|| {
+ rx.recv();
});
- while tx.send(1).is_ok() {}
- }
+ loop { tx.send(1) }
+ } #[should_fail] }
- #[test]
- fn port_gone_concurrent_shared() {
+ test! { fn port_gone_concurrent_shared() {
let (tx, rx) = channel::<int>();
let tx2 = tx.clone();
- let _t = Thread::spawn(move|| {
- rx.recv().unwrap();
+ spawn(move|| {
+ rx.recv();
});
- while tx.send(1).is_ok() && tx2.send(1).is_ok() {}
- }
+ loop {
+ tx.send(1);
+ tx2.send(1);
+ }
+ } #[should_fail] }
- #[test]
- fn smoke_chan_gone() {
+ test! { fn smoke_chan_gone() {
let (tx, rx) = channel::<int>();
drop(tx);
- assert!(rx.recv().is_err());
- }
+ rx.recv();
+ } #[should_fail] }
- #[test]
- fn smoke_chan_gone_shared() {
+ test! { fn smoke_chan_gone_shared() {
let (tx, rx) = channel::<()>();
let tx2 = tx.clone();
drop(tx);
drop(tx2);
- assert!(rx.recv().is_err());
- }
+ rx.recv();
+ } #[should_fail] }
- #[test]
- fn chan_gone_concurrent() {
+ test! { fn chan_gone_concurrent() {
let (tx, rx) = channel::<int>();
- let _t = Thread::spawn(move|| {
- tx.send(1).unwrap();
- tx.send(1).unwrap();
+ spawn(move|| {
+ tx.send(1);
+ tx.send(1);
});
- while rx.recv().is_ok() {}
- }
+ loop { rx.recv(); }
+ } #[should_fail] }
- #[test]
- fn stress() {
+ test! { fn stress() {
let (tx, rx) = channel::<int>();
- let t = Thread::spawn(move|| {
- for _ in range(0u, 10000) { tx.send(1i).unwrap(); }
+ spawn(move|| {
+ for _ in range(0u, 10000) { tx.send(1i); }
});
for _ in range(0u, 10000) {
- assert_eq!(rx.recv().unwrap(), 1);
+ assert_eq!(rx.recv(), 1);
}
- t.join().ok().unwrap();
- }
+ } }
- #[test]
- fn stress_shared() {
+ test! { fn stress_shared() {
static AMT: uint = 10000;
static NTHREADS: uint = 8;
let (tx, rx) = channel::<int>();
+ let (dtx, drx) = channel::<()>();
- let t = Thread::spawn(move|| {
+ spawn(move|| {
for _ in range(0, AMT * NTHREADS) {
- assert_eq!(rx.recv().unwrap(), 1);
+ assert_eq!(rx.recv(), 1);
}
match rx.try_recv() {
Ok(..) => panic!(),
_ => {}
}
+ dtx.send(());
});
for _ in range(0, NTHREADS) {
let tx = tx.clone();
- Thread::spawn(move|| {
- for _ in range(0, AMT) { tx.send(1).unwrap(); }
- }).detach();
+ spawn(move|| {
+ for _ in range(0, AMT) { tx.send(1); }
+ });
}
drop(tx);
- t.join().ok().unwrap();
- }
+ drx.recv();
+ } }
#[test]
fn send_from_outside_runtime() {
let (tx1, rx1) = channel::<()>();
let (tx2, rx2) = channel::<int>();
- let t1 = Thread::spawn(move|| {
- tx1.send(()).unwrap();
+ let (tx3, rx3) = channel::<()>();
+ let tx4 = tx3.clone();
+ spawn(move|| {
+ tx1.send(());
for _ in range(0i, 40) {
- assert_eq!(rx2.recv().unwrap(), 1);
+ assert_eq!(rx2.recv(), 1);
}
+ tx3.send(());
});
- rx1.recv().unwrap();
- let t2 = Thread::spawn(move|| {
+ rx1.recv();
+ spawn(move|| {
for _ in range(0i, 40) {
- tx2.send(1).unwrap();
+ tx2.send(1);
}
+ tx4.send(());
});
- t1.join().ok().unwrap();
- t2.join().ok().unwrap();
+ rx3.recv();
+ rx3.recv();
}
#[test]
fn recv_from_outside_runtime() {
let (tx, rx) = channel::<int>();
- let t = Thread::spawn(move|| {
+ let (dtx, drx) = channel();
+ spawn(move|| {
for _ in range(0i, 40) {
- assert_eq!(rx.recv().unwrap(), 1);
+ assert_eq!(rx.recv(), 1);
}
+ dtx.send(());
});
for _ in range(0u, 40) {
- tx.send(1).unwrap();
+ tx.send(1);
}
- t.join().ok().unwrap();
+ drx.recv();
}
#[test]
fn no_runtime() {
let (tx1, rx1) = channel::<int>();
let (tx2, rx2) = channel::<int>();
- let t1 = Thread::spawn(move|| {
- assert_eq!(rx1.recv().unwrap(), 1);
- tx2.send(2).unwrap();
+ let (tx3, rx3) = channel::<()>();
+ let tx4 = tx3.clone();
+ spawn(move|| {
+ assert_eq!(rx1.recv(), 1);
+ tx2.send(2);
+ tx4.send(());
});
- let t2 = Thread::spawn(move|| {
- tx1.send(1).unwrap();
- assert_eq!(rx2.recv().unwrap(), 2);
+ spawn(move|| {
+ tx1.send(1);
+ assert_eq!(rx2.recv(), 2);
+ tx3.send(());
});
- t1.join().ok().unwrap();
- t2.join().ok().unwrap();
+ rx3.recv();
+ rx3.recv();
}
- #[test]
- fn oneshot_single_thread_close_port_first() {
+ test! { fn oneshot_single_thread_close_port_first() {
// Simple test of closing without sending
let (_tx, rx) = channel::<int>();
drop(rx);
- }
+ } }
- #[test]
- fn oneshot_single_thread_close_chan_first() {
+ test! { fn oneshot_single_thread_close_chan_first() {
// Simple test of closing without sending
let (tx, _rx) = channel::<int>();
drop(tx);
- }
+ } }
- #[test]
- fn oneshot_single_thread_send_port_close() {
+ test! { fn oneshot_single_thread_send_port_close() {
// Testing that the sender cleans up the payload if receiver is closed
let (tx, rx) = channel::<Box<int>>();
drop(rx);
- assert!(tx.send(box 0).is_err());
- }
+ tx.send(box 0);
+ } #[should_fail] }
- #[test]
- fn oneshot_single_thread_recv_chan_close() {
+ test! { fn oneshot_single_thread_recv_chan_close() {
// Receiving on a closed chan will panic
let res = Thread::spawn(move|| {
let (tx, rx) = channel::<int>();
drop(tx);
- rx.recv().unwrap();
+ rx.recv();
}).join();
// What is our res?
assert!(res.is_err());
- }
+ } }
- #[test]
- fn oneshot_single_thread_send_then_recv() {
+ test! { fn oneshot_single_thread_send_then_recv() {
let (tx, rx) = channel::<Box<int>>();
- tx.send(box 10).unwrap();
- assert!(rx.recv().unwrap() == box 10);
- }
+ tx.send(box 10);
+ assert!(rx.recv() == box 10);
+ } }
- #[test]
- fn oneshot_single_thread_try_send_open() {
+ test! { fn oneshot_single_thread_try_send_open() {
let (tx, rx) = channel::<int>();
- assert!(tx.send(10).is_ok());
- assert!(rx.recv().unwrap() == 10);
- }
+ assert!(tx.send_opt(10).is_ok());
+ assert!(rx.recv() == 10);
+ } }
- #[test]
- fn oneshot_single_thread_try_send_closed() {
+ test! { fn oneshot_single_thread_try_send_closed() {
let (tx, rx) = channel::<int>();
drop(rx);
- assert!(tx.send(10).is_err());
- }
+ assert!(tx.send_opt(10).is_err());
+ } }
- #[test]
- fn oneshot_single_thread_try_recv_open() {
+ test! { fn oneshot_single_thread_try_recv_open() {
let (tx, rx) = channel::<int>();
- tx.send(10).unwrap();
- assert!(rx.recv() == Ok(10));
- }
+ tx.send(10);
+ assert!(rx.recv_opt() == Ok(10));
+ } }
- #[test]
- fn oneshot_single_thread_try_recv_closed() {
+ test! { fn oneshot_single_thread_try_recv_closed() {
let (tx, rx) = channel::<int>();
drop(tx);
- assert!(rx.recv().is_err());
- }
+ assert!(rx.recv_opt() == Err(()));
+ } }
- #[test]
- fn oneshot_single_thread_peek_data() {
+ test! { fn oneshot_single_thread_peek_data() {
let (tx, rx) = channel::<int>();
- assert_eq!(rx.try_recv(), Err(TryRecvError::Empty));
- tx.send(10).unwrap();
+ assert_eq!(rx.try_recv(), Err(Empty));
+ tx.send(10);
assert_eq!(rx.try_recv(), Ok(10));
- }
+ } }
- #[test]
- fn oneshot_single_thread_peek_close() {
+ test! { fn oneshot_single_thread_peek_close() {
let (tx, rx) = channel::<int>();
drop(tx);
- assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected));
- assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected));
- }
+ assert_eq!(rx.try_recv(), Err(Disconnected));
+ assert_eq!(rx.try_recv(), Err(Disconnected));
+ } }
- #[test]
- fn oneshot_single_thread_peek_open() {
+ test! { fn oneshot_single_thread_peek_open() {
let (_tx, rx) = channel::<int>();
- assert_eq!(rx.try_recv(), Err(TryRecvError::Empty));
- }
+ assert_eq!(rx.try_recv(), Err(Empty));
+ } }
- #[test]
- fn oneshot_multi_task_recv_then_send() {
+ test! { fn oneshot_multi_task_recv_then_send() {
let (tx, rx) = channel::<Box<int>>();
- let _t = Thread::spawn(move|| {
- assert!(rx.recv().unwrap() == box 10);
+ spawn(move|| {
+ assert!(rx.recv() == box 10);
});
- tx.send(box 10).unwrap();
- }
+ tx.send(box 10);
+ } }
- #[test]
- fn oneshot_multi_task_recv_then_close() {
+ test! { fn oneshot_multi_task_recv_then_close() {
let (tx, rx) = channel::<Box<int>>();
- let _t = Thread::spawn(move|| {
+ spawn(move|| {
drop(tx);
});
let res = Thread::spawn(move|| {
- assert!(rx.recv().unwrap() == box 10);
+ assert!(rx.recv() == box 10);
}).join();
assert!(res.is_err());
- }
+ } }
- #[test]
- fn oneshot_multi_thread_close_stress() {
+ test! { fn oneshot_multi_thread_close_stress() {
for _ in range(0, stress_factor()) {
let (tx, rx) = channel::<int>();
- let _t = Thread::spawn(move|| {
+ spawn(move|| {
drop(rx);
});
drop(tx);
}
- }
+ } }
- #[test]
- fn oneshot_multi_thread_send_close_stress() {
+ test! { fn oneshot_multi_thread_send_close_stress() {
for _ in range(0, stress_factor()) {
let (tx, rx) = channel::<int>();
- let _t = Thread::spawn(move|| {
+ spawn(move|| {
drop(rx);
});
let _ = Thread::spawn(move|| {
- tx.send(1).unwrap();
+ tx.send(1);
}).join();
}
- }
+ } }
- #[test]
- fn oneshot_multi_thread_recv_close_stress() {
+ test! { fn oneshot_multi_thread_recv_close_stress() {
for _ in range(0, stress_factor()) {
let (tx, rx) = channel::<int>();
- Thread::spawn(move|| {
+ spawn(move|| {
let res = Thread::spawn(move|| {
- rx.recv().unwrap();
+ rx.recv();
}).join();
assert!(res.is_err());
- }).detach();
- let _t = Thread::spawn(move|| {
- Thread::spawn(move|| {
+ });
+ spawn(move|| {
+ spawn(move|| {
drop(tx);
- }).detach();
+ });
});
}
- }
+ } }
- #[test]
- fn oneshot_multi_thread_send_recv_stress() {
+ test! { fn oneshot_multi_thread_send_recv_stress() {
for _ in range(0, stress_factor()) {
let (tx, rx) = channel();
- let _t = Thread::spawn(move|| {
- tx.send(box 10i).unwrap();
+ spawn(move|| {
+ tx.send(box 10i);
+ });
+ spawn(move|| {
+ assert!(rx.recv() == box 10i);
});
- assert!(rx.recv().unwrap() == box 10i);
}
- }
+ } }
- #[test]
- fn stream_send_recv_stress() {
+ test! { fn stream_send_recv_stress() {
for _ in range(0, stress_factor()) {
let (tx, rx) = channel();
fn send(tx: Sender<Box<int>>, i: int) {
if i == 10 { return }
- Thread::spawn(move|| {
- tx.send(box i).unwrap();
+ spawn(move|| {
+ tx.send(box i);
send(tx, i + 1);
- }).detach();
+ });
}
fn recv(rx: Receiver<Box<int>>, i: int) {
if i == 10 { return }
- Thread::spawn(move|| {
- assert!(rx.recv().unwrap() == box i);
+ spawn(move|| {
+ assert!(rx.recv() == box i);
recv(rx, i + 1);
- }).detach();
+ });
}
}
- }
+ } }
- #[test]
- fn recv_a_lot() {
+ test! { fn recv_a_lot() {
// Regression test that we don't run out of stack in scheduler context
let (tx, rx) = channel();
- for _ in range(0i, 10000) { tx.send(()).unwrap(); }
- for _ in range(0i, 10000) { rx.recv().unwrap(); }
- }
+ for _ in range(0i, 10000) { tx.send(()); }
+ for _ in range(0i, 10000) { rx.recv(); }
+ } }
- #[test]
- fn shared_chan_stress() {
+ test! { fn shared_chan_stress() {
let (tx, rx) = channel();
let total = stress_factor() + 100;
for _ in range(0, total) {
let tx = tx.clone();
- Thread::spawn(move|| {
- tx.send(()).unwrap();
- }).detach();
+ spawn(move|| {
+ tx.send(());
+ });
}
for _ in range(0, total) {
- rx.recv().unwrap();
+ rx.recv();
}
- }
+ } }
- #[test]
- fn test_nested_recv_iter() {
+ test! { fn test_nested_recv_iter() {
let (tx, rx) = channel::<int>();
let (total_tx, total_rx) = channel::<int>();
- let _t = Thread::spawn(move|| {
+ spawn(move|| {
let mut acc = 0;
for x in rx.iter() {
acc += x;
}
- total_tx.send(acc).unwrap();
+ total_tx.send(acc);
});
- tx.send(3).unwrap();
- tx.send(1).unwrap();
- tx.send(2).unwrap();
+ tx.send(3);
+ tx.send(1);
+ tx.send(2);
drop(tx);
- assert_eq!(total_rx.recv().unwrap(), 6);
- }
+ assert_eq!(total_rx.recv(), 6);
+ } }
- #[test]
- fn test_recv_iter_break() {
+ test! { fn test_recv_iter_break() {
let (tx, rx) = channel::<int>();
let (count_tx, count_rx) = channel();
- let _t = Thread::spawn(move|| {
+ spawn(move|| {
let mut count = 0;
for x in rx.iter() {
if count >= 3 {
count += x;
}
}
- count_tx.send(count).unwrap();
+ count_tx.send(count);
});
- tx.send(2).unwrap();
- tx.send(2).unwrap();
- tx.send(2).unwrap();
- let _ = tx.send(2);
+ tx.send(2);
+ tx.send(2);
+ tx.send(2);
+ let _ = tx.send_opt(2);
drop(tx);
- assert_eq!(count_rx.recv().unwrap(), 4);
- }
+ assert_eq!(count_rx.recv(), 4);
+ } }
- #[test]
- fn try_recv_states() {
+ test! { fn try_recv_states() {
let (tx1, rx1) = channel::<int>();
let (tx2, rx2) = channel::<()>();
let (tx3, rx3) = channel::<()>();
- let _t = Thread::spawn(move|| {
- rx2.recv().unwrap();
- tx1.send(1).unwrap();
- tx3.send(()).unwrap();
- rx2.recv().unwrap();
+ spawn(move|| {
+ rx2.recv();
+ tx1.send(1);
+ tx3.send(());
+ rx2.recv();
drop(tx1);
- tx3.send(()).unwrap();
+ tx3.send(());
});
- assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty));
- tx2.send(()).unwrap();
- rx3.recv().unwrap();
+ assert_eq!(rx1.try_recv(), Err(Empty));
+ tx2.send(());
+ rx3.recv();
assert_eq!(rx1.try_recv(), Ok(1));
- assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty));
- tx2.send(()).unwrap();
- rx3.recv().unwrap();
- assert_eq!(rx1.try_recv(), Err(TryRecvError::Disconnected));
- }
+ assert_eq!(rx1.try_recv(), Err(Empty));
+ tx2.send(());
+ rx3.recv();
+ assert_eq!(rx1.try_recv(), Err(Disconnected));
+ } }
// This bug used to end up in a livelock inside of the Receiver destructor
// because the internal state of the Shared packet was corrupted
- #[test]
- fn destroy_upgraded_shared_port_when_sender_still_active() {
+ test! { fn destroy_upgraded_shared_port_when_sender_still_active() {
let (tx, rx) = channel();
let (tx2, rx2) = channel();
- let _t = Thread::spawn(move|| {
- rx.recv().unwrap(); // wait on a oneshot
+ spawn(move|| {
+ rx.recv(); // wait on a oneshot
drop(rx); // destroy a shared
- tx2.send(()).unwrap();
+ tx2.send(());
});
// make sure the other task has gone to sleep
for _ in range(0u, 5000) { Thread::yield_now(); }
// upgrade to a shared chan and send a message
let t = tx.clone();
drop(tx);
- t.send(()).unwrap();
+ t.send(());
// wait for the child task to exit before we exit
- rx2.recv().unwrap();
- }
+ rx2.recv();
+ }}
}
#[cfg(test)]
mod sync_tests {
- use prelude::v1::*;
-
+ use prelude::*;
use os;
- use thread::Thread;
- use super::*;
pub fn stress_factor() -> uint {
match os::getenv("RUST_TEST_STRESS") {
- Some(val) => val.parse().unwrap(),
+ Some(val) => from_str::<uint>(val.as_slice()).unwrap(),
None => 1,
}
}
- #[test]
- fn smoke() {
+ test! { fn smoke() {
let (tx, rx) = sync_channel::<int>(1);
- tx.send(1).unwrap();
- assert_eq!(rx.recv().unwrap(), 1);
- }
+ tx.send(1);
+ assert_eq!(rx.recv(), 1);
+ } }
- #[test]
- fn drop_full() {
+ test! { fn drop_full() {
let (tx, _rx) = sync_channel(1);
- tx.send(box 1i).unwrap();
- }
+ tx.send(box 1i);
+ } }
- #[test]
- fn smoke_shared() {
+ test! { fn smoke_shared() {
let (tx, rx) = sync_channel::<int>(1);
- tx.send(1).unwrap();
- assert_eq!(rx.recv().unwrap(), 1);
+ tx.send(1);
+ assert_eq!(rx.recv(), 1);
let tx = tx.clone();
- tx.send(1).unwrap();
- assert_eq!(rx.recv().unwrap(), 1);
- }
+ tx.send(1);
+ assert_eq!(rx.recv(), 1);
+ } }
- #[test]
- fn smoke_threads() {
+ test! { fn smoke_threads() {
let (tx, rx) = sync_channel::<int>(0);
- let _t = Thread::spawn(move|| {
- tx.send(1).unwrap();
+ spawn(move|| {
+ tx.send(1);
});
- assert_eq!(rx.recv().unwrap(), 1);
- }
+ assert_eq!(rx.recv(), 1);
+ } }
- #[test]
- fn smoke_port_gone() {
+ test! { fn smoke_port_gone() {
let (tx, rx) = sync_channel::<int>(0);
drop(rx);
- assert!(tx.send(1).is_err());
- }
+ tx.send(1);
+ } #[should_fail] }
- #[test]
- fn smoke_shared_port_gone2() {
+ test! { fn smoke_shared_port_gone2() {
let (tx, rx) = sync_channel::<int>(0);
drop(rx);
let tx2 = tx.clone();
drop(tx);
- assert!(tx2.send(1).is_err());
- }
+ tx2.send(1);
+ } #[should_fail] }
- #[test]
- fn port_gone_concurrent() {
+ test! { fn port_gone_concurrent() {
let (tx, rx) = sync_channel::<int>(0);
- let _t = Thread::spawn(move|| {
- rx.recv().unwrap();
+ spawn(move|| {
+ rx.recv();
});
- while tx.send(1).is_ok() {}
- }
+ loop { tx.send(1) }
+ } #[should_fail] }
- #[test]
- fn port_gone_concurrent_shared() {
+ test! { fn port_gone_concurrent_shared() {
let (tx, rx) = sync_channel::<int>(0);
let tx2 = tx.clone();
- let _t = Thread::spawn(move|| {
- rx.recv().unwrap();
+ spawn(move|| {
+ rx.recv();
});
- while tx.send(1).is_ok() && tx2.send(1).is_ok() {}
- }
+ loop {
+ tx.send(1);
+ tx2.send(1);
+ }
+ } #[should_fail] }
- #[test]
- fn smoke_chan_gone() {
+ test! { fn smoke_chan_gone() {
let (tx, rx) = sync_channel::<int>(0);
drop(tx);
- assert!(rx.recv().is_err());
- }
+ rx.recv();
+ } #[should_fail] }
- #[test]
- fn smoke_chan_gone_shared() {
+ test! { fn smoke_chan_gone_shared() {
let (tx, rx) = sync_channel::<()>(0);
let tx2 = tx.clone();
drop(tx);
drop(tx2);
- assert!(rx.recv().is_err());
- }
+ rx.recv();
+ } #[should_fail] }
- #[test]
- fn chan_gone_concurrent() {
+ test! { fn chan_gone_concurrent() {
let (tx, rx) = sync_channel::<int>(0);
- Thread::spawn(move|| {
- tx.send(1).unwrap();
- tx.send(1).unwrap();
- }).detach();
- while rx.recv().is_ok() {}
- }
+ spawn(move|| {
+ tx.send(1);
+ tx.send(1);
+ });
+ loop { rx.recv(); }
+ } #[should_fail] }
- #[test]
- fn stress() {
+ test! { fn stress() {
let (tx, rx) = sync_channel::<int>(0);
- Thread::spawn(move|| {
- for _ in range(0u, 10000) { tx.send(1).unwrap(); }
- }).detach();
+ spawn(move|| {
+ for _ in range(0u, 10000) { tx.send(1); }
+ });
for _ in range(0u, 10000) {
- assert_eq!(rx.recv().unwrap(), 1);
+ assert_eq!(rx.recv(), 1);
}
- }
+ } }
- #[test]
- fn stress_shared() {
+ test! { fn stress_shared() {
static AMT: uint = 1000;
static NTHREADS: uint = 8;
let (tx, rx) = sync_channel::<int>(0);
let (dtx, drx) = sync_channel::<()>(0);
- Thread::spawn(move|| {
+ spawn(move|| {
for _ in range(0, AMT * NTHREADS) {
- assert_eq!(rx.recv().unwrap(), 1);
+ assert_eq!(rx.recv(), 1);
}
match rx.try_recv() {
Ok(..) => panic!(),
_ => {}
}
- dtx.send(()).unwrap();
- }).detach();
+ dtx.send(());
+ });
for _ in range(0, NTHREADS) {
let tx = tx.clone();
- Thread::spawn(move|| {
- for _ in range(0, AMT) { tx.send(1).unwrap(); }
- }).detach();
+ spawn(move|| {
+ for _ in range(0, AMT) { tx.send(1); }
+ });
}
drop(tx);
- drx.recv().unwrap();
- }
+ drx.recv();
+ } }
- #[test]
- fn oneshot_single_thread_close_port_first() {
+ test! { fn oneshot_single_thread_close_port_first() {
// Simple test of closing without sending
let (_tx, rx) = sync_channel::<int>(0);
drop(rx);
- }
+ } }
- #[test]
- fn oneshot_single_thread_close_chan_first() {
+ test! { fn oneshot_single_thread_close_chan_first() {
// Simple test of closing without sending
let (tx, _rx) = sync_channel::<int>(0);
drop(tx);
- }
+ } }
- #[test]
- fn oneshot_single_thread_send_port_close() {
+ test! { fn oneshot_single_thread_send_port_close() {
// Testing that the sender cleans up the payload if receiver is closed
let (tx, rx) = sync_channel::<Box<int>>(0);
drop(rx);
- assert!(tx.send(box 0).is_err());
- }
+ tx.send(box 0);
+ } #[should_fail] }
- #[test]
- fn oneshot_single_thread_recv_chan_close() {
+ test! { fn oneshot_single_thread_recv_chan_close() {
// Receiving on a closed chan will panic
let res = Thread::spawn(move|| {
let (tx, rx) = sync_channel::<int>(0);
drop(tx);
- rx.recv().unwrap();
+ rx.recv();
}).join();
// What is our res?
assert!(res.is_err());
- }
+ } }
- #[test]
- fn oneshot_single_thread_send_then_recv() {
+ test! { fn oneshot_single_thread_send_then_recv() {
let (tx, rx) = sync_channel::<Box<int>>(1);
- tx.send(box 10).unwrap();
- assert!(rx.recv().unwrap() == box 10);
- }
+ tx.send(box 10);
+ assert!(rx.recv() == box 10);
+ } }
- #[test]
- fn oneshot_single_thread_try_send_open() {
+ test! { fn oneshot_single_thread_try_send_open() {
let (tx, rx) = sync_channel::<int>(1);
assert_eq!(tx.try_send(10), Ok(()));
- assert!(rx.recv().unwrap() == 10);
- }
+ assert!(rx.recv() == 10);
+ } }
- #[test]
- fn oneshot_single_thread_try_send_closed() {
+ test! { fn oneshot_single_thread_try_send_closed() {
let (tx, rx) = sync_channel::<int>(0);
drop(rx);
- assert_eq!(tx.try_send(10), Err(TrySendError::Disconnected(10)));
- }
+ assert_eq!(tx.try_send(10), Err(RecvDisconnected(10)));
+ } }
- #[test]
- fn oneshot_single_thread_try_send_closed2() {
+ test! { fn oneshot_single_thread_try_send_closed2() {
let (tx, _rx) = sync_channel::<int>(0);
- assert_eq!(tx.try_send(10), Err(TrySendError::Full(10)));
- }
+ assert_eq!(tx.try_send(10), Err(Full(10)));
+ } }
- #[test]
- fn oneshot_single_thread_try_recv_open() {
+ test! { fn oneshot_single_thread_try_recv_open() {
let (tx, rx) = sync_channel::<int>(1);
- tx.send(10).unwrap();
- assert!(rx.recv() == Ok(10));
- }
+ tx.send(10);
+ assert!(rx.recv_opt() == Ok(10));
+ } }
- #[test]
- fn oneshot_single_thread_try_recv_closed() {
+ test! { fn oneshot_single_thread_try_recv_closed() {
let (tx, rx) = sync_channel::<int>(0);
drop(tx);
- assert!(rx.recv().is_err());
- }
+ assert!(rx.recv_opt() == Err(()));
+ } }
- #[test]
- fn oneshot_single_thread_peek_data() {
+ test! { fn oneshot_single_thread_peek_data() {
let (tx, rx) = sync_channel::<int>(1);
- assert_eq!(rx.try_recv(), Err(TryRecvError::Empty));
- tx.send(10).unwrap();
+ assert_eq!(rx.try_recv(), Err(Empty));
+ tx.send(10);
assert_eq!(rx.try_recv(), Ok(10));
- }
+ } }
- #[test]
- fn oneshot_single_thread_peek_close() {
+ test! { fn oneshot_single_thread_peek_close() {
let (tx, rx) = sync_channel::<int>(0);
drop(tx);
- assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected));
- assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected));
- }
+ assert_eq!(rx.try_recv(), Err(Disconnected));
+ assert_eq!(rx.try_recv(), Err(Disconnected));
+ } }
- #[test]
- fn oneshot_single_thread_peek_open() {
+ test! { fn oneshot_single_thread_peek_open() {
let (_tx, rx) = sync_channel::<int>(0);
- assert_eq!(rx.try_recv(), Err(TryRecvError::Empty));
- }
+ assert_eq!(rx.try_recv(), Err(Empty));
+ } }
- #[test]
- fn oneshot_multi_task_recv_then_send() {
+ test! { fn oneshot_multi_task_recv_then_send() {
let (tx, rx) = sync_channel::<Box<int>>(0);
- let _t = Thread::spawn(move|| {
- assert!(rx.recv().unwrap() == box 10);
+ spawn(move|| {
+ assert!(rx.recv() == box 10);
});
- tx.send(box 10).unwrap();
- }
+ tx.send(box 10);
+ } }
- #[test]
- fn oneshot_multi_task_recv_then_close() {
+ test! { fn oneshot_multi_task_recv_then_close() {
let (tx, rx) = sync_channel::<Box<int>>(0);
- let _t = Thread::spawn(move|| {
+ spawn(move|| {
drop(tx);
});
let res = Thread::spawn(move|| {
- assert!(rx.recv().unwrap() == box 10);
+ assert!(rx.recv() == box 10);
}).join();
assert!(res.is_err());
- }
+ } }
- #[test]
- fn oneshot_multi_thread_close_stress() {
+ test! { fn oneshot_multi_thread_close_stress() {
for _ in range(0, stress_factor()) {
let (tx, rx) = sync_channel::<int>(0);
- let _t = Thread::spawn(move|| {
+ spawn(move|| {
drop(rx);
});
drop(tx);
}
- }
+ } }
- #[test]
- fn oneshot_multi_thread_send_close_stress() {
+ test! { fn oneshot_multi_thread_send_close_stress() {
for _ in range(0, stress_factor()) {
let (tx, rx) = sync_channel::<int>(0);
- let _t = Thread::spawn(move|| {
+ spawn(move|| {
drop(rx);
});
let _ = Thread::spawn(move || {
- tx.send(1).unwrap();
+ tx.send(1);
}).join();
}
- }
+ } }
- #[test]
- fn oneshot_multi_thread_recv_close_stress() {
+ test! { fn oneshot_multi_thread_recv_close_stress() {
for _ in range(0, stress_factor()) {
let (tx, rx) = sync_channel::<int>(0);
- let _t = Thread::spawn(move|| {
+ spawn(move|| {
let res = Thread::spawn(move|| {
- rx.recv().unwrap();
+ rx.recv();
}).join();
assert!(res.is_err());
});
- let _t = Thread::spawn(move|| {
- Thread::spawn(move|| {
+ spawn(move|| {
+ spawn(move|| {
drop(tx);
- }).detach();
+ });
});
}
- }
+ } }
- #[test]
- fn oneshot_multi_thread_send_recv_stress() {
+ test! { fn oneshot_multi_thread_send_recv_stress() {
for _ in range(0, stress_factor()) {
let (tx, rx) = sync_channel::<Box<int>>(0);
- let _t = Thread::spawn(move|| {
- tx.send(box 10i).unwrap();
+ spawn(move|| {
+ tx.send(box 10i);
+ });
+ spawn(move|| {
+ assert!(rx.recv() == box 10i);
});
- assert!(rx.recv().unwrap() == box 10i);
}
- }
+ } }
- #[test]
- fn stream_send_recv_stress() {
+ test! { fn stream_send_recv_stress() {
for _ in range(0, stress_factor()) {
let (tx, rx) = sync_channel::<Box<int>>(0);
fn send(tx: SyncSender<Box<int>>, i: int) {
if i == 10 { return }
- Thread::spawn(move|| {
- tx.send(box i).unwrap();
+ spawn(move|| {
+ tx.send(box i);
send(tx, i + 1);
- }).detach();
+ });
}
fn recv(rx: Receiver<Box<int>>, i: int) {
if i == 10 { return }
- Thread::spawn(move|| {
- assert!(rx.recv().unwrap() == box i);
+ spawn(move|| {
+ assert!(rx.recv() == box i);
recv(rx, i + 1);
- }).detach();
+ });
}
}
- }
+ } }
- #[test]
- fn recv_a_lot() {
+ test! { fn recv_a_lot() {
// Regression test that we don't run out of stack in scheduler context
let (tx, rx) = sync_channel(10000);
- for _ in range(0u, 10000) { tx.send(()).unwrap(); }
- for _ in range(0u, 10000) { rx.recv().unwrap(); }
- }
+ for _ in range(0u, 10000) { tx.send(()); }
+ for _ in range(0u, 10000) { rx.recv(); }
+ } }
- #[test]
- fn shared_chan_stress() {
+ test! { fn shared_chan_stress() {
let (tx, rx) = sync_channel(0);
let total = stress_factor() + 100;
for _ in range(0, total) {
let tx = tx.clone();
- Thread::spawn(move|| {
- tx.send(()).unwrap();
- }).detach();
+ spawn(move|| {
+ tx.send(());
+ });
}
for _ in range(0, total) {
- rx.recv().unwrap();
+ rx.recv();
}
- }
+ } }
- #[test]
- fn test_nested_recv_iter() {
+ test! { fn test_nested_recv_iter() {
let (tx, rx) = sync_channel::<int>(0);
let (total_tx, total_rx) = sync_channel::<int>(0);
- let _t = Thread::spawn(move|| {
+ spawn(move|| {
let mut acc = 0;
for x in rx.iter() {
acc += x;
}
- total_tx.send(acc).unwrap();
+ total_tx.send(acc);
});
- tx.send(3).unwrap();
- tx.send(1).unwrap();
- tx.send(2).unwrap();
+ tx.send(3);
+ tx.send(1);
+ tx.send(2);
drop(tx);
- assert_eq!(total_rx.recv().unwrap(), 6);
- }
+ assert_eq!(total_rx.recv(), 6);
+ } }
- #[test]
- fn test_recv_iter_break() {
+ test! { fn test_recv_iter_break() {
let (tx, rx) = sync_channel::<int>(0);
let (count_tx, count_rx) = sync_channel(0);
- let _t = Thread::spawn(move|| {
+ spawn(move|| {
let mut count = 0;
for x in rx.iter() {
if count >= 3 {
count += x;
}
}
- count_tx.send(count).unwrap();
+ count_tx.send(count);
});
- tx.send(2).unwrap();
- tx.send(2).unwrap();
- tx.send(2).unwrap();
+ tx.send(2);
+ tx.send(2);
+ tx.send(2);
let _ = tx.try_send(2);
drop(tx);
- assert_eq!(count_rx.recv().unwrap(), 4);
- }
+ assert_eq!(count_rx.recv(), 4);
+ } }
- #[test]
- fn try_recv_states() {
+ test! { fn try_recv_states() {
let (tx1, rx1) = sync_channel::<int>(1);
let (tx2, rx2) = sync_channel::<()>(1);
let (tx3, rx3) = sync_channel::<()>(1);
- let _t = Thread::spawn(move|| {
- rx2.recv().unwrap();
- tx1.send(1).unwrap();
- tx3.send(()).unwrap();
- rx2.recv().unwrap();
+ spawn(move|| {
+ rx2.recv();
+ tx1.send(1);
+ tx3.send(());
+ rx2.recv();
drop(tx1);
- tx3.send(()).unwrap();
+ tx3.send(());
});
- assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty));
- tx2.send(()).unwrap();
- rx3.recv().unwrap();
+ assert_eq!(rx1.try_recv(), Err(Empty));
+ tx2.send(());
+ rx3.recv();
assert_eq!(rx1.try_recv(), Ok(1));
- assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty));
- tx2.send(()).unwrap();
- rx3.recv().unwrap();
- assert_eq!(rx1.try_recv(), Err(TryRecvError::Disconnected));
- }
+ assert_eq!(rx1.try_recv(), Err(Empty));
+ tx2.send(());
+ rx3.recv();
+ assert_eq!(rx1.try_recv(), Err(Disconnected));
+ } }
// This bug used to end up in a livelock inside of the Receiver destructor
// because the internal state of the Shared packet was corrupted
- #[test]
- fn destroy_upgraded_shared_port_when_sender_still_active() {
+ test! { fn destroy_upgraded_shared_port_when_sender_still_active() {
let (tx, rx) = sync_channel::<()>(0);
let (tx2, rx2) = sync_channel::<()>(0);
- let _t = Thread::spawn(move|| {
- rx.recv().unwrap(); // wait on a oneshot
+ spawn(move|| {
+ rx.recv(); // wait on a oneshot
drop(rx); // destroy a shared
- tx2.send(()).unwrap();
+ tx2.send(());
});
// make sure the other task has gone to sleep
for _ in range(0u, 5000) { Thread::yield_now(); }
// upgrade to a shared chan and send a message
let t = tx.clone();
drop(tx);
- t.send(()).unwrap();
+ t.send(());
// wait for the child task to exit before we exit
- rx2.recv().unwrap();
- }
+ rx2.recv();
+ } }
- #[test]
- fn send1() {
+ test! { fn send_opt1() {
let (tx, rx) = sync_channel::<int>(0);
- let _t = Thread::spawn(move|| { rx.recv().unwrap(); });
- assert_eq!(tx.send(1), Ok(()));
- }
+ spawn(move|| { rx.recv(); });
+ assert_eq!(tx.send_opt(1), Ok(()));
+ } }
- #[test]
- fn send2() {
+ test! { fn send_opt2() {
let (tx, rx) = sync_channel::<int>(0);
- let _t = Thread::spawn(move|| { drop(rx); });
- assert!(tx.send(1).is_err());
- }
+ spawn(move|| { drop(rx); });
+ assert_eq!(tx.send_opt(1), Err(1));
+ } }
- #[test]
- fn send3() {
+ test! { fn send_opt3() {
let (tx, rx) = sync_channel::<int>(1);
- assert_eq!(tx.send(1), Ok(()));
- let _t =Thread::spawn(move|| { drop(rx); });
- assert!(tx.send(1).is_err());
- }
+ assert_eq!(tx.send_opt(1), Ok(()));
+ spawn(move|| { drop(rx); });
+ assert_eq!(tx.send_opt(1), Err(1));
+ } }
- #[test]
- fn send4() {
+ test! { fn send_opt4() {
let (tx, rx) = sync_channel::<int>(0);
let tx2 = tx.clone();
let (done, donerx) = channel();
let done2 = done.clone();
- let _t = Thread::spawn(move|| {
- assert!(tx.send(1).is_err());
- done.send(()).unwrap();
+ spawn(move|| {
+ assert_eq!(tx.send_opt(1), Err(1));
+ done.send(());
});
- let _t = Thread::spawn(move|| {
- assert!(tx2.send(2).is_err());
- done2.send(()).unwrap();
+ spawn(move|| {
+ assert_eq!(tx2.send_opt(2), Err(2));
+ done2.send(());
});
drop(rx);
- donerx.recv().unwrap();
- donerx.recv().unwrap();
- }
+ donerx.recv();
+ donerx.recv();
+ } }
- #[test]
- fn try_send1() {
+ test! { fn try_send1() {
let (tx, _rx) = sync_channel::<int>(0);
- assert_eq!(tx.try_send(1), Err(TrySendError::Full(1)));
- }
+ assert_eq!(tx.try_send(1), Err(Full(1)));
+ } }
- #[test]
- fn try_send2() {
+ test! { fn try_send2() {
let (tx, _rx) = sync_channel::<int>(1);
assert_eq!(tx.try_send(1), Ok(()));
- assert_eq!(tx.try_send(1), Err(TrySendError::Full(1)));
- }
+ assert_eq!(tx.try_send(1), Err(Full(1)));
+ } }
- #[test]
- fn try_send3() {
+ test! { fn try_send3() {
let (tx, rx) = sync_channel::<int>(1);
assert_eq!(tx.try_send(1), Ok(()));
drop(rx);
- assert_eq!(tx.try_send(1), Err(TrySendError::Disconnected(1)));
- }
+ assert_eq!(tx.try_send(1), Err(RecvDisconnected(1)));
+ } }
- #[test]
- fn issue_15761() {
+ test! { fn try_send4() {
+ let (tx, rx) = sync_channel::<int>(0);
+ spawn(move|| {
+ for _ in range(0u, 1000) { Thread::yield_now(); }
+ assert_eq!(tx.try_send(1), Ok(()));
+ });
+ assert_eq!(rx.recv(), 1);
+ } #[ignore(reason = "flaky on libnative")] }
+
+ test! { fn issue_15761() {
fn repro() {
let (tx1, rx1) = sync_channel::<()>(3);
let (tx2, rx2) = sync_channel::<()>(3);
- let _t = Thread::spawn(move|| {
- rx1.recv().unwrap();
+ spawn(move|| {
+ rx1.recv();
tx2.try_send(()).unwrap();
});
tx1.try_send(()).unwrap();
- rx2.recv().unwrap();
+ rx2.recv();
}
for _ in range(0u, 100) {
repro()
}
- }
+ } }
}
/// ```
/// use std::sync::RWLock;
///
-/// let lock = RWLock::new(5i);
+/// let lock = RWLock::new(5);
///
/// // many reader locks can be held at once
/// {
use io::{self, IoError, IoResult};
use prelude::v1::*;
use sys::{last_error, retry};
-use c_str::CString;
+use ffi::CString;
use num::Int;
use path::BytesContainer;
use collections;
use self::SocketStatus::*;
use self::InAddr::*;
-use c_str::ToCStr;
+use ffi::CString;
+use ffi;
use io::net::addrinfo;
use io::net::ip::{SocketAddr, IpAddr, Ipv4Addr, Ipv6Addr};
use io::{IoResult, IoError};
use libc::{self, c_char, c_int};
-use c_str::CString;
use mem;
use num::Int;
use ptr::{self, null, null_mut};
+use str;
use sys::{self, retry, c, sock_t, last_error, last_net_error, last_gai_error, close_sock,
wrlen, msglen_t, os, wouldblock, set_nonblocking, timer, ms_to_timeval,
decode_error_detailed};
assert!(host.is_some() || servname.is_some());
- let c_host = host.map(|x| x.to_c_str());
+ let c_host = host.map(|x| CString::from_slice(x.as_bytes()));
let c_host = c_host.as_ref().map(|x| x.as_ptr()).unwrap_or(null());
- let c_serv = servname.map(|x| x.to_c_str());
+ let c_serv = servname.map(|x| CString::from_slice(x.as_bytes()));
let c_serv = c_serv.as_ref().map(|x| x.as_ptr()).unwrap_or(null());
let hint = hint.map(|hint| {
}
unsafe {
- Ok(CString::new(hostbuf.as_ptr(), false).as_str().unwrap().to_string())
+ Ok(str::from_utf8(ffi::c_str_to_bytes(&hostbuf.as_ptr()))
+ .unwrap().to_string())
}
}
/// to symbols. This is a bit of a hokey implementation as-is, but it works for
/// all unix platforms we support right now, so it at least gets the job done.
-use c_str::CString;
-use io::{IoResult, Writer};
+use prelude::v1::*;
+
+use ffi;
+use io::IoResult;
use libc;
use mem;
-use option::Option::{self, Some, None};
-use result::Result::{Ok, Err};
+use str;
use sync::{StaticMutex, MUTEX_INIT};
use sys_common::backtrace::*;
#[cfg(all(target_os = "ios", target_arch = "arm"))]
#[inline(never)]
pub fn write(w: &mut Writer) -> IoResult<()> {
- use iter::{IteratorExt, range};
use result;
- use slice::SliceExt;
extern {
fn backtrace(buf: *mut *mut libc::c_void,
output(w, idx,addr, None)
} else {
output(w, idx, addr, Some(unsafe {
- CString::new(info.dli_sname, false)
+ ffi::c_str_to_bytes(&info.dli_sname)
}))
}
}
#[cfg(not(any(target_os = "macos", target_os = "ios")))]
fn print(w: &mut Writer, idx: int, addr: *mut libc::c_void) -> IoResult<()> {
- use iter::{Iterator, IteratorExt};
use os;
- use path::GenericPath;
- use ptr::PtrExt;
use ptr;
- use slice::SliceExt;
////////////////////////////////////////////////////////////////////////
// libbacktrace.h API
if ret == 0 || data.is_null() {
output(w, idx, addr, None)
} else {
- output(w, idx, addr, Some(unsafe { CString::new(data, false) }))
+ output(w, idx, addr, Some(unsafe { ffi::c_str_to_bytes(&data) }))
}
}
// Finally, after all that work above, we can emit a symbol.
fn output(w: &mut Writer, idx: int, addr: *mut libc::c_void,
- s: Option<CString>) -> IoResult<()> {
+ s: Option<&[u8]>) -> IoResult<()> {
try!(write!(w, " {:2}: {:2$} - ", idx, addr, HEX_WIDTH));
- match s.as_ref().and_then(|c| c.as_str()) {
+ match s.and_then(|s| str::from_utf8(s).ok()) {
Some(string) => try!(demangle(w, string)),
None => try!(write!(w, "<unknown>")),
}
use prelude::v1::*;
-use c_str::{CString, ToCStr};
+use ffi::{self, CString};
use io::{FilePermission, Write, UnstableFileStat, Open, FileAccess, FileMode};
use io::{IoResult, FileStat, SeekStyle};
use io::{Read, Truncate, SeekCur, SeekSet, ReadWrite, SeekEnd, Append};
}
}
+fn cstr(path: &Path) -> CString {
+ CString::from_slice(path.as_vec())
+}
+
pub fn open(path: &Path, fm: FileMode, fa: FileAccess) -> IoResult<FileDesc> {
let flags = match fm {
Open => 0,
libc::S_IRUSR | libc::S_IWUSR),
};
- let path = path.to_c_str();
+ let path = cstr(path);
match retry(|| unsafe { libc::open(path.as_ptr(), flags, mode) }) {
-1 => Err(super::last_error()),
fd => Ok(FileDesc::new(fd, true)),
}
pub fn mkdir(p: &Path, mode: uint) -> IoResult<()> {
- let p = p.to_c_str();
+ let p = cstr(p);
mkerr_libc(unsafe { libc::mkdir(p.as_ptr(), mode as libc::mode_t) })
}
use libc::{opendir, readdir_r, closedir};
fn prune(root: &CString, dirs: Vec<Path>) -> Vec<Path> {
- let root = unsafe { CString::new(root.as_ptr(), false) };
let root = Path::new(root);
dirs.into_iter().filter(|path| {
let mut buf = Vec::<u8>::with_capacity(size as uint);
let ptr = buf.as_mut_ptr() as *mut dirent_t;
- let p = p.to_c_str();
+ let p = CString::from_slice(p.as_vec());
let dir_ptr = unsafe {opendir(p.as_ptr())};
if dir_ptr as uint != 0 {
let mut entry_ptr = 0 as *mut dirent_t;
while unsafe { readdir_r(dir_ptr, ptr, &mut entry_ptr) == 0 } {
if entry_ptr.is_null() { break }
- let cstr = unsafe {
- CString::new(rust_list_dir_val(entry_ptr), false)
- };
- paths.push(Path::new(cstr));
+ paths.push(unsafe {
+ Path::new(ffi::c_str_to_bytes(&rust_list_dir_val(entry_ptr)))
+ });
}
assert_eq!(unsafe { closedir(dir_ptr) }, 0);
Ok(prune(&p, paths))
}
pub fn unlink(p: &Path) -> IoResult<()> {
- let p = p.to_c_str();
+ let p = cstr(p);
mkerr_libc(unsafe { libc::unlink(p.as_ptr()) })
}
pub fn rename(old: &Path, new: &Path) -> IoResult<()> {
- let old = old.to_c_str();
- let new = new.to_c_str();
+ let old = cstr(old);
+ let new = cstr(new);
mkerr_libc(unsafe {
libc::rename(old.as_ptr(), new.as_ptr())
})
}
pub fn chmod(p: &Path, mode: uint) -> IoResult<()> {
- let p = p.to_c_str();
+ let p = cstr(p);
mkerr_libc(retry(|| unsafe {
libc::chmod(p.as_ptr(), mode as libc::mode_t)
}))
}
pub fn rmdir(p: &Path) -> IoResult<()> {
- let p = p.to_c_str();
+ let p = cstr(p);
mkerr_libc(unsafe { libc::rmdir(p.as_ptr()) })
}
pub fn chown(p: &Path, uid: int, gid: int) -> IoResult<()> {
- let p = p.to_c_str();
+ let p = cstr(p);
mkerr_libc(retry(|| unsafe {
libc::chown(p.as_ptr(), uid as libc::uid_t, gid as libc::gid_t)
}))
}
pub fn readlink(p: &Path) -> IoResult<Path> {
- let c_path = p.to_c_str();
+ let c_path = cstr(p);
let p = c_path.as_ptr();
let mut len = unsafe { libc::pathconf(p as *mut _, libc::_PC_NAME_MAX) };
if len == -1 {
}
pub fn symlink(src: &Path, dst: &Path) -> IoResult<()> {
- let src = src.to_c_str();
- let dst = dst.to_c_str();
+ let src = cstr(src);
+ let dst = cstr(dst);
mkerr_libc(unsafe { libc::symlink(src.as_ptr(), dst.as_ptr()) })
}
pub fn link(src: &Path, dst: &Path) -> IoResult<()> {
- let src = src.to_c_str();
- let dst = dst.to_c_str();
+ let src = cstr(src);
+ let dst = cstr(dst);
mkerr_libc(unsafe { libc::link(src.as_ptr(), dst.as_ptr()) })
}
}
pub fn stat(p: &Path) -> IoResult<FileStat> {
- let p = p.to_c_str();
+ let p = cstr(p);
let mut stat: libc::stat = unsafe { mem::zeroed() };
match unsafe { libc::stat(p.as_ptr(), &mut stat) } {
0 => Ok(mkstat(&stat)),
}
pub fn lstat(p: &Path) -> IoResult<FileStat> {
- let p = p.to_c_str();
+ let p = cstr(p);
let mut stat: libc::stat = unsafe { mem::zeroed() };
match unsafe { libc::lstat(p.as_ptr(), &mut stat) } {
0 => Ok(mkstat(&stat)),
}
pub fn utime(p: &Path, atime: u64, mtime: u64) -> IoResult<()> {
- let p = p.to_c_str();
+ let p = cstr(p);
let buf = libc::utimbuf {
actime: (atime / 1000) as libc::time_t,
modtime: (mtime / 1000) as libc::time_t,
#![allow(unused_unsafe)]
#![allow(unused_mut)]
-extern crate libc;
-
-use num;
-use num::{Int, SignedInt};
use prelude::v1::*;
+
+use ffi;
use io::{self, IoResult, IoError};
+use libc;
+use num::{Int, SignedInt};
+use num;
+use str;
use sys_common::mkerr_libc;
macro_rules! helper_init { (static $name:ident: Helper<$m:ty>) => (
}
pub fn last_gai_error(s: libc::c_int) -> IoError {
- use c_str::CString;
let mut err = decode_error(s);
err.detail = Some(unsafe {
- CString::new(gai_strerror(s), false).as_str().unwrap().to_string()
+ str::from_utf8(ffi::c_str_to_bytes(&gai_strerror(s))).unwrap().to_string()
});
err
}
use prelude::v1::*;
-use c_str::ToCStr;
use error::{FromError, Error};
+use ffi::{self, CString};
use fmt;
use io::{IoError, IoResult};
use libc::{self, c_int, c_char, c_void};
+use os::TMPBUF_SZ;
use os;
use path::{BytesContainer};
use ptr;
+use str;
use sys::fs::FileDesc;
-use os::TMPBUF_SZ;
-
const BUF_BYTES : uint = 2048u;
/// Returns the platform-specific value of errno
panic!("strerror_r failure");
}
- String::from_raw_buf(p as *const u8)
+ let p = p as *const _;
+ str::from_utf8(ffi::c_str_to_bytes(&p)).unwrap().to_string()
}
}
}
pub fn getcwd() -> IoResult<Path> {
- use c_str::CString;
-
let mut buf = [0 as c_char; BUF_BYTES];
unsafe {
if libc::getcwd(buf.as_mut_ptr(), buf.len() as libc::size_t).is_null() {
Err(IoError::last_error())
} else {
- Ok(Path::new(CString::new(buf.as_ptr(), false)))
+ Ok(Path::new(ffi::c_str_to_bytes(&buf.as_ptr())))
}
}
}
pub unsafe fn get_env_pairs() -> Vec<Vec<u8>> {
- use c_str::CString;
-
extern {
fn rust_env_pairs() -> *const *const c_char;
}
}
let mut result = Vec::new();
while *environ != 0 as *const _ {
- let env_pair =
- CString::new(*environ, false).as_bytes_no_nul().to_vec();
+ let env_pair = ffi::c_str_to_bytes(&*environ).to_vec();
result.push(env_pair);
environ = environ.offset(1);
}
}
pub fn chdir(p: &Path) -> IoResult<()> {
- p.with_c_str(|buf| {
- unsafe {
- match libc::chdir(buf) == (0 as c_int) {
- true => Ok(()),
- false => Err(IoError::last_error()),
- }
+ let p = CString::from_slice(p.as_vec());
+ unsafe {
+ match libc::chdir(p.as_ptr()) == (0 as c_int) {
+ true => Ok(()),
+ false => Err(IoError::last_error()),
}
- })
+ }
}
pub fn page_size() -> uint {
use prelude::v1::*;
+use ffi::CString;
use libc;
-use c_str::CString;
use mem;
use sync::{Arc, Mutex};
use sync::atomic::{AtomicBool, Ordering};
}
s.sun_family = libc::AF_UNIX as libc::sa_family_t;
for (slot, value) in s.sun_path.iter_mut().zip(addr.iter()) {
- *slot = value;
+ *slot = *value;
}
// count the null terminator
use prelude::v1::*;
use self::Req::*;
-use c_str::{CString, ToCStr};
use collections;
+use ffi::CString;
use hash::Hash;
use io::process::{ProcessExit, ExitStatus, ExitSignal};
use io::{self, IoResult, IoError, EndOfFile};
// We may use this in the child, so perform allocations before the
// fork
- let devnull = "/dev/null".to_c_str();
+ let devnull = b"/dev/null\0";
set_cloexec(output.fd());
} else {
libc::O_RDWR
};
- libc::open(devnull.as_ptr(), flags, 0)
+ libc::open(devnull.as_ptr() as *const _, flags, 0)
}
Some(obj) => {
let fd = obj.as_inner().fd();
use mem;
use os;
use ptr;
-use sync::atomic::{mod, Ordering};
+use sync::atomic::{self, Ordering};
use sync::mpsc::{channel, Sender, Receiver, TryRecvError};
use sys::c;
use sys::fs::FileDesc;
/// copy of that function in my mingw install (maybe it was broken?). Instead,
/// this takes the route of using StackWalk64 in order to walk the stack.
-use c_str::CString;
+use dynamic_lib::DynamicLibrary;
+use ffi;
use intrinsics;
use io::{IoResult, Writer};
use libc;
use option::Option::{Some, None};
use path::Path;
use result::Result::{Ok, Err};
-use sync::{StaticMutex, MUTEX_INIT};
use slice::SliceExt;
-use str::StrExt;
-use dynamic_lib::DynamicLibrary;
+use str::{self, StrExt};
+use sync::{StaticMutex, MUTEX_INIT};
use sys_common::backtrace::*;
if ret == libc::TRUE {
try!(write!(w, " - "));
- let cstr = unsafe { CString::new(info.Name.as_ptr(), false) };
- let bytes = cstr.as_bytes();
- match cstr.as_str() {
- Some(s) => try!(demangle(w, s)),
- None => try!(w.write(bytes[..bytes.len()-1])),
+ let ptr = info.Name.as_ptr() as *const libc::c_char;
+ let bytes = unsafe { ffi::c_str_to_bytes(&ptr) };
+ match str::from_utf8(bytes) {
+ Ok(s) => try!(demangle(w, s)),
+ Err(..) => try!(w.write(bytes[..bytes.len()-1])),
}
}
try!(w.write(&['\n' as u8]));
use intrinsics::{atomic_store_relaxed, transmute};
use libc::types::os::arch::extra::{LPCWSTR, HMODULE, LPCSTR, LPVOID};
use prelude::v1::*;
- use c_str::ToCStr;
+ use ffi::CString;
extern "system" {
fn GetModuleHandleW(lpModuleName: LPCWSTR) -> HMODULE;
unsafe fn store_func(ptr: *mut uint, module: &str, symbol: &str, fallback: uint) {
let mut module: Vec<u16> = module.utf16_units().collect();
module.push(0);
- symbol.with_c_str(|symbol| {
- let handle = GetModuleHandleW(module.as_ptr());
- let func: uint = transmute(GetProcAddress(handle, symbol));
- atomic_store_relaxed(ptr, if func == 0 {
- fallback
- } else {
- func
- })
+ let symbol = CString::from_slice(symbol.as_bytes());
+ let handle = GetModuleHandleW(module.as_ptr());
+ let func: uint = transmute(GetProcAddress(handle, symbol.as_ptr()));
+ atomic_store_relaxed(ptr, if func == 0 {
+ fallback
+ } else {
+ func
})
}
use alloc::arc::Arc;
use libc::{self, c_int};
-use c_str::CString;
use mem;
use sys::os::fill_utf16_buf_and_decode;
use path;
use prelude::v1::*;
use libc;
-use c_str::CString;
+use ffi::CString;
+use io::{self, IoError, IoResult};
use mem;
use ptr;
-use sync::{Arc, Mutex};
+use str;
use sync::atomic::{AtomicBool, Ordering};
-use io::{self, IoError, IoResult};
+use sync::{Arc, Mutex};
use sys_common::{self, eof};
-use super::{c, os, timer, to_utf16, decode_error_detailed};
+use super::{c, os, timer, decode_error_detailed};
+
+fn to_utf16(c: &CString) -> IoResult<Vec<u16>> {
+ super::to_utf16(str::from_utf8(c.as_bytes()).ok())
+}
struct Event(libc::HANDLE);
}
pub fn connect(addr: &CString, timeout: Option<u64>) -> IoResult<UnixStream> {
- let addr = try!(to_utf16(addr.as_str()));
+ let addr = try!(to_utf16(addr));
let start = timer::now();
loop {
match UnixStream::try_connect(addr.as_ptr()) {
// Although we technically don't need the pipe until much later, we
// create the initial handle up front to test the validity of the name
// and such.
- let addr_v = try!(to_utf16(addr.as_str()));
+ let addr_v = try!(to_utf16(addr));
let ret = unsafe { pipe(addr_v.as_ptr(), true) };
if ret == libc::INVALID_HANDLE_VALUE {
Err(super::last_error())
// proceed in accepting new clients in the future
if self.inner.closed.load(Ordering::SeqCst) { return Err(eof()) }
- let name = try!(to_utf16(self.listener.name.as_str()));
+ let name = try!(to_utf16(&self.listener.name));
// Once we've got a "server handle", we need to wait for a client to
// connect. The ConnectNamedPipe function will block this thread until
impl Clone for UnixAcceptor {
fn clone(&self) -> UnixAcceptor {
- let name = to_utf16(self.listener.name.as_str()).ok().unwrap();
+ let name = to_utf16(&self.listener.name).ok().unwrap();
UnixAcceptor {
inner: self.inner.clone(),
event: Event::new(true, false).ok().unwrap(),
use prelude::v1::*;
+use collections;
+use ffi::CString;
+use hash::Hash;
+use io::fs::PathExtensions;
+use io::process::{ProcessExit, ExitStatus, ExitSignal};
+use io::{IoResult, IoError};
+use io;
use libc::{pid_t, c_void, c_int};
use libc;
-use c_str::{CString, ToCStr};
-use io;
use mem;
use os;
-use ptr;
-use io::process::{ProcessExit, ExitStatus, ExitSignal};
-use collections;
use path::BytesContainer;
-use hash::Hash;
-use io::{IoResult, IoError};
-
+use ptr;
+use str;
+use sys::fs::FileDesc;
use sys::fs;
use sys::{self, retry, c, wouldblock, set_nonblocking, ms_to_timeval, timer};
-use sys::fs::FileDesc;
use sys_common::helper_thread::Helper;
use sys_common::{AsInner, mkerr_libc, timeout};
-use io::fs::PathExtensions;
-
pub use sys_common::ProcessConfig;
/// A value representing a child process.
// Split the value and test each path to see if the
// program exists.
for path in os::split_paths(v.container_as_bytes()).into_iter() {
- let path = path.join(cfg.program().as_bytes_no_nul())
+ let path = path.join(cfg.program().as_bytes())
.with_extension(os::consts::EXE_EXTENSION);
if path.exists() {
- return Some(path.to_c_str())
+ return Some(CString::from_slice(path.as_vec()))
}
}
break
fn make_command_line(prog: &CString, args: &[CString]) -> String {
let mut cmd = String::new();
- append_arg(&mut cmd, prog.as_str()
+ append_arg(&mut cmd, str::from_utf8(prog.as_bytes()).ok()
.expect("expected program name to be utf-8 encoded"));
for arg in args.iter() {
cmd.push(' ');
- append_arg(&mut cmd, arg.as_str()
+ append_arg(&mut cmd, str::from_utf8(arg.as_bytes()).ok()
.expect("expected argument to be utf-8 encoded"));
}
return cmd;
{
match d {
Some(dir) => {
- let dir_str = dir.as_str()
+ let dir_str = str::from_utf8(dir.as_bytes()).ok()
.expect("expected workingdirectory to be utf-8 encoded");
let mut dir_str: Vec<u16> = dir_str.utf16_units().collect();
dir_str.push(0);
mod test {
use prelude::v1::*;
- use any::{Any, AnyRefExt};
+ use any::Any;
use sync::mpsc::{channel, Sender};
use boxed::BoxAny;
use result;
/// A mark represents a unique id associated with a macro expansion
pub type Mrk = u32;
+#[cfg(stage0)]
impl<S: Encoder<E>, E> Encodable<S, E> for Ident {
fn encode(&self, s: &mut S) -> Result<(), E> {
s.emit_str(token::get_ident(*self).get())
}
}
+#[cfg(not(stage0))]
+impl Encodable for Ident {
+ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+ s.emit_str(token::get_ident(*self).get())
+ }
+}
+
+#[cfg(stage0)]
impl<D: Decoder<E>, E> Decodable<D, E> for Ident {
fn decode(d: &mut D) -> Result<Ident, E> {
Ok(str_to_ident(try!(d.read_str())[]))
}
}
+#[cfg(not(stage0))]
+impl Decodable for Ident {
+ fn decode<D: Decoder>(d: &mut D) -> Result<Ident, D::Error> {
+ Ok(str_to_ident(try!(d.read_str())[]))
+ }
+}
+
/// Function name (not all functions have names)
pub type FnIdent = Option<Ident>;
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Show)]
pub enum Lit_ {
LitStr(InternedString, StrStyle),
- LitBinary(Rc<Vec<u8> >),
+ LitBinary(Rc<Vec<u8>>),
LitByte(u8),
LitChar(char),
LitInt(u64, LitIntType),
TyPtr(MutTy),
/// A reference (`&'a T` or `&'a mut T`)
TyRptr(Option<Lifetime>, MutTy),
- /// A closure (e.g. `|uint| -> bool`)
- TyClosure(P<ClosureTy>),
/// A bare function (e.g. `fn(uint) -> bool`)
TyBareFn(P<BareFnTy>),
/// A tuple (`(A, B, C, D,...)`)
}
}
+#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)]
+pub enum ImplPolarity {
+ /// impl Trait for Type
+ Positive,
+ /// impl !Trait for Type
+ Negative,
+}
+
+impl fmt::Show for ImplPolarity {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ ImplPolarity::Positive => "positive".fmt(f),
+ ImplPolarity::Negative => "negative".fmt(f),
+ }
+ }
+}
+
+
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Show)]
pub enum FunctionRetTy {
/// Functions with return type ! that always
TyParamBounds,
Vec<TraitItem>),
ItemImpl(Unsafety,
+ ImplPolarity,
Generics,
Option<TraitRef>, // (optional) trait this impl implements
P<Ty>, // self
// are ASTs encodable?
#[test]
fn check_asts_encodable() {
- use std::io;
- let e = Crate {
- module: Mod {
- inner: Span {
- lo: BytePos(11),
- hi: BytePos(19),
- expn_id: NO_EXPANSION,
- },
- view_items: Vec::new(),
- items: Vec::new(),
- },
- attrs: Vec::new(),
- config: Vec::new(),
- span: Span {
- lo: BytePos(10),
- hi: BytePos(20),
- expn_id: NO_EXPANSION,
- },
- exported_macros: Vec::new(),
- };
- // doesn't matter which encoder we use....
- let _f = &e as &serialize::Encodable<json::Encoder, fmt::Error>;
+ fn assert_encodable<T: serialize::Encodable>() {}
+ assert_encodable::<Crate>();
}
}
let parent = self.parent;
self.parent = i.id;
match i.node {
- ItemImpl(_, _, _, _, ref impl_items) => {
+ ItemImpl(_, _, _, _, _, ref impl_items) => {
for impl_item in impl_items.iter() {
match *impl_item {
MethodImplItem(ref m) => {
fn visit_ty(&mut self, ty: &'ast Ty) {
match ty.node {
- TyClosure(ref fd) => {
- self.visit_fn_decl(&*fd.decl);
- }
TyBareFn(ref fd) => {
self.visit_fn_decl(&*fd.decl);
}
impl Eq for Span {}
+#[cfg(stage0)]
impl<S:Encoder<E>, E> Encodable<S, E> for Span {
/* Note #1972 -- spans are encoded but not decoded */
fn encode(&self, s: &mut S) -> Result<(), E> {
}
}
+#[cfg(not(stage0))]
+impl Encodable for Span {
+ /* Note #1972 -- spans are encoded but not decoded */
+ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+ s.emit_nil()
+ }
+}
+
+#[cfg(stage0)]
impl<D:Decoder<E>, E> Decodable<D, E> for Span {
fn decode(_d: &mut D) -> Result<Span, E> {
Ok(DUMMY_SP)
}
}
+#[cfg(not(stage0))]
+impl Decodable for Span {
+ fn decode<D: Decoder>(_d: &mut D) -> Result<Span, D::Error> {
+ Ok(DUMMY_SP)
+ }
+}
+
pub fn spanned<T>(lo: BytePos, hi: BytePos, t: T) -> Spanned<T> {
respan(mk_sp(lo, hi), t)
}
F: FnMut(&[ast::Attribute]) -> bool
{
let item = match item {
- ast::ItemImpl(u, a, b, c, impl_items) => {
+ ast::ItemImpl(u, o, a, b, c, impl_items) => {
let impl_items = impl_items.into_iter()
.filter(|ii| impl_item_in_cfg(cx, ii))
.collect();
- ast::ItemImpl(u, a, b, c, impl_items)
+ ast::ItemImpl(u, o, a, b, c, impl_items)
}
ast::ItemTrait(u, a, b, methods) => {
let methods = methods.into_iter()
args: Vec::new(),
ret_ty: Self,
attributes: attrs,
- combine_substructure: combine_substructure(|c, s, sub| {
+ combine_substructure: combine_substructure(box |c, s, sub| {
cs_clone("Clone", c, s, sub)
}),
}
cx.expr_binary(span, ast::BiAnd, subexpr, eq)
},
cx.expr_bool(span, true),
- |cx, span, _, _| cx.expr_bool(span, false),
+ box |cx, span, _, _| cx.expr_bool(span, false),
cx, span, substr)
}
fn cs_ne(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<Expr> {
cx.expr_binary(span, ast::BiOr, subexpr, eq)
},
cx.expr_bool(span, false),
- |cx, span, _, _| cx.expr_bool(span, true),
+ box |cx, span, _, _| cx.expr_bool(span, true),
cx, span, substr)
}
args: vec!(borrowed_self()),
ret_ty: Literal(Path::new(vec!("bool"))),
attributes: attrs,
- combine_substructure: combine_substructure(|a, b, c| {
+ combine_substructure: combine_substructure(box |a, b, c| {
$f(a, b, c)
})
}
args: vec!(borrowed_self()),
ret_ty: Literal(Path::new(vec!("bool"))),
attributes: attrs,
- combine_substructure: combine_substructure(|cx, span, substr| {
+ combine_substructure: combine_substructure(box |cx, span, substr| {
cs_op($op, $equal, cx, span, substr)
})
}
args: vec![borrowed_self()],
ret_ty: ret_ty,
attributes: attrs,
- combine_substructure: combine_substructure(|cx, span, substr| {
+ combine_substructure: combine_substructure(box |cx, span, substr| {
cs_partial_cmp(cx, span, substr)
})
};
cx.expr_block(cx.block(span, vec!(assign), Some(if_)))
},
equals_expr.clone(),
- |cx, span, (self_args, tag_tuple), _non_self_args| {
+ box |cx, span, (self_args, tag_tuple), _non_self_args| {
if self_args.len() != 2 {
cx.span_bug(span, "not exactly 2 arguments in `deriving(PartialOrd)`")
} else {
cx.expr_binary(span, ast::BiOr, cmp, and)
},
cx.expr_bool(span, equal),
- |cx, span, (self_args, tag_tuple), _non_self_args| {
+ box |cx, span, (self_args, tag_tuple), _non_self_args| {
if self_args.len() != 2 {
cx.span_bug(span, "not exactly 2 arguments in `deriving(PartialOrd)`")
} else {
let block = cx.block(span, stmts, None);
cx.expr_block(block)
},
- |cx, sp, _, _| cx.span_bug(sp, "non matching enums in deriving(Eq)?"),
+ box |cx, sp, _, _| cx.span_bug(sp, "non matching enums in deriving(Eq)?"),
cx,
span,
substr)
args: vec!(),
ret_ty: nil_ty(),
attributes: attrs,
- combine_substructure: combine_substructure(|a, b, c| {
+ combine_substructure: combine_substructure(box |a, b, c| {
cs_total_eq_assert(a, b, c)
})
}
args: vec!(borrowed_self()),
ret_ty: Literal(Path::new(vec!("std", "cmp", "Ordering"))),
attributes: attrs,
- combine_substructure: combine_substructure(|a, b, c| {
+ combine_substructure: combine_substructure(box |a, b, c| {
cs_cmp(a, b, c)
}),
}
cx.expr_block(cx.block(span, vec!(assign), Some(if_)))
},
cx.expr_path(equals_path.clone()),
- |cx, span, (self_args, tag_tuple), _non_self_args| {
+ box |cx, span, (self_args, tag_tuple), _non_self_args| {
if self_args.len() != 2 {
cx.span_bug(span, "not exactly 2 arguments in `deriving(Ord)`")
} else {
let trait_def = TraitDef {
span: span,
attributes: Vec::new(),
- path: Path::new_(vec!(krate, "Decodable"), None,
- vec!(box Literal(Path::new_local("__D")),
- box Literal(Path::new_local("__E"))), true),
+ path: Path::new_(vec!(krate, "Decodable"), None, vec!(), true),
additional_bounds: Vec::new(),
- generics: LifetimeBounds {
- lifetimes: Vec::new(),
- bounds: vec!(("__D", vec!(Path::new_(
- vec!(krate, "Decoder"), None,
- vec!(box Literal(Path::new_local("__E"))), true))),
- ("__E", vec!()))
- },
+ generics: LifetimeBounds::empty(),
methods: vec!(
MethodDef {
name: "decode",
- generics: LifetimeBounds::empty(),
+ generics: LifetimeBounds {
+ lifetimes: Vec::new(),
+ bounds: vec!(("__D", vec!(Path::new_(
+ vec!(krate, "Decoder"), None,
+ vec!(), true))))
+ },
explicit_self: None,
args: vec!(Ptr(box Literal(Path::new_local("__D")),
Borrowed(None, MutMutable))),
- ret_ty: Literal(Path::new_(vec!("std", "result", "Result"), None,
- vec!(box Self,
- box Literal(Path::new_local("__E"))), true)),
+ ret_ty: Literal(Path::new_(
+ vec!("std", "result", "Result"),
+ None,
+ vec!(box Self, box Literal(Path::new_(
+ vec!["__D", "Error"], None, vec![], false
+ ))),
+ true
+ )),
attributes: Vec::new(),
- combine_substructure: combine_substructure(|a, b, c| {
+ combine_substructure: combine_substructure(box |a, b, c| {
decodable_substructure(a, b, c, krate)
}),
})
args: Vec::new(),
ret_ty: Self,
attributes: attrs,
- combine_substructure: combine_substructure(|a, b, c| {
+ combine_substructure: combine_substructure(box |a, b, c| {
default_substructure(a, b, c)
})
})
let trait_def = TraitDef {
span: span,
attributes: Vec::new(),
- path: Path::new_(vec!(krate, "Encodable"), None,
- vec!(box Literal(Path::new_local("__S")),
- box Literal(Path::new_local("__E"))), true),
+ path: Path::new_(vec!(krate, "Encodable"), None, vec!(), true),
additional_bounds: Vec::new(),
- generics: LifetimeBounds {
- lifetimes: Vec::new(),
- bounds: vec!(("__S", vec!(Path::new_(
- vec!(krate, "Encoder"), None,
- vec!(box Literal(Path::new_local("__E"))), true))),
- ("__E", vec!()))
- },
+ generics: LifetimeBounds::empty(),
methods: vec!(
MethodDef {
name: "encode",
- generics: LifetimeBounds::empty(),
+ generics: LifetimeBounds {
+ lifetimes: Vec::new(),
+ bounds: vec!(("__S", vec!(Path::new_(
+ vec!(krate, "Encoder"), None,
+ vec!(), true))))
+ },
explicit_self: borrowed_explicit_self(),
args: vec!(Ptr(box Literal(Path::new_local("__S")),
Borrowed(None, MutMutable))),
- ret_ty: Literal(Path::new_(vec!("std", "result", "Result"),
- None,
- vec!(box Tuple(Vec::new()),
- box Literal(Path::new_local("__E"))),
- true)),
+ ret_ty: Literal(Path::new_(
+ vec!("std", "result", "Result"),
+ None,
+ vec!(box Tuple(Vec::new()), box Literal(Path::new_(
+ vec!["__S", "Error"], None, vec![], false
+ ))),
+ true
+ )),
attributes: Vec::new(),
- combine_substructure: combine_substructure(|a, b, c| {
+ combine_substructure: combine_substructure(box |a, b, c| {
encodable_substructure(a, b, c)
}),
})
/// Combine the values of all the fields together. The last argument is
/// all the fields of all the structures.
pub type CombineSubstructureFunc<'a> =
- |&mut ExtCtxt, Span, &Substructure|: 'a -> P<Expr>;
+ Box<FnMut(&mut ExtCtxt, Span, &Substructure) -> P<Expr> + 'a>;
/// Deal with non-matching enum variants. The tuple is a list of
/// identifiers (one for each `Self` argument, which could be any of the
/// holding the variant index value for each of the `Self` arguments. The
/// last argument is all the non-`Self` args of the method being derived.
pub type EnumNonMatchCollapsedFunc<'a> =
- |&mut ExtCtxt,
- Span,
- (&[Ident], &[Ident]),
- &[P<Expr>]|: 'a
- -> P<Expr>;
+ Box<FnMut(&mut ExtCtxt, Span, (&[Ident], &[Ident]), &[P<Expr>]) -> P<Expr> + 'a>;
pub fn combine_substructure<'a>(f: CombineSubstructureFunc<'a>)
-> RefCell<CombineSubstructureFunc<'a>> {
ident,
a,
ast::ItemImpl(ast::Unsafety::Normal,
+ ast::ImplPolarity::Positive,
trait_generics,
opt_trait_ref,
self_type,
};
let mut f = self.combine_substructure.borrow_mut();
let f: &mut CombineSubstructureFunc = &mut *f;
- (*f)(cx, trait_.span, &substructure)
+ f.call_mut((cx, trait_.span, &substructure))
}
fn get_ret_ty(&self,
pub fn cs_fold<F>(use_foldl: bool,
mut f: F,
base: P<Expr>,
- enum_nonmatch_f: EnumNonMatchCollapsedFunc,
+ mut enum_nonmatch_f: EnumNonMatchCollapsedFunc,
cx: &mut ExtCtxt,
trait_span: Span,
substructure: &Substructure)
}
},
EnumNonMatchingCollapsed(ref all_args, _, tuple) =>
- enum_nonmatch_f(cx, trait_span, (all_args[], tuple),
- substructure.nonself_args),
+ enum_nonmatch_f.call_mut((cx, trait_span, (all_args[], tuple),
+ substructure.nonself_args)),
StaticEnum(..) | StaticStruct(..) => {
cx.span_bug(trait_span, "static function in `derive`")
}
/// ```
#[inline]
pub fn cs_same_method<F>(f: F,
- enum_nonmatch_f: EnumNonMatchCollapsedFunc,
+ mut enum_nonmatch_f: EnumNonMatchCollapsedFunc,
cx: &mut ExtCtxt,
trait_span: Span,
substructure: &Substructure)
f(cx, trait_span, called)
},
EnumNonMatchingCollapsed(ref all_self_args, _, tuple) =>
- enum_nonmatch_f(cx, trait_span, (all_self_args[], tuple),
- substructure.nonself_args),
+ enum_nonmatch_f.call_mut((cx, trait_span, (all_self_args[], tuple),
+ substructure.nonself_args)),
StaticEnum(..) | StaticStruct(..) => {
cx.span_bug(trait_span, "static function in `derive`")
}
args: vec!(Ptr(box Literal(args), Borrowed(None, MutMutable))),
ret_ty: nil_ty(),
attributes: attrs,
- combine_substructure: combine_substructure(|a, b, c| {
+ combine_substructure: combine_substructure(box |a, b, c| {
hash_substructure(a, b, c)
})
}
true)),
// #[inline] liable to cause code-bloat
attributes: attrs.clone(),
- combine_substructure: combine_substructure(|c, s, sub| {
+ combine_substructure: combine_substructure(box |c, s, sub| {
cs_from("i64", c, s, sub)
}),
},
true)),
// #[inline] liable to cause code-bloat
attributes: attrs,
- combine_substructure: combine_substructure(|c, s, sub| {
+ combine_substructure: combine_substructure(box |c, s, sub| {
cs_from("u64", c, s, sub)
}),
})
),
ret_ty: Self,
attributes: Vec::new(),
- combine_substructure: combine_substructure(|a, b, c| {
+ combine_substructure: combine_substructure(box |a, b, c| {
rand_substructure(a, b, c)
})
}
args: vec!(fmtr),
ret_ty: Literal(Path::new(vec!("std", "fmt", "Result"))),
attributes: Vec::new(),
- combine_substructure: combine_substructure(|a, b, c| {
+ combine_substructure: combine_substructure(box |a, b, c| {
show_substructure(a, b, c)
})
}
fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
let prev_type = self.current_impl_type.clone();
- if let ast::Item_::ItemImpl(_, _, _, ref ty, _) = item.node {
+ if let ast::Item_::ItemImpl(_, _, _, _, ref ty, _) = item.node {
self.current_impl_type = Some(ty.clone());
}
use std::cell::RefCell;
use std::collections::HashMap;
-use std::collections::hash_map::Entry::{Occupied, Vacant};
/// The SCTable contains a table of SyntaxContext_'s. It
/// represents a flattened tree structure, to avoid having
/// Extend a syntax context with a given mark and sctable (explicit memoization)
fn apply_mark_internal(m: Mrk, ctxt: SyntaxContext, table: &SCTable) -> SyntaxContext {
let key = (ctxt, m);
- * match table.mark_memo.borrow_mut().entry(key) {
- Vacant(entry) => entry.set(idx_push(&mut *table.table.borrow_mut(), Mark(m, ctxt))),
- Occupied(entry) => entry.into_mut(),
- }
+ * table.mark_memo.borrow_mut().entry(&key).get().unwrap_or_else(
+ |vacant_entry|
+ vacant_entry.insert(idx_push(&mut *table.table.borrow_mut(), Mark(m, ctxt))))
}
/// Extend a syntax context with a given rename
table: &SCTable) -> SyntaxContext {
let key = (ctxt, id, to);
- * match table.rename_memo.borrow_mut().entry(key) {
- Vacant(entry) => entry.set(idx_push(&mut *table.table.borrow_mut(), Rename(id, to, ctxt))),
- Occupied(entry) => entry.into_mut(),
- }
+ * table.rename_memo.borrow_mut().entry(&key).get().unwrap_or_else(
+ |vacant_entry|
+ vacant_entry.insert(idx_push(&mut *table.table.borrow_mut(), Rename(id, to, ctxt))))
}
/// Apply a list of renamings to a context
}
}
&TtToken(sp, MatchNt(bind_name, _, _, _)) => {
- match ret_val.entry(bind_name) {
+ match ret_val.entry(&bind_name) {
Vacant(spot) => {
- spot.set(res[*idx].clone());
+ spot.insert(res[*idx].clone());
*idx += 1;
}
Occupied(..) => {
// A way to temporarily opt out of the new orphan rules. This will *never* be accepted.
("old_orphan_check", Deprecated),
+ // OIBIT specific features
+ ("optin_builtin_traits", Active),
+
// These are used to test this portion of the compiler, they don't actually
// mean anything
("test_accepted_feature", Accepted),
}
}
- ast::ItemImpl(_, _, _, _, ref items) => {
+ ast::ItemImpl(_, polarity, _, _, _, ref items) => {
+ match polarity {
+ ast::ImplPolarity::Negative => {
+ self.gate_feature("optin_builtin_traits",
+ i.span,
+ "negative trait bounds are not yet fully implemented; \
+ use marker types for now");
+ },
+ _ => {}
+ }
+
if attr::contains_name(i.attrs[],
"unsafe_destructor") {
self.gate_feature("unsafe_destructor",
}
fn visit_ty(&mut self, t: &ast::Ty) {
- if let ast::TyClosure(ref closure) = t.node {
- // this used to be blocked by a feature gate, but it should just
- // be plain impossible right now
- assert!(closure.onceness != ast::Once);
- }
-
visit::walk_ty(self, t);
}
TyRptr(region, mt) => {
TyRptr(fld.fold_opt_lifetime(region), fld.fold_mt(mt))
}
- TyClosure(f) => {
- TyClosure(f.map(|ClosureTy {unsafety, onceness, bounds, decl, lifetimes}| {
- ClosureTy {
- unsafety: unsafety,
- onceness: onceness,
- bounds: fld.fold_bounds(bounds),
- decl: fld.fold_fn_decl(decl),
- lifetimes: fld.fold_lifetime_defs(lifetimes)
- }
- }))
- }
TyBareFn(f) => {
TyBareFn(f.map(|BareFnTy {lifetimes, unsafety, abi, decl}| BareFnTy {
lifetimes: fld.fold_lifetime_defs(lifetimes),
let struct_def = folder.fold_struct_def(struct_def);
ItemStruct(struct_def, folder.fold_generics(generics))
}
- ItemImpl(unsafety, generics, ifce, ty, impl_items) => {
+ ItemImpl(unsafety, polarity, generics, ifce, ty, impl_items) => {
let mut new_impl_items = Vec::new();
for impl_item in impl_items.iter() {
match *impl_item {
}
};
ItemImpl(unsafety,
+ polarity,
folder.fold_generics(generics),
ifce,
folder.fold_ty(ty),
let node = folder.fold_item_underscore(node);
let ident = match node {
// The node may have changed, recompute the "pretty" impl name.
- ItemImpl(_, _, ref maybe_trait, ref ty, _) => {
+ ItemImpl(_, _, _, ref maybe_trait, ref ty, _) => {
ast_util::impl_pretty_name(maybe_trait, &**ty)
}
_ => ident
}
}
+#[cfg(stage0)]
impl<S: Encoder<E>, T: Encodable<S, E>, E> Encodable<S, E> for OwnedSlice<T> {
fn encode(&self, s: &mut S) -> Result<(), E> {
self.as_slice().encode(s)
}
}
+#[cfg(not(stage0))]
+impl<T: Encodable> Encodable for OwnedSlice<T> {
+ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+ self.as_slice().encode(s)
+ }
+}
+
+#[cfg(stage0)]
impl<D: Decoder<E>, T: Decodable<D, E>, E> Decodable<D, E> for OwnedSlice<T> {
fn decode(d: &mut D) -> Result<OwnedSlice<T>, E> {
Ok(OwnedSlice::from_vec(match Decodable::decode(d) {
}))
}
}
+
+#[cfg(not(stage0))]
+impl<T: Decodable> Decodable for OwnedSlice<T> {
+ fn decode<D: Decoder>(d: &mut D) -> Result<OwnedSlice<T>, D::Error> {
+ Ok(OwnedSlice::from_vec(match Decodable::decode(d) {
+ Ok(t) => t,
+ Err(e) => return Err(e)
+ }))
+ }
+}
ObsoleteExternCrateRenaming,
ObsoleteProcType,
ObsoleteProcExpr,
+ ObsoleteClosureType,
}
pub trait ParserObsoleteMethods {
ObsoleteExternCrateRenaming => (
"`extern crate foo = bar` syntax",
"write `extern crate bar as foo` instead"
+ ),
+ ObsoleteClosureType => (
+ "`|uint| -> bool` closure type syntax",
+ "use unboxed closures instead, no type annotation needed"
)
};
use self::ItemOrViewItem::*;
use abi;
-use ast::{AssociatedType, BareFnTy, ClosureTy};
+use ast::{AssociatedType, BareFnTy};
use ast::{RegionTyParamBound, TraitTyParamBound, TraitBoundModifier};
use ast::{ProvidedMethod, Public, Unsafety};
use ast::{Mod, BiAdd, Arg, Arm, Attribute, BindByRef, BindByValue};
use ast::{ExprMethodCall, ExprParen, ExprPath};
use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary};
use ast::{ExprVec, ExprWhile, ExprWhileLet, ExprForLoop, Field, FnDecl};
-use ast::{Many};
use ast::{FnUnboxedClosureKind, FnMutUnboxedClosureKind};
use ast::{FnOnceUnboxedClosureKind};
use ast::{ForeignItem, ForeignItemStatic, ForeignItemFn, ForeignMod, FunctionRetTy};
use ast::{Delimited, SequenceRepetition, TokenTree, TraitItem, TraitRef};
use ast::{TtDelimited, TtSequence, TtToken};
use ast::{TupleVariantKind, Ty, Ty_, TypeBinding};
-use ast::{TypeField, TyFixedLengthVec, TyClosure, TyBareFn};
+use ast::{TypeField, TyFixedLengthVec, TyBareFn};
use ast::{TyTypeof, TyInfer, TypeMethod};
use ast::{TyParam, TyParamBound, TyParen, TyPath, TyPolyTraitRef, TyPtr, TyQPath};
use ast::{TyRptr, TyTup, TyU32, TyVec, UnUniq};
*/
- let unsafety = self.parse_unsafety();
+ let ty_closure_span = self.last_span;
- let lifetime_defs = self.parse_legacy_lifetime_defs(lifetime_defs);
+ // To be helpful, parse the closure type as ever
+ let _ = self.parse_unsafety();
- let inputs = if self.eat(&token::OrOr) {
- Vec::new()
- } else {
+ let _ = self.parse_legacy_lifetime_defs(lifetime_defs);
+
+ if !self.eat(&token::OrOr) {
self.expect_or();
- let inputs = self.parse_seq_to_before_or(
+ let _ = self.parse_seq_to_before_or(
&token::Comma,
|p| p.parse_arg_general(false));
self.expect_or();
- inputs
- };
+ }
- let bounds = self.parse_colon_then_ty_param_bounds(BoundParsingMode::Bare);
+ let _ = self.parse_colon_then_ty_param_bounds(BoundParsingMode::Bare);
- let output = self.parse_ret_ty();
- let decl = P(FnDecl {
- inputs: inputs,
- output: output,
- variadic: false
- });
+ let _ = self.parse_ret_ty();
- TyClosure(P(ClosureTy {
- unsafety: unsafety,
- onceness: Many,
- bounds: bounds,
- decl: decl,
- lifetimes: lifetime_defs,
- }))
+ self.obsolete(ty_closure_span, ObsoleteClosureType);
+
+ TyInfer
}
pub fn parse_unsafety(&mut self) -> Unsafety {
/// actually, this seems to be the main entry point for
/// parsing an arbitrary expression.
pub fn parse_assign_expr(&mut self) -> P<Expr> {
- let lo = self.span.lo;
let lhs = self.parse_binops();
+ self.parse_assign_expr_with(lhs)
+ }
+
+ pub fn parse_assign_expr_with(&mut self, lhs: P<Expr>) -> P<Expr> {
let restrictions = self.restrictions & RESTRICTION_NO_STRUCT_LITERAL;
match self.token {
token::Eq => {
self.bump();
let rhs = self.parse_expr_res(restrictions);
- self.mk_expr(lo, rhs.span.hi, ExprAssign(lhs, rhs))
+ self.mk_expr(lhs.span.lo, rhs.span.hi, ExprAssign(lhs, rhs))
}
token::BinOpEq(op) => {
self.bump();
token::Shr => BiShr
};
let rhs_span = rhs.span;
+ let span = lhs.span;
let assign_op = self.mk_assign_op(aop, lhs, rhs);
- self.mk_expr(lo, rhs_span.hi, assign_op)
+ self.mk_expr(span.lo, rhs_span.hi, assign_op)
}
_ => {
lhs
let e = self.mk_mac_expr(span.lo,
span.hi,
macro.and_then(|m| m.node));
- let e =
- self.parse_dot_or_call_expr_with(e);
+ let e = self.parse_dot_or_call_expr_with(e);
+ let e = self.parse_more_binops(e, 0);
+ let e = self.parse_assign_expr_with(e);
self.handle_expression_like_statement(
e,
ast::DUMMY_NODE_ID,
// allow this to be parsed as a trait.
let could_be_trait = self.token != token::OpenDelim(token::Paren);
+ let neg_span = self.span;
+ let polarity = if self.eat(&token::Not) {
+ ast::ImplPolarity::Negative
+ } else {
+ ast::ImplPolarity::Positive
+ };
+
// Parse the trait.
let mut ty = self.parse_ty_sum();
ty = self.parse_ty_sum();
opt_trait_ref
} else {
+ match polarity {
+ ast::ImplPolarity::Negative => {
+ // This is a negated type implementation
+ // `impl !MyType {}`, which is not allowed.
+ self.span_err(neg_span, "inherent implementation can't be negated");
+ },
+ _ => {}
+ }
None
};
let ident = ast_util::impl_pretty_name(&opt_trait, &*ty);
(ident,
- ItemImpl(unsafety, generics, opt_trait, ty, impl_items),
+ ItemImpl(unsafety, polarity, generics, opt_trait, ty, impl_items),
Some(attrs))
}
self.span_err(ty.span, "`virtual` structs have been removed from the language");
}
- self.parse_where_clause(&mut generics);
+ // There is a special case worth noting here, as reported in issue #17904.
+ // If we are parsing a tuple struct it is the case that the where clause
+ // should follow the field list. Like so:
+ //
+ // struct Foo<T>(T) where T: Copy;
+ //
+ // If we are parsing a normal record-style struct it is the case
+ // that the where clause comes before the body, and after the generics.
+ // So if we look ahead and see a brace or a where-clause we begin
+ // parsing a record style struct.
+ //
+ // Otherwise if we look ahead and see a paren we parse a tuple-style
+ // struct.
+
+ let (fields, ctor_id) = if self.token.is_keyword(keywords::Where) {
+ self.parse_where_clause(&mut generics);
+ if self.eat(&token::Semi) {
+ // If we see a: `struct Foo<T> where T: Copy;` style decl.
+ (Vec::new(), Some(ast::DUMMY_NODE_ID))
+ } else {
+ // If we see: `struct Foo<T> where T: Copy { ... }`
+ (self.parse_record_struct_body(&class_name), None)
+ }
+ // No `where` so: `struct Foo<T>;`
+ } else if self.eat(&token::Semi) {
+ (Vec::new(), Some(ast::DUMMY_NODE_ID))
+ // Record-style struct definition
+ } else if self.token == token::OpenDelim(token::Brace) {
+ let fields = self.parse_record_struct_body(&class_name);
+ (fields, None)
+ // Tuple-style struct definition with optional where-clause.
+ } else {
+ let fields = self.parse_tuple_struct_body(&class_name, &mut generics);
+ (fields, Some(ast::DUMMY_NODE_ID))
+ };
- let mut fields: Vec<StructField>;
- let is_tuple_like;
+ (class_name,
+ ItemStruct(P(ast::StructDef {
+ fields: fields,
+ ctor_id: ctor_id,
+ }), generics),
+ None)
+ }
+ pub fn parse_record_struct_body(&mut self, class_name: &ast::Ident) -> Vec<StructField> {
+ let mut fields = Vec::new();
if self.eat(&token::OpenDelim(token::Brace)) {
- // It's a record-like struct.
- is_tuple_like = false;
- fields = Vec::new();
while self.token != token::CloseDelim(token::Brace) {
fields.push(self.parse_struct_decl_field(true));
}
+
if fields.len() == 0 {
self.fatal(format!("unit-like struct definition should be \
- written as `struct {};`",
- token::get_ident(class_name))[]);
+ written as `struct {};`",
+ token::get_ident(class_name.clone()))[]);
}
+
self.bump();
- } else if self.check(&token::OpenDelim(token::Paren)) {
- // It's a tuple-like struct.
- is_tuple_like = true;
- fields = self.parse_unspanned_seq(
+ } else {
+ let token_str = self.this_token_to_string();
+ self.fatal(format!("expected `where`, or `{}` after struct \
+ name, found `{}`", "{",
+ token_str)[]);
+ }
+
+ fields
+ }
+
+ pub fn parse_tuple_struct_body(&mut self,
+ class_name: &ast::Ident,
+ generics: &mut ast::Generics)
+ -> Vec<StructField> {
+ // This is the case where we find `struct Foo<T>(T) where T: Copy;`
+ if self.check(&token::OpenDelim(token::Paren)) {
+ let fields = self.parse_unspanned_seq(
&token::OpenDelim(token::Paren),
&token::CloseDelim(token::Paren),
seq_sep_trailing_allowed(token::Comma),
|p| {
- let attrs = p.parse_outer_attributes();
- let lo = p.span.lo;
- let struct_field_ = ast::StructField_ {
- kind: UnnamedField(p.parse_visibility()),
- id: ast::DUMMY_NODE_ID,
- ty: p.parse_ty_sum(),
- attrs: attrs,
- };
- spanned(lo, p.span.hi, struct_field_)
- });
+ let attrs = p.parse_outer_attributes();
+ let lo = p.span.lo;
+ let struct_field_ = ast::StructField_ {
+ kind: UnnamedField(p.parse_visibility()),
+ id: ast::DUMMY_NODE_ID,
+ ty: p.parse_ty_sum(),
+ attrs: attrs,
+ };
+ spanned(lo, p.span.hi, struct_field_)
+ });
+
if fields.len() == 0 {
self.fatal(format!("unit-like struct definition should be \
- written as `struct {};`",
- token::get_ident(class_name))[]);
+ written as `struct {};`",
+ token::get_ident(class_name.clone()))[]);
}
+
+ self.parse_where_clause(generics);
self.expect(&token::Semi);
- } else if self.eat(&token::Semi) {
- // It's a unit-like struct.
- is_tuple_like = true;
- fields = Vec::new();
+ fields
+ // This is the case where we just see struct Foo<T> where T: Copy;
+ } else if self.token.is_keyword(keywords::Where) {
+ self.parse_where_clause(generics);
+ self.expect(&token::Semi);
+ Vec::new()
+ // This case is where we see: `struct Foo<T>;`
} else {
let token_str = self.this_token_to_string();
- self.fatal(format!("expected `{}`, `(`, or `;` after struct \
- name, found `{}`", "{",
- token_str)[])
+ self.fatal(format!("expected `where`, `{}`, `(`, or `;` after struct \
+ name, found `{}`", "{", token_str)[]);
}
-
- let _ = ast::DUMMY_NODE_ID; // FIXME: Workaround for crazy bug.
- let new_id = ast::DUMMY_NODE_ID;
- (class_name,
- ItemStruct(P(ast::StructDef {
- fields: fields,
- ctor_id: if is_tuple_like { Some(new_id) } else { None },
- }), generics),
- None)
}
/// Parse a structure field declaration
}
}
+#[cfg(stage0)]
impl<D:Decoder<E>, E> Decodable<D, E> for InternedString {
fn decode(d: &mut D) -> Result<InternedString, E> {
Ok(get_name(get_ident_interner().intern(
}
}
+#[cfg(not(stage0))]
+impl Decodable for InternedString {
+ fn decode<D: Decoder>(d: &mut D) -> Result<InternedString, D::Error> {
+ Ok(get_name(get_ident_interner().intern(
+ try!(d.read_str())[])))
+ }
+}
+
+#[cfg(stage0)]
impl<S:Encoder<E>, E> Encodable<S, E> for InternedString {
fn encode(&self, s: &mut S) -> Result<(), E> {
s.emit_str(self.string[])
}
}
+#[cfg(not(stage0))]
+impl Encodable for InternedString {
+ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+ s.emit_str(self.string[])
+ }
+}
+
/// Returns the string contents of a name, using the task-local interner.
#[inline]
pub fn get_name(name: ast::Name) -> InternedString {
Some(&generics),
None));
}
- ast::TyClosure(ref f) => {
- let generics = ast::Generics {
- lifetimes: f.lifetimes.clone(),
- ty_params: OwnedSlice::empty(),
- where_clause: ast::WhereClause {
- id: ast::DUMMY_NODE_ID,
- predicates: Vec::new(),
- },
- };
- try!(self.print_ty_fn(None,
- Some('&'),
- f.unsafety,
- f.onceness,
- &*f.decl,
- None,
- &f.bounds,
- Some(&generics),
- None));
- }
ast::TyPath(ref path, _) => {
try!(self.print_path(path, false));
}
}
ast::ItemImpl(unsafety,
+ polarity,
ref generics,
ref opt_trait,
ref ty,
try!(space(&mut self.s));
}
+ match polarity {
+ ast::ImplPolarity::Negative => {
+ try!(word(&mut self.s, "!"));
+ },
+ _ => {}
+ }
+
match opt_trait {
&Some(ref t) => {
try!(self.print_trait_ref(t));
span: codemap::Span) -> IoResult<()> {
try!(self.print_ident(ident));
try!(self.print_generics(generics));
- try!(self.print_where_clause(generics));
if ast_util::struct_def_is_tuple_like(struct_def) {
if !struct_def.fields.is_empty() {
try!(self.popen());
));
try!(self.pclose());
}
+ try!(self.print_where_clause(generics));
try!(word(&mut self.s, ";"));
try!(self.end());
self.end() // close the outer-box
} else {
+ try!(self.print_where_clause(generics));
try!(self.nbsp());
try!(self.bopen());
try!(self.hardbreak_if_not_bol());
}
}
+#[cfg(stage0)]
impl<E, D: Decoder<E>, T: 'static + Decodable<D, E>> Decodable<D, E> for P<T> {
fn decode(d: &mut D) -> Result<P<T>, E> {
Decodable::decode(d).map(P)
}
}
+#[cfg(not(stage0))]
+impl<T: 'static + Decodable> Decodable for P<T> {
+ fn decode<D: Decoder>(d: &mut D) -> Result<P<T>, D::Error> {
+ Decodable::decode(d).map(P)
+ }
+}
+
+#[cfg(stage0)]
impl<E, S: Encoder<E>, T: Encodable<S, E>> Encodable<S, E> for P<T> {
fn encode(&self, s: &mut S) -> Result<(), E> {
(**self).encode(s)
}
}
+
+#[cfg(not(stage0))]
+impl<T: Encodable> Encodable for P<T> {
+ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+ (**self).encode(s)
+ }
+}
//! This module shows spans for all expressions in the crate
//! to help with compiler debugging.
+use std::str::FromStr;
+
use ast;
use diagnostic;
use visit;
use visit::Visitor;
+enum Mode {
+ Expression,
+ Pattern,
+ Type,
+}
+
+impl FromStr for Mode {
+ fn from_str(s: &str) -> Option<Mode> {
+ let mode = match s {
+ "expr" => Mode::Expression,
+ "pat" => Mode::Pattern,
+ "ty" => Mode::Type,
+ _ => return None
+ };
+ Some(mode)
+ }
+}
+
struct ShowSpanVisitor<'a> {
span_diagnostic: &'a diagnostic::SpanHandler,
+ mode: Mode,
}
impl<'a, 'v> Visitor<'v> for ShowSpanVisitor<'a> {
fn visit_expr(&mut self, e: &ast::Expr) {
- self.span_diagnostic.span_note(e.span, "expression");
+ if let Mode::Expression = self.mode {
+ self.span_diagnostic.span_note(e.span, "expression");
+ }
visit::walk_expr(self, e);
}
+ fn visit_pat(&mut self, p: &ast::Pat) {
+ if let Mode::Pattern = self.mode {
+ self.span_diagnostic.span_note(p.span, "pattern");
+ }
+ visit::walk_pat(self, p);
+ }
+
+ fn visit_ty(&mut self, t: &ast::Ty) {
+ if let Mode::Type = self.mode {
+ self.span_diagnostic.span_note(t.span, "type");
+ }
+ visit::walk_ty(self, t);
+ }
+
fn visit_mac(&mut self, macro: &ast::Mac) {
visit::walk_mac(self, macro);
}
}
-pub fn run(span_diagnostic: &diagnostic::SpanHandler, krate: &ast::Crate) {
- let mut v = ShowSpanVisitor { span_diagnostic: span_diagnostic };
+pub fn run(span_diagnostic: &diagnostic::SpanHandler,
+ mode: &str,
+ krate: &ast::Crate) {
+ let mode = match mode.parse() {
+ Some(mode) => mode,
+ None => return
+ };
+ let mut v = ShowSpanVisitor {
+ span_diagnostic: span_diagnostic,
+ mode: mode,
+ };
visit::walk_crate(&mut v, krate);
}
visitor.visit_generics(type_parameters);
walk_enum_def(visitor, enum_definition, type_parameters)
}
- ItemImpl(_,
+ ItemImpl(_, _,
ref type_parameters,
ref trait_reference,
ref typ,
visitor.visit_ty(&**tuple_element_type)
}
}
- TyClosure(ref function_declaration) => {
- for argument in function_declaration.decl.inputs.iter() {
- visitor.visit_ty(&*argument.ty)
- }
- walk_fn_ret_ty(visitor, &function_declaration.decl.output);
- walk_ty_param_bounds_helper(visitor, &function_declaration.bounds);
- walk_lifetime_decls_helper(visitor, &function_declaration.lifetimes);
- }
TyBareFn(ref function_declaration) => {
for argument in function_declaration.decl.inputs.iter() {
visitor.visit_ty(&*argument.ty)
use term::Terminal;
use term::color::{Color, RED, YELLOW, GREEN, CYAN};
-use std::any::{Any, AnyRefExt};
+use std::any::Any;
use std::cmp;
use std::collections::BTreeMap;
use std::f64;
/// Returns a HashMap with the number of occurrences of every element in the
/// sequence that the iterator exposes.
-pub fn freq_count<T: Iterator<Item=U>, U: Eq+Hash>(mut iter: T) -> hash_map::HashMap<U, uint> {
+pub fn freq_count<T, U>(mut iter: T) -> hash_map::HashMap<U, uint>
+ where T: Iterator<Item=U>, U: Eq + Clone + Hash
+{
let mut map: hash_map::HashMap<U,uint> = hash_map::HashMap::new();
for elem in iter {
- match map.entry(elem) {
+ match map.entry(&elem) {
Occupied(mut entry) => { *entry.get_mut() += 1; },
- Vacant(entry) => { entry.set(1); },
+ Vacant(entry) => { entry.insert(1); },
}
}
map
// re-export char so that std et al see it correctly
/// Character manipulation (`char` type, Unicode Scalar Value)
///
-/// This module provides the `Char` and `UnicodeChar` traits, as well as their
-/// implementation for the primitive `char` type, in order to allow basic character
-/// manipulation.
+/// This module provides the `CharExt` trait, as well as its
+/// implementation for the primitive `char` type, in order to allow
+/// basic character manipulation.
///
/// A `char` actually represents a
/// *[Unicode Scalar Value](http://www.unicode.org/glossary/#unicode_scalar_value)*,
/// however the converse is not always true due to the above range limits
/// and, as such, should be performed via the `from_u32` function..
pub mod char {
- pub use core::char::{MAX, from_u32};
- pub use core::char::{from_digit};
- pub use core::char::Char;
+ pub use core::char::{MAX, from_u32, from_digit};
pub use normalize::{decompose_canonical, decompose_compatible, compose};
pub use tables::normalization::canonical_combining_class;
pub use tables::UNICODE_VERSION;
- pub use u_char::UnicodeChar;
+ pub use u_char::CharExt;
}
pub mod str {
#![allow(missing_docs, non_upper_case_globals, non_snake_case)]
/// The version of [Unicode](http://www.unicode.org/)
-/// that the `UnicodeChar` and `UnicodeStrPrelude` traits are based on.
+/// that the unicode parts of `CharExt` and `UnicodeStrPrelude` traits are based on.
pub const UNICODE_VERSION: (uint, uint, uint) = (7, 0, 0);
fn bsearch_range_table(c: char, r: &'static [(char,char)]) -> bool {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//! Unicode-intensive `char` methods.
+//! Unicode-intensive `char` methods along with the `core` methods.
//!
//! These methods implement functionality for `char` that requires knowledge of
//! Unicode definitions, including normalization, categorization, and display information.
+use core::char;
+use core::char::CharExt as C;
use core::option::Option;
use tables::{derived_property, property, general_category, conversions, charwidth};
-/// Useful functions for Unicode characters.
-#[experimental = "pending prelude organization"]
-pub trait UnicodeChar {
+/// Functionality for manipulating `char`.
+#[stable]
+pub trait CharExt {
+ /// Checks if a `char` parses as a numeric digit in the given radix.
+ ///
+ /// Compared to `is_numeric()`, this function only recognizes the characters
+ /// `0-9`, `a-z` and `A-Z`.
+ ///
+ /// # Return value
+ ///
+ /// Returns `true` if `c` is a valid digit under `radix`, and `false`
+ /// otherwise.
+ ///
+ /// # Panics
+ ///
+ /// Panics if given a radix > 36.
+ #[unstable = "pending integer conventions"]
+ fn is_digit(self, radix: uint) -> bool;
+
+ /// Converts a character to the corresponding digit.
+ ///
+ /// # Return value
+ ///
+ /// If `c` is between '0' and '9', the corresponding value between 0 and
+ /// 9. If `c` is 'a' or 'A', 10. If `c` is 'b' or 'B', 11, etc. Returns
+ /// none if the character does not refer to a digit in the given radix.
+ ///
+ /// # Panics
+ ///
+ /// Panics if given a radix outside the range [0..36].
+ #[unstable = "pending integer conventions"]
+ fn to_digit(self, radix: uint) -> Option<uint>;
+
+ /// Returns an iterator that yields the hexadecimal Unicode escape
+ /// of a character, as `char`s.
+ ///
+ /// All characters are escaped with Rust syntax of the form `\\u{NNNN}`
+ /// where `NNNN` is the shortest hexadecimal representation of the code
+ /// point.
+ #[stable]
+ fn escape_unicode(self) -> char::EscapeUnicode;
+
+ /// Returns an iterator that yields the 'default' ASCII and
+ /// C++11-like literal escape of a character, as `char`s.
+ ///
+ /// The default is chosen with a bias toward producing literals that are
+ /// legal in a variety of languages, including C++11 and similar C-family
+ /// languages. The exact rules are:
+ ///
+ /// * Tab, CR and LF are escaped as '\t', '\r' and '\n' respectively.
+ /// * Single-quote, double-quote and backslash chars are backslash-
+ /// escaped.
+ /// * Any other chars in the range [0x20,0x7e] are not escaped.
+ /// * Any other chars are given hex Unicode escapes; see `escape_unicode`.
+ #[stable]
+ fn escape_default(self) -> char::EscapeDefault;
+
+ /// Returns the amount of bytes this character would need if encoded in
+ /// UTF-8.
+ #[stable]
+ fn len_utf8(self) -> uint;
+
+ /// Returns the amount of bytes this character would need if encoded in
+ /// UTF-16.
+ #[stable]
+ fn len_utf16(self) -> uint;
+
+ /// Encodes this character as UTF-8 into the provided byte buffer,
+ /// and then returns the number of bytes written.
+ ///
+ /// If the buffer is not large enough, nothing will be written into it
+ /// and a `None` will be returned.
+ #[unstable = "pending decision about Iterator/Writer/Reader"]
+ fn encode_utf8(self, dst: &mut [u8]) -> Option<uint>;
+
+ /// Encodes this character as UTF-16 into the provided `u16` buffer,
+ /// and then returns the number of `u16`s written.
+ ///
+ /// If the buffer is not large enough, nothing will be written into it
+ /// and a `None` will be returned.
+ #[unstable = "pending decision about Iterator/Writer/Reader"]
+ fn encode_utf16(self, dst: &mut [u16]) -> Option<uint>;
+
/// Returns whether the specified character is considered a Unicode
/// alphabetic code point.
+ #[stable]
fn is_alphabetic(self) -> bool;
/// Returns whether the specified character satisfies the 'XID_Start'
/// 'XID_Start' is a Unicode Derived Property specified in
/// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications),
/// mostly similar to ID_Start but modified for closure under NFKx.
+ #[experimental = "mainly needed for compiler internals"]
fn is_xid_start(self) -> bool;
/// Returns whether the specified `char` satisfies the 'XID_Continue'
/// 'XID_Continue' is a Unicode Derived Property specified in
/// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications),
/// mostly similar to 'ID_Continue' but modified for closure under NFKx.
+ #[experimental = "mainly needed for compiler internals"]
fn is_xid_continue(self) -> bool;
/// Indicates whether a character is in lowercase.
///
/// This is defined according to the terms of the Unicode Derived Core
/// Property `Lowercase`.
+ #[stable]
fn is_lowercase(self) -> bool;
/// Indicates whether a character is in uppercase.
///
/// This is defined according to the terms of the Unicode Derived Core
/// Property `Uppercase`.
+ #[stable]
fn is_uppercase(self) -> bool;
/// Indicates whether a character is whitespace.
///
/// Whitespace is defined in terms of the Unicode Property `White_Space`.
+ #[stable]
fn is_whitespace(self) -> bool;
/// Indicates whether a character is alphanumeric.
///
/// Alphanumericness is defined in terms of the Unicode General Categories
/// 'Nd', 'Nl', 'No' and the Derived Core Property 'Alphabetic'.
+ #[stable]
fn is_alphanumeric(self) -> bool;
/// Indicates whether a character is a control code point.
///
/// Control code points are defined in terms of the Unicode General
/// Category `Cc`.
+ #[stable]
fn is_control(self) -> bool;
/// Indicates whether the character is numeric (Nd, Nl, or No).
+ #[stable]
fn is_numeric(self) -> bool;
/// Converts a character to its lowercase equivalent.
///
/// Returns the lowercase equivalent of the character, or the character
/// itself if no conversion is possible.
+ #[experimental = "pending case transformation decisions"]
fn to_lowercase(self) -> char;
/// Converts a character to its uppercase equivalent.
/// [`SpecialCasing`.txt`]: ftp://ftp.unicode.org/Public/UNIDATA/SpecialCasing.txt
///
/// [2]: http://www.unicode.org/versions/Unicode4.0.0/ch03.pdf#G33992
+ #[experimental = "pending case transformation decisions"]
fn to_uppercase(self) -> char;
/// Returns this character's displayed width in columns, or `None` if it is a
fn width(self, is_cjk: bool) -> Option<uint>;
}
-#[experimental = "pending prelude organization"]
-impl UnicodeChar for char {
+#[stable]
+impl CharExt for char {
+ #[unstable = "pending integer conventions"]
+ fn is_digit(self, radix: uint) -> bool { C::is_digit(self, radix) }
+ #[unstable = "pending integer conventions"]
+ fn to_digit(self, radix: uint) -> Option<uint> { C::to_digit(self, radix) }
+ #[stable]
+ fn escape_unicode(self) -> char::EscapeUnicode { C::escape_unicode(self) }
+ #[stable]
+ fn escape_default(self) -> char::EscapeDefault { C::escape_default(self) }
+ #[stable]
+ fn len_utf8(self) -> uint { C::len_utf8(self) }
+ #[stable]
+ fn len_utf16(self) -> uint { C::len_utf16(self) }
+ #[unstable = "pending decision about Iterator/Writer/Reader"]
+ fn encode_utf8(self, dst: &mut [u8]) -> Option<uint> { C::encode_utf8(self, dst) }
+ #[unstable = "pending decision about Iterator/Writer/Reader"]
+ fn encode_utf16(self, dst: &mut [u16]) -> Option<uint> { C::encode_utf16(self, dst) }
+
+ #[stable]
fn is_alphabetic(self) -> bool {
match self {
'a' ... 'z' | 'A' ... 'Z' => true,
}
}
+ #[experimental = "mainly needed for compiler internals"]
fn is_xid_start(self) -> bool { derived_property::XID_Start(self) }
+ #[experimental = "mainly needed for compiler internals"]
fn is_xid_continue(self) -> bool { derived_property::XID_Continue(self) }
+ #[stable]
fn is_lowercase(self) -> bool {
match self {
'a' ... 'z' => true,
}
}
+ #[stable]
fn is_uppercase(self) -> bool {
match self {
'A' ... 'Z' => true,
}
}
+ #[stable]
fn is_whitespace(self) -> bool {
match self {
' ' | '\x09' ... '\x0d' => true,
}
}
+ #[stable]
fn is_alphanumeric(self) -> bool {
self.is_alphabetic() || self.is_numeric()
}
+ #[stable]
fn is_control(self) -> bool { general_category::Cc(self) }
+ #[stable]
fn is_numeric(self) -> bool {
match self {
'0' ... '9' => true,
}
}
+ #[experimental = "pending case transformation decisions"]
fn to_lowercase(self) -> char { conversions::to_lower(self) }
+ #[experimental = "pending case transformation decisions"]
fn to_uppercase(self) -> char { conversions::to_upper(self) }
#[experimental = "needs expert opinion. is_cjk flag stands out as ugly"]
//! Unicode-intensive string manipulations.
//!
//! This module provides functionality to `str` that requires the Unicode methods provided by the
-//! UnicodeChar trait.
+//! unicode parts of the CharExt trait.
use self::GraphemeState::*;
use core::prelude::*;
use core::slice;
use core::str::Split;
-use u_char::UnicodeChar;
+use u_char::CharExt as UCharExt; // conflicts with core::prelude::CharExt
use tables::grapheme::GraphemeCat;
/// An iterator over the words of a string, separated by a sequence of whitespace
let mut buf = [0u16; 2];
self.chars.next().map(|ch| {
- let n = ch.encode_utf16(buf.as_mut_slice()).unwrap_or(0);
+ let n = CharExt::encode_utf16(ch, buf.as_mut_slice()).unwrap_or(0);
if n == 2 { self.extra = buf[1]; }
buf[0]
})
-Subproject commit ec1fdb3b9d3b1fb9e1dae97a65dd3a13db9bfb23
+Subproject commit b820135911e17c7a46b901db56baa48e5155bf46
-Subproject commit 3a37981744a5af2433fed551f742465c78c9af7f
+Subproject commit b5ac4cd44321da10dfd70f070dbc9094ca3f92ff
# If this file is modified, then llvm will be forcibly cleaned and then rebuilt.
# The actual contents of this file do not matter, but to trigger a change on the
# build bots then the contents should be changed so git updates the mtime.
-2015-01-03
+2015-01-05
+S 2015-01-04 b2085d9
+ freebsd-x86_64 50ccb6bf9c0645d0746a5167493a39b2be40c2d4
+ linux-i386 b880b98d832c9a049b8ef6a50df50061e363de5a
+ linux-x86_64 82a09c162474b69d2d1e4e8399086f3f0f4e31c3
+ macos-i386 569055bb10d96ab25f78ecf2c80ffbccd5e69b8d
+ macos-x86_64 cff1f9ebd63dae6890359b7d353bd9486d8ecdfc
+ winnt-i386 553790fe493413287a19d17a42bf7225d3e2272d
+ winnt-x86_64 bab0d13960afb7ccdd6bf11452de1b9c457cc3e9
+
S 2015-01-02 c894171
freebsd-x86_64 ea8bcf75eada3539f5cbab51708eecf40d436b77
linux-i386 646ae265721e3cbe19404aae4fea4ffa1f1d90cf
#![crate_name="cci_impl_lib"]
pub trait uint_helpers {
- fn to(&self, v: uint, f: |uint|);
+ fn to<F>(&self, v: uint, f: F) where F: FnMut(uint);
}
impl uint_helpers for uint {
#[inline]
- fn to(&self, v: uint, f: |uint|) {
+ fn to<F>(&self, v: uint, mut f: F) where F: FnMut(uint) {
let mut i = *self;
while i < v {
f(i);
#![crate_name="cci_iter_lib"]
#[inline]
-pub fn iter<T>(v: &[T], f: |&T|) {
+pub fn iter<T, F>(v: &[T], mut f: F) where F: FnMut(&T) {
let mut i = 0u;
let n = v.len();
while i < n {
// same as cci_iter_lib, more-or-less, but not marked inline
-pub fn iter(v: Vec<uint> , f: |uint|) {
+pub fn iter<F>(v: Vec<uint> , mut f: F) where F: FnMut(uint) {
let mut i = 0u;
let n = v.len();
while i < n {
// part of issue-6919.rs
-pub struct C<'a> {
- pub k: ||: 'a,
+pub struct C<K> where K: FnOnce() {
+ pub k: K,
}
fn no_op() { }
-pub const D : C<'static> = C {
- k: no_op
+pub const D : C<fn()> = C {
+ k: no_op as fn()
};
ids.push(TypeId::of::<FooEnum>());
ids.push(TypeId::of::<FooUniq>());
ids.push(TypeId::of::<FooPtr>());
- ids.push(TypeId::of::<FooClosure>());
ids.push(TypeId::of::<&'static FooTrait>());
ids.push(TypeId::of::<FooStruct>());
ids.push(TypeId::of::<FooTuple>());
// Skipping ty_bare_fn (how do you get a bare function type, rather than proc or closure?)
- // Tests ty_closure (does not test all types of closures)
- pub type FooClosure = |arg: u8|: 'static -> u8;
-
// Tests ty_trait
pub trait FooTrait {
fn foo_method(&self) -> uint;
fn baz() { }
pub fn test() {
- let none: Option<Path> = None; // appease the typechecker
+ let none: Option<&Path> = None; // appease the typechecker
let lib = DynamicLibrary::open(none).unwrap();
unsafe {
assert!(lib.symbol::<int>("foo").is_ok());
pub fn foo<T>() {
fn death() -> int { panic!() }
- debug!("{}", (||{ death() })());
+ debug!("{}", (|&:|{ death() })());
}
impl Results {
pub fn bench_int<T:MutableSet<uint>,
- R: rand::Rng>(
+ R:rand::Rng,
+ F:FnMut() -> T>(
&mut self,
rng: &mut R,
num_keys: uint,
rand_cap: uint,
- f: || -> T) { {
+ mut f: F) {
+ {
let mut set = f();
timed(&mut self.sequential_ints, || {
for i in range(0u, num_keys) {
}
pub fn bench_str<T:MutableSet<String>,
- R:rand::Rng>(
+ R:rand::Rng,
+ F:FnMut() -> T>(
&mut self,
rng: &mut R,
num_keys: uint,
- f: || -> T) {
+ mut f: F) {
{
let mut set = f();
timed(&mut self.sequential_strings, || {
use std::sync::mpsc::channel;
use std::os;
use std::thread::Thread;
-use std::uint;
// This is a simple bench that creates M pairs of tasks. These
// tasks ping-pong back and forth over a pair of streams. This is a
// Create pairs of tasks that pingpong back and forth.
fn run_pair(n: uint) {
- // Create a stream A->B
- let (atx, arx) = channel::<()>();
- // Create a stream B->A
- let (btx, brx) = channel::<()>();
+ // Create a channel: A->B
+ let (atx, arx) = channel();
+ // Create a channel: B->A
+ let (btx, brx) = channel();
Thread::spawn(move|| {
let (tx, rx) = (atx, brx);
for _ in range(0, n) {
- tx.send(());
- rx.recv();
+ tx.send(()).unwrap();
+ rx.recv().unwrap();
}
}).detach();
Thread::spawn(move|| {
let (tx, rx) = (btx, arx);
for _ in range(0, n) {
- rx.recv();
- tx.send(());
+ rx.recv().unwrap();
+ tx.send(()).unwrap();
}
}).detach();
}
// given a Vec<u8>, for each window call a function
// i.e., for "hello" and windows of size four,
// run it("hell") and it("ello"), then return "llo"
-fn windows_with_carry(bb: &[u8], nn: uint, it: |window: &[u8]|) -> Vec<u8> {
+fn windows_with_carry<F>(bb: &[u8], nn: uint, mut it: F) -> Vec<u8> where
+ F: FnMut(&[u8]),
+{
let mut ii = 0u;
let len = bb.len();
// returns an infinite iterator of repeated applications of f to x,
// i.e. [x, f(x), f(f(x)), ...], as haskell iterate function.
-fn iterate<'a, T>(x: T, f: |&T|: 'a -> T) -> Iterate<'a, T> {
+fn iterate<T, F>(x: T, f: F) -> Iterate<T, F> where F: FnMut(&T) -> T {
Iterate {f: f, next: x}
}
-struct Iterate<'a, T> {
- f: |&T|: 'a -> T,
+struct Iterate<T, F> where F: FnMut(&T) -> T {
+ f: F,
next: T
}
-impl<'a, T> Iterator for Iterate<'a, T> {
+impl<T, F> Iterator for Iterate<T, F> where F: FnMut(&T) -> T {
type Item = T;
fn next(&mut self) -> Option<T> {
struct sty(Vec<int> );
-fn unpack(_unpack: |v: &sty| -> Vec<int> ) {}
+fn unpack<F>(_unpack: F) where F: FnOnce(&sty) -> Vec<int> {}
fn main() {
let _foo = unpack(|s| {
fn main() {
let nyan : cat = cat(52u, 99);
- nyan.speak = || println!("meow"); //~ ERROR attempted to take value of method
+ nyan.speak = |&:| println!("meow"); //~ ERROR attempted to take value of method
}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test equality constraints in a where clause where the type being
+// equated appears in a supertrait.
+
+#![feature(associated_types)]
+
+pub trait Vehicle {
+ type Color;
+
+ fn go(&self) { }
+}
+
+pub trait Box {
+ type Color;
+
+ fn mail(&self) { }
+}
+
+pub trait BoxCar : Box + Vehicle {
+}
+
+fn dent<C:BoxCar>(c: C, color: C::Color) {
+ //~^ ERROR ambiguous associated type `Color` in bounds of `C`
+ //~| NOTE could derive from `Vehicle`
+ //~| NOTE could derive from `Box`
+}
+
+fn dent_object<COLOR>(c: BoxCar<Color=COLOR>) {
+ //~^ ERROR ambiguous associated type
+}
+
+fn paint<C:BoxCar>(c: C, d: C::Color) {
+ //~^ ERROR ambiguous associated type `Color` in bounds of `C`
+ //~| NOTE could derive from `Vehicle`
+ //~| NOTE could derive from `Box`
+}
+
+pub fn main() { }
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test equality constraints in a where clause where the type being
+// equated appears in a supertrait.
+
+#![feature(associated_types)]
+
+pub trait Vehicle {
+ type Color;
+
+ fn go(&self) { }
+}
+
+pub trait Car : Vehicle {
+ fn honk(&self) { }
+ fn chip_paint(&self, c: Self::Color) { }
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+struct Black;
+struct ModelT;
+impl Vehicle for ModelT { type Color = Black; }
+impl Car for ModelT { }
+
+///////////////////////////////////////////////////////////////////////////
+
+struct Blue;
+struct ModelU;
+impl Vehicle for ModelU { type Color = Blue; }
+impl Car for ModelU { }
+
+///////////////////////////////////////////////////////////////////////////
+
+fn dent<C:Car>(c: C, color: C::Color) { c.chip_paint(color) }
+fn a() { dent(ModelT, Black); }
+fn b() { dent(ModelT, Blue); } //~ ERROR type mismatch
+fn c() { dent(ModelU, Black); } //~ ERROR type mismatch
+fn d() { dent(ModelU, Blue); }
+
+///////////////////////////////////////////////////////////////////////////
+
+fn e() { ModelT.chip_paint(Black); }
+fn f() { ModelT.chip_paint(Blue); } //~ ERROR mismatched types
+fn g() { ModelU.chip_paint(Black); } //~ ERROR mismatched types
+fn h() { ModelU.chip_paint(Blue); }
+
+pub fn main() { }
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test equality constraints in a where clause where the type being
+// equated appears in a supertrait.
+
+#![feature(associated_types)]
+
+pub trait Vehicle {
+ type Color;
+
+ fn go(&self) { }
+}
+
+pub trait Car : Vehicle {
+ fn honk(&self) { }
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+struct Black;
+struct ModelT;
+impl Vehicle for ModelT { type Color = Black; }
+impl Car for ModelT { }
+
+///////////////////////////////////////////////////////////////////////////
+
+struct Blue;
+struct ModelU;
+impl Vehicle for ModelU { type Color = Blue; }
+impl Car for ModelU { }
+
+///////////////////////////////////////////////////////////////////////////
+
+fn black_car<C:Car<Color=Black>>(c: C) {
+}
+
+fn blue_car<C:Car<Color=Blue>>(c: C) {
+}
+
+fn a() { black_car(ModelT); }
+fn b() { blue_car(ModelT); } //~ ERROR type mismatch
+fn c() { black_car(ModelU); } //~ ERROR type mismatch
+fn d() { blue_car(ModelU); }
+
+pub fn main() { }
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we report an error if the trait ref in an qualified type
+// uses invalid type arguments.
+
+#![feature(associated_types)]
+
+trait Foo<T> {
+ type Bar;
+ fn get_bar(&self) -> Self::Bar;
+}
+
+fn f<T:Foo<int>>(t: &T) {
+ let u: <T as Foo<uint>>::Bar = t.get_bar();
+ //~^ ERROR the trait `Foo<uint>` is not implemented for the type `T`
+}
+
+fn main() { }
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we do not ICE when an impl is missing an associated type (and that we report
+// a useful error, of course).
+
+#![feature(associated_types)]
+
+trait Trait {
+ type Type;
+}
+
+impl Trait for int {} //~ ERROR missing: `Type`
+
+fn main() {}
+
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Make sure that fn-to-block coercion isn't incorrectly lifted over
-// other tycons.
-
-fn main() {
- fn f(f: fn(fn(fn()))) {
- }
-
- fn g(f: fn(||)) {
- }
-
- f(g);
- //~^ ERROR mismatched types: expected `fn(fn(fn()))`
-}
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Make sure that fn-to-block coercion isn't incorrectly lifted over
-// other tycons.
-
-fn coerce(b: ||) -> extern fn() {
- fn lol(f: extern fn(v: ||) -> extern fn(),
- g: ||) -> extern fn() { return f(g); }
- fn fn_id(f: extern fn()) -> extern fn() { return f }
- return lol(fn_id, b);
- //~^ ERROR mismatched types
-}
-
-fn main() {
- let i = 8i;
- let f = coerce(|| println!("{}", i) );
- f();
-}
println!("{}", *q);
}
-fn borrow(_x: &[int], _f: ||) {}
+fn borrow<F>(_x: &[int], _f: F) where F: FnOnce() {}
fn b() {
// here we alias the mutable vector into an imm slice and try to
struct X(Either<(uint,uint), fn()>);
impl X {
- pub fn with(&self, blk: |x: &Either<(uint,uint), fn()>|) {
+ pub fn with<F>(&self, blk: F) where F: FnOnce(&Either<(uint, uint), fn()>) {
let X(ref e) = *self;
blk(e)
}
|opt| { //~ ERROR cannot borrow `x` as mutable more than once at a time
match opt {
&Either::Right(ref f) => {
- x = X(Either::Left((0,0)));
+ x = X(Either::Left((0, 0)));
(*f)()
},
_ => panic!()
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-fn force(f: ||) { f(); }
+fn force<F>(f: F) where F: FnOnce() { f(); }
fn main() {
let x: int;
force(|| { //~ ERROR capture of possibly uninitialized variable: `x`
// Ensure that invoking a closure counts as a unique immutable borrow
+#![feature(unboxed_closures)]
-type Fn<'a> = ||:'a;
+type Fn<'a> = Box<FnMut() + 'a>;
struct Test<'a> {
- f: ||: 'a
+ f: Box<FnMut() + 'a>
}
-fn call(f: |Fn|) {
- f(|| {
- //~^ ERROR: closure requires unique access to `f` but it is already borrowed
- f(|| {})
+fn call<F>(mut f: F) where F: FnMut(Fn) {
+ f(box || {
+ //~^ ERROR: cannot borrow `f` as mutable more than once
+ f(box || {})
});
}
fn test1() {
- call(|a| {
- a();
+ call(|mut a| {
+ a.call_mut(());
});
}
-fn test2(f: &||) {
- (*f)(); //~ ERROR: closure invocation in a `&` reference
+fn test2<F>(f: &F) where F: FnMut() {
+ (*f)(); //~ ERROR: cannot borrow immutable dereference of `&`-pointer `*f` as mutable
}
-fn test3(f: &mut ||) {
+fn test3<F>(f: &mut F) where F: FnMut() {
(*f)();
}
fn test4(f: &Test) {
- (f.f)() //~ ERROR: closure invocation in a `&` reference
+ f.f.call_mut(()) //~ ERROR: cannot borrow immutable dereference of `Box` `*f.f` as mutable
}
fn test5(f: &mut Test) {
- (f.f)()
+ f.f.call_mut(())
}
fn test6() {
- let f = || {};
- (|| {
+ let mut f = |&mut:| {};
+ (|&mut:| {
f();
})();
}
fn test7() {
- fn foo(_: |g: |int|, b: int|) {}
- let f = |g: |int|, b: int| {};
- f(|a| { //~ ERROR: cannot borrow `f` as immutable because previous closure
+ fn foo<F>(_: F) where F: FnMut(Box<FnMut(int)>, int) {}
+ let mut f = |&mut: g: Box<FnMut(int)>, b: int| {};
+ f(box |a| { //~ ERROR: cannot borrow `f` as immutable because it is also borrowed as mutable
foo(f); //~ ERROR: cannot move out of captured outer variable
}, 3);
}
fn a() {
let mut x = 3i;
- let c1 = || x = 4;
- let c2 = || x * 5; //~ ERROR cannot borrow `x`
+ let c1 = |&mut:| x = 4;
+ let c2 = |&mut:| x * 5; //~ ERROR cannot borrow `x`
}
fn b() {
let mut x = 3i;
- let c1 = || set(&mut x);
- let c2 = || get(&x); //~ ERROR cannot borrow `x`
+ let c1 = |&mut:| set(&mut x);
+ let c2 = |&mut:| get(&x); //~ ERROR cannot borrow `x`
}
fn c() {
let mut x = 3i;
- let c1 = || set(&mut x);
- let c2 = || x * 5; //~ ERROR cannot borrow `x`
+ let c1 = |&mut:| set(&mut x);
+ let c2 = |&mut:| x * 5; //~ ERROR cannot borrow `x`
}
fn d() {
let mut x = 3i;
- let c2 = || x * 5;
+ let c2 = |&mut:| x * 5;
x = 5; //~ ERROR cannot assign
}
fn e() {
let mut x = 3i;
- let c1 = || get(&x);
+ let c1 = |&mut:| get(&x);
x = 5; //~ ERROR cannot assign
}
fn f() {
let mut x = box 3i;
- let c1 = || get(&*x);
+ let c1 = |&mut:| get(&*x);
*x = 5; //~ ERROR cannot assign
}
}
let mut x = box Foo { f: box 3 };
- let c1 = || get(&*x.f);
+ let c1 = |&mut:| get(&*x.f);
*x.f = 5; //~ ERROR cannot assign to `*x.f`
}
}
let mut x = box Foo { f: box 3 };
- let c1 = || get(&*x.f);
- let c2 = || *x.f = 5; //~ ERROR cannot borrow `x` as mutable
+ let c1 = |&mut:| get(&*x.f);
+ let c2 = |&mut:| *x.f = 5; //~ ERROR cannot borrow `x` as mutable
}
fn main() {
}
fn a(x: &int) {
- let c1 = || set(&mut *x);
+ let c1 = |&mut:| set(&mut *x);
//~^ ERROR cannot borrow
- let c2 = || set(&mut *x);
+ let c2 = |&mut:| set(&mut *x);
//~^ ERROR cannot borrow
//~| ERROR closure requires unique access
}
fn a() {
let mut x = 3i;
- let c1 = || x = 4;
- let c2 = || x = 5; //~ ERROR cannot borrow `x` as mutable more than once
+ let c1 = |&mut:| x = 4;
+ let c2 = |&mut:| x = 5; //~ ERROR cannot borrow `x` as mutable more than once
}
fn set(x: &mut int) {
fn b() {
let mut x = 3i;
- let c1 = || set(&mut x);
- let c2 = || set(&mut x); //~ ERROR cannot borrow `x` as mutable more than once
+ let c1 = |&mut:| set(&mut x);
+ let c2 = |&mut:| set(&mut x); //~ ERROR cannot borrow `x` as mutable more than once
}
fn c() {
let mut x = 3i;
- let c1 = || x = 5;
- let c2 = || set(&mut x); //~ ERROR cannot borrow `x` as mutable more than once
+ let c1 = |&mut:| x = 5;
+ let c2 = |&mut:| set(&mut x); //~ ERROR cannot borrow `x` as mutable more than once
}
fn d() {
let mut x = 3i;
- let c1 = || x = 5;
- let c2 = || { let _y = || set(&mut x); }; // (nested closure)
+ let c1 = |&mut:| x = 5;
+ let c2 = |&mut:| { let _y = |&mut:| set(&mut x); }; // (nested closure)
//~^ ERROR cannot borrow `x` as mutable more than once
}
}
let mut x = box Foo { f: box 3 };
- let c1 = || set(&mut *x.f);
- let c2 = || set(&mut *x.f);
+ let c1 = |&mut:| set(&mut *x.f);
+ let c2 = |&mut:| set(&mut *x.f);
//~^ ERROR cannot borrow `x` as mutable more than once
}
let mut this = &mut Foo {
x: 1,
};
- let r = || {
+ let mut r = |&mut:| {
let p = &this.x;
&mut this.x; //~ ERROR cannot borrow
};
}
fn a(x: &mut int) {
- let c1 = || get(x);
- let c2 = || get(x);
+ let c1 = |&mut:| get(x);
+ let c2 = |&mut:| get(x);
}
fn b(x: &mut int) {
- let c1 = || get(x);
- let c2 = || set(x); //~ ERROR closure requires unique access to `x`
+ let c1 = |&mut:| get(x);
+ let c2 = |&mut:| set(x); //~ ERROR closure requires unique access to `x`
}
fn c(x: &mut int) {
- let c1 = || get(x);
- let c2 = || { get(x); set(x); }; //~ ERROR closure requires unique access to `x`
+ let c1 = |&mut:| get(x);
+ let c2 = |&mut:| { get(x); set(x); }; //~ ERROR closure requires unique access to `x`
}
fn d(x: &mut int) {
- let c1 = || set(x);
- let c2 = || set(x); //~ ERROR closure requires unique access to `x`
+ let c1 = |&mut:| set(x);
+ let c2 = |&mut:| set(x); //~ ERROR closure requires unique access to `x`
}
fn e(x: &mut int) {
- let c1: || = || x = panic!(); //~ ERROR closure cannot assign to immutable local variable
+ let c1 = |&mut:| x = panic!(); //~ ERROR closure cannot assign to immutable local variable
}
fn main() {
fn main() {
let mut ptr = box Foo { x: 0 };
- let test = |foo: &Foo| {
+ let mut test = |&mut: foo: &Foo| {
ptr = box Foo { x: ptr.x + 1 };
};
test(&*ptr); //~ ERROR cannot borrow `*ptr`
// except according to those terms.
fn main() {
- let j: || -> int = || {
+ let j = |&:| -> int {
let i: int;
i //~ ERROR use of possibly uninitialized variable: `i`
};
// except according to those terms.
fn main() {
- let f: || -> int = || {
+ let f = |&:| -> int {
let i: int;
i //~ ERROR use of possibly uninitialized variable: `i`
};
}
impl Foo {
- pub fn foo(&mut self, fun: |&int|) {
+ pub fn foo<F>(&mut self, mut fun: F) where F: FnMut(&int) {
for f in self.n.iter() {
fun(f);
}
fn borrow(_v: &int) {}
fn borrow_mut(_v: &mut int) {}
fn cond() -> bool { panic!() }
-fn for_func(_f: || -> bool) { panic!() }
+fn for_func<F>(_f: F) where F: FnOnce() -> bool { panic!() }
fn produce<T>() -> T { panic!(); }
fn inc(v: &mut Box<int>) {
}
}
-fn loop_break_pops_scopes<'r>(_v: &'r mut [uint], f: |&'r mut uint| -> bool) {
+fn loop_break_pops_scopes<'r, F>(_v: &'r mut [uint], mut f: F) where
+ F: FnMut(&'r mut uint) -> bool,
+{
// Here we check that when you break out of an inner loop, the
// borrows that go out of scope as you exit the inner loop are
// removed from the bitset.
}
}
-fn loop_loop_pops_scopes<'r>(_v: &'r mut [uint], f: |&'r mut uint| -> bool) {
+fn loop_loop_pops_scopes<'r, F>(_v: &'r mut [uint], mut f: F) where F: FnMut(&'r mut uint) -> bool {
// Similar to `loop_break_pops_scopes` but for the `loop` keyword
while cond() {
fn borrow(_v: &int) {}
fn borrow_mut(_v: &mut int) {}
fn cond() -> bool { panic!() }
-fn for_func(_f: || -> bool) { panic!() }
+fn for_func<F>(_f: F) where F: FnOnce() -> bool { panic!() }
fn produce<T>() -> T { panic!(); }
fn inc(v: &mut Box<int>) {
use std::thread::Thread;
-fn borrow(v: &int, f: |x: &int|) {
+fn borrow<F>(v: &int, f: F) where F: FnOnce(&int) {
f(v);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-fn borrow(v: &int, f: |x: &int|) {
+fn borrow<F>(v: &int, f: F) where F: FnOnce(&int) {
f(v);
}
trait methods {
fn impurem(&self);
- fn blockm(&self, f: ||);
+ fn blockm<F>(&self, f: F) where F: FnOnce();
}
impl methods for point {
fn impurem(&self) {
}
- fn blockm(&self, f: ||) { f() }
+ fn blockm<F>(&self, f: F) where F: FnOnce() { f() }
}
fn a() {
// (locally rooted) mutable, unique vector, and that we then prevent
// modifications to the contents.
-fn takes_imm_elt(_v: &int, f: ||) {
+fn takes_imm_elt<F>(_v: &int, f: F) where F: FnOnce() {
f();
}
pub fn main() {
let bar = box 3;
- let _g = || {
+ let _g = |&mut:| {
let _h = move |:| -> int { *bar }; //~ ERROR cannot move out of captured outer variable
};
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-fn with(f: |&String|) {}
+fn with<F>(f: F) where F: FnOnce(&String) {}
fn arg_item(&_x: &String) {}
//~^ ERROR cannot move out of dereference of `&`-pointer
fn bar() {
// Original borrow ends at end of closure
- || {
+ |&:| {
let mut x = 1u;
let y = &mut x;
let z = &mut x; //~ ERROR cannot borrow
fn cond() -> bool { true }
-fn foo(_: ||) {}
+fn foo<F>(_: F) where F: FnOnce() {}
fn main() {
let pth = break; //~ ERROR: `break` outside of loop
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-struct X {
- field: ||:'static + Send,
+struct X<F> where F: FnOnce() + 'static + Send {
+ field: F,
}
-fn foo(blk: ||:'static) -> X {
- return X { field: blk }; //~ ERROR expected bounds `Send`
+fn foo<F>(blk: F) -> X<F> where F: FnOnce() + 'static {
+ //~^ ERROR the trait `core::kinds::Send` is not implemented for the type
+ return X { field: blk };
}
fn main() {
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-
-trait Foo {}
-
-fn take(f: ||:Foo) {
- //~^ ERROR only the builtin traits can be used as closure or object bounds
-}
-
-fn main() {}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-fn bar(blk: ||:'static) {
+fn bar<F>(blk: F) where F: FnOnce() + 'static {
}
fn foo(x: &()) {
bar(|| { //~ ERROR cannot infer an appropriate lifetime
let _ = x;
- //~^ ERROR captured variable `x` does not outlive
})
}
// except according to those terms.
-fn take_any(_: ||) {
+fn take_any<F>(_: F) where F: FnOnce() {
}
-fn take_const_owned(_: ||:Sync+Send) {
+fn take_const_owned<F>(_: F) where F: FnOnce() + Sync + Send {
}
-fn give_any(f: ||) {
+fn give_any<F>(f: F) where F: FnOnce() {
take_any(f);
}
-fn give_owned(f: ||:Send) {
+fn give_owned<F>(f: F) where F: FnOnce() + Send {
take_any(f);
- take_const_owned(f); //~ ERROR expected bounds `Send+Sync`, found bounds `Send`
+ take_const_owned(f); //~ ERROR the trait `core::kinds::Sync` is not implemented for the type
}
fn main() {}
fn main() {
let string = "world!";
- let f: |&str| = |s| println!("{}{}", s, string);
+ let f = |&: s: &str| println!("{}{}", s, string);
call_bare(f) //~ ERROR mismatched types
}
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-fn foo(f: || -> !) {}
-
-fn main() {
- // Type inference didn't use to be able to handle this:
- foo(|| panic!());
- foo(|| -> ! panic!());
- foo(|| 22i); //~ ERROR computation may converge in a function marked as diverging
- foo(|| -> ! 22i); //~ ERROR computation may converge in a function marked as diverging
- let x = || -> ! 1i; //~ ERROR computation may converge in a function marked as diverging
-}
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Test that coercions from fn item types are ok, but not fn pointer
-// types to closures/procs are not allowed.
-
-fn foo() {}
-
-fn fn_item_type() {
- let f = foo;
-
- let f_closure: || = f;
-}
-
-fn fn_pointer_type() {
- let f = foo as fn();
- let f_closure: || = f;
- //~^ ERROR: mismatched types
-}
-
-fn main() { }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// ignore-test FIXME(#20574)
+
#![deny(unreachable_code)]
fn main() {
- let x: || -> ! = || panic!();
+ let x = |:| panic!();
x();
std::io::println("Foo bar"); //~ ERROR: unreachable statement
}
extern fn f() {
}
+fn is_fn<F>(_: F) where F: Fn() {}
+
fn main() {
// extern functions are extern "C" fn
let _x: extern "C" fn() = f; // OK
- let _x: || = f; //~ ERROR mismatched types
+ is_fn(f); //~ ERROR the trait `core::ops::Fn()` is not implemented for the type `extern "C" fn()
}
fn takes_mut(x: &mut int) { }
-fn apply<T>(t: T, f: |T|) {
+fn apply<T, F>(t: T, f: F) where F: FnOnce(T) {
f(t)
}
}
fn g() {
- let _frob: |Box<int>| = |q| { *q = 2; }; //~ ERROR cannot assign
+ let _frob = |&: q: Box<int>| { *q = 2; }; //~ ERROR cannot assign
}
// except according to those terms.
fn test<'x>(x: &'x int) {
- drop::< for<'z>|&'z int| -> &'z int >(|z| {
+ drop::<Box<for<'z> FnMut(&'z int) -> &'z int>>(box |z| {
x
//~^ ERROR cannot infer an appropriate lifetime
});
fn main() {
let mut ptr = box Foo { x: 0 };
- let test = |foo: &Foo| {
+ let mut test = |&mut: foo: &Foo| {
println!("access {}", foo.x);
ptr = box Foo { x: ptr.x + 1 };
println!("access {}", foo.x);
fn main() {
let mut v = vec!(1i);
- let f = || v.push(2i);
+ let mut f = |&mut:| v.push(2i);
let _w = v; //~ ERROR: cannot move out of `v`
f();
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// ignore-test FIXME(japari) remove test
+
struct Foo {
f: for <'b> |&'b int|:
'b -> &'b int //~ ERROR use of undeclared lifetime name `'b`
// wrong arity.
fn _foo<F: Fn()> (f: F) {
- |t| f(t); //~ ERROR E0057
+ |&: t| f(t); //~ ERROR E0057
}
fn main() {}
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-trait MyItem<T> {}
-impl<T> MyItem<T> for T {}
-
-pub fn build_archive<'a, I: MyItem<&'a (|&uint|:'a)>>(files: I) {}
-
-fn main() {
- build_archive(&(|_| { }));
-//~^ ERROR not implemented
-}
// and rejected.
fn main() {
- (|| box *[0u].as_slice())();
+ (|&:| box *[0u].as_slice())();
//~^ ERROR cannot move out of dereference
//~^^ ERROR cannot move a value of type [uint]
}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct Baz<U> where U: Eq(U); //This is parsed as the new Fn* style parenthesis syntax.
+struct Baz<U> where U: Eq(U) -> R; // Notice this parses as well.
+struct Baz<U>(U) where U: Eq; // This rightfully signals no error as well.
+struct Foo<T> where T: Copy, (T); //~ ERROR unexpected token in `where` clause
+struct Bar<T> { x: T } where T: Copy //~ ERROR expected item, found `where`
+
+fn main() {}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-struct Obj<'a> {
- closure: ||: 'a -> u32
+struct Obj<F> where F: FnMut() -> u32 {
+ closure: F,
}
fn main() {
let o = Obj { closure: || 42 };
- o.closure(); //~ ERROR type `Obj<'_>` does not implement any method in scope named `closure`
+ o.closure(); //~ ERROR does not implement any method in scope named `closure`
//~^ NOTE use `(s.closure)(...)` if you meant to call the function stored in the `closure` field
}
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-type Step<'s, R, T> = |R, T|: 's -> R;
-type Transducer<'t, R, T, U> = |Step<'t, R, U>|: 't -> Step<'t, R, T>;
-
-fn mapping<'f, R, T, U>(f: |T|: 'f -> U) -> &'f Transducer<'f, R, T, U> {
- |step| |r, x|
- step(r, f(x))
- //~^ ERROR the type of this value must be known in this context
-}
-
-fn main() {}
fn main() {
let c = RefCell::new(vec![]);
let mut y = 1u;
- c.push(|| y = 0);
- c.push(|| y = 0);
+ c.push(box || y = 0);
+ c.push(box || y = 0);
//~^ ERROR cannot borrow `y` as mutable more than once at a time
}
let c = RefCell::new(vec![]);
let mut y = 1u;
- Push::push(&c, || y = 0);
- Push::push(&c, || y = 0);
+ Push::push(&c, box || y = 0);
+ Push::push(&c, box || y = 0);
}
trait Push<'c> {
- fn push<'f: 'c>(&self, push: ||:'f -> ());
+ fn push<'f: 'c>(&self, push: Box<FnMut() + 'f>);
}
-impl<'c> Push<'c> for RefCell<Vec<||:'c>> {
- fn push<'f: 'c>(&self, fun: ||:'f -> ()) {
+impl<'c> Push<'c> for RefCell<Vec<Box<FnMut() + 'c>>> {
+ fn push<'f: 'c>(&self, fun: Box<FnMut() + 'f>) {
self.borrow_mut().push(fun)
}
}
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![feature(lang_items)]
-#![no_std]
-#![crate_type="rlib"]
-#[lang="sized"] pub trait Sized for Sized? {}
-
-fn ice(f: for <'s> ||
- :'s //~ ERROR use of undeclared lifetime name `'s`
-) {}
-fn main() { ice(||{}) }
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-fn main() {
- let n = 0u;
-
- let f = move || n += 1; //~error boxed closures can't capture by value
-}
fn akemi(homura: Homura) {
let Some(ref madoka) = Some(homura.kaname()); //~ ERROR does not implement any method
- madoka.clone(); //~ ERROR the type of this value must be known
+ madoka.clone();
}
fn main() { }
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-fn foo(t: &mut int){
- println!("{}", t);
-}
-
-fn main() {
- let test = 10;
-
- let h = move || { //~error boxed closures can't capture by value
- let mut r = &mut test.clone();
- foo(r);
- };
-
- h();
-}
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-struct S;
-
-impl S {
- fn foo(&self) {
- let _ = move || { self }; //~error boxed closures can't capture by value
- }
-}
-
-fn main() {
-}
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-struct S;
-
-impl S {
- fn foo(&self) {
- let _ = move || { self.foo() }; //~error boxed closures can't capture by value
- }
-}
-
-fn main() {
-}
// except according to those terms.
trait vec_monad<A> {
- fn bind<B>(&self, f: |A| -> Vec<B> );
+ fn bind<B, F>(&self, f: F) where F: FnMut(A) -> Vec<B>;
}
impl<A> vec_monad<A> for Vec<A> {
- fn bind<B>(&self, f: |A| -> Vec<B> ) {
+ fn bind<B, F>(&self, mut f: F) where F: FnMut(A) -> Vec<B> {
let mut r = panic!();
for elt in self.iter() { r = r + f(*elt); }
//~^ ERROR the type of this value must be known
}
}
fn main() {
- ["hi"].bind(|x| [x] );
+ ["hi"].bind(|&mut: x| [x] );
//~^ ERROR type `[&str; 1]` does not implement any method in scope named `bind`
}
fn main() {
let needlesArr: Vec<char> = vec!('a', 'f');
- needlesArr.iter().fold(|x, y| {
+ needlesArr.iter().fold(|&: x, y| {
});
//~^^ ERROR this function takes 2 parameters but 1 parameter was supplied
//
// except according to those terms.
trait A {
- fn a(&self) {
- || self.b() //~ ERROR type `&Self` does not implement any method in scope named `b`
- }
+ fn a(&self) {
+ |&:| self.b() //~ ERROR type `&Self` does not implement any method in scope named `b`
+ //~^ ERROR expected (), found closure
+ }
}
fn main() {}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(unboxed_closures)]
+
fn id<T>(t: T) -> T { t }
-fn f<'r, T>(v: &'r T) -> ||: 'r -> T {
- id(|| *v) //~ ERROR cannot infer
+fn f<'r, T>(v: &'r T) -> Box<FnMut() -> T + 'r> {
+ id(box |&mut:| *v) //~ ERROR cannot infer
}
fn main() {
let v = &5i;
- println!("{}", f(v)());
+ println!("{}", f(v).call_mut(()));
}
+++ /dev/null
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-fn foopy() {}
-
-static f: ||: 'static = foopy;
-
-fn main () {
- f(); //~ ERROR closure invocation in a static location
-}
// except according to those terms.
fn f() { }
-struct S(||); //~ ERROR explicit lifetime bound required
+struct S(Box<FnMut()>); //~ ERROR explicit lifetime bound required
pub static C: S = S(f);
fn g() { }
-type T = ||; //~ ERROR explicit lifetime bound required
+type T = Box<FnMut()>; //~ ERROR explicit lifetime bound required
pub static D: T = g;
fn main() {}
// Regression test for issue #5239
fn main() {
- let x: |int| -> int = |ref x| { x += 1; };
+ let x = |&: ref x: int| -> int { x += 1; };
//~^ ERROR binary assignment operation `+=` cannot be applied to type `&int`
}
*x * 2
}
-fn invoke(f: || -> uint) {
+fn invoke<F>(f: F) where F: FnOnce() -> uint {
f();
}
fn main() {
let x : Box<uint> = box 9;
- let sq : || -> uint = || { *x * *x };
+ let sq = |:| { *x * *x };
twice(x); //~ ERROR: cannot move out of
invoke(sq);
pub fn remove_package_from_database() {
let mut lines_to_use: Vec<&CrateId> = Vec::new();
- let push_id = |installed_id: &CrateId| {
+ let push_id = |&mut: installed_id: &CrateId| {
lines_to_use.push(installed_id);
//~^ ERROR cannot infer an appropriate lifetime for automatic coercion due to
// conflicting requirements
}
-pub fn list_database(f: |&CrateId|) {
+pub fn list_database<F>(mut f: F) where F: FnMut(&CrateId) {
let stuff = ["foo", "bar"];
for l in stuff.iter() {
// mutable object types are not ok
assert_copy::<&'a mut (Dummy+Copy)>(); //~ ERROR `core::kinds::Copy` is not implemented
- // closures are like an `&mut` object
- assert_copy::<||>(); //~ ERROR `core::kinds::Copy` is not implemented
-
// unsafe ptrs are ok
assert_copy::<*const int>();
assert_copy::<*const &'a mut int>();
// Test that Copy bounds inherited by trait are checked.
use std::any::Any;
-use std::any::AnyRefExt;
trait Foo : Copy {
}
assert_send::<Box<Dummy>>(); //~ ERROR the trait `core::kinds::Send` is not implemented
}
-fn closure_with_no_bound_not_ok<'a>() {
- assert_send::<||:'static>(); //~ ERROR the trait `core::kinds::Send` is not implemented
-}
-
fn object_with_send_bound_ok() {
assert_send::<&'static (Dummy+Send)>();
assert_send::<Box<Dummy+Send>>();
- assert_send::<||:Send>;
}
fn main() { }
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(dead_code)]
+#![deny(raw_pointer_derive)]
+
+#[derive(Clone)]
+struct Foo {
+ x: *const int //~ ERROR use of `#[derive]` with a raw pointer
+}
+
+#[derive(Clone)]
+struct Bar(*mut int); //~ ERROR use of `#[derive]` with a raw pointer
+
+#[derive(Clone)]
+enum Baz {
+ A(*const int), //~ ERROR use of `#[derive]` with a raw pointer
+ B { x: *mut int } //~ ERROR use of `#[derive]` with a raw pointer
+}
+
+#[derive(Clone)]
+struct Buzz {
+ x: (*const int, //~ ERROR use of `#[derive]` with a raw pointer
+ *const uint) //~ ERROR use of `#[derive]` with a raw pointer
+}
+
+fn main() {}
+++ /dev/null
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![allow(dead_code)]
-#![deny(raw_pointer_deriving)]
-
-#[derive(Clone)]
-struct Foo {
- x: *const int //~ ERROR use of `#[derive]` with a raw pointer
-}
-
-#[derive(Clone)]
-struct Bar(*mut int); //~ ERROR use of `#[derive]` with a raw pointer
-
-#[derive(Clone)]
-enum Baz {
- A(*const int), //~ ERROR use of `#[derive]` with a raw pointer
- B { x: *mut int } //~ ERROR use of `#[derive]` with a raw pointer
-}
-
-#[derive(Clone)]
-struct Buzz {
- x: (*const int, //~ ERROR use of `#[derive]` with a raw pointer
- *const uint) //~ ERROR use of `#[derive]` with a raw pointer
-}
-
-fn main() {}
_ => {}
}
- let x = |mut y: int| 10i; //~ ERROR: variable does not need to be mutable
+ let x = |&: mut y: int| 10i; //~ ERROR: variable does not need to be mutable
fn what(mut foo: int) {} //~ ERROR: variable does not need to be mutable
// positive cases
_ => {}
}
- let x = |mut y: int| y = 32i;
+ let x = |&mut: mut y: int| y = 32i;
fn nothing(mut foo: int) { foo = 37i; }
// leading underscore should avoid the warning, just like the
let mut _allowed = 1i;
}
-fn callback(f: ||) {}
+fn callback<F>(f: F) where F: FnOnce() {}
// make sure the lint attribute can be turned off
#[allow(unused_mut)]
}
}
-fn callback<T>(_f: || -> T) -> T { panic!() }
+fn callback<T, F>(_f: F) -> T where F: FnOnce() -> T { panic!() }
unsafe fn unsf() {}
fn bad1() { unsafe {} } //~ ERROR: unnecessary `unsafe` block
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-fn force(f: || -> int) -> int { f() }
+fn force<F>(f: F) -> int where F: FnOnce() -> int { f() }
fn main() { println!("{}", force(|| {})); } //~ ERROR mismatched types
Baz
}
-fn f(s: &S, g: |&S|) {
+fn f<G>(s: &S, g: G) where G: FnOnce(&S) {
g(s)
}
fn main() {
let i = box 3;
- let _f = || test(i); //~ ERROR cannot move out
+ let _f = |&:| test(i); //~ ERROR cannot move out
}
// bound must be noncopyable. For details see
// http://smallcultfollowing.com/babysteps/blog/2013/04/30/the-case-of-the-recurring-closure/
+#![feature(unboxed_closures)]
+
struct R<'a> {
// This struct is needed to create the
// otherwise infinite type of a fn that
// accepts itself as argument:
- c: |&mut R, bool|: 'a
+ c: Box<FnMut(&mut R, bool) + 'a>
}
fn innocent_looking_victim() {
match x {
Some(ref msg) => {
(f.c)(f, true);
- //~^ ERROR: cannot borrow `*f` as mutable because
+ //~^ ERROR: cannot borrow `*f` as mutable more than once at a time
println!("{}", msg);
},
None => panic!("oops"),
})
}
-fn conspirator(f: |&mut R, bool|) {
- let mut r = R {c: f};
+fn conspirator<F>(mut f: F) where F: FnMut(&mut R, bool) {
+ let mut r = R {c: box f};
f(&mut r, false) //~ ERROR use of moved value
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-fn let_in<T>(x: T, f: |T|) {}
+fn let_in<T, F>(x: T, f: F) where F: FnOnce(T) {}
fn main() {
let_in(3u, |i| { assert!(i == 3i); });
// except according to those terms.
fn main() {
- let f = |3: int| println!("hello");
+ let f = |&: 3: int| println!("hello");
//~^ ERROR refutable pattern in function argument: `_` not covered
f(4);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-fn call_rec(f: |uint| -> uint) -> uint {
- (|x| f(x))(call_rec(f)) //~ ERROR cannot move out of `f`
+fn call_rec<F>(mut f: F) -> uint where F: FnMut(uint) -> uint {
+ (|&mut: x| f(x))(call_rec(f)) //~ ERROR cannot move out of `f`
}
fn main() {}
+++ /dev/null
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-fn env<'a>(blk: |p: ||: 'a|) {
- // Test that the closure here cannot be assigned
- // the lifetime `'a`, which outlives the current
- // block.
-
- let mut state = 0i;
- let statep = &mut state;
- blk(|| *statep = 1i); //~ ERROR captured variable `statep` does not outlive
-}
-
-fn no_env_no_for<'a>(blk: |p: |||: 'a) {
- // Test that a closure with no free variables CAN
- // outlive the block in which it is created.
-
- blk(|| ())
-}
-
-fn repeating_loop() {
- // Test that the closure cannot be created within `loop` loop and
- // called without, even though the state that it closes over is
- // external to the loop.
-
- let closure;
- let state = 0i;
-
- loop {
- closure = || state; //~ ERROR cannot infer
- break;
- }
-
- closure();
-}
-
-fn repeating_while() {
- // Test that the closure cannot be created within `while` loop and
- // called without, even though the state that it closes over is
- // external to the loop.
-
- let closure;
- let state = 0i;
-
- while true {
- closure = || state; //~ ERROR cannot infer
- break;
- }
-
- closure();
-}
-
-fn main() {}
impl dog {
pub fn chase_cat(&mut self) {
- let _f = || {
+ let _f = |&:| {
let p: &'static mut uint = &mut self.food; //~ ERROR cannot infer
*p = 3u;
};
//~^ ERROR declared lifetime bound not satisfied
}
-fn closure_with_lifetime_not_ok<'a>() {
- assert_send::<||:'a>();
- //~^ ERROR not implemented
-}
-
// unsafe pointers are ok unless they point at unsendable things
struct UniqueUnsafePtr(Unique<*const int>);
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(associated_types)]
+
+trait X {}
+
+trait Iter {
+ type Item: X;
+
+ fn into_item(self) -> Self::Item;
+ fn as_item(&self) -> &Self::Item;
+}
+
+fn bad1<T: Iter>(v: T) -> Box<X+'static>
+{
+ let item = v.into_item();
+ box item //~ ERROR associated type `<T as Iter>::Item` may not live long enough
+}
+
+fn bad2<T: Iter>(v: T) -> Box<X+'static>
+ where Box<T::Item> : X
+{
+ let item = box v.into_item();
+ box item //~ ERROR associated type `<T as Iter>::Item` may not live long enough
+}
+
+fn bad3<'a, T: Iter>(v: T) -> Box<X+'a>
+{
+ let item = v.into_item();
+ box item //~ ERROR associated type `<T as Iter>::Item` may not live long enough
+}
+
+fn bad4<'a, T: Iter>(v: T) -> Box<X+'a>
+ where Box<T::Item> : X
+{
+ let item = box v.into_item();
+ box item //~ ERROR associated type `<T as Iter>::Item` may not live long enough
+}
+
+fn ok1<'a, T: Iter>(v: T) -> Box<X+'a>
+ where T::Item : 'a
+{
+ let item = v.into_item();
+ box item // OK, T::Item : 'a is declared
+}
+
+fn ok2<'a, T: Iter>(v: &T, w: &'a T::Item) -> Box<X+'a>
+ where T::Item : Clone
+{
+ let item = Clone::clone(w);
+ box item // OK, T::Item : 'a is implied
+}
+
+fn ok3<'a, T: Iter>(v: &'a T) -> Box<X+'a>
+ where T::Item : Clone + 'a
+{
+ let item = Clone::clone(v.as_item());
+ box item // OK, T::Item : 'a was declared
+}
+
+fn meh1<'a, T: Iter>(v: &'a T) -> Box<X+'a>
+ where T::Item : Clone
+{
+ // This case is kind of interesting. It's the same as `ok3` but
+ // without the explicit declaration. In principle, it seems like
+ // we ought to be able to infer that `T::Item : 'a` because we
+ // invoked `v.as_self()` which yielded a value of type `&'a
+ // T::Item`. But we're not that smart at present.
+
+ let item = Clone::clone(v.as_item());
+ box item //~ ERROR associated type `<T as Iter>::Item` may not live
+}
+
+fn main() {}
+
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+
+trait X {}
+
+fn p1<T>(v: T) -> Box<X+'static>
+ where T : X
+{
+ box v //~ ERROR parameter type `T` may not live long enough
+}
+
+fn p2<T>(v: Box<T>) -> Box<X+'static>
+ where Box<T> : X
+{
+ box v //~ ERROR parameter type `T` may not live long enough
+}
+
+fn p3<'a,T>(v: T) -> Box<X+'a>
+ where T : X
+{
+ box v //~ ERROR parameter type `T` may not live long enough
+}
+
+fn p4<'a,T>(v: Box<T>) -> Box<X+'a>
+ where Box<T> : X
+{
+ box v //~ ERROR parameter type `T` may not live long enough
+}
+
+fn main() {}
+
}
}
-fn map_nums<'a,'b>(x: &ast, f: |uint| -> uint) -> &'a ast<'b> {
+fn map_nums<'a,'b, F>(x: &ast, f: &mut F) -> &'a ast<'b> where F: FnMut(uint) -> uint {
match *x {
ast::num(x) => {
- return &ast::num(f(x)); //~ ERROR borrowed value does not live long enough
+ return &ast::num((*f)(x)); //~ ERROR borrowed value does not live long enough
}
ast::add(x, y) => {
- let m_x = map_nums(x, |z| f(z));
- let m_y = map_nums(y, |z| f(z));
+ let m_x = map_nums(x, f);
+ let m_y = map_nums(y, f);
return &ast::add(m_x, m_y); //~ ERROR borrowed value does not live long enough
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-fn with_int(f: |x: &int|) {
+fn with_int<F>(f: F) where F: FnOnce(&int) {
let x = 3;
f(&x);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-fn with_int(f: |x: &int|) {
+fn with_int<F>(f: F) where F: FnOnce(&int) {
let x = 3;
f(&x);
}
struct S;
impl S {
- fn f<B>(&self, _: |&i32| -> B) {
+ fn f<B, F>(&self, _: F) where F: FnOnce(&i32) -> B {
}
}
}
}
-fn with<R:Deref>(f: |x: &int| -> R) -> int {
+fn with<R:Deref, F>(f: F) -> int where F: FnOnce(&int) -> R {
f(&3).get()
}
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-fn of<'a,T>() -> |T|:'a { panic!(); }
-fn subtype<T>(x: |T|) { panic!(); }
-
-fn test_fn<'x,'y,'z,T>(_x: &'x T, _y: &'y T, _z: &'z T) {
- // Here, x, y, and z are free. Other letters
- // are bound. Note that the arrangement
- // subtype::<T1>(of::<T2>()) will typecheck
- // iff T1 <: T2.
-
- subtype::< for<'a>|&'a T|>(
- of::< for<'a>|&'a T|>());
-
- subtype::< for<'a>|&'a T|>(
- of::< for<'b>|&'b T|>());
-
- subtype::< for<'b>|&'b T|>(
- of::<|&'x T|>());
-
- subtype::<|&'x T|>(
- of::< for<'b>|&'b T|>()); //~ ERROR mismatched types
-
- subtype::< for<'a,'b>|&'a T, &'b T|>(
- of::< for<'a>|&'a T, &'a T|>());
-
- subtype::< for<'a>|&'a T, &'a T|>(
- of::< for<'a,'b>|&'a T, &'b T|>()); //~ ERROR mismatched types
-
- subtype::< for<'a,'b>|&'a T, &'b T|>(
- of::<|&'x T, &'y T|>());
-
- subtype::<|&'x T, &'y T|>(
- of::< for<'a,'b>|&'a T, &'b T|>()); //~ ERROR mismatched types
-}
-
-fn main() {}
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Before fn subtyping was properly implemented,
-// we reported errors in this case:
-
-fn not_ok<'b>(a: &uint, b: &'b uint) {
- let mut g: |x: &uint| = |x: &'b uint| {};
- //~^ ERROR mismatched types
- g(a);
-}
-
-fn main() {
-}
panic!();
}
-fn ordering4<'a, 'b>(a: &'a uint, b: &'b uint, x: |&'a &'b uint|) {
+fn ordering4<'a, 'b, F>(a: &'a uint, b: &'b uint, x: F) where F: FnOnce(&'a &'b uint) {
// Do not infer ordering from closure argument types.
let z: Option<&'a &'b uint> = None;
//~^ ERROR reference has a longer lifetime than the data it references
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-fn wants_static_fn(_x: ||: 'static) {}
-
-fn main() {
- let i = 3i;
- wants_static_fn(|| {
- println!("i={}", i); //~ ERROR captured variable `i` does not outlive
- })
-}
// except according to those terms.
struct parameterized1<'a> {
- g: ||: 'a
+ g: Box<FnMut() + 'a>
}
struct not_parameterized1 {
- g: ||: 'static
+ g: Box<FnMut() + 'static>
}
struct not_parameterized2 {
- g: ||: 'static
+ g: Box<FnMut() + 'static>
}
fn take1<'a>(p: parameterized1) -> parameterized1<'a> { p }
fn borrow<T>(x: &T) -> &T {x}
-fn foo(cond: || -> bool, make_box: || -> Box<int>) {
+fn foo<C, M>(mut cond: C, mut make_box: M) where
+ C: FnMut() -> bool,
+ M: FnMut() -> Box<int>,
+{
let mut y: ∫
loop {
let x = make_box();
fn select<'r>(x: &'r int, y: &'r int) -> &'r int { x }
-fn with<T>(f: |x: &int| -> T) -> T {
+fn with<T, F>(f: F) -> T where F: FnOnce(&int) -> T {
f(&20)
}
struct invariant<'a> {
- f: |x: &mut &'a int|: 'static
+ f: Box<FnOnce(&mut &'a int) + 'static>,
}
fn to_same_lifetime<'r>(bi: invariant<'r>) {
struct invariant<'a> {
- f: ||: 'static -> &mut &'a int
+ f: Box<for<'b> FnOnce() -> &'b mut &'a int + 'static>,
}
fn to_same_lifetime<'r>(bi: invariant<'r>) {
struct indirect1 {
// Here the lifetime parameter of direct is bound by the fn()
- g: |direct|: 'static
+ g: Box<FnOnce(direct) + 'static>
}
struct indirect2<'a> {
// But here it is set to 'a
- g: |direct<'a>|: 'static
+ g: Box<FnOnce(direct<'a>) + 'static>
}
fn take_direct<'a,'b>(p: direct<'a>) -> direct<'b> { p } //~ ERROR mismatched types
// &'a CAN be declared on functions and used then:
fn g<'a>(a: &'a int) { } // OK
- fn h(a: for<'a>|&'a int|) { } // OK
-
- // But not in the bound of a closure, it's not in scope *there*
- fn i(a: for<'a>|&int|:'a) { } //~ ERROR undeclared lifetime
+ fn h(a: Box<for<'a> FnOnce(&'a int)>) { } // OK
}
// Test nesting of lifetimes in fn type declarations
fn fn_types(a: &'a int, //~ ERROR undeclared lifetime
- b: for<'a>|a: &'a int,
- b: &'b int, //~ ERROR undeclared lifetime
- c: for<'b>|a: &'a int,
- b: &'b int|,
- d: &'b int|, //~ ERROR undeclared lifetime
+ b: Box<for<'a> FnOnce(&'a int,
+ &'b int, //~ ERROR undeclared lifetime
+ Box<for<'b> FnOnce(&'a int,
+ &'b int)>,
+ &'b int)>, //~ ERROR undeclared lifetime
c: &'a int) //~ ERROR undeclared lifetime
{
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-fn ignore(_f: for<'z>|&'z int| -> &'z int) {}
+fn ignore<F>(_f: F) where F: for<'z> FnOnce(&'z int) -> &'z int {}
fn nested() {
let y = 3;
let y = 3;
let mut ay = &y;
- ignore::< for<'z>|&'z int|>(|z| {
+ ignore::<Box<for<'z> FnMut(&'z int)>>(box |z| {
ay = x; //~ ERROR cannot infer
ay = &y;
ay = z;
});
- ignore::< for<'z>|&'z int| -> &'z int>(|z| {
+ ignore::< Box<for<'z> FnMut(&'z int) -> &'z int>>(box |z| {
if false { return x; } //~ ERROR cannot infer an appropriate lifetime for automatic
if false { return ay; }
return z;
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn assert_send<T: Send>(_t: T) {}
+
+fn main() {
+ let line = String::new();
+ match [line.as_slice()] { //~ ERROR `line` does not live long enough
+ [ word ] => { assert_send(word); }
+ }
+}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ let a0 = 0u8;
+ let f = 1u8;
+ let mut a1 = &a0;
+ match (&a1,) {
+ (&ref b0,) => {
+ a1 = &f; //~ ERROR cannot assign
+ }
+ }
+}
x //~^ ERROR borrowed value does not live long enough
}
-fn with<R>(f: |Box<int>| -> R) -> R { f(box 3) }
+fn with<R, F>(f: F) -> R where F: FnOnce(Box<int>) -> R { f(box 3) }
fn arg_closure() -> &'static int {
with(|box ref x| x) //~ ERROR borrowed value does not live long enough
// some point regions-ret-borrowed reported an error but this file did
// not, due to special hardcoding around the anonymous region.
-fn with<R>(f: for<'a>|x: &'a int| -> R) -> R {
+fn with<R, F>(f: F) -> R where F: for<'a> FnOnce(&'a int) -> R {
f(&3)
}
// used to successfully compile because we failed to account for the
// fact that fn(x: &int) rebound the region &.
-fn with<R>(f: |x: &int| -> R) -> R {
+fn with<R, F>(f: F) -> R where F: FnOnce(&int) -> R {
f(&3)
}
let x = f();
let y = f();
}
- // Boxed closure case
- {
- let mut x = 0u;
- let f = || &mut x; //~ ERROR cannot infer
- let x = f();
- let y = f();
- }
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(unboxed_closures)]
+
struct closure_box<'a> {
- cl: ||: 'a
+ cl: Box<FnMut() + 'a>,
}
-fn box_it<'r>(x: ||: 'r) -> closure_box<'r> {
+fn box_it<'r>(x: Box<FnMut() + 'r>) -> closure_box<'r> {
closure_box {cl: x}
}
fn main() {
let cl_box = {
- let mut i = 3;
- box_it(|| i += 1) //~ ERROR cannot infer
+ let mut i = 3i;
+ box_it(box || i += 1) //~ ERROR cannot infer
};
- (cl_box.cl)();
+ cl_box.cl.call_mut(());
}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::kinds::Send;
+
+struct TestType;
+
+trait TestTrait {}
+
+unsafe impl !Send for TestType {}
+//~^ ERROR negative trait bounds
+
+fn main() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(optin_builtin_traits)]
+
+use std::kinds::Send;
+
+struct TestType;
+
+impl !TestType {}
+//~^ ERROR inherent implementation can't be negated
+
+trait TestTrait {}
+
+unsafe impl !Send for TestType {}
+impl !TestTrait for TestType {}
+
+struct TestType2<T>;
+
+impl<T> !TestType2<T> {}
+//~^ ERROR inherent implementation can't be negated
+
+unsafe impl<T> !Send for TestType2<T> {}
+impl<T> !TestTrait for TestType2<T> {}
+
+fn main() {}
// error-pattern:can't use type parameters from outer function; try using
fn foo<T>(x: T) {
- fn bar(f: |T| -> T) { }
+ fn bar(f: Box<FnMut(T) -> T>) { }
}
fn main() { foo(1); }
pub fn main() {
let mut f = |&mut: x: int, y: int| -> int { x + y };
- let z = f.call_mut((1u, 2)); //~ ERROR type mismatch
+ let z = f(1u, 2); //~ ERROR mismatched types
println!("{}", z);
}
use std::ops::FnMut;
fn call_it<F:FnMut<(int,int),int>>(y: int, mut f: F) -> int {
- f.call_mut((2, y))
+ f(2, y)
}
pub fn main() {
// Test syntax checks for `type` keyword.
-struct S1 for type; //~ ERROR expected `{`, `(`, or `;` after struct name, found `for`
+struct S1 for type; //~ ERROR expected `where`, `{`, `(`, or `;` after struct name, found `for`
pub fn main() {
}
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-extern crate serialize;
-
-use std::fmt;
-use serialize::{Encodable, Encoder};
-
-pub fn buffer_encode<'a,
- T:Encodable<serialize::json::Encoder<'a>,fmt::Error>>(
- to_encode_object: &T)
- -> String {
- let mut m = String::new();
- {
- let mut encoder =
- serialize::json::Encoder::new(&mut m);
- //~^ ERROR `m` does not live long enough
- to_encode_object.encode(&mut encoder);
- }
- m
-}
-
-fn main() {}
fn some_generic_fun<T1, T2>(a: T1, b: T2) -> (T2, T1) {
- let closure = |x, y| {
+ let closure = |&: x, y| {
zzz(); // #break
(y, x)
};
// Nothing to do here really, just make sure it compiles. See issue #8513.
fn main() {
- let _ = ||();
+ let _ = |&:|();
let _ = range(1u,3).map(|_| 5i);
}
zzz(); // #break
sentinel();
- let stack_closure: |int| = |x| {
+ let closure = |&: x: int| {
zzz(); // #break
sentinel();
zzz(); // #break
sentinel();
- stack_closure(1000);
+ closure(1000);
zzz(); // #break
sentinel();
fn main() {
let x = C { θ: 0 };
- (|c: C| c.θ )(x);
+ (|&: c: C| c.θ )(x);
}
}
struct WindowCallbacks<'a> {
- pos_callback: Option<WindowPosCallback<'a>>,
+ pos_callback: Option<Box<FnMut(&Window, i32, i32) + 'a>>,
}
-pub type WindowPosCallback<'a> = |&Window, i32, i32|: 'a;
-
fn main() {
let x = WindowCallbacks { pos_callback: None };
}
// CLOSURES
-// gdb-command:whatis stack_closure1
-// gdb-check:type = struct (&mut|int|, uint)
+// gdb-command:whatis closure1
+// gdb-check:type = struct (closure, uint)
-// gdb-command:whatis stack_closure2
-// gdb-check:type = struct (&mut|i8, f32| -> f32, uint)
+// gdb-command:whatis closure2
+// gdb-check:type = struct (closure, uint)
#![omit_gdb_pretty_printer_section]
// how that maps to rustc's internal representation of these forms.
// Once closures have reached their 1.0 form, the tests below should
// probably be expanded.
- let stack_closure1 = (|x:int| {}, 0u);
- let stack_closure2 = (|x:i8, y: f32| { (x as f32) + y }, 0u);
+ let closure1 = (|&: x:int| {}, 0u);
+ let closure2 = (|&: x:i8, y: f32| { (x as f32) + y }, 0u);
zzz(); // #break
}
let struct_ref = &a_struct;
let owned = box 6;
- let closure = || {
+ let mut closure = |&mut:| {
let closure_local = 8;
- let nested_closure = || {
+ let mut nested_closure = |&mut:| {
zzz(); // #break
variable = constant + a_struct.a + struct_ref.a + *owned + closure_local;
};
let owned = box 6;
{
- let closure = || {
+ let mut first_closure = |&mut:| {
zzz(); // #break
variable = constant + a_struct.a + struct_ref.a + *owned;
};
- closure();
+ first_closure();
}
{
- let mut unboxed_closure = |&mut:| {
+ let mut second_closure = |&mut:| {
zzz(); // #break
variable = constant + a_struct.a + struct_ref.a + *owned;
};
- unboxed_closure();
+ second_closure();
}
}
fn call_it(f: Box<FnMut(String) -> String>) { }
-fn call_this(f: |&str|: Send) { }
+fn call_this<F>(f: F) where F: Fn(&str) + Send { }
-fn call_that(f: <'a>|&'a int, &'a int| -> int) { }
+fn call_that<F>(f: F) where F: for<'a>Fn(&'a int, &'a int) -> int { }
fn call_extern(f: fn() -> int) { }
// preserved. They are needed to disambiguate `{return n+1}; - 0` from
// `({return n+1}-0)`.
-fn id(f: || -> int) -> int { f() }
+fn id<F>(f: F) -> int where F: Fn() -> int { f() }
fn wsucc(_n: int) -> int { id(|| { 1 }) - 0 }
fn main() { }
// pp-exact
-fn f(f: |int|) { f(10) }
+fn f<F>(f: F) where F: Fn(int) { f(10) }
fn main() { f(|i| { assert!(i == 10) }) }
// pp-exact
fn from_foreign_fn(_x: fn()) { }
-fn from_stack_closure(_x: ||) { }
+fn from_stack_closure<F>(_x: F) where F: Fn() { }
fn main() { }
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(optin_builtin_traits)]
+
+// pp-exact
+
+trait UnsafeTrait {
+ fn foo(&self);
+}
+
+impl !UnsafeTrait for int {
+ fn foo(&self) { }
+}
+
+pub fn main() { }
}
}
-pub fn callback(f: ||) {
+pub fn callback<F>(f: F) where F: FnOnce() {
let _a = A;
f();
}
return r;
}
-fn f2(a: int, f: |int|) -> int { f(1); return a; }
+fn f2<F>(a: int, f: F) -> int where F: FnOnce(int) { f(1); return a; }
pub fn main() {
let mut a = X {x: 1};
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn pairwise_sub(mut t: Box<DoubleEndedIterator<Item=int>>) -> int {
+ let mut result = 0;
+ loop {
+ let front = t.next();
+ let back = t.next_back();
+ match (front, back) {
+ (Some(f), Some(b)) => { result += b - f; }
+ _ => { return result; }
+ }
+ }
+}
+
+fn main() {
+ let v = vec!(1, 2, 3, 4, 5, 6);
+ let r = pairwise_sub(box v.into_iter());
+ assert_eq!(r, 9);
+}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn pairwise_sub<T:DoubleEndedIterator<Item=int>>(mut t: T) -> int {
+ let mut result = 0;
+ loop {
+ let front = t.next();
+ let back = t.next_back();
+ match (front, back) {
+ (Some(f), Some(b)) => { result += b - f; }
+ _ => { return result; }
+ }
+ }
+}
+
+fn main() {
+ let v = vec!(1, 2, 3, 4, 5, 6);
+ let r =pairwise_sub(v.into_iter());
+ assert_eq!(r, 9);
+}
fn f<T>(x: Vec<T>) -> T { return x.into_iter().next().unwrap(); }
-fn g(act: |Vec<int> | -> int) -> int { return act(vec!(1, 2, 3)); }
+fn g<F>(act: F) -> int where F: FnOnce(Vec<int>) -> int { return act(vec!(1, 2, 3)); }
pub fn main() {
assert_eq!(g(f), 1);
- let f1: |Vec<String>| -> String = f;
+ let f1 = f;
assert_eq!(f1(vec!["x".to_string(), "y".to_string(), "z".to_string()]),
"x".to_string());
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-fn asBlock(f: || -> uint) -> uint {
+fn asBlock<F>(f: F) -> uint where F: FnOnce() -> uint {
return f();
}
// except according to those terms.
pub fn main() {
- fn as_buf<T>(s: String, f: |String| -> T) -> T { f(s) }
+ fn as_buf<T, F>(s: String, f: F) -> T where F: FnOnce(String) -> T { f(s) }
as_buf("foo".to_string(), |foo: String| -> () println!("{}", foo) );
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-fn force(f: || -> int) -> int { return f(); }
+fn force<F>(f: F) -> int where F: FnOnce() -> int { return f(); }
+
pub fn main() {
fn f() -> int { return 7; }
assert_eq!(force(f), 7);
- let g = {||force(f)};
+ let g = {|&:|force(f)};
assert_eq!(g(), 7);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-fn iter_vec<T>(v: Vec<T> , f: |&T|) { for x in v.iter() { f(x); } }
+fn iter_vec<T, F>(v: Vec<T> , mut f: F) where F: FnMut(&T) { for x in v.iter() { f(x); } }
pub fn main() {
let v = vec!(1i, 2, 3, 4, 5, 6, 7);
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-fn iter_vec<T>(v: Vec<T> , f: |&T|) { for x in v.iter() { f(x); } }
+fn iter_vec<T, F>(v: Vec<T>, mut f: F) where F: FnMut(&T) { for x in v.iter() { f(x); } }
pub fn main() {
let v = vec!(1i, 2, 3, 4, 5);
// except according to those terms.
-fn borrow(x: &int, f: |x: &int|) {
+fn borrow<F>(x: &int, f: F) where F: FnOnce(&int) {
f(x)
}
// the closures are in scope. Issue #6801.
fn a() -> int {
- let mut x = 3;
+ let mut x = 3i;
x += 1;
- let c1 = || x * 4;
- let c2 = || x * 5;
+ let c1 = |&:| x * 4;
+ let c2 = |&:| x * 5;
c1() * c2() * x
}
fn b() -> int {
let mut x = 3;
x += 1;
- let c1 = || get(&x);
- let c2 = || get(&x);
+ let c1 = |&:| get(&x);
+ let c2 = |&:| get(&x);
c1() * c2() * x
}
fn c() -> int {
let mut x = 3;
x += 1;
- let c1 = || x * 5;
- let c2 = || get(&x);
+ let c1 = |&:| x * 5;
+ let c2 = |&:| get(&x);
c1() * c2() * x
}
swap(&mut values, &mut x.values);
}
-fn iter_ints(x: &Ints, f: |x: &int| -> bool) -> bool {
+fn iter_ints<F>(x: &Ints, mut f: F) -> bool where F: FnMut(&int) -> bool {
let l = x.values.len();
range(0u, l).all(|i| f(&x.values[i]))
}
extern crate libc;
-use std::c_str::ToCStr;
+use std::ffi::CString;
mod mlibc {
use libc::{c_char, c_long, c_longlong};
}
fn atol(s: String) -> int {
- s.as_slice().with_c_str(|x| unsafe { mlibc::atol(x) as int })
+ let c = CString::from_slice(s.as_bytes());
+ unsafe { mlibc::atol(c.as_ptr()) as int }
}
fn atoll(s: String) -> i64 {
- s.as_slice().with_c_str(|x| unsafe { mlibc::atoll(x) as i64 })
+ let c = CString::from_slice(s.as_bytes());
+ unsafe { mlibc::atoll(c.as_ptr()) as i64 }
}
pub fn main() {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
fn foo() -> int { 22 }
pub fn main() {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-fn each<T>(x: &[T], f: |&T|) {
+fn each<T, F>(x: &[T], mut f: F) where F: FnMut(&T) {
for val in x.iter() {
f(val)
}
fn foo(i: int) -> int { i + 1 }
-fn apply<A>(f: |A| -> A, v: A) -> A { f(v) }
+fn apply<A, F>(f: F, v: A) -> A where F: FnOnce(A) -> A { f(v) }
pub fn main() {
- let f = {|i| foo(i)};
+ let f = {|: i| foo(i)};
assert_eq!(apply(f, 2), 3);
}
// Test a rather underspecified example:
pub fn main() {
- let f = {|i| i};
+ let f = {|&: i| i};
assert_eq!(f(2i), 2i);
assert_eq!(f(5i), 5i);
}
println!("{}", f("Fred".to_string()))
}
-fn call_a_thunk(f: ||) {
+fn call_a_thunk<F>(f: F) where F: FnOnce() {
f();
}
-fn call_this(f: |&str|:Send) {
+fn call_this<F>(f: F) where F: FnOnce(&str) + Send {
f("Hello!");
}
-fn call_that(f: <'a>|&'a int, &'a int| -> int) {
- let (ten, forty_two) = (10, 42);
- println!("Your lucky number is {}", f(&ten, &forty_two));
-}
-
-fn call_cramped(f:||->uint,g:<'a>||->&'a uint) {
- let number = f();
- let other_number = *g();
- println!("Ticket {} wins an all-expenses-paid trip to Mountain View", number + other_number);
-}
-
fn call_bare(f: fn(&str)) {
f("Hello world!")
}
call_this(|s| println!("{}", s));
- call_that(|x, y| *x + *y);
-
- let z = 100;
- call_that(|x, y| *x + *y - z);
-
- call_cramped(|| 1, || unsafe {
- static a: uint = 100;
- mem::transmute(&a)
- });
-
// External functions
call_bare(println);
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![allow(dead_code)]
-
-fn f(x: || -> !) -> ! {
- x();
-}
-
-fn main() {
- let x: || -> ! = || panic!();
- let _y: || -> ! = || x();
-}
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![allow(dead_code)]
-#![feature(unboxed_closures)]
-
-// compile-flags:-g
-
-fn foo<T>() {}
-
-trait Bar3 {}
-impl<'b> Bar3 for <'a>|&'a int|: 'b + Send -> &'a int {}
-
-struct Foo<'a> {
- a: ||: 'a,
- b: ||: 'static,
- c: <'b>||: 'a,
- d: ||: 'a + Sync,
- e: <'b>|int|: 'a + Sync -> &'b f32,
-}
-
-fn f<'a>(a: &'a int, f: <'b>|&'b int| -> &'b int) -> &'a int {
- f(a)
-}
-
-fn g<'a>(a: &'a int) -> &'a int {
- a
-}
-
-struct A;
-
-impl A {
- fn foo<T>(&self) {}
-}
-
-fn bar<'b>() {
- foo::<||>();
- foo::<|| -> ()>();
- foo::<||:>();
- foo::<||:'b>();
- foo::<||:'b + Sync>();
- foo::<||:Sync>();
- foo::< <'a>|int, f32, &'a int|:'b + Sync -> &'a int>();
-
- foo::<<'a>||>();
-
- // issue #11209
- let _: ||: 'b; // for comparison
- let _: <'a> ||;
-
- let _: Option<||:'b>;
- let _: Option<<'a>||>;
- let _: Option< <'a>||>;
-
- // issue #11210
- let _: ||: 'static;
-
- let a = A;
- a.foo::<<'a>||>();
-
- // issue #13490
- let _ = || -> ! loop {};
-
- // issue #17021
- let c = box |&:| {};
-}
-
-struct B<T>;
-impl<'b> B<<'a>||: 'b> {}
-
-pub fn main() {
-}
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![feature(unboxed_closures)]
-
-fn id<T>(x: T) -> T {
- x
-}
-
-#[derive(PartialEq, Show)]
-struct Foo<T>(T);
-
-#[derive(PartialEq, Show)]
-enum Bar<T> {
- Baz(T)
-}
-
-pub fn main() {
- let f: |int| -> int = id;
- assert_eq!(f(5), 5);
-
- let f: |int| -> Foo<int> = Foo;
- assert_eq!(f(5), Foo(5));
-
- let f: |int| -> Bar<int> = Bar::Baz;
- assert_eq!(f(5), Bar::Baz(5));
-
- let f: |int| -> Option<int> = Some;
- assert_eq!(f(5), Some(5));
-}
return 0xca7f000d;
}
-struct Bar<'a> { f: ||: 'a -> int }
+struct Bar<F> where F: FnMut() -> int { f: F }
-static mut b : Bar<'static> = Bar { f: foo };
+static mut b : Bar<fn() -> int> = Bar { f: foo as fn() -> int};
pub fn main() {
unsafe { assert_eq!((b.f)(), 0xca7f000d); }
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(macro_rules)]
+
+use std::collections::Bitv;
+use std::default::Default;
+use std::iter::FromIterator;
+use std::option::IntoIter as OptionIter;
+use std::rand::Rand;
+use std::rand::XorShiftRng as DummyRng;
+// FIXME the glob std::prelude::*; import of Vec is missing non-static inherent methods.
+use std::vec::Vec;
+
+#[derive(PartialEq, Eq)]
+struct Newt<T>(T);
+
+fn id<T>(x: T) -> T { x }
+fn eq<T: Eq>(a: T, b: T) -> bool { a == b }
+fn u8_as_i8(x: u8) -> i8 { x as i8 }
+fn odd(x: uint) -> bool { x % 2 == 1 }
+fn dummy_rng() -> DummyRng { DummyRng::new_unseeded() }
+
+macro_rules! tests {
+ ($($expr:expr: $ty:ty /($($test:expr),*);)+) => (pub fn main() {$({
+ const C: $ty = $expr;
+ static S: $ty = $expr;
+ assert!(eq(C($($test),*), $expr($($test),*)));
+ assert!(eq(S($($test),*), $expr($($test),*)));
+ assert!(eq(C($($test),*), S($($test),*)));
+ })+})
+}
+
+tests! {
+ // Free function.
+ id: fn(int) -> int /(5);
+ id::<int>: fn(int) -> int /(5);
+
+ // Enum variant constructor.
+ Some: fn(int) -> Option<int> /(5);
+ Some::<int>: fn(int) -> Option<int> /(5);
+
+ // Tuple struct constructor.
+ Newt: fn(int) -> Newt<int> /(5);
+ Newt::<int>: fn(int) -> Newt<int> /(5);
+
+ // Inherent static methods.
+ Vec::new: fn() -> Vec<()> /();
+ Vec::<()>::new: fn() -> Vec<()> /();
+ Vec::with_capacity: fn(uint) -> Vec<()> /(5);
+ Vec::<()>::with_capacity: fn(uint) -> Vec<()> /(5);
+ Bitv::from_fn: fn(uint, fn(uint) -> bool) -> Bitv /(5, odd);
+ Bitv::from_fn::<fn(uint) -> bool>: fn(uint, fn(uint) -> bool) -> Bitv /(5, odd);
+
+ // Inherent non-static method.
+ Vec::map_in_place: fn(Vec<u8>, fn(u8) -> i8) -> Vec<i8>
+ /(vec![b'f', b'o', b'o'], u8_as_i8);
+ Vec::map_in_place::<i8, fn(u8) -> i8>: fn(Vec<u8>, fn(u8) -> i8) -> Vec<i8>
+ /(vec![b'f', b'o', b'o'], u8_as_i8);
+ // FIXME these break with "type parameter might not appear here pointing at `<u8>`.
+ // Vec::<u8>::map_in_place: fn(Vec<u8>, fn(u8) -> i8) -> Vec<i8>
+ // /(vec![b'f', b'o', b'o'], u8_as_i8);
+ // Vec::<u8>::map_in_place::<i8, fn(u8) -> i8>: fn(Vec<u8>, fn(u8) -> i8) -> Vec<i8>
+ // /(vec![b'f', b'o', b'o'], u8_as_i8);
+
+ // Trait static methods.
+ // FIXME qualified path expressions aka UFCS i.e. <T as Trait>::method.
+ Default::default: fn() -> int /();
+ Rand::rand: fn(&mut DummyRng) -> int /(&mut dummy_rng());
+ Rand::rand::<DummyRng>: fn(&mut DummyRng) -> int /(&mut dummy_rng());
+
+ // Trait non-static methods.
+ Clone::clone: fn(&int) -> int /(&5);
+ FromIterator::from_iter: fn(OptionIter<int>) -> Vec<int> /(Some(5).into_iter());
+ FromIterator::from_iter::<OptionIter<int>>: fn(OptionIter<int>) -> Vec<int>
+ /(Some(5).into_iter());
+}
// except according to those terms.
use std::{str, string};
-use std::c_str::ToCStr;
const A: [u8; 2] = ['h' as u8, 'i' as u8];
const B: &'static [u8; 2] = &A;
assert_eq!(String::from_raw_buf_len(C, B.len()), "hi".to_string());
assert!(*C == A[0]);
assert!(*(&B[0] as *const u8) == A[0]);
-
- let bar = str::from_utf8_unchecked(&A).to_c_str();
- assert_eq!(bar.as_str(), "hi".to_c_str().as_str());
}
}
fn f() { }
static bare_fns: &'static [fn()] = &[f, f];
-struct S<'a>(||:'a);
-static mut closures: &'static mut [S<'static>] = &mut [S(f), S(f)];
+struct S<F: FnOnce()>(F);
+static mut closures: &'static mut [S<fn()>] = &mut [S(f as fn()), S(f as fn())];
pub fn main() {
unsafe {
}
pub fn main() {
- let wrapped = {||wrapper3(chan::chan_t)};
+ let wrapped = {|&:|wrapper3(chan::chan_t)};
wrapped();
}
trait Trait {}
fn main() {
- // Closures - ||
- assert_eq!(size_of::<||>(), size_of::<Option<||>>());
-
// Functions
assert_eq!(size_of::<fn(int)>(), size_of::<Option<fn(int)>>());
assert_eq!(size_of::<extern "C" fn(int)>(), size_of::<Option<extern "C" fn(int)>>());
fn test_fn() {
- type t = ||: 'static -> int;
fn ten() -> int { return 10; }
- let rs: t = ten;
+ let rs = ten;
assert!((rs() == 10));
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
-type compare<'a, T> = |Box<T>, Box<T>|: 'a -> bool;
-
-fn test_generic<T:Clone>(expected: Box<T>, eq: compare<T>) {
+fn test_generic<T, F>(expected: Box<T>, eq: F) where T: Clone, F: FnOnce(Box<T>, Box<T>) -> bool {
let actual: Box<T> = { expected.clone() };
- assert!((eq(expected, actual)));
+ assert!(eq(expected, actual));
}
fn test_box() {
println!("{}", *b2);
return *b1 == *b2;
}
- test_generic::<bool>(box true, compare_box);
+ test_generic::<bool, _>(box true, compare_box);
}
pub fn main() { test_box(); }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
-type compare<'a, T> = |T, T|: 'a -> bool;
-
-fn test_generic<T:Clone>(expected: T, eq: compare<T>) {
+fn test_generic<T, F>(expected: T, eq: F) where T: Clone, F: FnOnce(T, T) -> bool {
let actual: T = { expected.clone() };
- assert!((eq(expected, actual)));
+ assert!(eq(expected, actual));
}
fn test_vec() {
fn compare_vec(v1: Box<int>, v2: Box<int>) -> bool { return v1 == v2; }
- test_generic::<Box<int>>(box 1, compare_vec);
+ test_generic::<Box<int>, _>(box 1, compare_vec);
}
pub fn main() { test_vec(); }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
-
-// Tests for standalone blocks as expressions with dynamic type sizes
-type compare<'a, T> = |T, T|: 'a -> bool;
-
-fn test_generic<T:Clone>(expected: T, eq: compare<T>) {
+fn test_generic<T: Clone, F>(expected: T, eq: F) where F: FnOnce(T, T) -> bool {
let actual: T = { expected.clone() };
- assert!((eq(expected, actual)));
+ assert!(eq(expected, actual));
}
fn test_bool() {
fn compare_bool(b1: bool, b2: bool) -> bool { return b1 == b2; }
- test_generic::<bool>(true, compare_bool);
+ test_generic::<bool, _>(true, compare_bool);
}
#[derive(Clone)]
fn compare_rec(t1: Pair, t2: Pair) -> bool {
t1.a == t2.a && t1.b == t2.b
}
- test_generic::<Pair>(Pair {a: 1, b: 2}, compare_rec);
+ test_generic::<Pair, _>(Pair {a: 1, b: 2}, compare_rec);
}
pub fn main() { test_bool(); test_rec(); }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
-// Tests for if as expressions with dynamic type sizes
-type compare<T> = |T, T|: 'static -> bool;
-
-fn test_generic<T:Clone>(expected: T, not_expected: T, eq: compare<T>) {
+fn test_generic<T, F>(expected: T, not_expected: T, eq: F) where
+ T: Clone,
+ F: FnOnce(T, T) -> bool,
+{
let actual: T = if true { expected.clone() } else { not_expected };
- assert!((eq(expected, actual)));
+ assert!(eq(expected, actual));
}
fn test_bool() {
fn compare_bool(b1: bool, b2: bool) -> bool { return b1 == b2; }
- test_generic::<bool>(true, false, compare_bool);
+ test_generic::<bool, _>(true, false, compare_bool);
}
#[derive(Clone)]
fn compare_rec(t1: Pair, t2: Pair) -> bool {
t1.a == t2.a && t1.b == t2.b
}
- test_generic::<Pair>(Pair{a: 1, b: 2}, Pair{a: 2, b: 3}, compare_rec);
+ test_generic::<Pair, _>(Pair{a: 1, b: 2}, Pair{a: 2, b: 3}, compare_rec);
}
pub fn main() { test_bool(); test_rec(); }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
-type compare<T> = |Box<T>, Box<T>|: 'static -> bool;
-
-fn test_generic<T:Clone>(expected: Box<T>, eq: compare<T>) {
+fn test_generic<T: Clone, F>(expected: Box<T>, eq: F) where F: FnOnce(Box<T>, Box<T>) -> bool {
let actual: Box<T> = match true {
true => { expected.clone() },
_ => panic!("wat")
};
- assert!((eq(expected, actual)));
+ assert!(eq(expected, actual));
}
fn test_box() {
fn compare_box(b1: Box<bool>, b2: Box<bool>) -> bool {
return *b1 == *b2;
}
- test_generic::<bool>(box true, compare_box);
+ test_generic::<bool, _>(box true, compare_box);
}
pub fn main() { test_box(); }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
-type compare<'a, T> = |T, T|: 'a -> bool;
-
-fn test_generic<T:Clone>(expected: T, eq: compare<T>) {
+fn test_generic<T: Clone, F>(expected: T, eq: F) where F: FnOnce(T, T) -> bool {
let actual: T = match true {
true => expected.clone(),
_ => panic!("wat")
};
- assert!((eq(expected, actual)));
+ assert!(eq(expected, actual));
}
fn test_vec() {
fn compare_box(v1: Box<int>, v2: Box<int>) -> bool { return v1 == v2; }
- test_generic::<Box<int>>(box 1, compare_box);
+ test_generic::<Box<int>, _>(box 1, compare_box);
}
pub fn main() { test_vec(); }
fn bare() {}
-fn likes_block(f: ||) { f() }
+fn likes_block<F>(f: F) where F: FnOnce() { f() }
pub fn main() {
likes_block(bare);
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-struct r<'a> {
- field: ||: 'a,
+struct r<F> where F: FnOnce() {
+ field: F,
}
pub fn main() {
fn f() {}
- let _i: r = r {field: f};
+ let _i: r<fn()> = r {field: f as fn()};
}
// except according to those terms.
pub fn main() {
- let f: |(int,int)| = |(x, y)| {
+ let f = |&: (x, y): (int, int)| {
assert_eq!(x, 1);
assert_eq!(y, 2);
};
pub fn main() {
// We should be able to type infer inside of ||s.
- let _f = || {
+ let _f = |&:| {
let i = 10i;
};
}
// except according to those terms.
-fn two(it: |int|) { it(0); it(1); }
+fn two<F>(mut it: F) where F: FnMut(int) { it(0); it(1); }
pub fn main() {
let mut a: Vec<int> = vec!(-1, -1, -1, -1);
-fn pairs(it: |(int, int)|) {
+fn pairs<F>(mut it: F) where F: FnMut((int, int)) {
let mut i: int = 0;
let mut j: int = 0;
while i < 10 { it((i, j)); i += 1; j += i; }
assert_eq!(sum, 45);
}
-fn first_ten(it: |int|) {
+fn first_ten<F>(mut it: F) where F: FnMut(int) {
let mut i: int = 0;
while i < 10 { println!("first_ten"); it(i); i = i + 1; }
}
// ignore-fast doesn't like extern crate
extern crate libc;
-use std::c_str::ToCStr;
+use std::ffi::CString;
mod mlibc {
use libc::{c_char, size_t};
fn strlen(str: String) -> uint {
// C string is terminated with a zero
- str.as_slice().with_c_str(|buf| {
- unsafe {
- mlibc::my_strlen(buf) as uint
- }
- })
+ let s = CString::from_slice(str.as_bytes());
+ unsafe {
+ mlibc::my_strlen(s.as_ptr()) as uint
+ }
}
pub fn main() {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-fn ho(f: |int| -> int) -> int { let n: int = f(3); return n; }
+fn ho<F>(f: F) -> int where F: FnOnce(int) -> int { let n: int = f(3); return n; }
fn direct(x: int) -> int { return x + 1; }
trait vec_utils<T> {
- fn map_<U>(x: &Self, f: |&T| -> U) -> Vec<U> ;
+ fn map_<U, F>(x: &Self, f: F) -> Vec<U> where F: FnMut(&T) -> U;
}
impl<T> vec_utils<T> for Vec<T> {
- fn map_<U>(x: &Vec<T> , f: |&T| -> U) -> Vec<U> {
+ fn map_<U, F>(x: &Vec<T> , mut f: F) -> Vec<U> where F: FnMut(&T) -> U {
let mut r = Vec::new();
for elt in x.iter() {
r.push(f(elt));
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(unboxed_closures)]
+
/**
A somewhat reduced test case to expose some Valgrind issues.
This originally came from the word-count benchmark.
*/
-pub fn map(filename: String, emit: map_reduce::putter) {
+pub fn map(filename: String, mut emit: map_reduce::putter) {
emit(filename, "1".to_string());
}
use std::str;
use std::thread::Thread;
- pub type putter<'a> = |String, String|: 'a;
+ pub type putter<'a> = Box<FnMut(String, String) + 'a>;
pub type mapper = extern fn(String, putter);
}
let ctrl_clone = ctrl.clone();
- ::map(input, |a,b| emit(&mut intermediates, ctrl.clone(), a, b) );
+ ::map(input, box |a,b| emit(&mut intermediates, ctrl.clone(), a, b) );
ctrl_clone.send(ctrl_proto::mapper_done).unwrap();
}
fn dummy(&self) { }
}
-fn g(_: |&Typer|) {
-}
+fn g<F>(_: F) where F: FnOnce(&Typer) {}
fn h() {
g(|typer| typer.dummy())
fn foo22(t: for<'a> extern "C" fn(int) -> int) { }
fn foo23(t: for<'a> unsafe extern "C" fn(int) -> int) { }
-fn foo30(t: for<'a> |int| -> int) { }
-fn foo31(t: for<'a> unsafe |int| -> int) { }
-
fn main() {
}
impl<'ast> PrinterSupport<'ast> for NoAnn<'ast> {
}
-fn foo<'ast> (f: Option<&'ast uint>, g: |&PrinterSupport|) {
+fn foo<'ast, G>(f: Option<&'ast uint>, g: G) where G: FnOnce(&PrinterSupport) {
let annotation = NoAnn { f: f };
g(&annotation)
}
// ...
}
-fn encode_json<
- T: for<'a> Encodable<json::Encoder<'a>,
- fmt::Error>>(val: &T,
- wr: &mut SeekableMemWriter) {
+fn encode_json<T: Encodable>(val: &T, wr: &mut SeekableMemWriter) {
write!(wr, "{}", json::as_json(val));
}
-fn encode_rbml<'a,
- T: Encodable<writer::Encoder<'a, SeekableMemWriter>,
- io::IoError>>(val: &T,
- wr: &'a mut SeekableMemWriter) {
+fn encode_rbml<T: Encodable>(val: &T, wr: &mut SeekableMemWriter) {
let mut encoder = writer::Encoder::new(wr);
val.encode(&mut encoder);
}
fn repro(self, s: MyStruct) -> String;
}
-impl Repro for |MyStruct|:'static -> String {
+impl<F> Repro for F where F: FnOnce(MyStruct) -> String {
fn repro(self, s: MyStruct) -> String {
self(s)
}
}
pub fn main() {
- assert_eq!("MyStruct".to_string(), do_stuff(|s: MyStruct| format!("{}", s)));
+ assert_eq!("MyStruct".to_string(), do_stuff(|: s: MyStruct| format!("{}", s)));
}
ids.push(TypeId::of::<testtypes::FooEnum>());
ids.push(TypeId::of::<testtypes::FooUniq>());
ids.push(TypeId::of::<testtypes::FooPtr>());
- ids.push(TypeId::of::<testtypes::FooClosure>());
ids.push(TypeId::of::<&'static testtypes::FooTrait>());
ids.push(TypeId::of::<testtypes::FooStruct>());
ids.push(TypeId::of::<testtypes::FooTuple>());
// except according to those terms.
struct Foo<'a> {
- listener: ||: 'a
+ listener: Box<FnMut() + 'a>,
}
impl<'a> Foo<'a> {
- fn new(listener: ||: 'a) -> Foo<'a> {
- Foo { listener: listener }
+ fn new<F>(listener: F) -> Foo<'a> where F: FnMut() + 'a {
+ Foo { listener: box listener }
}
}
pub fn main() {
- {|i| if 1i == i { }};
+ {|&: i| if 1i == i { }};
}
struct CharPredMatcher<'a, 'b> {
str: &'a str,
- pred: |char|:'b -> bool
+ pred: Box<FnMut(char) -> bool + 'b>,
}
impl<'a, 'b> Matcher for CharPredMatcher<'a, 'b> {
fn into_matcher(self, &'a str) -> T;
}
-impl<'a, 'b> IntoMatcher<'a, CharPredMatcher<'a, 'b>> for |char|:'b -> bool {
+impl<'a, 'b, F> IntoMatcher<'a, CharPredMatcher<'a, 'b>> for F where F: FnMut(char) -> bool + 'b {
fn into_matcher(self, s: &'a str) -> CharPredMatcher<'a, 'b> {
CharPredMatcher {
str: s,
- pred: self
+ pred: box self,
}
}
}
fn main() {
let s = "abcbdef";
- match_indices(s, |c: char| c == 'b')
+ match_indices(s, |&mut: c: char| c == 'b')
.collect::<Vec<(uint, uint)>>();
}
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-pub fn main() {
- let early_error: |&str|: 'static -> ! = |_msg| { panic!() };
-}
}
#[unsafe_destructor]
-impl<T: for<'a> Encodable<json::Encoder<'a>, fmt::Error>> Drop for Foo<T> {
+impl<T: Encodable> Drop for Foo<T> {
fn drop(&mut self) {
json::encode(&self.v);
}
fn main() {
let mut buf = Vec::new();
- |c: u8| buf.push(c);
+ |&mut: c: u8| buf.push(c);
}
fn compose<K: 'a>(mut self, mut rhs: Parser<'a, O, K>) -> Parser<'a, I, K> {
Parser {
parse: box move |&mut: x: I| {
- match (*self.parse).call_mut((x,)) {
- Ok(r) => (*rhs.parse).call_mut((r,)),
+ match (self.parse)(x) {
+ Ok(r) => (rhs.parse)(r),
Err(e) => Err(e)
}
}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct Foo<T> where T: Copy;
+struct Bar<T>(T) where T: Copy;
+struct Bleh<T, U>(T, U) where T: Copy, U: Sized;
+struct Baz<T> where T: Copy {
+ field: T
+}
+
+fn main() {}
#![allow(non_camel_case_types)]
pub fn main() {
- let one: || -> uint = || {
+ let one = |&:| {
enum r { a };
r::a as uint
};
- let two: || -> uint = || {
+ let two = |&:| {
enum r { a };
r::a as uint
};
}
}
-fn closure(f: ||) { f() }
+fn closure<F>(f: F) where F: FnOnce() { f() }
fn setsockopt_bytes(_sock: int) { }
// except according to those terms.
-type Connection = |Vec<u8>|: 'static;
+type Connection = Box<FnMut(Vec<u8>) + 'static>;
fn f() -> Option<Connection> {
- let mock_connection: Connection = |_| {};
+ let mock_connection: Connection = box |&mut: _| {};
Some(mock_connection)
}
};
let path = path::Path::new("blah");
- assert!(loader.call_mut((&path,)).is_ok());
+ assert!(loader(&path).is_ok());
}
pub fn main() {}
// except according to those terms.
pub fn main() {
- let x = 1;
- let y: || -> int = || x;
+ let x = 1u;
+ let y = |&:| x;
let _z = y();
}
enum PureCounter { PureCounterVariant(uint) }
-fn each(thing: PureCounter, blk: |v: &uint|) {
+fn each<F>(thing: PureCounter, blk: F) where F: FnOnce(&uint) {
let PureCounter::PureCounterVariant(ref x) = thing;
blk(x);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-type ErrPrinter<'a> = |&str, &str|: 'a;
-
fn example_err(prog: &str, arg: &str) {
println!("{}: {}", prog, arg)
}
-fn exit(print: ErrPrinter, prog: &str, arg: &str) {
+fn exit<F>(print: F, prog: &str, arg: &str) where F: FnOnce(&str, &str) {
print(prog, arg);
}
-struct X<'a> {
- err: ErrPrinter<'a>
+struct X<F> where F: FnOnce(&str, &str) {
+ err: F,
}
-impl<'a> X<'a> {
+impl<F> X<F> where F: FnOnce(&str, &str) {
pub fn boom(self) {
exit(self.err, "prog", "arg");
}
use serialize::{json, Decodable};
-trait JD : Decodable<json::Decoder, json::DecoderError> { }
+trait JD : Decodable {}
fn exec<T: JD>() {
let doc = json::from_str("").unwrap();
// Regression test for issue #5239
pub fn main() {
- let _f: |int| -> int = |ref x: int| { *x };
+ let _f = |&: ref x: int| { *x };
let foo = 10;
assert!(_f(foo) == 10);
}
// except according to those terms.
-fn swap(f: |Vec<int> | -> Vec<int> ) -> Vec<int> {
+fn swap<F>(f: F) -> Vec<int> where F: FnOnce(Vec<int>) -> Vec<int> {
let x = vec!(1, 2, 3);
f(x)
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-pub trait OpInt<'a> { fn call(&mut self, int, int) -> int; }
+pub trait OpInt { fn call(&mut self, int, int) -> int; }
-impl<'a> OpInt<'a> for |int, int|: 'a -> int {
+impl<F> OpInt for F where F: FnMut(int, int) -> int {
fn call(&mut self, a:int, b:int) -> int {
(*self)(a, b)
}
fn muli(x:int, y:int) -> int { x * y }
pub fn main() {
- let mut f = |x,y| muli(x,y);
+ let mut f = |&mut: x, y| muli(x, y);
{
let g = &mut f;
let h = g as &mut OpInt;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-fn f<T>(g: || -> T) -> T { g() }
+fn f<T, F>(g: F) -> T where F: FnOnce() -> T { g() }
pub fn main() {
let _x = f( | | { 10i });
let _: () = f(| | { });
// empty block with no type info should compile too
let _ = f(||{});
- let _ = (||{});
+ let _ = (|&:|{});
}
pub fn light_fuse(fld: Box<bomb>) {
int3!();
- let f = || {
+ let f = |&:| {
int3!();
fld.boom(Ident_new()); // *** 1
};
-fn range_(a: int, b: int, it: |int|) {
+fn range_<F>(a: int, b: int, mut it: F) where F: FnMut(int) {
assert!((a < b));
let mut i: int = a;
while i < b { it(i); i += 1; }
pub fn main() {
let mut e = Refs{refs: vec!(), n: 0};
- let _f: || = || println!("{}", e.n);
+ let _f = |&:| println!("{}", e.n);
let x: &[int] = e.refs.as_slice();
assert_eq!(x.len(), 0);
}
// Issue #1818
-fn lp<T>(s: String, f: |String| -> T) -> T {
+fn lp<T, F>(s: String, mut f: F) -> T where F: FnMut(String) -> T {
while false {
let r = f(s);
return (r);
panic!();
}
-fn apply<T>(s: String, f: |String| -> T) -> T {
- fn g<T>(s: String, f: |String| -> T) -> T {f(s)}
+fn apply<T, F>(s: String, mut f: F) -> T where F: FnMut(String) -> T {
+ fn g<T, F>(s: String, mut f: F) -> T where F: FnMut(String) -> T {f(s)}
g(s, |v| { let r = f(v); r })
}
// Make sure #1399 stays fixed
+#![feature(unboxed_closures)]
struct A { a: Box<int> }
-fn foo() -> ||: 'static -> int {
+fn foo() -> Box<FnMut() -> int + 'static> {
let k = box 22i;
let _u = A {a: k.clone()};
- let result: ||: 'static -> int = || 22;
- result
+ let result = |&mut:| 22;
+ box result
}
pub fn main() {
- assert_eq!(foo()(), 22);
+ assert_eq!(foo().call_mut(()), 22);
}
struct A { a: Box<int> }
pub fn main() {
- fn invoke(f: ||) { f(); }
+ fn invoke<F>(f: F) where F: FnOnce() { f(); }
let k = box 22i;
let _u = A {a: k.clone()};
invoke(|| println!("{}", k.clone()) )
enum thing { a, b, c, }
-fn foo(it: |int|) { it(10); }
+fn foo<F>(it: F) where F: FnOnce(int) { it(10); }
pub fn main() {
let mut x = true;
trait vec_monad<A> {
- fn bind<B>(&self, f: |&A| -> Vec<B> ) -> Vec<B> ;
+ fn bind<B, F>(&self, f: F ) -> Vec<B> where F: FnMut(&A) -> Vec<B> ;
}
impl<A> vec_monad<A> for Vec<A> {
- fn bind<B>(&self, f: |&A| -> Vec<B> ) -> Vec<B> {
+ fn bind<B, F>(&self, mut f: F) -> Vec<B> where F: FnMut(&A) -> Vec<B> {
let mut r = Vec::new();
for elt in self.iter() {
r.extend(f(elt).into_iter());
}
trait option_monad<A> {
- fn bind<B>(&self, f: |&A| -> Option<B>) -> Option<B>;
+ fn bind<B, F>(&self, f: F) -> Option<B> where F: FnOnce(&A) -> Option<B>;
}
impl<A> option_monad<A> for Option<A> {
- fn bind<B>(&self, f: |&A| -> Option<B>) -> Option<B> {
+ fn bind<B, F>(&self, f: F) -> Option<B> where F: FnOnce(&A) -> Option<B> {
match *self {
Some(ref a) => { f(a) }
None => { None }
// except according to those terms.
// Issue #922
-fn f2(_thing: ||) { }
+fn f2<F>(_thing: F) where F: FnOnce() { }
-fn f(thing: ||) {
+fn f<F>(thing: F) where F: FnOnce() {
f2(thing);
}
}
fn g() {
- let frob: |Box<int>| = |mut q| { *q = 2; assert!(*q == 2); };
+ let frob = |&: mut q: Box<int>| { *q = 2; assert!(*q == 2); };
let w = box 37;
frob(w);
x = 30;
assert_eq!(x, 30);
- (|A { x: mut t }: A| { t = t+1; t })(A { x: 34 });
+ (|&: A { x: mut t }: A| { t = t+1; t })(A { x: 34 });
}
// Tests for the new |args| expr lambda syntax
-fn f(i: int, f: |int| -> int) -> int { f(i) }
+fn f<F>(i: int, f: F) -> int where F: FnOnce(int) -> int { f(i) }
-fn g(_g: ||) { }
+fn g<G>(_g: G) where G: FnOnce() { }
pub fn main() {
assert_eq!(f(10, |a| a), 10);
repr: int
}
-fn apply<T>(x: T, f: |T|) {
+fn apply<T, F>(x: T, f: F) where F: FnOnce(T) {
f(x);
}
// traits.
use std::any::Any;
-use std::any::AnyRefExt;
trait Wrap {
fn get(&self) -> int;
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Tests calls to closure arguments where the closure takes 1 argument.
+// This is a bit tricky due to rust-call ABI.
+
+fn foo(f: &mut FnMut(int) -> int) -> int {
+ f(22)
+}
+
+fn main() {
+ let z = foo(&mut |x| x *100);
+ assert_eq!(z, 2200);
+}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Tests calls to closure arguments where the closure takes 2 arguments.
+// This is a bit tricky due to rust-call ABI.
+
+fn foo(f: &mut FnMut(int, int) -> int) -> int {
+ f(1, 2)
+}
+
+fn main() {
+ let z = foo(&mut |x, y| x * 10 + y);
+ assert_eq!(z, 12);
+}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Tests calls to closure arguments where the closure takes 0 arguments.
+// This is a bit tricky due to rust-call ABI.
+
+fn foo(f: &mut FnMut() -> int) -> int {
+ f()
+}
+
+fn main() {
+ let z = foo(&mut || 22);
+ assert_eq!(z, 22);
+}
x: 3,
y: 3,
};
- let ans = s.call_mut((3,));
+ let ans = s(3);
assert_eq!(ans, 27);
let s = S2 {
x: 3,
y: 3,
};
- let ans = s.call_once((3, 1));
+ let ans = s(3, 1);
assert_eq!(ans, 27);
}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test parsing binary operators after macro invocations.
+
+#![feature(macro_rules)]
+
+macro_rules! id {
+ ($e: expr) => { $e }
+}
+
+fn foo() {
+ id!(1i) + 1;
+ id![1i] - 1;
+ id!(1i) * 1;
+ id![1i] / 1;
+ id!(1i) % 1;
+
+ id!(1i) & 1;
+ id![1i] | 1;
+ id!(1i) ^ 1;
+
+ let mut x = 1i;
+ id![x] = 2;
+ id!(x) += 1;
+
+ id!(1f64).clone();
+
+ id!([1i, 2, 3])[1];
+ id![drop](1i);
+
+ id!(true) && true;
+ id![true] || true;
+}
+
+fn main() {}
}
pub fn main() {
- let f = |(x, _): (int, int)| println!("{}", x + 1);
- let g = |Foo { x: x, y: _y }: Foo| println!("{}", x + 1);
+ let f = |&: (x, _): (int, int)| println!("{}", x + 1);
+ let g = |&: Foo { x: x, y: _y }: Foo| println!("{}", x + 1);
f((2, 3));
g(Foo { x: 1, y: 2 });
}
// except according to those terms.
-fn something(f: ||) { f(); }
+fn something<F>(f: F) where F: FnOnce() { f(); }
pub fn main() {
something(|| println!("hi!") );
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(unboxed_closures)]
+
struct closure_box<'a> {
- cl: ||: 'a,
+ cl: Box<FnMut() + 'a>,
}
-fn box_it(x: ||) -> closure_box {
+fn box_it<'a>(x: Box<FnMut() + 'a>) -> closure_box<'a> {
closure_box {cl: x}
}
let mut i = 3i;
assert_eq!(i, 3);
{
- let cl = || i += 1;
- let cl_box = box_it(cl);
- (cl_box.cl)();
+ let cl = |&mut:| i += 1;
+ let mut cl_box = box_it(box cl);
+ cl_box.cl.call_mut(());
}
assert_eq!(i, 4);
}
// Test lifetimes are linked properly when we autoslice a vector.
// Issue #3148.
-fn subslice(v: ||) -> || { v }
+fn subslice<F>(v: F) -> F where F: FnOnce() { v }
-fn both(v: ||) -> || {
+fn both<F>(v: F) -> F where F: FnOnce() {
subslice(subslice(v))
}
// Here, `f` is a function that takes a pointer `x` and a function
// `g`, where `g` requires its argument `y` to be in the same region
// that `x` is in.
-fn has_same_region(f: <'a>|x: &'a int, g: |y: &'a int||) {
+fn has_same_region(f: Box<for<'a> FnMut(&'a int, Box<FnMut(&'a int)>)>) {
// `f` should be the type that `wants_same_region` wants, but
// right now the compiler complains that it isn't.
wants_same_region(f);
}
-fn wants_same_region(_f: <'b>|x: &'b int, g: |y: &'b int||) {
+fn wants_same_region(_f: Box<for<'b> FnMut(&'b int, Box<FnMut(&'b int)>)>) {
}
pub fn main() {
#![allow(unused_variable)]
// Should pass region checking.
-fn ok(f: |x: &uint|) {
+fn ok(f: Box<FnMut(&uint)>) {
// Here, g is a function that can accept a uint pointer with
// lifetime r, and f is a function that can accept a uint pointer
// with any lifetime. The assignment g = f should be OK (i.e.,
// f's type should be a subtype of g's type), because f can be
// used in any context that expects g's type. But this currently
// fails.
- let mut g: <'r>|y: &'r uint| = |x| { };
+ let mut g: Box<for<'r> FnMut(&'r uint)> = box |x| { };
g = f;
}
// This version is the same as above, except that here, g's type is
// inferred.
-fn ok_inferred(f: |x: &uint|) {
- let mut g: <'r>|x: &'r uint| = |_| {};
+fn ok_inferred(f: Box<FnMut(&uint)>) {
+ let mut g: Box<for<'r> FnMut(&'r uint)> = box |_| {};
g = f;
}
fn takes_two(x: &int, y: &int) -> int { *x + *y }
-fn with<T>(f: |x: &int| -> T) -> T {
+fn with<T, F>(f: F) -> T where F: FnOnce(&int) -> T {
f(&20)
}
pub fn main() {
fn explicit() {
- fn test(_x: Option<|f: <'a> |g: &'a int||>) {}
- test(Some(|_f: <'a> |g: &'a int|| {}));
+ fn test<F>(_x: Option<Box<F>>) where F: FnMut(Box<for<'a> FnMut(&'a int)>) {}
+ test(Some(box |&mut: _f: Box<for<'a> FnMut(&'a int)>| {}));
}
// The code below is shorthand for the code above (and more likely
// to represent what one encounters in practice).
fn implicit() {
- fn test(_x: Option<|f: |g: & int||>) {}
- test(Some(|_f: |g: & int|| {}));
+ fn test<F>(_x: Option<Box<F>>) where F: FnMut(Box< FnMut(& int)>) {}
+ test(Some(box |&mut: _f: Box< FnMut(& int)>| {}));
}
explicit();
#![allow(dead_code)]
-fn with<'a>(_: |&'a Vec<int>| -> &'a Vec<int>) { }
+fn with<'a, F>(_: F) where F: FnOnce(&'a Vec<int>) -> &'a Vec<int> { }
fn foo() {
with(|&ref ints| ints);
fn region_identity(x: &uint) -> &uint { x }
-fn apply<T>(t: T, f: |T| -> T) -> T { f(t) }
+fn apply<T, F>(t: T, f: F) -> T where F: FnOnce(T) -> T { f(t) }
fn parameterized(x: &uint) -> uint {
let z = apply(x, ({|y|
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Check that the type checker permits us to reassign `z` which
+// started out with a longer lifetime and was reassigned to a shorter
+// one (it should infer to be the intersection).
+
+fn foo(x: &int) {
+ let a = 1;
+ let mut z = x;
+ z = &a;
+}
+
+pub fn main() {
+ foo(&1);
+}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Check that the type checker permits us to reassign `z` which
+// started out with a longer lifetime and was reassigned to a shorter
+// one (it should infer to be the intersection).
+
+fn foo(x: &int) {
+ let a = 1;
+ match x {
+ mut z => {
+ z = &a;
+ }
+ }
+}
+
+pub fn main() {
+ foo(&1);
+}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that this fairly specialized, but also reasonable, pattern
+// typechecks. The pattern involves regions bound in closures that
+// wind up related to inference variables.
+//
+// NB. Changes to the region implementatiosn have broken this pattern
+// a few times, but it happens to be used in the compiler so those
+// changes were caught. However, those uses in the compiler could
+// easily get changed or refactored away in the future.
+
+struct Ctxt<'tcx> {
+ x: &'tcx Vec<int>
+}
+
+struct Foo<'a,'tcx:'a> {
+ cx: &'a Ctxt<'tcx>,
+}
+
+impl<'a,'tcx> Foo<'a,'tcx> {
+ fn bother(&mut self) -> int {
+ self.elaborate_bounds(|this| {
+ // (*) Here: type of `this` is `&'f0 Foo<&'f1, '_2>`,
+ // where `'f0` and `'f1` are fresh, free regions that
+ // result from the bound regions on the closure, and `'2`
+ // is a region inference variable created by the call. Due
+ // to the constraints on the type, we find that `'_2 : 'f1
+ // + 'f2` must hold (and can be assumed by the callee).
+ // Region inference has to do some clever stuff to avoid
+ // inferring `'_2` to be `'static` in this case, because
+ // it is created outside the closure but then related to
+ // regions bound by the closure itself. See the
+ // `region_inference.rs` file (and the `givens` field, in
+ // particular) for more details.
+ this.foo()
+ })
+ }
+
+ fn foo(&mut self) -> int {
+ 22
+ }
+
+ fn elaborate_bounds(
+ &mut self,
+ mk_cand: for<'b>|this: &mut Foo<'b, 'tcx>| -> int)
+ -> int
+ {
+ mk_cand(self)
+ }
+}
+
+fn main() {
+ let v = vec!();
+ let cx = Ctxt { x: &v };
+ let mut foo = Foo { cx: &cx };
+ assert_eq!(foo.bother(), 22); // just so the code is not dead, basically
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(unboxed_closures)]
+
struct closure_box<'a> {
- cl: ||: 'a,
+ cl: Box<FnMut() + 'a>,
}
-fn box_it(x: ||) -> closure_box {
+fn box_it<'a>(x: Box<FnMut() + 'a>) -> closure_box<'a> {
closure_box {cl: x}
}
-fn call_static_closure(cl: closure_box<'static>) {
- (cl.cl)();
+fn call_static_closure(mut cl: closure_box<'static>) {
+ cl.cl.call_mut(())
}
pub fn main() {
- let cl_box = box_it(|| println!("Hello, world!"));
+ let cl_box = box_it(box |&mut:| println!("Hello, world!"));
call_static_closure(cl_box);
}
extern crate libc;
+use std::ffi::CString;
use std::io::TempDir;
-use std::c_str::ToCStr;
use std::io::fs::PathExtensions;
use std::io::fs;
use std::io;
let test_file = &old_path.join("temp.txt");
/* Write the temp input file */
- let ostream = test_file.with_c_str(|fromp| {
- "w+b".with_c_str(|modebuf| {
- libc::fopen(fromp, modebuf)
- })
- });
+ let fromp = CString::from_slice(test_file.as_vec());
+ let modebuf = CString::from_slice(b"w+b");
+ let ostream = libc::fopen(fromp.as_ptr(), modebuf.as_ptr());
assert!((ostream as uint != 0u));
let s = "hello".to_string();
- "hello".with_c_str(|buf| {
- let write_len = libc::fwrite(buf as *const libc::c_void,
- 1u as libc::size_t,
- (s.len() + 1u) as libc::size_t,
- ostream);
- assert_eq!(write_len, (s.len() + 1) as libc::size_t)
- });
+ let buf = CString::from_slice(b"hello");
+ let write_len = libc::fwrite(buf.as_ptr() as *mut _,
+ 1u as libc::size_t,
+ (s.len() + 1u) as libc::size_t,
+ ostream);
+ assert_eq!(write_len, (s.len() + 1) as libc::size_t);
assert_eq!(libc::fclose(ostream), (0u as libc::c_int));
let new_path = tmpdir.join_many(&["quux", "blat"]);
static mut calls: uint = 0;
fn surrounding() {
- let return_works = |n: int| {
+ let return_works = |&: n: int| {
unsafe { calls += 1 }
if n >= 0 { return; }
// except according to those terms.
-fn test(f: |uint| -> uint) -> uint {
+fn test<F>(f: F) -> uint where F: FnOnce(uint) -> uint {
return f(22u);
}
trait uint_utils {
fn str(&self) -> String;
- fn multi(&self, f: |uint|);
+ fn multi<F>(&self, f: F) where F: FnMut(uint);
}
impl uint_utils for uint {
fn str(&self) -> String {
self.to_string()
}
- fn multi(&self, f: |uint|) {
+ fn multi<F>(&self, mut f: F) where F: FnMut(uint) {
let mut c = 0u;
while c < *self { f(c); c += 1u; }
}
trait vec_utils<T> {
fn length_(&self, ) -> uint;
- fn iter_(&self, f: |&T|);
- fn map_<U>(&self, f: |&T| -> U) -> Vec<U> ;
+ fn iter_<F>(&self, f: F) where F: FnMut(&T);
+ fn map_<U, F>(&self, f: F) -> Vec<U> where F: FnMut(&T) -> U;
}
impl<T> vec_utils<T> for Vec<T> {
fn length_(&self) -> uint { self.len() }
- fn iter_(&self, f: |&T|) { for x in self.iter() { f(x); } }
- fn map_<U>(&self, f: |&T| -> U) -> Vec<U> {
+ fn iter_<F>(&self, mut f: F) where F: FnMut(&T) { for x in self.iter() { f(x); } }
+ fn map_<U, F>(&self, mut f: F) -> Vec<U> where F: FnMut(&T) -> U {
let mut r = Vec::new();
for elt in self.iter() {
r.push(f(elt));
assert_eq!((vec!(1i)).length_().str(), "1".to_string());
let vect = vec!(3i, 4).map_(|a| *a + 4);
assert_eq!(vect[0], 7);
- let vect = (vec!(3i, 4)).map_::<uint>(|a| *a as uint + 4u);
+ let vect = (vec!(3i, 4)).map_::<uint, _>(|a| *a as uint + 4u);
assert_eq!(vect[0], 7u);
let mut x = 0u;
10u.multi(|_n| x += 2u );
impl S { fn new(v: int) -> S { S { val: v } } }
impl Drop for S { fn drop(&mut self) { } }
-pub fn f<T>((b1, b2): (T, T), f: |T| -> T) -> Partial<T> {
+pub fn f<T, F>((b1, b2): (T, T), mut f: F) -> Partial<T> where F: FnMut(T) -> T {
let p = Partial { x: b1, y: b2 };
// Move of `p` is legal even though we are also moving `p.y`; the
pub type Two<T> = (Partial<T>, Partial<T>);
-pub fn f<T>((b1, b2): (T, T), (b3, b4): (T, T), f: |T| -> T) -> Two<T> {
+pub fn f<T, F>((b1, b2): (T, T), (b3, b4): (T, T), mut f: F) -> Two<T> where F: FnMut(T) -> T {
let p = Partial { x: b1, y: b2 };
let q = Partial { x: b3, y: b4 };
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(optin_builtin_traits)]
+
+use std::kinds::Send;
+
+struct TestType;
+
+impl TestType {}
+
+trait TestTrait {}
+
+unsafe impl !Send for TestType {}
+impl !TestTrait for TestType {}
+
+struct TestType2<T>;
+
+impl<T> TestType2<T> {}
+
+unsafe impl<T> !Send for TestType2<T> {}
+impl<T> !TestTrait for TestType2<T> {}
+
+fn main() {}
let path = {
let p = TempDir::new_in(&Path::new("."), "foobar").unwrap();
let p = p.path();
- assert!(p.as_vec().ends_with(b"foobar"));
+ assert!(p.as_str().unwrap().contains("foobar"));
p.clone()
};
assert!(!path.exists());
assert!(r.is_err());
}
-fn in_tmpdir(f: ||) {
+fn in_tmpdir<F>(f: F) where F: FnOnce() {
let tmpdir = TempDir::new("test").ok().expect("can't make tmpdir");
assert!(os::change_dir(tmpdir.path()).is_ok());
// Tests that a heterogeneous list of existential types can be put inside an Arc
// and shared between tasks as long as all types fulfill Send.
+// ignore-pretty
+
+#![feature(unboxed_closures)]
+
use std::sync::Arc;
use std::sync::mpsc::channel;
use std::thread::Thread;
trait Pet {
- fn name(&self, blk: |&str|);
+ fn name(&self, blk: Box<FnMut(&str)>);
fn num_legs(&self) -> uint;
fn of_good_pedigree(&self) -> bool;
}
}
impl Pet for Catte {
- fn name(&self, blk: |&str|) { blk(self.name.as_slice()) }
+ fn name(&self, mut blk: Box<FnMut(&str)>) { blk(self.name.as_slice()) }
fn num_legs(&self) -> uint { 4 }
fn of_good_pedigree(&self) -> bool { self.num_whiskers >= 4 }
}
impl Pet for Dogge {
- fn name(&self, blk: |&str|) { blk(self.name.as_slice()) }
+ fn name(&self, mut blk: Box<FnMut(&str)>) { blk(self.name.as_slice()) }
fn num_legs(&self) -> uint { 4 }
fn of_good_pedigree(&self) -> bool {
self.bark_decibels < 70 || self.tricks_known > 20
}
}
impl Pet for Goldfyshe {
- fn name(&self, blk: |&str|) { blk(self.name.as_slice()) }
+ fn name(&self, mut blk: Box<FnMut(&str)>) { blk(self.name.as_slice()) }
fn num_legs(&self) -> uint { 0 }
fn of_good_pedigree(&self) -> bool { self.swim_speed >= 500 }
}
}
fn check_names(arc: Arc<Vec<Box<Pet+Sync+Send>>>) {
for pet in arc.iter() {
- pet.name(|name| {
+ pet.name(box |name| {
assert!(name.as_bytes()[0] == 'a' as u8 && name.as_bytes()[1] == 'l' as u8);
})
}
}
trait map<T> {
- fn map<U>(&self, f: |&T| -> U) -> Vec<U> ;
+ fn map<U, F>(&self, f: F) -> Vec<U> where F: FnMut(&T) -> U;
}
impl<T> map<T> for Vec<T> {
- fn map<U>(&self, f: |&T| -> U) -> Vec<U> {
+ fn map<U, F>(&self, mut f: F) -> Vec<U> where F: FnMut(&T) -> U {
let mut r = Vec::new();
for i in self.iter() {
r.push(f(i));
let f = TypeId::of::<fn(for<'a> fn(&'a int) -> &'a int)>();
assert!(e != f);
}
- // Stack closures
- {
- let a = TypeId::of::<|&'static int, &'static int|>();
- let b = TypeId::of::<for<'a> |&'static int, &'a int|>();
- let c = TypeId::of::<for<'a, 'b> |&'a int, &'b int|>();
- let d = TypeId::of::<for<'a, 'b> |&'b int, &'a int|>();
- assert!(a != b);
- assert!(a != c);
- assert!(a != d);
- assert!(b != c);
- assert!(b != d);
- assert_eq!(c, d);
-
- // Make sure De Bruijn indices are handled correctly
- let e = TypeId::of::<for<'a> |(|&'a int| -> &'a int)|>();
- let f = TypeId::of::<|for<'a> |&'a int| -> &'a int|>();
- assert!(e != f);
- }
// Boxed unboxed closures
{
let a = TypeId::of::<Box<Fn(&'static int, &'static int)>>();
b: uint,
}
-fn range_(lo: uint, hi: uint, it: |uint|) {
+fn range_<F>(lo: uint, hi: uint, mut it: F) where F: FnMut(uint) {
let mut lo_ = lo;
while lo_ < hi { it(lo_); lo_ += 1u; }
}
pub fn main() {
let mut adder = make_adder(3);
- let z = adder.call_mut((2,));
+ let z = adder(2);
println!("{}", z);
assert_eq!(z, 5);
}
--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that the call operator autoderefs when calling a bounded type parameter.
+
+#![feature(unboxed_closures)]
+
+use std::ops::FnMut;
+
+fn call_with_2(x: &fn(int) -> int) -> int
+{
+ x(2) // look ma, no `*`
+}
+
+fn subtract_22(x: int) -> int { x - 22 }
+
+pub fn main() {
+ let subtract_22: fn(int) -> int = subtract_22;
+ let z = call_with_2(&subtract_22);
+ assert_eq!(z, -20);
+}
--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that the call operator autoderefs when calling a bounded type parameter.
+
+#![feature(unboxed_closures)]
+
+use std::ops::FnMut;
+
+fn call_with_2<F>(x: &mut F) -> int
+ where F : FnMut(int) -> int
+{
+ x(2) // look ma, no `*`
+}
+
+pub fn main() {
+ let z = call_with_2(&mut |x| x - 22);
+ assert_eq!(z, -20);
+}
--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that the call operator autoderefs when calling to an object type.
+
+#![feature(unboxed_closures)]
+
+use std::ops::FnMut;
+
+fn make_adder(x: int) -> Box<FnMut(int)->int + 'static> {
+ box move |y| { x + y }
+}
+
+pub fn main() {
+ let mut adder = make_adder(3);
+ let z = adder(2);
+ println!("{}", z);
+ assert_eq!(z, 5);
+}
+
fn square(x: int) -> int { x * x }
fn call_it<F:Fn(int)->int>(f: &F, x: int) -> int {
- f.call((x,))
+ f(x)
}
fn call_it_mut<F:FnMut(int)->int>(f: &mut F, x: int) -> int {
- f.call_mut((x,))
+ f(x)
}
fn call_it_once<F:FnOnce(int)->int>(f: F, x: int) -> int {
- f.call_once((x,))
+ f(x)
}
fn main() {
}
fn call_it<F:Fn(int)->int>(f: &F, x: int) -> int {
- f.call((x,))
+ f(x)
}
fn call_it_mut<F:FnMut(int)->int>(f: &mut F, x: int) -> int {
- f.call_mut((x,))
+ f(x)
}
fn call_it_once<F:FnOnce(int)->int>(f: F, x: int) -> int {
- f.call_once((x,))
+ f(x)
}
fn main() {
}
fn call_it_mut<F:FnMut(int)->int>(f: &mut F, x: int) -> int {
- f.call_mut((x,))
+ f(x)
}
fn call_it_once<F:FnOnce(int)->int>(f: F, x: int) -> int {
- f.call_once((x,))
+ f(x)
}
fn main() {
use std::ops::FnMut;
fn call_it<F:FnMut<(int,int),int>>(y: int, mut f: F) -> int {
- f.call_mut((2, y))
+ f(2, y)
}
pub fn main() {
}
fn call_it<F:FnMut(int)->int>(mut f: F, x: int) -> int {
- f.call_mut((x,)) + 3
+ f(x) + 3
}
fn call_box(f: &mut FnMut(int) -> int, x: int) -> int {
- f.call_mut((x,)) + 3
+ f(x) + 3
}
fn main() {
task.call((0i, ));
let mut task: Box<FnMut(int) -> int> = box |&mut: x| x;
- task.call_mut((0i, ));
+ task(0i);
call(|:x| x, 22);
}
fn call<F:FnOnce(int) -> int>(f: F, x: int) -> int {
- f.call_once((x,))
+ f(x)
}
pub fn main() {
let mut f = |&mut: x: int, y: int| -> int { x + y };
- let z = f.call_mut((1, 2));
+ let z = f(1, 2);
assert_eq!(z, 3);
}
fn main() {
let onetime = |: x| x;
- onetime.call_once((0i,));
+ onetime(0i);
}
// unnamed argument &int is now parse x: &int
-fn called(_f: |&int|) {
+fn called<F>(_f: F) where F: FnOnce(&int) {
}
pub fn main() {
pub fn main() {
let _x = box 1i;
- let lam_move: || = || {};
+ let lam_move = |&:| {};
lam_move();
}
extern crate libc;
-use std::c_str::{CString, ToCStr};
+use std::ffi::{self, CString};
use libc::{c_char, c_int};
// ignore-fast doesn't like extern crate
fn sprintf(s: *mut c_char, format: *const c_char, ...) -> c_int;
}
-unsafe fn check<T>(expected: &str, f: |*mut c_char| -> T) {
+unsafe fn check<T, F>(expected: &str, f: F) where F: FnOnce(*mut c_char) -> T {
let mut x = [0 as c_char; 50];
f(&mut x[0] as *mut c_char);
- let res = CString::new(&x[0], false);
- assert_eq!(expected, res.as_str().unwrap());
+ assert_eq!(expected.as_bytes(), ffi::c_str_to_bytes(&x.as_ptr()));
}
pub fn main() {
unsafe {
// Call with just the named parameter
- "Hello World\n".with_c_str(|c| {
- check("Hello World\n", |s| sprintf(s, c));
- });
+ let c = CString::from_slice(b"Hello World\n");
+ check("Hello World\n", |s| sprintf(s, c.as_ptr()));
// Call with variable number of arguments
- "%d %f %c %s\n".with_c_str(|c| {
- check("42 42.500000 a %d %f %c %s\n\n", |s| {
- sprintf(s, c, 42i, 42.5f64, 'a' as c_int, c);
- })
+ let c = CString::from_slice(b"%d %f %c %s\n");
+ check("42 42.500000 a %d %f %c %s\n\n", |s| {
+ sprintf(s, c.as_ptr(), 42i, 42.5f64, 'a' as c_int, c.as_ptr());
});
// Make a function pointer
- let x: unsafe extern "C" fn(*mut c_char, *const c_char, ...) -> c_int = sprintf;
+ let x: unsafe extern fn(*mut c_char, *const c_char, ...) -> c_int = sprintf;
// A function that takes a function pointer
- unsafe fn call(p: unsafe extern "C" fn(*mut c_char, *const c_char, ...) -> c_int) {
- // Call with just the named parameter via fn pointer
- "Hello World\n".with_c_str(|c| {
- check("Hello World\n", |s| p(s, c));
- });
+ unsafe fn call(p: unsafe extern fn(*mut c_char, *const c_char, ...) -> c_int) {
+ // Call with just the named parameter
+ let c = CString::from_slice(b"Hello World\n");
+ check("Hello World\n", |s| sprintf(s, c.as_ptr()));
// Call with variable number of arguments
- "%d %f %c %s\n".with_c_str(|c| {
- check("42 42.500000 a %d %f %c %s\n\n", |s| {
- p(s, c, 42i, 42.5f64, 'a' as c_int, c);
- })
+ let c = CString::from_slice(b"%d %f %c %s\n");
+ check("42 42.500000 a %d %f %c %s\n\n", |s| {
+ sprintf(s, c.as_ptr(), 42i, 42.5f64, 'a' as c_int, c.as_ptr());
});
}
#![feature(advanced_slice_patterns)]
-fn foldl<T,U:Clone>(values: &[T],
- initial: U,
- function: |partial: U, element: &T| -> U)
- -> U {
+fn foldl<T, U, F>(values: &[T],
+ initial: U,
+ mut function: F)
+ -> U where
+ U: Clone,
+ F: FnMut(U, &T) -> U,
+{
match values {
[ref head, tail..] =>
foldl(tail, function(initial, head), function),
}
}
-fn foldr<T,U:Clone>(values: &[T],
- initial: U,
- function: |element: &T, partial: U| -> U)
- -> U {
+fn foldr<T, U, F>(values: &[T],
+ initial: U,
+ mut function: F)
+ -> U where
+ U: Clone,
+ F: FnMut(&T, U) -> U,
+{
match values {
[head.., ref tail] =>
foldr(head, function(tail, initial), function),
return while !x.get() { x.set(true); };
}
let i = &Cell::new(false);
- let dont = {||the(i)};
+ let dont = {|&:|the(i)};
dont();
assert!((i.get()));
}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that the `wf` checker properly handles bound regions in object
+// types. Compiling this code used to trigger an ICE.
+
+pub struct Context<'tcx> {
+ vec: &'tcx Vec<int>
+}
+
+pub type Cmd<'a> = &'a int;
+
+pub type DecodeInlinedItem<'a> =
+ Box<for<'tcx> FnMut(Cmd, &Context<'tcx>) -> Result<&'tcx int, ()> + 'a>;
+
+fn foo(d: DecodeInlinedItem) {
+}
+
+fn main() { }