diff --git a/concurrency.md b/concurrency.md index c600644..a382e4e 100644 --- a/concurrency.md +++ b/concurrency.md @@ -1,16 +1,8 @@ % Concurrency and Paralellism -```Not sure if I want this -Safe Rust features *a ton* of tooling to make concurrency and parallelism totally -safe, easy, and fearless. This is a case where we'll really just -[defer to TRPL][trpl-conc] for the basics. - -TL;DR: The `Send` and `Sync` traits in conjunction with Rust's ownership model and -normal generic bounds make using concurrent APIs really easy and painless for -a user of Safe Rust. -``` -## Data Races and Race Conditions + +# Data Races and Race Conditions Safe Rust guarantees an absence of data races, which are defined as: @@ -77,7 +69,10 @@ if idx.load(Ordering::SeqCst) < data.len() { } ``` -## 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 synchronization @@ -153,7 +148,10 @@ into the collection. TODO: better explain what can or can't be Send or Sync. Sufficient to appeal only to data races? -## Atomics + + + +# Atomics Rust pretty blatantly just inherits LLVM's model for atomics, which in turn is largely based off of the C11 model for atomics. This is not due these models @@ -165,7 +163,10 @@ least, we can benefit from existing tooling and research around C's model. Trying to fully explain these models is fairly hopeless, so we're just going to drop that problem in LLVM's lap. -## Actually Doing Things Concurrently + + + +# Actually Doing Things Concurrently 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 diff --git a/data.md b/data.md index 9189209..1100848 100644 --- a/data.md +++ b/data.md @@ -4,7 +4,10 @@ Low-level programming cares a lot about data layout. It's a big deal. It also pe influences the rest of the language, so we're going to start by digging into how data is represented in Rust. -## The rust repr + + + +# The rust repr Rust gives you the following ways to lay out composite data: @@ -124,7 +127,7 @@ In principle enums can use fairly elaborate algorithms to cache bits throughout with special constrained representations. As such it is *especially* desirable that we leave enum layout unspecified today. -## Dynamically Sized Types (DSTs) +# Dynamically Sized Types (DSTs) Rust also supports types without a statically known size. On the surface, this is a bit nonsensical: Rust must know the size of something in order to @@ -150,6 +153,9 @@ struct Foo { } ``` + + + # Zero Sized Types (ZSTs) Rust actually allows types to be specified that occupy *no* space: @@ -182,6 +188,9 @@ consequence of types with no size. In particular, pointer offsets are no-ops, an standard allocators (including jemalloc, the one used by Rust) generally consider passing in `0` as Undefined Behaviour. + + + # Drop Flags For unfortunate legacy implementation reasons, Rust as of 1.0.0 will do a nasty trick to @@ -212,12 +221,17 @@ struct Foo { For details as to *why* this is done, and how to make it not happen, check out [SOME OTHER SECTION]. -## Alternative representations + + + +# Alternative representations Rust allows you to specify alternative data layout strategies from the default Rust one. -### repr(C) + + +## repr(C) This is the most important `repr`. It has fairly simple intent: do what C does. The order, size, and alignment of fields is exactly what you would expect from @@ -241,14 +255,18 @@ still consumes a byte of space. * This is equivalent to repr(u32) for enums (see below) -### repr(packed) + + +## repr(packed) `repr(packed)` forces rust to strip any padding it would normally apply. This may improve the memory footprint of a type, but will have negative side-effects from "field access is heavily penalized" to "completely breaks everything" based on target platform. -### repr(u8), repr(u16), repr(u32), repr(u64) + + +## repr(u8), repr(u16), repr(u32), repr(u64) These specify the size to make a c-like enum (one which has no values in its variants). diff --git a/intro.md b/intro.md index 12b105d..7d3036f 100644 --- a/intro.md +++ b/intro.md @@ -7,7 +7,10 @@ Unsafe Rust. TURPL does not assume you have read TRPL, but does assume you know the basics of the language and systems programming. We will not explain the stack or heap, we will not explain the syntax. -## Sections + + + +# Sections * [Data Layout](data.html) * [Ownership and Lifetimes](lifetimes.html) @@ -16,7 +19,10 @@ stack or heap, we will not explain the syntax. * [Ownership-oriented resource management (RAII)](raii.html) * [Concurrency](concurrency.html) -## A Tale Of Two Languages + + + +# A Tale Of Two Languages Rust can be thought of as two different languages: Safe Rust, and Unsafe Rust. Any time someone opines the guarantees of Rust, they are almost surely talking about @@ -60,7 +66,10 @@ The fact that Rust is written with a healthy spoonful of Unsafe Rust is no diffe However it *does* mean that Rust doesn't need to fall back to the pervasive unsafety of C to do the nasty things that need to get done. -## What does `unsafe` mean? + + + +# What does `unsafe` mean? Rust tries to model memory safety through the `unsafe` keyword. Interestingly, the meaning of `unsafe` largely revolves around what diff --git a/lifetimes.md b/lifetimes.md index 159a3b0..4be895f 100644 --- a/lifetimes.md +++ b/lifetimes.md @@ -7,7 +7,7 @@ language-design problem. -## The Tagged Union Problem +# The Tagged Union Problem The core of the lifetime and mutability system derives from a simple problem: internal pointers to tagged unions. For instance, consider the following code: @@ -68,7 +68,7 @@ For more details see Dan Grossman's Existential Types for Imperative Languages: -## Lifetimes +# Lifetimes Rust's static checks are managed by the *borrow checker* (borrowck), which tracks mutability and outstanding loans. This analysis can in principle be done without @@ -101,7 +101,7 @@ more than a local lint against incorrect usage of a value. -## Weird Lifetimes +# Weird Lifetimes Given the following code: @@ -150,7 +150,7 @@ a bug. -## Lifetime Elision +# Lifetime Elision In order to make common patterns more ergonomic, Rust allows lifetimes to be *elided* in function, impl, and type signatures. @@ -217,7 +217,7 @@ fn new<'a>(buf: &'a mut [u8]) -> BufWriter<'a> // expanded -## 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 @@ -258,7 +258,7 @@ these are unstable due to their awkward nature and questionable utility. -## Higher-Rank Lifetimes +# Higher-Rank Lifetimes Generics in Rust generally allow types to be instantiated with arbitrary associated lifetimes, but this fixes the lifetimes they work with once @@ -328,7 +328,7 @@ maximally useful outside of the Fn traits. -## Subtyping and Variance +# Subtyping and Variance Although Rust doesn't have any notion of inheritance, it *does* include subtyping. In Rust, subtyping derives entirely from *lifetimes*. Since lifetimes are derived @@ -474,7 +474,7 @@ struct Foo<'a, 'b, A, B, C, D, E, F, G, H> { -## 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 @@ -513,7 +513,7 @@ pub struct Iter<'a, T: 'a> { -## Dropck +# Dropck When a type is going out of scope, Rust will try to Drop it. Drop executes arbitrary code, and in fact allows us to "smuggle" arbitrary code execution @@ -557,7 +557,7 @@ standard library made a utility for itself called `Unique` which: -## Splitting Lifetimes +# Splitting Lifetimes The mutual exclusion property of mutable references can be very limiting when working with a composite structure. Borrowck understands some basic stuff, but diff --git a/raii.md b/raii.md index 13a2bdf..7636303 100644 --- a/raii.md +++ b/raii.md @@ -176,4 +176,4 @@ On balance this is an ok choice. Certainly if you're just getting started. In the future, we expect there to be a first-class way to announce that a field should be automatically dropped. -[uninit]: \ No newline at end of file +[uninit]: uninitialized.html \ No newline at end of file