Keywords Rust divides keywords into three categories: • strict • reserved • weak Strict keywords These keywords can only be used in their correct contexts. They cannot be used as the names of: • Items • Variables and function parameters • F...
Shebang A shebang is an optional line that is typically used in Unix-like systems to specify an interpreter for executing the file. [!EXAMPLE] #!/usr/bin/env rustx fn main() { println!("Hello!"); } @root SHEBANG -> `#!` !((WHITESPACE | LINE...
Input format CHAR -> [U+0000-U+D7FF U+E000-U+10FFFF] // a Unicode scalar value ASCII -> [U+0000-U+007F] NUL -> U+0000 EOF -> !CHAR // End of file or input This chapter describes how a source file is interpreted as a sequence of tokens. See...
Notation Grammar The following notations are used by the Lexer and Syntax grammar snippets: | Notation | Examples | Meaning | |-------------------|-------------------------------|-------------------------------------------| | CAPITAL | KW_I...
Introduction This book is the primary reference for the Rust programming language. [!NOTE] For known bugs and omissions in this book, see our GitHub issues. If you see a case where the compiler behavior and the text here do not agree, file...
#[panic_handler] #[panic_handler] is used to define the behavior of panic! in #![no_std] applications. The #[panic_handler] attribute must be applied to a function with signature fn(&PanicInfo) -> ! and such function must appear once in the...
Beneath std This section documents features that are normally provided by the std crate and that #![no_std] developers have to deal with (i.e. provide) to build #![no_std] binary crates. Using libc In order to build a #[no_std] executable w...
Foreign Function Interface Introduction This guide will use the snappy compression/decompression library as an introduction to writing bindings for foreign code. Rust is currently unable to call directly into a C++ library, but snappy inclu...
Final Code Here's the final code, with some added comments and re-ordered imports: use std::marker::PhantomData; use std::ops::Deref; use std::ptr::NonNull; use std::sync::atomic::{self, AtomicUsize, Ordering}; pub struct Arc<T> { ptr: NonN...
Dropping We now need a way to decrease the reference count and drop the data once it is low enough, otherwise the data will live forever on the heap. To do this, we can implement Drop. Basically, we need to: 1. Decrement the reference count...
Cloning Now that we've got some basic code set up, we'll need a way to clone the Arc. Basically, we need to: 1. Increment the atomic reference count 2. Construct a new instance of the Arc from the inner pointer First, we need to get access...
Base Code Now that we've decided the layout for our implementation of Arc, let's create some basic code. Constructing the Arc We'll first need a way to construct an Arc<T>. This is pretty simple, as we just need to box the ArcInner<T> and g...
Layout Let's start by making the layout for our implementation of Arc. An Arc<T> provides thread-safe shared ownership of a value of type T, allocated in the heap. Sharing implies immutability in Rust, so we don't need to design anything th...
Implementing Arc In this section, we'll be implementing a simpler version of std::sync::Arc. Similarly to the implementation of Vec we made earlier, we won't be taking advantage of as many optimizations, intrinsics, or unstable code as the...
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, we'll be implementing versions of the standard library's Arc an...
The Final Code use std::alloc::{self, Layout}; use std::marker::PhantomData; use std::mem; use std::ops::{Deref, DerefMut}; use std::ptr::{self, NonNull}; struct RawVec<T> { ptr: NonNull<T>, cap: usize, } unsafe impl<T: Send> Send for RawVe...
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 raw allocations, which are exactly the two things that c...
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 untouched. For now we'll only implement the "basic" full-range version. use std::mar...
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 we've implemented it and identified actual logic duplication, this is a goo...