Auto merge of #28897 - steveklabnik:rollup, r=steveklabnik
- Successful merges: #28836, #28856, #28874, #28876, #28878, #28880, #28882, #28885, #28889, #28896 - Failed merges:
This commit is contained in:
commit
b75fe81055
16 changed files with 178 additions and 84 deletions
|
@ -85,3 +85,20 @@ Use inner doc comments _only_ to document crates and file-level modules:
|
||||||
//!
|
//!
|
||||||
//! The core library is a something something...
|
//! The core library is a something something...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Explain context.
|
||||||
|
|
||||||
|
Rust doesn't have special constructors, only functions that return new
|
||||||
|
instances. These aren't visible in the automatically generated documentation
|
||||||
|
for a type, so you should specifically link to them:
|
||||||
|
|
||||||
|
``` rust
|
||||||
|
/// An iterator that yields `None` forever after the underlying iterator
|
||||||
|
/// yields `None` once.
|
||||||
|
///
|
||||||
|
/// These can be created through
|
||||||
|
/// [`iter.fuse()`](trait.Iterator.html#method.fuse).
|
||||||
|
pub struct Fuse<I> {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
|
@ -26,7 +26,7 @@ shells out to the system linker (`gcc` on most systems, `link.exe` on MSVC),
|
||||||
so it makes sense to provide extra command line
|
so it makes sense to provide extra command line
|
||||||
arguments, but this will not always be the case. In the future `rustc` may use
|
arguments, but this will not always be the case. In the future `rustc` may use
|
||||||
LLVM directly to link native libraries, in which case `link_args` will have no
|
LLVM directly to link native libraries, in which case `link_args` will have no
|
||||||
meaning. You can achieve the same effect as the `link-args` attribute with the
|
meaning. You can achieve the same effect as the `link_args` attribute with the
|
||||||
`-C link-args` argument to `rustc`.
|
`-C link-args` argument to `rustc`.
|
||||||
|
|
||||||
It is highly recommended to *not* use this attribute, and rather use the more
|
It is highly recommended to *not* use this attribute, and rather use the more
|
||||||
|
@ -71,7 +71,7 @@ Dynamic linking on Linux can be undesirable if you wish to use new library
|
||||||
features on old systems or target systems which do not have the required
|
features on old systems or target systems which do not have the required
|
||||||
dependencies for your program to run.
|
dependencies for your program to run.
|
||||||
|
|
||||||
Static linking is supported via an alternative `libc`, `musl`. You can compile
|
Static linking is supported via an alternative `libc`, [`musl`](http://www.musl-libc.org). You can compile
|
||||||
your own version of Rust with `musl` enabled and install it into a custom
|
your own version of Rust with `musl` enabled and install it into a custom
|
||||||
directory with the instructions below:
|
directory with the instructions below:
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
% Closures
|
% Closures
|
||||||
|
|
||||||
Rust not only has named functions, but anonymous functions as well. Anonymous
|
Sometimes it is useful to wrap up a function and _free variables_ for better
|
||||||
functions that have an associated environment are called ‘closures’, because they
|
clarity and reuse. The free variables that can be used come from the
|
||||||
close over an environment. Rust has a really great implementation of them, as
|
enclosing scope and are ‘closed over’ when used in the function. From this, we
|
||||||
we’ll see.
|
get the name ‘closures’ and Rust provides a really great implementation of
|
||||||
|
them, as we’ll see.
|
||||||
|
|
||||||
# Syntax
|
# Syntax
|
||||||
|
|
||||||
|
@ -34,7 +35,7 @@ assert_eq!(4, plus_two(2));
|
||||||
```
|
```
|
||||||
|
|
||||||
You’ll notice a few things about closures that are a bit different from regular
|
You’ll notice a few things about closures that are a bit different from regular
|
||||||
functions defined with `fn`. The first is that we did not need to
|
named functions defined with `fn`. The first is that we did not need to
|
||||||
annotate the types of arguments the closure takes or the values it returns. We
|
annotate the types of arguments the closure takes or the values it returns. We
|
||||||
can:
|
can:
|
||||||
|
|
||||||
|
@ -44,14 +45,15 @@ let plus_one = |x: i32| -> i32 { x + 1 };
|
||||||
assert_eq!(2, plus_one(1));
|
assert_eq!(2, plus_one(1));
|
||||||
```
|
```
|
||||||
|
|
||||||
But we don’t have to. Why is this? Basically, it was chosen for ergonomic reasons.
|
But we don’t have to. Why is this? Basically, it was chosen for ergonomic
|
||||||
While specifying the full type for named functions is helpful with things like
|
reasons. While specifying the full type for named functions is helpful with
|
||||||
documentation and type inference, the types of closures are rarely documented
|
things like documentation and type inference, the full type signatures of
|
||||||
since they’re anonymous, and they don’t cause the kinds of error-at-a-distance
|
closures are rarely documented since they’re anonymous, and they don’t cause
|
||||||
problems that inferring named function types can.
|
the kinds of error-at-a-distance problems that inferring named function types
|
||||||
|
can.
|
||||||
|
|
||||||
The second is that the syntax is similar, but a bit different. I’ve added spaces
|
The second is that the syntax is similar, but a bit different. I’ve added
|
||||||
here for easier comparison:
|
spaces here for easier comparison:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
fn plus_one_v1 (x: i32) -> i32 { x + 1 }
|
fn plus_one_v1 (x: i32) -> i32 { x + 1 }
|
||||||
|
@ -63,8 +65,8 @@ Small differences, but they’re similar.
|
||||||
|
|
||||||
# Closures and their environment
|
# Closures and their environment
|
||||||
|
|
||||||
Closures are called such because they ‘close over their environment’. It
|
The environment for a closure can include bindings from its enclosing scope in
|
||||||
looks like this:
|
addition to parameters and local bindings. It looks like this:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let num = 5;
|
let num = 5;
|
||||||
|
@ -197,9 +199,10 @@ frame. Without `move`, a closure may be tied to the stack frame that created
|
||||||
it, while a `move` closure is self-contained. This means that you cannot
|
it, while a `move` closure is self-contained. This means that you cannot
|
||||||
generally return a non-`move` closure from a function, for example.
|
generally return a non-`move` closure from a function, for example.
|
||||||
|
|
||||||
But before we talk about taking and returning closures, we should talk some more
|
But before we talk about taking and returning closures, we should talk some
|
||||||
about the way that closures are implemented. As a systems language, Rust gives
|
more about the way that closures are implemented. As a systems language, Rust
|
||||||
you tons of control over what your code does, and closures are no different.
|
gives you tons of control over what your code does, and closures are no
|
||||||
|
different.
|
||||||
|
|
||||||
# Closure implementation
|
# Closure implementation
|
||||||
|
|
||||||
|
@ -288,9 +291,9 @@ isn’t interesting. The next part is:
|
||||||
# some_closure(1) }
|
# some_closure(1) }
|
||||||
```
|
```
|
||||||
|
|
||||||
Because `Fn` is a trait, we can bound our generic with it. In this case, our closure
|
Because `Fn` is a trait, we can bound our generic with it. In this case, our
|
||||||
takes a `i32` as an argument and returns an `i32`, and so the generic bound we use
|
closure takes a `i32` as an argument and returns an `i32`, and so the generic
|
||||||
is `Fn(i32) -> i32`.
|
bound we use is `Fn(i32) -> i32`.
|
||||||
|
|
||||||
There’s one other key point here: because we’re bounding a generic with a
|
There’s one other key point here: because we’re bounding a generic with a
|
||||||
trait, this will get monomorphized, and therefore, we’ll be doing static
|
trait, this will get monomorphized, and therefore, we’ll be doing static
|
||||||
|
@ -452,7 +455,7 @@ autogenerated name.
|
||||||
The error also points out that the return type is expected to be a reference,
|
The error also points out that the return type is expected to be a reference,
|
||||||
but what we are trying to return is not. Further, we cannot directly assign a
|
but what we are trying to return is not. Further, we cannot directly assign a
|
||||||
`'static` lifetime to an object. So we'll take a different approach and return
|
`'static` lifetime to an object. So we'll take a different approach and return
|
||||||
a "trait object" by `Box`ing up the `Fn`. This _almost_ works:
|
a ‘trait object’ by `Box`ing up the `Fn`. This _almost_ works:
|
||||||
|
|
||||||
```rust,ignore
|
```rust,ignore
|
||||||
fn factory() -> Box<Fn(i32) -> i32> {
|
fn factory() -> Box<Fn(i32) -> i32> {
|
||||||
|
|
|
@ -563,8 +563,8 @@ What's going on here?
|
||||||
First, both `extern crate` and `use` allow renaming the thing that is being
|
First, both `extern crate` and `use` allow renaming the thing that is being
|
||||||
imported. So the crate is still called "phrases", but here we will refer
|
imported. So the crate is still called "phrases", but here we will refer
|
||||||
to it as "sayings". Similarly, the first `use` statement pulls in the
|
to it as "sayings". Similarly, the first `use` statement pulls in the
|
||||||
`japanese::farewells` module from the crate, but makes it available as
|
`japanese::greetings` module from the crate, but makes it available as
|
||||||
`jp_farewells` as opposed to simply `farewells`. This can help to avoid
|
`ja_greetings` as opposed to simply `greetings`. This can help to avoid
|
||||||
ambiguity when importing similarly-named items from different places.
|
ambiguity when importing similarly-named items from different places.
|
||||||
|
|
||||||
The second `use` statement uses a star glob to bring in _all_ symbols from the
|
The second `use` statement uses a star glob to bring in _all_ symbols from the
|
||||||
|
|
|
@ -42,12 +42,12 @@ loop is just a handy way to write this `loop`/`match`/`break` construct.
|
||||||
`for` loops aren't the only thing that uses iterators, however. Writing your
|
`for` loops aren't the only thing that uses iterators, however. Writing your
|
||||||
own iterator involves implementing the `Iterator` trait. While doing that is
|
own iterator involves implementing the `Iterator` trait. While doing that is
|
||||||
outside of the scope of this guide, Rust provides a number of useful iterators
|
outside of the scope of this guide, Rust provides a number of useful iterators
|
||||||
to accomplish various tasks. Before we talk about those, we should talk about a
|
to accomplish various tasks. But first, a few notes about limitations of ranges.
|
||||||
Rust anti-pattern. And that's using ranges like this.
|
|
||||||
|
|
||||||
Yes, we just talked about how ranges are cool. But ranges are also very
|
Ranges are very primitive, and we often can use better alternatives. Consider
|
||||||
primitive. For example, if you needed to iterate over the contents of a vector,
|
following Rust anti-pattern: using ranges to emulate a C-style `for` loop. Let’s
|
||||||
you may be tempted to write this:
|
suppose you needed to iterate over the contents of a vector. You may be tempted
|
||||||
|
to write this:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let nums = vec![1, 2, 3];
|
let nums = vec![1, 2, 3];
|
||||||
|
@ -281,8 +281,8 @@ If you are trying to execute a closure on an iterator for its side effects,
|
||||||
just use `for` instead.
|
just use `for` instead.
|
||||||
|
|
||||||
There are tons of interesting iterator adapters. `take(n)` will return an
|
There are tons of interesting iterator adapters. `take(n)` will return an
|
||||||
iterator over the next `n` elements of the original iterator. Let's try it out with our infinite
|
iterator over the next `n` elements of the original iterator. Let's try it out
|
||||||
iterator from before:
|
with an infinite iterator:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
for i in (1..).take(5) {
|
for i in (1..).take(5) {
|
||||||
|
|
|
@ -43,11 +43,11 @@ With that in mind, let’s learn about lifetimes.
|
||||||
Lending out a reference to a resource that someone else owns can be
|
Lending out a reference to a resource that someone else owns can be
|
||||||
complicated. For example, imagine this set of operations:
|
complicated. For example, imagine this set of operations:
|
||||||
|
|
||||||
- I acquire a handle to some kind of resource.
|
1. I acquire a handle to some kind of resource.
|
||||||
- I lend you a reference to the resource.
|
2. I lend you a reference to the resource.
|
||||||
- I decide I’m done with the resource, and deallocate it, while you still have
|
3. I decide I’m done with the resource, and deallocate it, while you still have
|
||||||
your reference.
|
your reference.
|
||||||
- You decide to use the resource.
|
4. You decide to use the resource.
|
||||||
|
|
||||||
Uh oh! Your reference is pointing to an invalid resource. This is called a
|
Uh oh! Your reference is pointing to an invalid resource. This is called a
|
||||||
dangling pointer or ‘use after free’, when the resource is memory.
|
dangling pointer or ‘use after free’, when the resource is memory.
|
||||||
|
|
|
@ -299,7 +299,7 @@ match x {
|
||||||
```
|
```
|
||||||
|
|
||||||
This prints `no`, because the `if` applies to the whole of `4 | 5`, and not to
|
This prints `no`, because the `if` applies to the whole of `4 | 5`, and not to
|
||||||
just the `5`, In other words, the the precedence of `if` behaves like this:
|
just the `5`. In other words, the precedence of `if` behaves like this:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
(4 | 5) if y => ...
|
(4 | 5) if y => ...
|
||||||
|
|
|
@ -61,7 +61,8 @@ pub struct DebugStruct<'a, 'b: 'a> {
|
||||||
has_fields: bool,
|
has_fields: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn debug_struct_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, name: &str)
|
pub fn debug_struct_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>,
|
||||||
|
name: &str)
|
||||||
-> DebugStruct<'a, 'b> {
|
-> DebugStruct<'a, 'b> {
|
||||||
let result = fmt.write_str(name);
|
let result = fmt.write_str(name);
|
||||||
DebugStruct {
|
DebugStruct {
|
||||||
|
@ -84,7 +85,8 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> {
|
||||||
|
|
||||||
if self.is_pretty() {
|
if self.is_pretty() {
|
||||||
let mut writer = PadAdapter::new(self.fmt);
|
let mut writer = PadAdapter::new(self.fmt);
|
||||||
fmt::write(&mut writer, format_args!("{}\n{}: {:#?}", prefix, name, value))
|
fmt::write(&mut writer,
|
||||||
|
format_args!("{}\n{}: {:#?}", prefix, name, value))
|
||||||
} else {
|
} else {
|
||||||
write!(self.fmt, "{} {}: {:?}", prefix, name, value)
|
write!(self.fmt, "{} {}: {:?}", prefix, name, value)
|
||||||
}
|
}
|
||||||
|
@ -195,10 +197,18 @@ impl<'a, 'b: 'a> DebugInner<'a, 'b> {
|
||||||
self.result = self.result.and_then(|_| {
|
self.result = self.result.and_then(|_| {
|
||||||
if self.is_pretty() {
|
if self.is_pretty() {
|
||||||
let mut writer = PadAdapter::new(self.fmt);
|
let mut writer = PadAdapter::new(self.fmt);
|
||||||
let prefix = if self.has_fields { "," } else { "" };
|
let prefix = if self.has_fields {
|
||||||
|
","
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
};
|
||||||
fmt::write(&mut writer, format_args!("{}\n{:#?}", prefix, entry))
|
fmt::write(&mut writer, format_args!("{}\n{:#?}", prefix, entry))
|
||||||
} else {
|
} else {
|
||||||
let prefix = if self.has_fields { ", " } else { "" };
|
let prefix = if self.has_fields {
|
||||||
|
", "
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
};
|
||||||
write!(self.fmt, "{}{:?}", prefix, entry)
|
write!(self.fmt, "{}{:?}", prefix, entry)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -207,7 +217,11 @@ impl<'a, 'b: 'a> DebugInner<'a, 'b> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn finish(&mut self) {
|
pub fn finish(&mut self) {
|
||||||
let prefix = if self.is_pretty() && self.has_fields { "\n" } else { "" };
|
let prefix = if self.is_pretty() && self.has_fields {
|
||||||
|
"\n"
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
};
|
||||||
self.result = self.result.and_then(|_| self.fmt.write_str(prefix));
|
self.result = self.result.and_then(|_| self.fmt.write_str(prefix));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,7 +246,7 @@ pub fn debug_set_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugSet<'a, 'b
|
||||||
fmt: fmt,
|
fmt: fmt,
|
||||||
result: result,
|
result: result,
|
||||||
has_fields: false,
|
has_fields: false,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,7 +261,9 @@ impl<'a, 'b: 'a> DebugSet<'a, 'b> {
|
||||||
/// Adds the contents of an iterator of entries to the set output.
|
/// Adds the contents of an iterator of entries to the set output.
|
||||||
#[stable(feature = "debug_builders", since = "1.2.0")]
|
#[stable(feature = "debug_builders", since = "1.2.0")]
|
||||||
pub fn entries<D, I>(&mut self, entries: I) -> &mut DebugSet<'a, 'b>
|
pub fn entries<D, I>(&mut self, entries: I) -> &mut DebugSet<'a, 'b>
|
||||||
where D: fmt::Debug, I: IntoIterator<Item=D> {
|
where D: fmt::Debug,
|
||||||
|
I: IntoIterator<Item = D>
|
||||||
|
{
|
||||||
for entry in entries {
|
for entry in entries {
|
||||||
self.entry(&entry);
|
self.entry(&entry);
|
||||||
}
|
}
|
||||||
|
@ -278,7 +294,7 @@ pub fn debug_list_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugList<'a,
|
||||||
fmt: fmt,
|
fmt: fmt,
|
||||||
result: result,
|
result: result,
|
||||||
has_fields: false,
|
has_fields: false,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -293,7 +309,9 @@ impl<'a, 'b: 'a> DebugList<'a, 'b> {
|
||||||
/// Adds the contents of an iterator of entries to the list output.
|
/// Adds the contents of an iterator of entries to the list output.
|
||||||
#[stable(feature = "debug_builders", since = "1.2.0")]
|
#[stable(feature = "debug_builders", since = "1.2.0")]
|
||||||
pub fn entries<D, I>(&mut self, entries: I) -> &mut DebugList<'a, 'b>
|
pub fn entries<D, I>(&mut self, entries: I) -> &mut DebugList<'a, 'b>
|
||||||
where D: fmt::Debug, I: IntoIterator<Item=D> {
|
where D: fmt::Debug,
|
||||||
|
I: IntoIterator<Item = D>
|
||||||
|
{
|
||||||
for entry in entries {
|
for entry in entries {
|
||||||
self.entry(&entry);
|
self.entry(&entry);
|
||||||
}
|
}
|
||||||
|
@ -335,10 +353,19 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> {
|
||||||
self.result = self.result.and_then(|_| {
|
self.result = self.result.and_then(|_| {
|
||||||
if self.is_pretty() {
|
if self.is_pretty() {
|
||||||
let mut writer = PadAdapter::new(self.fmt);
|
let mut writer = PadAdapter::new(self.fmt);
|
||||||
let prefix = if self.has_fields { "," } else { "" };
|
let prefix = if self.has_fields {
|
||||||
fmt::write(&mut writer, format_args!("{}\n{:#?}: {:#?}", prefix, key, value))
|
","
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
};
|
||||||
|
fmt::write(&mut writer,
|
||||||
|
format_args!("{}\n{:#?}: {:#?}", prefix, key, value))
|
||||||
} else {
|
} else {
|
||||||
let prefix = if self.has_fields { ", " } else { "" };
|
let prefix = if self.has_fields {
|
||||||
|
", "
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
};
|
||||||
write!(self.fmt, "{}{:?}: {:?}", prefix, key, value)
|
write!(self.fmt, "{}{:?}: {:?}", prefix, key, value)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -350,7 +377,10 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> {
|
||||||
/// Adds the contents of an iterator of entries to the map output.
|
/// Adds the contents of an iterator of entries to the map output.
|
||||||
#[stable(feature = "debug_builders", since = "1.2.0")]
|
#[stable(feature = "debug_builders", since = "1.2.0")]
|
||||||
pub fn entries<K, V, I>(&mut self, entries: I) -> &mut DebugMap<'a, 'b>
|
pub fn entries<K, V, I>(&mut self, entries: I) -> &mut DebugMap<'a, 'b>
|
||||||
where K: fmt::Debug, V: fmt::Debug, I: IntoIterator<Item=(K, V)> {
|
where K: fmt::Debug,
|
||||||
|
V: fmt::Debug,
|
||||||
|
I: IntoIterator<Item = (K, V)>
|
||||||
|
{
|
||||||
for (k, v) in entries {
|
for (k, v) in entries {
|
||||||
self.entry(&k, &v);
|
self.entry(&k, &v);
|
||||||
}
|
}
|
||||||
|
@ -360,7 +390,11 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> {
|
||||||
/// Finishes output and returns any error encountered.
|
/// Finishes output and returns any error encountered.
|
||||||
#[stable(feature = "debug_builders", since = "1.2.0")]
|
#[stable(feature = "debug_builders", since = "1.2.0")]
|
||||||
pub fn finish(&mut self) -> fmt::Result {
|
pub fn finish(&mut self) -> fmt::Result {
|
||||||
let prefix = if self.is_pretty() && self.has_fields { "\n" } else { "" };
|
let prefix = if self.is_pretty() && self.has_fields {
|
||||||
|
"\n"
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
};
|
||||||
self.result.and_then(|_| write!(self.fmt, "{}}}", prefix))
|
self.result.and_then(|_| write!(self.fmt, "{}}}", prefix))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,9 @@ trait GenericRadix {
|
||||||
fn base(&self) -> u8;
|
fn base(&self) -> u8;
|
||||||
|
|
||||||
/// A radix-specific prefix string.
|
/// A radix-specific prefix string.
|
||||||
fn prefix(&self) -> &'static str { "" }
|
fn prefix(&self) -> &'static str {
|
||||||
|
""
|
||||||
|
}
|
||||||
|
|
||||||
/// Converts an integer to corresponding radix digit.
|
/// Converts an integer to corresponding radix digit.
|
||||||
fn digit(&self, x: u8) -> u8;
|
fn digit(&self, x: u8) -> u8;
|
||||||
|
@ -70,7 +72,10 @@ trait GenericRadix {
|
||||||
x = x / base; // Deaccumulate the number.
|
x = x / base; // Deaccumulate the number.
|
||||||
*byte = self.digit(n.to_u8()); // Store the digit in the buffer.
|
*byte = self.digit(n.to_u8()); // Store the digit in the buffer.
|
||||||
curr -= 1;
|
curr -= 1;
|
||||||
if x == zero { break }; // No more digits left to accumulate.
|
if x == zero {
|
||||||
|
// No more digits left to accumulate.
|
||||||
|
break
|
||||||
|
};
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Do the same as above, but accounting for two's complement.
|
// Do the same as above, but accounting for two's complement.
|
||||||
|
@ -79,7 +84,10 @@ trait GenericRadix {
|
||||||
x = x / base; // Deaccumulate the number.
|
x = x / base; // Deaccumulate the number.
|
||||||
*byte = self.digit(n.to_u8()); // Store the digit in the buffer.
|
*byte = self.digit(n.to_u8()); // Store the digit in the buffer.
|
||||||
curr -= 1;
|
curr -= 1;
|
||||||
if x == zero { break }; // No more digits left to accumulate.
|
if x == zero {
|
||||||
|
// No more digits left to accumulate.
|
||||||
|
break
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let buf = unsafe { str::from_utf8_unchecked(&buf[curr..]) };
|
let buf = unsafe { str::from_utf8_unchecked(&buf[curr..]) };
|
||||||
|
@ -141,13 +149,17 @@ pub struct Radix {
|
||||||
|
|
||||||
impl Radix {
|
impl Radix {
|
||||||
fn new(base: u8) -> Radix {
|
fn new(base: u8) -> Radix {
|
||||||
assert!(2 <= base && base <= 36, "the base must be in the range of 2..36: {}", base);
|
assert!(2 <= base && base <= 36,
|
||||||
|
"the base must be in the range of 2..36: {}",
|
||||||
|
base);
|
||||||
Radix { base: base }
|
Radix { base: base }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GenericRadix for Radix {
|
impl GenericRadix for Radix {
|
||||||
fn base(&self) -> u8 { self.base }
|
fn base(&self) -> u8 {
|
||||||
|
self.base
|
||||||
|
}
|
||||||
fn digit(&self, x: u8) -> u8 {
|
fn digit(&self, x: u8) -> u8 {
|
||||||
match x {
|
match x {
|
||||||
x @ 0 ... 9 => b'0' + x,
|
x @ 0 ... 9 => b'0' + x,
|
||||||
|
|
|
@ -53,5 +53,5 @@ pub enum Count {
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub enum Position {
|
pub enum Position {
|
||||||
Next,
|
Next,
|
||||||
At(usize)
|
At(usize),
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,7 +100,9 @@ pub trait Hash {
|
||||||
|
|
||||||
/// Feeds a slice of this type into the state provided.
|
/// Feeds a slice of this type into the state provided.
|
||||||
#[stable(feature = "hash_slice", since = "1.3.0")]
|
#[stable(feature = "hash_slice", since = "1.3.0")]
|
||||||
fn hash_slice<H: Hasher>(data: &[Self], state: &mut H) where Self: Sized {
|
fn hash_slice<H: Hasher>(data: &[Self], state: &mut H)
|
||||||
|
where Self: Sized
|
||||||
|
{
|
||||||
for piece in data {
|
for piece in data {
|
||||||
piece.hash(state);
|
piece.hash(state);
|
||||||
}
|
}
|
||||||
|
@ -121,7 +123,9 @@ pub trait Hasher {
|
||||||
/// Write a single `u8` into this hasher
|
/// Write a single `u8` into this hasher
|
||||||
#[inline]
|
#[inline]
|
||||||
#[stable(feature = "hasher_write", since = "1.3.0")]
|
#[stable(feature = "hasher_write", since = "1.3.0")]
|
||||||
fn write_u8(&mut self, i: u8) { self.write(&[i]) }
|
fn write_u8(&mut self, i: u8) {
|
||||||
|
self.write(&[i])
|
||||||
|
}
|
||||||
/// Write a single `u16` into this hasher.
|
/// Write a single `u16` into this hasher.
|
||||||
#[inline]
|
#[inline]
|
||||||
#[stable(feature = "hasher_write", since = "1.3.0")]
|
#[stable(feature = "hasher_write", since = "1.3.0")]
|
||||||
|
@ -145,8 +149,7 @@ pub trait Hasher {
|
||||||
#[stable(feature = "hasher_write", since = "1.3.0")]
|
#[stable(feature = "hasher_write", since = "1.3.0")]
|
||||||
fn write_usize(&mut self, i: usize) {
|
fn write_usize(&mut self, i: usize) {
|
||||||
let bytes = unsafe {
|
let bytes = unsafe {
|
||||||
::slice::from_raw_parts(&i as *const usize as *const u8,
|
::slice::from_raw_parts(&i as *const usize as *const u8, mem::size_of::<usize>())
|
||||||
mem::size_of::<usize>())
|
|
||||||
};
|
};
|
||||||
self.write(bytes);
|
self.write(bytes);
|
||||||
}
|
}
|
||||||
|
@ -154,23 +157,33 @@ pub trait Hasher {
|
||||||
/// Write a single `i8` into this hasher.
|
/// Write a single `i8` into this hasher.
|
||||||
#[inline]
|
#[inline]
|
||||||
#[stable(feature = "hasher_write", since = "1.3.0")]
|
#[stable(feature = "hasher_write", since = "1.3.0")]
|
||||||
fn write_i8(&mut self, i: i8) { self.write_u8(i as u8) }
|
fn write_i8(&mut self, i: i8) {
|
||||||
|
self.write_u8(i as u8)
|
||||||
|
}
|
||||||
/// Write a single `i16` into this hasher.
|
/// Write a single `i16` into this hasher.
|
||||||
#[inline]
|
#[inline]
|
||||||
#[stable(feature = "hasher_write", since = "1.3.0")]
|
#[stable(feature = "hasher_write", since = "1.3.0")]
|
||||||
fn write_i16(&mut self, i: i16) { self.write_u16(i as u16) }
|
fn write_i16(&mut self, i: i16) {
|
||||||
|
self.write_u16(i as u16)
|
||||||
|
}
|
||||||
/// Write a single `i32` into this hasher.
|
/// Write a single `i32` into this hasher.
|
||||||
#[inline]
|
#[inline]
|
||||||
#[stable(feature = "hasher_write", since = "1.3.0")]
|
#[stable(feature = "hasher_write", since = "1.3.0")]
|
||||||
fn write_i32(&mut self, i: i32) { self.write_u32(i as u32) }
|
fn write_i32(&mut self, i: i32) {
|
||||||
|
self.write_u32(i as u32)
|
||||||
|
}
|
||||||
/// Write a single `i64` into this hasher.
|
/// Write a single `i64` into this hasher.
|
||||||
#[inline]
|
#[inline]
|
||||||
#[stable(feature = "hasher_write", since = "1.3.0")]
|
#[stable(feature = "hasher_write", since = "1.3.0")]
|
||||||
fn write_i64(&mut self, i: i64) { self.write_u64(i as u64) }
|
fn write_i64(&mut self, i: i64) {
|
||||||
|
self.write_u64(i as u64)
|
||||||
|
}
|
||||||
/// Write a single `isize` into this hasher.
|
/// Write a single `isize` into this hasher.
|
||||||
#[inline]
|
#[inline]
|
||||||
#[stable(feature = "hasher_write", since = "1.3.0")]
|
#[stable(feature = "hasher_write", since = "1.3.0")]
|
||||||
fn write_isize(&mut self, i: isize) { self.write_usize(i as usize) }
|
fn write_isize(&mut self, i: isize) {
|
||||||
|
self.write_usize(i as usize)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -37,12 +37,12 @@ pub struct SipHasher {
|
||||||
// and simd implementations of SipHash will use vectors
|
// and simd implementations of SipHash will use vectors
|
||||||
// of v02 and v13. By placing them in this order in the struct,
|
// of v02 and v13. By placing them in this order in the struct,
|
||||||
// the compiler can pick up on just a few simd optimizations by itself.
|
// the compiler can pick up on just a few simd optimizations by itself.
|
||||||
v0: u64, // hash state
|
v0: u64, // hash state
|
||||||
v2: u64,
|
v2: u64,
|
||||||
v1: u64,
|
v1: u64,
|
||||||
v3: u64,
|
v3: u64,
|
||||||
tail: u64, // unprocessed bytes le
|
tail: u64, // unprocessed bytes le
|
||||||
ntail: usize, // how many bytes in tail are valid
|
ntail: usize, // how many bytes in tail are valid
|
||||||
}
|
}
|
||||||
|
|
||||||
// sadly, these macro definitions can't appear later,
|
// sadly, these macro definitions can't appear later,
|
||||||
|
@ -80,8 +80,7 @@ macro_rules! u8to64_le {
|
||||||
unsafe fn load_u64_le(buf: &[u8], i: usize) -> u64 {
|
unsafe fn load_u64_le(buf: &[u8], i: usize) -> u64 {
|
||||||
debug_assert!(i + 8 <= buf.len());
|
debug_assert!(i + 8 <= buf.len());
|
||||||
let mut data = 0u64;
|
let mut data = 0u64;
|
||||||
ptr::copy_nonoverlapping(buf.get_unchecked(i),
|
ptr::copy_nonoverlapping(buf.get_unchecked(i), &mut data as *mut _ as *mut u8, 8);
|
||||||
&mut data as *mut _ as *mut u8, 8);
|
|
||||||
data.to_le()
|
data.to_le()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,12 +151,12 @@ impl Hasher for SipHasher {
|
||||||
if self.ntail != 0 {
|
if self.ntail != 0 {
|
||||||
needed = 8 - self.ntail;
|
needed = 8 - self.ntail;
|
||||||
if length < needed {
|
if length < needed {
|
||||||
self.tail |= u8to64_le!(msg, 0, length) << 8*self.ntail;
|
self.tail |= u8to64_le!(msg, 0, length) << 8 * self.ntail;
|
||||||
self.ntail += length;
|
self.ntail += length;
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let m = self.tail | u8to64_le!(msg, 0, needed) << 8*self.ntail;
|
let m = self.tail | u8to64_le!(msg, 0, needed) << 8 * self.ntail;
|
||||||
|
|
||||||
self.v3 ^= m;
|
self.v3 ^= m;
|
||||||
compress!(self.v0, self.v1, self.v2, self.v3);
|
compress!(self.v0, self.v1, self.v2, self.v3);
|
||||||
|
|
|
@ -706,7 +706,8 @@ impl<T> Option<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T: Clone> Option<&'a T> {
|
impl<'a, T: Clone> Option<&'a T> {
|
||||||
/// Maps an Option<&T> to an Option<T> by cloning the contents of the Option.
|
/// Maps an `Option<&T>` to an `Option<T>` by cloning the contents of the
|
||||||
|
/// option.
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub fn cloned(self) -> Option<T> {
|
pub fn cloned(self) -> Option<T> {
|
||||||
self.map(|t| t.clone())
|
self.map(|t| t.clone())
|
||||||
|
|
|
@ -12,6 +12,21 @@
|
||||||
|
|
||||||
register_long_diagnostics! {
|
register_long_diagnostics! {
|
||||||
|
|
||||||
|
E0515: r##"
|
||||||
|
A constant index expression was out of bounds. Erroneous code example:
|
||||||
|
|
||||||
|
```
|
||||||
|
let x = &[0, 1, 2][7]; // error: const index-expr is out of bounds
|
||||||
|
```
|
||||||
|
|
||||||
|
Please specify a valid index (not inferior to 0 or superior to array length).
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```
|
||||||
|
let x = &[0, 1, 2][2]; // ok!
|
||||||
|
```
|
||||||
|
"##,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
register_diagnostics! {
|
register_diagnostics! {
|
||||||
|
|
|
@ -628,8 +628,8 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||||
if iv >= len {
|
if iv >= len {
|
||||||
// FIXME #3170: report this earlier on in the const-eval
|
// FIXME #3170: report this earlier on in the const-eval
|
||||||
// pass. Reporting here is a bit late.
|
// pass. Reporting here is a bit late.
|
||||||
cx.sess().span_err(e.span,
|
span_err!(cx.sess(), e.span, E0515,
|
||||||
"const index-expr is out of bounds");
|
"const index-expr is out of bounds");
|
||||||
C_undef(val_ty(arr).element_type())
|
C_undef(val_ty(arr).element_type())
|
||||||
} else {
|
} else {
|
||||||
const_get_elt(cx, arr, &[iv as c_uint])
|
const_get_elt(cx, arr, &[iv as c_uint])
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// ignore-tidy-cr ignore-license
|
// ignore-tidy-cr ignore-license
|
||||||
// ignore-tidy-cr (repeated again because of tidy bug)
|
// ignore-tidy-cr (repeated again because of tidy bug)
|
||||||
// license is ignored because tidy can't handle the CRLF here properly.
|
// license is ignored because tidy can't handle the CRLF here properly.
|
||||||
|
|
||||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||||
// file at the top-level directory of this distribution and at
|
// file at the top-level directory of this distribution and at
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
@ -11,33 +11,33 @@
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
// NB: this file needs CRLF line endings. The .gitattributes file in
|
// NB: this file needs CRLF line endings. The .gitattributes file in
|
||||||
// this directory should enforce it.
|
// this directory should enforce it.
|
||||||
|
|
||||||
// ignore-pretty
|
// ignore-pretty
|
||||||
|
|
||||||
/// Doc comment that ends in CRLF
|
/// Doc comment that ends in CRLF
|
||||||
pub fn foo() {}
|
pub fn foo() {}
|
||||||
|
|
||||||
/** Block doc comment that
|
/** Block doc comment that
|
||||||
* contains CRLF characters
|
* contains CRLF characters
|
||||||
*/
|
*/
|
||||||
pub fn bar() {}
|
pub fn bar() {}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let s = "string
|
let s = "string
|
||||||
literal";
|
literal";
|
||||||
assert_eq!(s, "string\nliteral");
|
assert_eq!(s, "string\nliteral");
|
||||||
|
|
||||||
let s = "literal with \
|
let s = "literal with \
|
||||||
escaped newline";
|
escaped newline";
|
||||||
assert_eq!(s, "literal with escaped newline");
|
assert_eq!(s, "literal with escaped newline");
|
||||||
|
|
||||||
let s = r"string
|
let s = r"string
|
||||||
literal";
|
literal";
|
||||||
assert_eq!(s, "string\nliteral");
|
assert_eq!(s, "string\nliteral");
|
||||||
|
|
||||||
// validate that our source file has CRLF endings
|
// validate that our source file has CRLF endings
|
||||||
let source = include_str!("lexer-crlf-line-endings-string-literal-doc-comment.rs");
|
let source = include_str!("lexer-crlf-line-endings-string-literal-doc-comment.rs");
|
||||||
assert!(source.contains("string\r\nliteral"));
|
assert!(source.contains("string\r\nliteral"));
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue