└── README.md /README.md: -------------------------------------------------------------------------------- 1 | # Rustic Symmetries 2 | 3 | In honor of the [second birthday of stable Rust][birthday], here is a small 4 | contribution to Rust documentation. 5 | 6 | Many concepts in Rust come in matching sets or have some pleasing symmetry. 7 | This is a summary or "cheat sheet" for some of these. 8 | 9 | Some of these tables may look intimidating, but they reflect the reality of 10 | systems programming with fine-grained control over memory. If you're just 11 | getting started with Rust, *don't panic* and do set this article aside! It's 12 | intended as a reference and a guide to how to organize these things in your 13 | head once you vaguely know what they are. 14 | 15 | Contributions are welcome! Just open a [pull request]. 16 | 17 | [birthday]: https://blog.rust-lang.org/2017/05/15/rust-at-two-years.html 18 | [pull request]: https://github.com/kmcallister/rustic-symmetries/pulls 19 | 20 | 21 | ## References 22 | 23 | | | Can [`Copy`][copy]? | Can mutate through? | 24 | | --- | --- | --- | 25 | | [`&T`][ref] | yes | no | 26 | | [`&mut T`][mut-ref] | no | yes | 27 | 28 | This demonstrates that neither `&T` nor `&mut T` is a subtype of the other, in 29 | the [Liskov] sense. 30 | 31 | 32 | ## Ownership and mutability 33 | 34 | Ownership controls when a value is destroyed. A value can have either a unique 35 | owner, or a number of references which collectively share ownership. The latter 36 | case usually involves reference counting. 37 | 38 | Interior mutability refers to any wrapper type `Wrapper` such that we can go 39 | from `&Wrapper` to `&mut T`, or at least have some of the capabilities of 40 | `&mut T`. 41 | 42 | The column headings here refer (more or less) to the point in time at which 43 | Rust's safety invariants are checked. Note that no unsafety can occur due to 44 | sharing the thread-unsafe structures between threads. The compiler will simply 45 | reject your code, through the magic of the [`Sync`][sync] trait. 46 | 47 | | | Static | Dynamic | Dynamic,
thread-safe | 48 | | --- | --- | --- | --- | 49 | | **Direct ownership** | `T` | | | 50 | | **Ownership via heap** | [`Box`][box] | | | 51 | | **Shared ownership** | | [`Rc`][rc] | [`Arc`][arc] | 52 | | **Get, set, compare
& swap, etc.** | [`&mut T`][mut-ref] | [`Cell`][cell] | [`AtomicFoo`][atomic] | 53 | | **Borrow immutably** | [`&T`][ref] | | | 54 | | **Borrow mutably,
or single reader** | | | [`Mutex`][mutex] | 55 | | **Borrow mutably,
or multiple readers** | [`&mut T`][mut-ref] | [`RefCell`][refcell] | [`RwLock`][rwlock] | 56 | | **Borrow mutably,
unsafe** | [`static mut`][static mut] | [`UnsafeCell`][unsafecell] | [`UnsafeCell`][unsafecell] | 57 | 58 | 59 | ## Numeric types 60 | 61 | | | Unsigned integer | Signed integer | Floating-point | 62 | | --- | --- | --- | --- | 63 | | **8 bits** | [`u8`][u8] | [`i8`][i8] | | 64 | | **16 bits** | [`u16`][u16] | [`i16`][i16] | | 65 | | **32 bits** | [`u32`][u32] | [`i32`][i32] | [`f32`][f32] | 66 | | **64 bits** | [`u64`][u64] | [`i64`][i64] | [`f64`][f64] | 67 | | **128 bits** | [`u128`][u128]α | [`i128`][i128]α | | 68 | | **Pointer-sized** | [`usize`][usize] | [`isize`][isize] | | 69 | 70 | α Nightly-only, as of rustc 1.18. 71 | 72 | 73 | ## Strings 74 | 75 | | Format | Borrowβ | Borrow substr? | Mutate | Copy on write | Owned, in heap | 76 | | --- | --- | --- | --- | --- | --- | 77 | | Any bytes | [`&[u8]`][slice] | yes | [`&mut` `[u8]`][slice] | [`Cow<[u8]>`][cow]
| [`Vec`][vec] | 78 | | [UTF-8] | [`&str`][str] | yes | [`&mut` `str`][str]α | [`Cow`][cow]
| [`String`][string] | 79 | | Platform-dependent | [`&OsStr`][osstr] | no | | [`Cow`][cow] | [`OsString`][osstring] | 80 | | Filesystem path | [`&Path`][path] | no | | [`Cow`][cow] | [`PathBuf`][pathbuf] | 81 | | `NUL`-terminated, safe | [`&CStr`][cstr] | no | | [`Cow`][cow] | [`CString`][cstring] | 82 | | `NUL`-terminated, raw | [`*const`
`c_char`][c_char]γ | yesδ | [`*mut`
`c_char`][c_char]γ | | [`*mut`
`c_char`][c_char]γε | 83 | 84 | α Nearly useless, because most mutations could change the length of a UTF-8 85 | codepoint. One exception is [ASCII-only case conversion][make_ascii_lowercase]. 86 | 87 | β In most cases, you can borrow static memory (e.g. a string literal) with a type 88 | like `&'static str`. 89 | 90 | γ With raw pointers, you are on your own regarding ownership / borrowing 91 | semantics. Any good C library will document its expectations. 92 | 93 | δ You can slice off the front of a `NUL`-terminated string, but not the end. 94 | 95 | ε On the general principle that if you own something you can mutate 96 | it. But you could use [`*const c_char`][c_char] instead. 97 | 98 | 99 | ## Functions and closures 100 | 101 | The *captures* or *free variables* of a closure are the variables used in a 102 | lambda expression which are not defined in the lambda or its arguments list. 103 | The captures come from the surrounding environment of a lambda expression. 104 | 105 | Rust infers which trait(s) a closure can implement from how the captures are 106 | used. You can force values to be moved into a closure by prefixing [the `move` 107 | keyword][move-closure]. 108 | 109 | Each lambda and `fn` has its own unique, un-nameable type (Voldemort type?). 110 | This enables static dispatch and inlining. Each of these un-nameable types can 111 | be coerced to the appropriate `fn` / `Fn` / `FnMut` / `FnOnce`. 112 | 113 | | | Is a | Can mutate captures? | Can move out of captures? | 114 | | --- | --- | --- | --- | 115 | | [`fn(A) -> B`][fnptr] | type | no captures | no captures | 116 | | [`Fn(A) -> B`][fn] | trait | no | no | 117 | | [`FnMut(A) -> B`][fnmut] | trait | yes | no | 118 | | [`FnOnce(A) -> B`][fnonce] | trait | yes | yes | 119 | | [`FnBox(A) -> B`][fnbox]α | trait | yes | yes | 120 | 121 | α Nightly-only, as of rustc 1.18. 122 | 123 | 124 | ## Sizes 125 | 126 | This table describes the sizes of some common types. 127 | 128 | A *word* is a pointer or a pointer-sized integer. 129 | 130 | The first size is the size of the value itself: the stuff that ends up on the 131 | stack if you put it in a `let` variable. The second size is the size of any 132 | *owned* data in the heap. 133 | 134 | We assume `T`, `A`, `B`, `C` are [`Sized`][sized]. 135 | 136 | | Type | Value size | Contents | Heap size | 137 | | --- | --- | --- | --- | 138 | | [`bool`][bool] | 1 byte | 0 or 1 | | 139 | | [`()`][tuple] | empty! | | | 140 | | [`(A, B, C)`][tuple]
[`struct`][struct] | sum of `A`, `B`, `C` + pad / align | values of type `A`, `B`, `C` | anything owned by `A`, `B`, or `C` | 141 | | [`enum`][enum] | size of tag
+ max of variants
+ pad / align | tag + one variant | anything owned by variant | 142 | | [`[T; n]`][array] | `n` × size of `T` | `n` elements of type `T` | anything owned by `T` | 143 | | [`&T`][ref], [`&mut T`][mut-ref]
[`*const T`][rawptr], [`*mut T`][rawptr] | 1 word | pointer | | 144 | | [`Box`][box] | 1 word | pointer | size of `T` | 145 | | [`Option`][option] | 1 word + size of `T` + pad / align (but see below) | tag + optionally `T` | anything owned by `T`, if `Some` | 146 | | [`Option<&T>`][option]
[`Option<&mut T>`][option] | 1 wordβ | pointer or `NULL` | | 147 | | [`Option>`][option] | 1 wordβ | pointer or `NULL` | size of `T`, if `Some` | 148 | | [`[T]`][slice], [`str`][str] | dynamic size | elements or codepoints | | 149 | | [`&[T]`][slice] | 2 words | pointer, length (in elements) | | 150 | | [`&str`][str] | 2 words | pointer, length (in bytes) | | 151 | | [`Box<[T]>`][box] | 2 words | pointer, length (in elements) | length × size of `T` | 152 | | [`Box`][box] | 2 words | pointer, length (in bytes) | length (bytes) | 153 | | [`Vec`][vec] | 3 words | pointer, length, capacity | capacity × size of `T` | 154 | | [`String`][string] | 3 words | pointer, length, capacity | capacity (bytes) | 155 | | [`Trait`][trait-object] | dynamic size | fields of concrete type | anything owned by fields | 156 | | [`&Trait`][trait-object] | 2 words | pointer to concrete value, pointer to vtable | | 157 | | [`Box`][trait-object] | 2 words | pointer to concrete value, pointer to vtable | size of concrete value | 158 | | [Specific `fn` used as a value][fnptr]α | empty! | | | 159 | | [Specific lambda][closure] | depends on captures,
but known statically | captures | anything owned by captures | 160 | | [`fn(A) -> B`][fnptr]
[`unsafe fn(A) -> B`][fnptr]
[`extern fn(A) -> B`][fnptr] | 1 wordα | pointer to code | | 161 | | [`PhantomData`][phantomdata] | empty! | | | 162 | | [`Rc`][rc]
[`Arc`][arc] | 1 word | pointer | 2 words + size of `T` + pad / align | 163 | | [`Cell`][cell] | size of `T` | `T` | anything owned by `T` | 164 | | [`AtomicT`][atomic] | size of `T` | `T` | | 165 | | [`RefCell`][refcell] | 1 word + size of `T` + pad / align | borrow flag, `T` | anything owned by `T` | 166 | | [`Mutex`][mutex]
[`RwLock`][rwlock] | 2 words + size of `T` + pad / align | poison flag, pointer to OS mutex, `T` | anything owned by `T` + OS mutex | 167 | 168 | α These are function pointers. Technically, they can have a different size 169 | from a data pointer, but this does not happen on common architectures. 170 | 171 | β This optimization actually applies to any `Option`-shaped enum which contains, 172 | somewhere, a field which cannot be 0. 173 | 174 | 175 | [UTF-8]: https://en.wikipedia.org/wiki/UTF-8 176 | [static mut]: https://doc.rust-lang.org/book/const-and-static.html#mutability 177 | [copy]: https://doc.rust-lang.org/std/marker/trait.Copy.html 178 | [ref]: http://rust-lang.github.io/book/second-edition/ch04-02-references-and-borrowing.html 179 | [mut-ref]: http://rust-lang.github.io/book/second-edition/ch04-02-references-and-borrowing.html#mutable-references 180 | [Liskov]: https://en.wikipedia.org/wiki/Liskov_substitution_principle 181 | [rc]: https://doc.rust-lang.org/std/rc/ 182 | [arc]: https://doc.rust-lang.org/std/sync/struct.Arc.html 183 | [box]: https://doc.rust-lang.org/std/boxed/ 184 | [mutex]: https://doc.rust-lang.org/std/sync/struct.Mutex.html 185 | [refcell]: https://doc.rust-lang.org/std/cell/struct.RefCell.html 186 | [rwlock]: https://doc.rust-lang.org/std/sync/struct.RwLock.html 187 | [unsafecell]: https://doc.rust-lang.org/std/cell/struct.UnsafeCell.html 188 | [slice]: https://doc.rust-lang.org/std/primitive.slice.html 189 | [vec]: https://doc.rust-lang.org/std/vec/struct.Vec.html 190 | [str]: https://doc.rust-lang.org/std/primitive.str.html 191 | [string]: https://doc.rust-lang.org/std/string/struct.String.html 192 | [osstr]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html 193 | [osstring]: https://doc.rust-lang.org/std/ffi/struct.OsString.html 194 | [make_ascii_lowercase]: https://doc.rust-lang.org/std/primitive.str.html#method.make_ascii_lowercase 195 | [path]: https://doc.rust-lang.org/std/path/struct.Path.html 196 | [pathbuf]: https://doc.rust-lang.org/std/path/struct.PathBuf.html 197 | [cow]: https://doc.rust-lang.org/std/borrow/enum.Cow.html 198 | [cstr]: https://doc.rust-lang.org/std/ffi/struct.CStr.html 199 | [cstring]: https://doc.rust-lang.org/std/ffi/struct.CString.html 200 | [c_char]: https://docs.rs/libc/0.2.22/libc/type.c_char.html 201 | [cell]: https://doc.rust-lang.org/std/cell/struct.Cell.html 202 | [atomic]: https://doc.rust-lang.org/std/sync/atomic/index.html 203 | [sync]: https://doc.rust-lang.org/std/marker/trait.Sync.html 204 | [i8]: https://doc.rust-lang.org/std/primitive.i8.html 205 | [i16]: https://doc.rust-lang.org/std/primitive.i16.html 206 | [i32]: https://doc.rust-lang.org/std/primitive.i32.html 207 | [i64]: https://doc.rust-lang.org/std/primitive.i64.html 208 | [i128]: https://doc.rust-lang.org/std/primitive.i128.html 209 | [isize]: https://doc.rust-lang.org/std/primitive.isize.html 210 | [u8]: https://doc.rust-lang.org/std/primitive.u8.html 211 | [u16]: https://doc.rust-lang.org/std/primitive.u16.html 212 | [u32]: https://doc.rust-lang.org/std/primitive.u32.html 213 | [u64]: https://doc.rust-lang.org/std/primitive.u64.html 214 | [u128]: https://doc.rust-lang.org/std/primitive.u128.html 215 | [usize]: https://doc.rust-lang.org/std/primitive.usize.html 216 | [f32]: https://doc.rust-lang.org/std/primitive.f32.html 217 | [f64]: https://doc.rust-lang.org/std/primitive.f64.html 218 | [tuple]: https://doc.rust-lang.org/std/primitive.tuple.html 219 | [struct]: https://rust-lang.github.io/book/second-edition/ch05-00-structs.html 220 | [enum]: https://rust-lang.github.io/book/second-edition/ch06-00-enums.html 221 | [trait-object]: https://rust-lang.github.io/book/second-edition/ch17-02-trait-objects.html 222 | [fnptr]: https://rust-lang.github.io/book/second-edition/ch19-05-advanced-functions-and-closures.html#function-pointers 223 | [fn]: https://doc.rust-lang.org/std/ops/trait.Fn.html 224 | [fnmut]: https://doc.rust-lang.org/std/ops/trait.FnMut.html 225 | [fnonce]: https://doc.rust-lang.org/std/ops/trait.FnOnce.html 226 | [fnbox]: https://doc.rust-lang.org/std/boxed/trait.FnBox.html 227 | [closure]: https://rust-lang.github.io/book/second-edition/ch13-01-closures.html 228 | [phantomdata]: https://doc.rust-lang.org/std/marker/struct.PhantomData.html 229 | [option]: https://doc.rust-lang.org/std/option/enum.Option.html 230 | [move-closure]: https://doc.rust-lang.org/book/closures.html#move-closures 231 | [sized]: https://doc.rust-lang.org/std/marker/trait.Sized.html 232 | [rawptr]: https://doc.rust-lang.org/std/primitive.pointer.html 233 | [array]: https://doc.rust-lang.org/std/primitive.array.html 234 | [bool]: https://doc.rust-lang.org/std/primitive.bool.html 235 | 236 | 237 | ## See also 238 | 239 | [rust-learning cheat sheets](https://github.com/ctjhoa/rust-learning#cheat-sheets) 240 | 241 | [Rust Cheatsheet](http://phaiax.github.io/rust-cheatsheet/) 242 | 243 | [Rust Iterator Cheat Sheet](https://danielkeep.github.io/itercheat_baked.html) 244 | 245 | [The Periodic Table of Rust Types](http://cosmic.mearie.org/2014/01/periodic-table-of-rust-types/) 246 | 247 | [Cheatsheet for Futures](https://rufflewind.com/img/rust-futures-cheatsheet.html) 248 | 249 | [Time complexity for collections](https://doc.rust-lang.org/std/collections/#sequences) 250 | --------------------------------------------------------------------------------