rollup merge of #23285: steveklabnik/gh11794
Fixes #11794 I mostly removed superflous examples which use the standard library. I have one more quesiton here though: threads. They're mostly a library thing, at this point, right?
This commit is contained in:
commit
3f1d57fcde
@ -645,18 +645,7 @@ fn bar() {
|
||||
|
||||
A number of minor features of Rust are not central enough to have their own
|
||||
syntax, and yet are not implementable as functions. Instead, they are given
|
||||
names, and invoked through a consistent syntax: `name!(...)`. Examples include:
|
||||
|
||||
* `format!` : format data into a string
|
||||
* `env!` : look up an environment variable's value at compile time
|
||||
* `file!`: return the path to the file being compiled
|
||||
* `stringify!` : pretty-print the Rust expression given as an argument
|
||||
* `include!` : include the Rust expression in the given file
|
||||
* `include_str!` : include the contents of the given file as a string
|
||||
* `include_bytes!` : include the contents of the given file as a binary blob
|
||||
* `error!`, `warn!`, `info!`, `debug!` : provide diagnostic information.
|
||||
|
||||
All of the above extensions are expressions with values.
|
||||
names, and invoked through a consistent syntax: `some_extension!(...)`.
|
||||
|
||||
Users of `rustc` can define new syntax extensions in two ways:
|
||||
|
||||
@ -744,38 +733,6 @@ Rust syntax is restricted in two ways:
|
||||
pairs when they occur at the beginning of, or immediately after, a `$(...)*`;
|
||||
requiring a distinctive token in front can solve the problem.
|
||||
|
||||
## Syntax extensions useful in macros
|
||||
|
||||
* `stringify!` : turn the identifier argument into a string literal
|
||||
* `concat!` : concatenates a comma-separated list of literals
|
||||
|
||||
## Syntax extensions for macro debugging
|
||||
|
||||
* `log_syntax!` : print out the arguments at compile time
|
||||
* `trace_macros!` : supply `true` or `false` to enable or disable macro expansion logging
|
||||
|
||||
## Quasiquoting
|
||||
|
||||
The following syntax extensions are used for quasiquoting Rust syntax trees,
|
||||
usually in [procedural macros](book/plugins.html#syntax-extensions):
|
||||
|
||||
* `quote_expr!`
|
||||
* `quote_item!`
|
||||
* `quote_pat!`
|
||||
* `quote_stmt!`
|
||||
* `quote_tokens!`
|
||||
* `quote_matcher!`
|
||||
* `quote_ty!`
|
||||
* `quote_attr!`
|
||||
|
||||
Keep in mind that when `$name : ident` appears in the input to
|
||||
`quote_tokens!`, the result contains unquoted `name` followed by two tokens.
|
||||
However, input of the same form passed to `quote_matcher!` becomes a
|
||||
quasiquoted MBE-matcher of a nonterminal. No unquotation happens. Otherwise
|
||||
the result of `quote_matcher!` is identical to that of `quote_tokens!`.
|
||||
|
||||
Documentation is very limited at the moment.
|
||||
|
||||
# Crates and source files
|
||||
|
||||
Rust is a *compiled* language. Its semantics obey a *phase distinction*
|
||||
@ -1521,22 +1478,6 @@ statics:
|
||||
Constants should in general be preferred over statics, unless large amounts of
|
||||
data are being stored, or single-address and mutability properties are required.
|
||||
|
||||
```
|
||||
use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
|
||||
|
||||
// Note that ATOMIC_USIZE_INIT is a *const*, but it may be used to initialize a
|
||||
// static. This static can be modified, so it is not placed in read-only memory.
|
||||
static COUNTER: AtomicUsize = ATOMIC_USIZE_INIT;
|
||||
|
||||
// This table is a candidate to be placed in read-only memory.
|
||||
static TABLE: &'static [usize] = &[1, 2, 3, /* ... */];
|
||||
|
||||
for slot in TABLE.iter() {
|
||||
println!("{}", slot);
|
||||
}
|
||||
COUNTER.fetch_add(1, Ordering::SeqCst);
|
||||
```
|
||||
|
||||
#### Mutable statics
|
||||
|
||||
If a static item is declared with the `mut` keyword, then it is allowed to
|
||||
@ -2376,18 +2317,6 @@ impl<T: PartialEq> PartialEq for Foo<T> {
|
||||
}
|
||||
```
|
||||
|
||||
Supported traits for `derive` are:
|
||||
|
||||
* Comparison traits: `PartialEq`, `Eq`, `PartialOrd`, `Ord`.
|
||||
* Serialization: `Encodable`, `Decodable`. These require `serialize`.
|
||||
* `Clone`, to create `T` from `&T` via a copy.
|
||||
* `Default`, to create an empty instance of a data type.
|
||||
* `FromPrimitive`, to create an instance from a numeric primitive.
|
||||
* `Hash`, to iterate over the bytes in a data type.
|
||||
* `Rand`, to create a random instance of a data type.
|
||||
* `Debug`, to format a value using the `{:?}` formatter.
|
||||
* `Copy`, for "Plain Old Data" types which can be copied by simply moving bits.
|
||||
|
||||
### Compiler Features
|
||||
|
||||
Certain aspects of Rust may be implemented in the compiler, but they're not
|
||||
@ -3883,75 +3812,27 @@ impl Printable for String {
|
||||
`self` refers to the value of type `String` that is the receiver for a call to
|
||||
the method `make_string`.
|
||||
|
||||
## Type kinds
|
||||
# The `Copy` trait
|
||||
|
||||
Types in Rust are categorized into kinds, based on various properties of the
|
||||
components of the type. The kinds are:
|
||||
Rust has a special trait, `Copy`, which when implemented changes the semantics
|
||||
of a value. Values whose type implements `Copy` are copied rather than moved
|
||||
upon assignment.
|
||||
|
||||
* `Send`
|
||||
: Types of this kind can be safely sent between threads.
|
||||
This kind includes scalars, boxes, procs, and
|
||||
structural types containing only other owned types.
|
||||
All `Send` types are `'static`.
|
||||
* `Copy`
|
||||
: Types of this kind consist of "Plain Old Data"
|
||||
which can be copied by simply moving bits.
|
||||
All values of this kind can be implicitly copied.
|
||||
This kind includes scalars and immutable references,
|
||||
as well as structural types containing other `Copy` types.
|
||||
* `'static`
|
||||
: Types of this kind do not contain any references (except for
|
||||
references with the `static` lifetime, which are allowed).
|
||||
This can be a useful guarantee for code
|
||||
that breaks borrowing assumptions
|
||||
using [`unsafe` operations](#unsafe-functions).
|
||||
* `Drop`
|
||||
: This is not strictly a kind,
|
||||
but its presence interacts with kinds:
|
||||
the `Drop` trait provides a single method `drop`
|
||||
that takes no parameters,
|
||||
and is run when values of the type are dropped.
|
||||
Such a method is called a "destructor",
|
||||
and are always executed in "top-down" order:
|
||||
a value is completely destroyed
|
||||
before any of the values it owns run their destructors.
|
||||
Only `Send` types can implement `Drop`.
|
||||
# The `Sized` trait
|
||||
|
||||
* _Default_
|
||||
: Types with destructors, closure environments,
|
||||
and various other _non-first-class_ types,
|
||||
are not copyable at all.
|
||||
Such types can usually only be accessed through pointers,
|
||||
or in some cases, moved between mutable locations.
|
||||
`Sized` is a special trait which indicates that the size of this type is known
|
||||
at compile-time.
|
||||
|
||||
Kinds can be supplied as _bounds_ on type parameters, like traits, in which
|
||||
case the parameter is constrained to types satisfying that kind.
|
||||
# The `Drop` trait
|
||||
|
||||
By default, type parameters do not carry any assumed kind-bounds at all. When
|
||||
instantiating a type parameter, the kind bounds on the parameter are checked to
|
||||
be the same or narrower than the kind of the type that it is instantiated with.
|
||||
The `Drop` trait provides a destructor, to be run whenever a value of this type
|
||||
is to be destroyed.
|
||||
|
||||
Sending operations are not part of the Rust language, but are implemented in
|
||||
the library. Generic functions that send values bound the kind of these values
|
||||
to sendable.
|
||||
# Memory model
|
||||
|
||||
# Memory and concurrency models
|
||||
|
||||
Rust has a memory model centered around concurrently-executing _threads_. Thus
|
||||
its memory model and its concurrency model are best discussed simultaneously,
|
||||
as parts of each only make sense when considered from the perspective of the
|
||||
other.
|
||||
|
||||
When reading about the memory model, keep in mind that it is partitioned in
|
||||
order to support threads; and when reading about threads, keep in mind that their
|
||||
isolation and communication mechanisms are only possible due to the ownership
|
||||
and lifetime semantics of the memory model.
|
||||
|
||||
## Memory model
|
||||
|
||||
A Rust program's memory consists of a static set of *items*, a set of
|
||||
[threads](#threads) each with its own *stack*, and a *heap*. Immutable portions of
|
||||
the heap may be shared between threads, mutable portions may not.
|
||||
A Rust program's memory consists of a static set of *items* and a *heap*.
|
||||
Immutable portions of the heap may be shared between threads, mutable portions
|
||||
may not.
|
||||
|
||||
Allocations in the stack consist of *slots*, and allocations in the heap
|
||||
consist of *boxes*.
|
||||
@ -3962,10 +3843,6 @@ The _items_ of a program are those functions, modules and types that have their
|
||||
value calculated at compile-time and stored uniquely in the memory image of the
|
||||
rust process. Items are neither dynamically allocated nor freed.
|
||||
|
||||
A thread's _stack_ consists of activation frames automatically allocated on entry
|
||||
to each function as the thread executes. A stack allocation is reclaimed when
|
||||
control leaves the frame containing it.
|
||||
|
||||
The _heap_ is a general term that describes boxes. The lifetime of an
|
||||
allocation in the heap depends on the lifetime of the box values pointing to
|
||||
it. Since box values may themselves be passed in and out of frames, or stored
|
||||
@ -3973,25 +3850,11 @@ in the heap, heap allocations may outlive the frame they are allocated within.
|
||||
|
||||
### Memory ownership
|
||||
|
||||
A thread owns all memory it can *safely* reach through local variables, as well
|
||||
as boxes and references.
|
||||
|
||||
When a thread sends a value that has the `Send` trait to another thread, it loses
|
||||
ownership of the value sent and can no longer refer to it. This is statically
|
||||
guaranteed by the combined use of "move semantics", and the compiler-checked
|
||||
_meaning_ of the `Send` trait: it is only instantiated for (transitively)
|
||||
sendable kinds of data constructor and pointers, never including references.
|
||||
|
||||
When a stack frame is exited, its local allocations are all released, and its
|
||||
references to boxes are dropped.
|
||||
|
||||
When a thread finishes, its stack is necessarily empty and it therefore has no
|
||||
references to any boxes; the remainder of its heap is immediately freed.
|
||||
|
||||
### Memory slots
|
||||
|
||||
A thread's stack contains slots.
|
||||
|
||||
A _slot_ is a component of a stack frame, either a function parameter, a
|
||||
[temporary](#lvalues,-rvalues-and-temporaries), or a local variable.
|
||||
|
||||
@ -4021,86 +3884,6 @@ state. Subsequent statements within a function may or may not initialize the
|
||||
local variables. Local variables can be used only after they have been
|
||||
initialized; this is enforced by the compiler.
|
||||
|
||||
### Boxes
|
||||
|
||||
A _box_ is a reference to a heap allocation holding another value, which is
|
||||
constructed by the prefix operator `box`. When the standard library is in use,
|
||||
the type of a box is `std::owned::Box<T>`.
|
||||
|
||||
An example of a box type and value:
|
||||
|
||||
```
|
||||
let x: Box<i32> = Box::new(10);
|
||||
```
|
||||
|
||||
Box values exist in 1:1 correspondence with their heap allocation, copying a
|
||||
box value makes a shallow copy of the pointer. Rust will consider a shallow
|
||||
copy of a box to move ownership of the value. After a value has been moved,
|
||||
the source location cannot be used unless it is reinitialized.
|
||||
|
||||
```
|
||||
let x: Box<i32> = Box::new(10);
|
||||
let y = x;
|
||||
// attempting to use `x` will result in an error here
|
||||
```
|
||||
|
||||
## Threads
|
||||
|
||||
Rust's primary concurrency mechanism is called a **thread**.
|
||||
|
||||
### Communication between threads
|
||||
|
||||
Rust threads are isolated and generally unable to interfere with one another's
|
||||
memory directly, except through [`unsafe` code](#unsafe-functions). All
|
||||
contact between threads is mediated by safe forms of ownership transfer, and data
|
||||
races on memory are prohibited by the type system.
|
||||
|
||||
When you wish to send data between threads, the values are restricted to the
|
||||
[`Send` type-kind](#type-kinds). Restricting communication interfaces to this
|
||||
kind ensures that no references move between threads. Thus access to an entire
|
||||
data structure can be mediated through its owning "root" value; no further
|
||||
locking or copying is required to avoid data races within the substructure of
|
||||
such a value.
|
||||
|
||||
### Thread
|
||||
|
||||
The _lifecycle_ of a threads consists of a finite set of states and events that
|
||||
cause transitions between the states. The lifecycle states of a thread are:
|
||||
|
||||
* running
|
||||
* blocked
|
||||
* panicked
|
||||
* dead
|
||||
|
||||
A thread begins its lifecycle — once it has been spawned — in the
|
||||
*running* state. In this state it executes the statements of its entry
|
||||
function, and any functions called by the entry function.
|
||||
|
||||
A thread may transition from the *running* state to the *blocked* state any time
|
||||
it makes a blocking communication call. When the call can be completed —
|
||||
when a message arrives at a sender, or a buffer opens to receive a message
|
||||
— then the blocked thread will unblock and transition back to *running*.
|
||||
|
||||
A thread may transition to the *panicked* state at any time, due being killed by
|
||||
some external event or internally, from the evaluation of a `panic!()` macro.
|
||||
Once *panicking*, a thread unwinds its stack and transitions to the *dead* state.
|
||||
Unwinding the stack of a thread is done by the thread itself, on its own control
|
||||
stack. If a value with a destructor is freed during unwinding, the code for the
|
||||
destructor is run, also on the thread's control stack. Running the destructor
|
||||
code causes a temporary transition to a *running* state, and allows the
|
||||
destructor code to cause any subsequent state transitions. The original thread
|
||||
of unwinding and panicking thereby may suspend temporarily, and may involve
|
||||
(recursive) unwinding of the stack of a failed destructor. Nonetheless, the
|
||||
outermost unwinding activity will continue until the stack is unwound and the
|
||||
thread transitions to the *dead* state. There is no way to "recover" from thread
|
||||
panics. Once a thread has temporarily suspended its unwinding in the *panicking*
|
||||
state, a panic occurring from within this destructor results in *hard* panic.
|
||||
A hard panic currently results in the process aborting.
|
||||
|
||||
A thread in the *dead* state cannot transition to other states; it exists only to
|
||||
have its termination status inspected by other threads, and/or to await
|
||||
reclamation when the last reference to it drops.
|
||||
|
||||
# Runtime services, linkage and debugging
|
||||
|
||||
The Rust _runtime_ is a relatively compact collection of Rust code that
|
||||
|
Loading…
Reference in New Issue
Block a user