mirror of https://github.com/rust-lang/nomicon
1. move everything under a src directory 2. add README.md to the SUMMARY.mdpull/10/head
parent
59c90266d3
commit
0e6c680ebd
@ -1,53 +0,0 @@
|
||||
# Summary
|
||||
|
||||
* [Meet Safe and Unsafe](meet-safe-and-unsafe.md)
|
||||
* [How Safe and Unsafe Interact](safe-unsafe-meaning.md)
|
||||
* [Working with Unsafe](working-with-unsafe.md)
|
||||
* [Data Layout](data.md)
|
||||
* [repr(Rust)](repr-rust.md)
|
||||
* [Exotically Sized Types](exotic-sizes.md)
|
||||
* [Other reprs](other-reprs.md)
|
||||
* [Ownership](ownership.md)
|
||||
* [References](references.md)
|
||||
* [Lifetimes](lifetimes.md)
|
||||
* [Limits of Lifetimes](lifetime-mismatch.md)
|
||||
* [Lifetime Elision](lifetime-elision.md)
|
||||
* [Unbounded Lifetimes](unbounded-lifetimes.md)
|
||||
* [Higher-Rank Trait Bounds](hrtb.md)
|
||||
* [Subtyping and Variance](subtyping.md)
|
||||
* [Drop Check](dropck.md)
|
||||
* [PhantomData](phantom-data.md)
|
||||
* [Splitting Borrows](borrow-splitting.md)
|
||||
* [Type Conversions](conversions.md)
|
||||
* [Coercions](coercions.md)
|
||||
* [The Dot Operator](dot-operator.md)
|
||||
* [Casts](casts.md)
|
||||
* [Transmutes](transmutes.md)
|
||||
* [Uninitialized Memory](uninitialized.md)
|
||||
* [Checked](checked-uninit.md)
|
||||
* [Drop Flags](drop-flags.md)
|
||||
* [Unchecked](unchecked-uninit.md)
|
||||
* [Ownership Based Resource Management](obrm.md)
|
||||
* [Constructors](constructors.md)
|
||||
* [Destructors](destructors.md)
|
||||
* [Leaking](leaking.md)
|
||||
* [Unwinding](unwinding.md)
|
||||
* [Exception Safety](exception-safety.md)
|
||||
* [Poisoning](poisoning.md)
|
||||
* [Concurrency](concurrency.md)
|
||||
* [Races](races.md)
|
||||
* [Send and Sync](send-and-sync.md)
|
||||
* [Atomics](atomics.md)
|
||||
* [Implementing Vec](vec.md)
|
||||
* [Layout](vec-layout.md)
|
||||
* [Allocating](vec-alloc.md)
|
||||
* [Push and Pop](vec-push-pop.md)
|
||||
* [Deallocating](vec-dealloc.md)
|
||||
* [Deref](vec-deref.md)
|
||||
* [Insert and Remove](vec-insert-remove.md)
|
||||
* [IntoIter](vec-into-iter.md)
|
||||
* [RawVec](vec-raw.md)
|
||||
* [Drain](vec-drain.md)
|
||||
* [Handling Zero-Sized Types](vec-zsts.md)
|
||||
* [Final Code](vec-final.md)
|
||||
* [Implementing Arc and Mutex](arc-and-mutex.md)
|
@ -1,4 +1,4 @@
|
||||
% The Rustonomicon
|
||||
# The Rustonomicon
|
||||
|
||||
#### The Dark Arts of Advanced and Unsafe Rust Programming
|
||||
|
@ -1,3 +1,55 @@
|
||||
# Summary
|
||||
|
||||
- [Chapter 1](./chapter_1.md)
|
||||
[Introduction](README.md)
|
||||
|
||||
* [Meet Safe and Unsafe](meet-safe-and-unsafe.md)
|
||||
* [How Safe and Unsafe Interact](safe-unsafe-meaning.md)
|
||||
* [Working with Unsafe](working-with-unsafe.md)
|
||||
* [Data Layout](data.md)
|
||||
* [repr(Rust)](repr-rust.md)
|
||||
* [Exotically Sized Types](exotic-sizes.md)
|
||||
* [Other reprs](other-reprs.md)
|
||||
* [Ownership](ownership.md)
|
||||
* [References](references.md)
|
||||
* [Lifetimes](lifetimes.md)
|
||||
* [Limits of Lifetimes](lifetime-mismatch.md)
|
||||
* [Lifetime Elision](lifetime-elision.md)
|
||||
* [Unbounded Lifetimes](unbounded-lifetimes.md)
|
||||
* [Higher-Rank Trait Bounds](hrtb.md)
|
||||
* [Subtyping and Variance](subtyping.md)
|
||||
* [Drop Check](dropck.md)
|
||||
* [PhantomData](phantom-data.md)
|
||||
* [Splitting Borrows](borrow-splitting.md)
|
||||
* [Type Conversions](conversions.md)
|
||||
* [Coercions](coercions.md)
|
||||
* [The Dot Operator](dot-operator.md)
|
||||
* [Casts](casts.md)
|
||||
* [Transmutes](transmutes.md)
|
||||
* [Uninitialized Memory](uninitialized.md)
|
||||
* [Checked](checked-uninit.md)
|
||||
* [Drop Flags](drop-flags.md)
|
||||
* [Unchecked](unchecked-uninit.md)
|
||||
* [Ownership Based Resource Management](obrm.md)
|
||||
* [Constructors](constructors.md)
|
||||
* [Destructors](destructors.md)
|
||||
* [Leaking](leaking.md)
|
||||
* [Unwinding](unwinding.md)
|
||||
* [Exception Safety](exception-safety.md)
|
||||
* [Poisoning](poisoning.md)
|
||||
* [Concurrency](concurrency.md)
|
||||
* [Races](races.md)
|
||||
* [Send and Sync](send-and-sync.md)
|
||||
* [Atomics](atomics.md)
|
||||
* [Implementing Vec](vec.md)
|
||||
* [Layout](vec-layout.md)
|
||||
* [Allocating](vec-alloc.md)
|
||||
* [Push and Pop](vec-push-pop.md)
|
||||
* [Deallocating](vec-dealloc.md)
|
||||
* [Deref](vec-deref.md)
|
||||
* [Insert and Remove](vec-insert-remove.md)
|
||||
* [IntoIter](vec-into-iter.md)
|
||||
* [RawVec](vec-raw.md)
|
||||
* [Drain](vec-drain.md)
|
||||
* [Handling Zero-Sized Types](vec-zsts.md)
|
||||
* [Final Code](vec-final.md)
|
||||
* [Implementing Arc and Mutex](arc-and-mutex.md)
|
||||
|
@ -1,4 +1,4 @@
|
||||
% Implementing Arc and Mutex
|
||||
# Implementing Arc and Mutex
|
||||
|
||||
Knowing the theory is all fine and good, but the *best* way to understand
|
||||
something is to use it. To better understand atomics and interior mutability,
|
@ -1,4 +1,4 @@
|
||||
% Atomics
|
||||
# Atomics
|
||||
|
||||
Rust pretty blatantly just inherits C11's memory model for atomics. This is not
|
||||
due to this model being particularly excellent or easy to understand. Indeed,
|
@ -1,4 +1,4 @@
|
||||
% Splitting Borrows
|
||||
# Splitting Borrows
|
||||
|
||||
The mutual exclusion property of mutable references can be very limiting when
|
||||
working with a composite structure. The borrow checker understands some basic
|
@ -1,4 +1,4 @@
|
||||
% Casts
|
||||
# Casts
|
||||
|
||||
Casts are a superset of coercions: every coercion can be explicitly
|
||||
invoked via a cast. However some conversions require a cast.
|
@ -1,4 +1,4 @@
|
||||
% Checked Uninitialized Memory
|
||||
# Checked Uninitialized Memory
|
||||
|
||||
Like C, all stack variables in Rust are uninitialized until a value is
|
||||
explicitly assigned to them. Unlike C, Rust statically prevents you from ever
|
@ -1,4 +1,4 @@
|
||||
% Coercions
|
||||
# Coercions
|
||||
|
||||
Types can implicitly be coerced to change in certain contexts. These changes are
|
||||
generally just *weakening* of types, largely focused around pointers and
|
@ -1,4 +1,4 @@
|
||||
% Concurrency and Parallelism
|
||||
# Concurrency and Parallelism
|
||||
|
||||
Rust as a language doesn't *really* have an opinion on how to do concurrency or
|
||||
parallelism. The standard library exposes OS threads and blocking sys-calls
|
@ -1,4 +1,4 @@
|
||||
% Constructors
|
||||
# Constructors
|
||||
|
||||
There is exactly one way to create an instance of a user-defined type: name it,
|
||||
and initialize all its fields at once:
|
@ -1,4 +1,4 @@
|
||||
% Type Conversions
|
||||
# Type Conversions
|
||||
|
||||
At the end of the day, everything is just a pile of bits somewhere, and type
|
||||
systems are just there to help us use those bits right. There are two common
|
@ -1,4 +1,4 @@
|
||||
% Data Representation in Rust
|
||||
# Data Representation in Rust
|
||||
|
||||
Low-level programming cares a lot about data layout. It's a big deal. It also
|
||||
pervasively influences the rest of the language, so we're going to start by
|
@ -1,4 +1,4 @@
|
||||
% Destructors
|
||||
# Destructors
|
||||
|
||||
What the language *does* provide is full-blown automatic destructors through the
|
||||
`Drop` trait, which provides the following method:
|
@ -1,4 +1,4 @@
|
||||
% The Dot Operator
|
||||
# The Dot Operator
|
||||
|
||||
The dot operator will perform a lot of magic to convert types. It will perform
|
||||
auto-referencing, auto-dereferencing, and coercion until types match.
|
@ -1,4 +1,4 @@
|
||||
% Drop Flags
|
||||
# Drop Flags
|
||||
|
||||
The examples in the previous section introduce an interesting problem for Rust.
|
||||
We have seen that it's possible to conditionally initialize, deinitialize, and
|
@ -1,4 +1,4 @@
|
||||
% Drop Check
|
||||
# Drop Check
|
||||
|
||||
We have seen how lifetimes provide us some fairly simple rules for ensuring
|
||||
that we never read dangling references. However up to this point we have only ever
|
@ -1,4 +1,4 @@
|
||||
% Exception Safety
|
||||
# Exception Safety
|
||||
|
||||
Although programs should use unwinding sparingly, there's a lot of code that
|
||||
*can* panic. If you unwrap a None, index out of bounds, or divide by 0, your
|
@ -1,4 +1,4 @@
|
||||
% Exotically Sized Types
|
||||
# Exotically Sized Types
|
||||
|
||||
Most of the time, we think in terms of types with a fixed, positive size. This
|
||||
is not always the case, however.
|
@ -1,4 +1,4 @@
|
||||
% Higher-Rank Trait Bounds (HRTBs)
|
||||
# Higher-Rank Trait Bounds (HRTBs)
|
||||
|
||||
Rust's `Fn` traits are a little bit magic. For instance, we can write the
|
||||
following code:
|
@ -1,4 +1,4 @@
|
||||
% Leaking
|
||||
# Leaking
|
||||
|
||||
Ownership-based resource management is intended to simplify composition. You
|
||||
acquire resources when you create the object, and you release the resources when
|
@ -1,4 +1,4 @@
|
||||
% Lifetime Elision
|
||||
# Lifetime Elision
|
||||
|
||||
In order to make common patterns more ergonomic, Rust allows lifetimes to be
|
||||
*elided* in function signatures.
|
@ -1,4 +1,4 @@
|
||||
% Limits of Lifetimes
|
||||
# Limits of Lifetimes
|
||||
|
||||
Given the following code:
|
||||
|
@ -1,4 +1,4 @@
|
||||
% Lifetimes
|
||||
# Lifetimes
|
||||
|
||||
Rust enforces these rules through *lifetimes*. Lifetimes are effectively
|
||||
just names for scopes somewhere in the program. Each reference,
|
@ -1,4 +1,4 @@
|
||||
% Meet Safe and Unsafe
|
||||
# Meet Safe and Unsafe
|
||||
|
||||
Programmers in safe "high-level" languages face a fundamental dilemma. On one
|
||||
hand, it would be *really* great to just say what you want and not worry about
|
@ -1,4 +1,4 @@
|
||||
% The Perils Of Ownership Based Resource Management (OBRM)
|
||||
# The Perils Of Ownership Based Resource Management (OBRM)
|
||||
|
||||
OBRM (AKA RAII: Resource Acquisition Is Initialization) is something you'll
|
||||
interact with a lot in Rust. Especially if you use the standard library.
|
@ -1,4 +1,4 @@
|
||||
% Alternative representations
|
||||
# Alternative representations
|
||||
|
||||
Rust allows you to specify alternative data layout strategies from the default.
|
||||
|
@ -1,4 +1,4 @@
|
||||
% Ownership and Lifetimes
|
||||
# Ownership and Lifetimes
|
||||
|
||||
Ownership is the breakout feature of Rust. It allows Rust to be completely
|
||||
memory-safe and efficient, while avoiding garbage collection. Before getting
|
@ -1,4 +1,4 @@
|
||||
% PhantomData
|
||||
# PhantomData
|
||||
|
||||
When working with unsafe code, we can often end up in a situation where
|
||||
types or lifetimes are logically associated with a struct, but not actually
|
@ -1,4 +1,4 @@
|
||||
% Poisoning
|
||||
# Poisoning
|
||||
|
||||
Although all unsafe code *must* ensure it has minimal exception safety, not all
|
||||
types ensure *maximal* exception safety. Even if the type does, your code may
|
@ -1,4 +1,4 @@
|
||||
% Data Races and Race Conditions
|
||||
# Data Races and Race Conditions
|
||||
|
||||
Safe Rust guarantees an absence of data races, which are defined as:
|
||||
|
@ -1,4 +1,4 @@
|
||||
% References
|
||||
# References
|
||||
|
||||
This section gives a high-level view of the memory model that *all* Rust
|
||||
programs must satisfy to be correct. Safe code is statically verified
|
@ -1,4 +1,4 @@
|
||||
% repr(Rust)
|
||||
# repr(Rust)
|
||||
|
||||
First and foremost, all types have an alignment specified in bytes. The
|
||||
alignment of a type specifies what addresses are valid to store the value at. A
|
@ -1,4 +1,4 @@
|
||||
% How Safe and Unsafe Interact
|
||||
# How Safe and Unsafe Interact
|
||||
|
||||
What's the relationship between Safe Rust and Unsafe Rust? How do they
|
||||
interact?
|
@ -1,4 +1,4 @@
|
||||
% Send and Sync
|
||||
# Send and Sync
|
||||
|
||||
Not everything obeys inherited mutability, though. Some types allow you to
|
||||
multiply alias a location in memory while mutating it. Unless these types use
|
@ -1,4 +1,4 @@
|
||||
% Subtyping and Variance
|
||||
# Subtyping and Variance
|
||||
|
||||
Although Rust doesn't have any notion of structural inheritance, it *does*
|
||||
include subtyping. In Rust, subtyping derives entirely from lifetimes. Since
|
@ -1,4 +1,4 @@
|
||||
% Transmutes
|
||||
# Transmutes
|
||||
|
||||
Get out of our way type system! We're going to reinterpret these bits or die
|
||||
trying! Even though this book is all about doing things that are unsafe, I
|
@ -1,4 +1,4 @@
|
||||
% Unbounded Lifetimes
|
||||
# Unbounded Lifetimes
|
||||
|
||||
Unsafe code can often end up producing references or lifetimes out of thin air.
|
||||
Such lifetimes come into the world as *unbounded*. The most common source of this
|
@ -1,4 +1,4 @@
|
||||
% Unchecked Uninitialized Memory
|
||||
# Unchecked Uninitialized Memory
|
||||
|
||||
One interesting exception to this rule is working with arrays. Safe Rust doesn't
|
||||
permit you to partially initialize an array. When you initialize an array, you
|
@ -1,4 +1,4 @@
|
||||
% Working With Uninitialized Memory
|
||||
# Working With Uninitialized Memory
|
||||
|
||||
All runtime-allocated memory in a Rust program begins its life as
|
||||
*uninitialized*. In this state the value of the memory is an indeterminate pile
|
@ -1,4 +1,4 @@
|
||||
% Unwinding
|
||||
# Unwinding
|
||||
|
||||
Rust has a *tiered* error-handling scheme:
|
||||
|
@ -1,4 +1,4 @@
|
||||
% Allocating Memory
|
||||
# Allocating Memory
|
||||
|
||||
Using Unique throws a wrench in an important feature of Vec (and indeed all of
|
||||
the std collections): an empty Vec doesn't actually allocate at all. So if we
|
@ -1,4 +1,4 @@
|
||||
% Deallocating
|
||||
# Deallocating
|
||||
|
||||
Next we should implement Drop so that we don't massively leak tons of resources.
|
||||
The easiest way is to just call `pop` until it yields None, and then deallocate
|
@ -1,4 +1,4 @@
|
||||
% Deref
|
||||
# Deref
|
||||
|
||||
Alright! We've got a decent minimal stack implemented. We can push, we can
|
||||
pop, and we can clean up after ourselves. However there's a whole mess of
|
@ -1,4 +1,4 @@
|
||||
% Drain
|
||||
# Drain
|
||||
|
||||
Let's move on to Drain. Drain is largely the same as IntoIter, except that
|
||||
instead of consuming the Vec, it borrows the Vec and leaves its allocation
|
@ -1,4 +1,4 @@
|
||||
% The Final Code
|
||||
# The Final Code
|
||||
|
||||
```rust
|
||||
#![feature(unique)]
|
@ -1,4 +1,4 @@
|
||||
% Insert and Remove
|
||||
# Insert and Remove
|
||||
|
||||
Something *not* provided by slice is `insert` and `remove`, so let's do those
|
||||
next.
|
@ -1,4 +1,4 @@
|
||||
% IntoIter
|
||||
# IntoIter
|
||||
|
||||
Let's move on to writing iterators. `iter` and `iter_mut` have already been
|
||||
written for us thanks to The Magic of Deref. However there's two interesting
|
@ -1,4 +1,4 @@
|
||||
% Layout
|
||||
# Layout
|
||||
|
||||
First off, we need to come up with the struct layout. A Vec has three parts:
|
||||
a pointer to the allocation, the size of the allocation, and the number of
|
@ -1,4 +1,4 @@
|
||||
% Push and Pop
|
||||
# Push and Pop
|
||||
|
||||
Alright. We can initialize. We can allocate. Let's actually implement some
|
||||
functionality! Let's start with `push`. All it needs to do is check if we're
|
@ -1,4 +1,4 @@
|
||||
% RawVec
|
||||
# RawVec
|
||||
|
||||
We've actually reached an interesting situation here: we've duplicated the logic
|
||||
for specifying a buffer and freeing its memory in Vec and IntoIter. Now that
|
@ -1,4 +1,4 @@
|
||||
% Handling Zero-Sized Types
|
||||
# Handling Zero-Sized Types
|
||||
|
||||
It's time. We're going to fight the specter that is zero-sized types. Safe Rust
|
||||
*never* needs to care about this, but Vec is very intensive on raw pointers and
|
@ -1,4 +1,4 @@
|
||||
% Example: Implementing Vec
|
||||
# Example: Implementing Vec
|
||||
|
||||
To bring everything together, we're going to write `std::Vec` from scratch.
|
||||
Because all the best tools for writing unsafe code are unstable, this
|
@ -1,4 +1,4 @@
|
||||
% Working with Unsafe
|
||||
# Working with Unsafe
|
||||
|
||||
Rust generally only gives us the tools to talk about Unsafe Rust in a scoped and
|
||||
binary manner. Unfortunately, reality is significantly more complicated than
|
Loading…
Reference in new issue