rust-core-stdlib-overview
A tour of the Rust standard library. This skill is a map, not a tutorial: it tells you which std module provides which capability, what the prelude auto-imports, how core / alloc / std are layered, and when to drop to no_std. Deep mechanics live in cross-referenced skills.
Cross-references: [[rust-impl-no-std]] [[rust-impl-concurrency]] [[rust-impl-channels]] [[rust-core-async-runtime]] [[rust-impl-async-tokio]]
When to use this skill
- User asks "is there a standard library type for X" or "do I need a crate for this"
- User asks "what does the prelude import", "what is
std::prelude::v1"
- User asks "what is the difference between
core, alloc, and std"
- User asks "how do I make my crate
no_std" at the map level (mechanics live in rust-impl-no-std)
- User confused about which
std::sync primitive to pick at the catalogue level
- User asks "which
std::collections type should I use" at the catalogue level
- User asks "where is X in
std" and you need the module location
For deep mechanics of any module (lock poisoning, async runtimes, lifetime rules of &Path), refer to the cross-referenced skills.
Layering: core, alloc, std
std is built on two lower layers. ALWAYS understand which layer you depend on before writing portable code.
| Layer |
What it provides |
Requires |
core |
Primitives, traits, Option, Result, Iterator, formatting, atomics, Future, Pin. No allocation, no OS. |
Always available, including bare-metal no_std. |
alloc |
Box, Vec, String, Rc, Arc, BTreeMap, BTreeSet, VecDeque, BinaryHeap, LinkedList. |
A global allocator. Available on no_std with extern crate alloc;. |
std |
Everything in core and alloc plus OS-dependent: std::fs, std::io, std::net, std::process, std::thread, std::env, std::sync::Mutex, HashMap, HashSet. |
An operating system. |
ALWAYS note: HashMap and HashSet are in std, NOT in alloc, because they depend on RandomState for hash-DoS resilience which is seeded from the OS RNG. NEVER assume you can use HashMap on no_std; use the hashbrown crate directly with a manual hasher.
ALWAYS note: std::collections re-exports the alloc::collections types (BTreeMap, BTreeSet, VecDeque, BinaryHeap, LinkedList) plus the std-only types (HashMap, HashSet). Switching to no_std + alloc loses the hash-based types.
The prelude
The prelude is the set of names automatically imported into every module of every crate. Edition 2024 adds two items.
| Item |
Prelude version |
Copy, Clone, Drop, Sized, Send, Sync, Unpin |
v1 (all editions) |
Option, Some, None, Result, Ok, Err |
v1 (all editions) |
Box, String, ToString, Vec, ToOwned |
v1 (all editions) |
Default, From, Into, TryFrom, TryInto |
v1 (all editions) |
Iterator, IntoIterator, DoubleEndedIterator, ExactSizeIterator, Extend |
v1 (all editions) |
AsRef, AsMut |
v1 (all editions) |
Debug, Eq, Hash, Ord, PartialEq, PartialOrd |
v1 (all editions) |
Fn, FnMut, FnOnce |
v1 (all editions) |
Future, IntoFuture |
edition 2024 prelude addition |
ALWAYS access the prelude as std::prelude::v1 (or core::prelude::v1 / alloc::prelude::v1 for the layered preludes). NEVER assume non-prelude items like std::collections::HashMap are auto-imported; you must use them.
Decision table: I need X to do Y, which std module
| I need to ... |
Use this std module |
Key type or function |
| Store a growable list |
std::vec |
Vec<T> |
| Look up by key (unordered) |
std::collections |
HashMap<K, V> |
| Look up by key (sorted) |
std::collections |
BTreeMap<K, V> |
| Queue / double-ended queue |
std::collections |
VecDeque<T> |
| Set of unique values (unordered) |
std::collections |
HashSet<T> |
| Set of unique values (sorted) |
std::collections |
BTreeSet<T> |
| Max-heap priority queue |
std::collections |
BinaryHeap<T> |
| Share data across threads |
std::sync |
Arc<T> |
| Mutual exclusion lock |
std::sync |
Mutex<T> |
| Multi-reader / single-writer lock |
std::sync |
RwLock<T> |
| Lock-free counter / flag |
std::sync::atomic |
AtomicUsize, AtomicBool, Ordering |
| One-time initialization (thread-safe, returns reference) |
std::sync |
OnceLock<T> (since 1.70) |
| Lazy global (thread-safe, holds closure) |
std::sync |
LazyLock<T, F> (since 1.80) |
| Wait for N threads |
std::sync |
Barrier |
| Condition variable |
std::sync |
Condvar |
| Read or write a file |
std::fs + std::io |
File::open, File::create, fs::read_to_string, fs::write |
| Buffered I/O |
std::io |
BufReader<R>, BufWriter<W> |
| Read stdin / write stdout |
std::io |
io::stdin, io::stdout, io::stderr |
| Spawn an OS thread |
std::thread |
thread::spawn, thread::scope (since 1.63) |
| Run a subprocess |
std::process |
Command::new(...).output() |
| Sleep / measure elapsed time |
std::time + std::thread |
thread::sleep, Instant::now, Duration::from_* |
| Wall-clock time |
std::time |
SystemTime::now |
| Manipulate filesystem paths |
std::path |
Path, PathBuf |
| Read environment variables / args |
std::env |
env::args, env::var, env::vars, env::current_dir |
| FFI string with C (NUL-terminated) |
std::ffi |
CString, CStr |
| FFI string with OS (platform-native) |
std::ffi |
OsString, OsStr |
| Format a string |
std::fmt |
format!, write!, Debug, Display |
| Pin a value |
std::pin |
Pin<P>, pin! macro |
| Channel between threads |
std::sync::mpsc |
channel, Sender, Receiver |
ALWAYS check this table before reaching for an external crate. NEVER add a dependency for capabilities that std already provides at acceptable quality.
std::collections at a glance
std::collections is the catalogue of generic containers. Selection rules:
- ALWAYS default to
Vec<T> for sequences. It is the most efficient choice for almost every use case.
- ALWAYS prefer
HashMap<K, V> for unordered key-value lookup when keys implement Hash + Eq.
- ALWAYS use
BTreeMap<K, V> when you need ordered iteration, range queries, or deterministic iteration order (HashMap iteration order is intentionally randomised).
- ALWAYS use
VecDeque<T> for FIFO queues; Vec::remove(0) is O(n), VecDeque::pop_front is O(1).
- ALWAYS use
BinaryHeap<T> for priority queues; it is a max-heap, use std::cmp::Reverse for a min-heap.
- NEVER reach for
LinkedList<T>; its only honest use case is constant-time splicing of large lists, which is almost never the bottleneck. Vec or VecDeque is faster in practice due to cache locality.
HashMap and hash-DoS resilience
HashMap uses RandomState as its default hasher. RandomState is seeded from the OS RNG at creation time. This is a deliberate hash-DoS protection: an attacker who can choose keys cannot force pathological O(n) collisions in the table.
Consequences:
- ALWAYS expect iteration order to differ between runs and between insertions. NEVER rely on
HashMap iteration order for any logic.
- For deterministic order, use
BTreeMap or wrap with IndexMap (external crate indexmap).
- For maximum speed when keys are trusted (internal benchmark, fixed dataset), use
HashMap with a non-random hasher such as FxHashMap (external crate rustc-hash) or AHashMap (external crate ahash). ALWAYS document the threat model when removing DoS protection.
- The underlying implementation of
HashMap is the hashbrown crate, which is the Swiss-table design used by ABSL. In no_std + alloc you depend on hashbrown directly.
std::sync at a glance
std::sync collects the synchronization primitives.
Arc<T> : atomic reference count, thread-safe shared ownership. ALWAYS use Arc, NEVER Rc, when sharing across threads.
Mutex<T> : exclusive lock. Returns LockResult<MutexGuard<T>>; Err indicates poisoning from a panic while locked. ALWAYS handle poisoning explicitly or call .unwrap() only when the panic is unrecoverable.
RwLock<T> : many readers OR one writer. ALWAYS prefer Mutex for write-heavy workloads; RwLock overhead beats Mutex only when reads dominate.
atomic (AtomicUsize, AtomicBool, AtomicPtr, AtomicI32, etc.) : lock-free integer / pointer operations with explicit Ordering. ALWAYS pick Ordering::Relaxed for counters with no cross-thread observation requirements; Ordering::Acquire / Ordering::Release for synchronization; Ordering::SeqCst only when you have proven a need.
Once : run a closure exactly once across threads. Legacy; ALWAYS prefer OnceLock or LazyLock for new code.
OnceLock<T> (since 1.70) : one-time initialization that returns &T. Replaces lazy_static for non-closure cases.
LazyLock<T, F> (since 1.80) : static lazily initialized by a closure on first access. Replaces lazy_static for closure cases.
Barrier : block N threads until all arrive.
Condvar : condition variable, used with Mutex<bool> or Mutex<Queue> for "wait until predicate holds" patterns.
mpsc (sub-module): multi-producer, single-consumer channel. channel() returns (Sender<T>, Receiver<T>); sync_channel(bound) for bounded backpressure.
NEVER use std::sync::Mutex inside async code (holding the guard across .await blocks the runtime worker). Use tokio::sync::Mutex or similar runtime-specific async locks. See [[rust-core-async-runtime]].
std::io at a glance
std::io defines the I/O traits and helpers. Almost all Read / Write consumers are generic over the trait, not concrete types.
| Item |
Purpose |
Read |
read(&mut self, buf: &mut [u8]) -> io::Result<usize> |
Write |
write(&mut self, buf: &[u8]) -> io::Result<usize>, plus write_all, flush |
BufRead |
read_line, lines(), fill_buf |
Seek |
seek(SeekFrom) |
BufReader<R> |
Wraps a Read with an in-memory buffer; ALWAYS wrap raw File reads in BufReader unless you are doing one big read |
BufWriter<W> |
Wraps a Write with an in-memory buffer; flush on drop (errors are swallowed; flush explicitly to detect them) |
io::stdin(), io::stdout(), io::stderr() |
Handles to the standard streams; each acquires a lock per call (prefer .lock() for tight loops) |
io::Result<T> |
Alias for Result<T, io::Error> |
io::Error, io::ErrorKind |
Error type and discriminant; use ErrorKind::NotFound, WouldBlock, etc. for matching |
io::copy(&mut R, &mut W) |
Copy bytes between any Read and any Write |
ALWAYS check the return of Write::write: a partial write is legal. Use write_all to loop until done, or handle the partial yourself.
NEVER call stdout().write_all(...) in a tight loop without locking once via stdout().lock(); each stdout() call acquires the lock and is significantly slower.
std::fs and std::path at a glance
std::fs covers filesystem operations; std::path covers cross-platform path manipulation.
Key items:
File::open(path) opens read-only; File::create(path) opens write-only-truncate; OpenOptions::new().read(true).write(true).create(true).append(true).open(path) for full control.
fs::read_to_string(path) reads an entire file into a String; fs::write(path, contents) writes a slice or string.
fs::metadata(path) returns Metadata (file size, mtime, permissions).
fs::create_dir, fs::create_dir_all, fs::remove_file, fs::remove_dir, fs::remove_dir_all, fs::rename, fs::copy.
fs::read_dir(path) returns an iterator of io::Result<DirEntry>.
Path is the borrowed unsized type (analogous to &str); PathBuf is the owned growable type (analogous to String).
- ALWAYS accept
&Path (or generically impl AsRef<Path>) in function parameters, NEVER &PathBuf.
- ALWAYS use
Path::join, Path::with_extension, Path::file_name, Path::components for manipulation; NEVER concatenate strings.
- NEVER assume paths are valid UTF-8; on Unix they are arbitrary bytes, on Windows they are arbitrary UTF-16. Use
Path::display() for human output and OsStr for byte-level work.
NEVER use blocking std::fs calls inside an async runtime (Tokio, async-std, smol); the runtime worker stalls. Use tokio::fs or wrap in tokio::task::spawn_blocking. See [[rust-impl-async-tokio]].
std::process at a glance
std::process::Command is the builder for spawning subprocesses.
use std::process::{Command, Stdio};
let output = Command::new("ls")
.arg("-la")
.arg("/tmp")
.env("LC_ALL", "C")
.stdout(Stdio::piped())
.output()?; // io::Result<Output>
assert!(output.status.success());
let stdout = String::from_utf8_lossy(&output.stdout);
Key API:
Command::new(program) ; chained .arg, .args, .env, .env_clear, .env_remove, .current_dir, .stdin, .stdout, .stderr.
.output() runs to completion and collects Output { status, stdout, stderr }.
.status() runs to completion and returns only the exit status.
.spawn() returns Child for streaming I/O; ALWAYS call .wait() or .wait_with_output() to reap the process.
process::exit(code) terminates the current process without unwinding (Drop is NOT run).
process::abort() aborts (no destructors, signal SIGABRT on Unix).
NEVER pass user-controlled strings through a shell. ALWAYS use Command::arg per argument; arguments are passed directly to the OS without shell interpretation.
std::thread at a glance
std::thread is the OS-thread API.
thread::spawn(|| { ... }) returns a JoinHandle<T>; closure must be 'static + Send, return type must be Send.
thread::scope(|s| { s.spawn(|| { ... }); ... }) (since 1.63) creates scoped threads that can borrow non-'static data; all scoped threads must finish before the scope returns. ALWAYS prefer thread::scope over thread::spawn when you need to borrow stack data.
JoinHandle::join() waits for the thread and returns Result<T, Box<dyn Any + Send>>; Err indicates the thread panicked.
thread::Builder::new().name("worker").stack_size(8 * 1024 * 1024).spawn(...) configures a thread before spawning.
thread::current() returns the current thread handle; thread::sleep(Duration); thread::park() / Thread::unpark().
thread_local! macro declares per-thread static storage.
ALWAYS join spawned threads, NEVER let them detach silently unless you genuinely have a fire-and-forget background task.
std::time at a glance
| Type |
Purpose |
Duration |
Span of time; constructors Duration::from_secs, from_millis, from_micros, from_nanos. Arithmetic via +, -, *, /. |
Instant |
Monotonic clock; Instant::now(), Instant::elapsed, Instant::duration_since. ALWAYS use for measuring elapsed time. |
SystemTime |
Wall-clock time; SystemTime::now(), SystemTime::UNIX_EPOCH. NEVER use for measuring elapsed time; the wall clock can jump backwards. |
thread::sleep(Duration::from_millis(100)) sleeps the current thread.
For async sleep, use tokio::time::sleep ; NEVER use thread::sleep inside an async runtime.
std::env at a glance
| Function |
Returns |
env::args() |
Args iterator over String command-line arguments (panics on non-UTF-8 on Unix; use env::args_os() for OsString) |
env::var("NAME") |
Result<String, VarError>; UTF-8 only |
env::var_os("NAME") |
Option<OsString>; any bytes |
env::vars() |
Iterator over (String, String) pairs (UTF-8 only) |
env::current_dir() |
io::Result<PathBuf> |
env::set_current_dir(path) |
io::Result<()> ; process-wide, NOT thread-local |
env::current_exe() |
io::Result<PathBuf> ; path of the running binary |
env::set_var(k, v) / env::remove_var(k) |
Modifies the process environment (since 1.85: unsafe-marked; calling concurrently from multiple threads is undefined behavior) |
ALWAYS use env::args_os() when arguments may contain non-UTF-8 (filenames on Unix). NEVER mutate environment variables (set_var / remove_var) from inside a library or from a multi-threaded program without external synchronization; libc setenv is not thread-safe.
std::ffi at a glance
Two pairs of borrowed/owned string types, with different invariants.
| Type |
Purpose |
CStr |
Borrowed NUL-terminated C string. Unsized, like str. |
CString |
Owned NUL-terminated C string. Constructed via CString::new(...). |
OsStr |
Borrowed platform-native string. Unsized. |
OsString |
Owned platform-native string. |
ALWAYS use CString / CStr for FFI with C APIs (extern "C" functions that take *const c_char). NEVER pass &str directly; &str is not NUL-terminated.
ALWAYS use OsString / OsStr for paths and environment variables that may contain non-UTF-8 bytes (Unix paths, Windows UTF-16 paths).
Conversion: CString::new("hello")? returns Result<CString, NulError>; the error fires if the input contains an interior NUL byte.
See [[rust-impl-ffi-bindgen]] for full FFI mechanics.
The no_std switch
To make a crate compile without std, add #![no_std] to src/lib.rs. Consequences:
- You lose
std::fs, std::io, std::net, std::process, std::thread, std::env, std::sync::Mutex, HashMap, HashSet, the standard println! macro that targets stdout.
- You keep all of
core : Option, Result, Iterator, traits, atomics, formatting machinery (but no default output target).
- ALWAYS add
extern crate alloc; if you want Box, Vec, String, Rc, Arc, BTreeMap. Then use alloc::vec::Vec;, etc.
- ALWAYS provide a
#[panic_handler] somewhere in the crate graph (typically in the binary or board crate, not in the library).
- For hash maps without
std, use the hashbrown crate directly with BuildHasherDefault<FxHasher> or a fixed seed.
See [[rust-impl-no-std]] for the full no_std workflow.
Common cross-references
- For ownership and borrowing rules used throughout the stdlib API: see [[rust-syntax-ownership]] and [[rust-syntax-borrowing]].
- For deeper async runtime semantics (when
std blocking calls are forbidden): see [[rust-core-async-runtime]] and [[rust-impl-async-tokio]].
- For lock-free programming with
std::sync::atomic: see [[rust-impl-concurrency]].
- For channel patterns built on
std::sync::mpsc: see [[rust-impl-channels]].
- For the
no_std workflow end to end: see [[rust-impl-no-std]].
Reference files
references/methods.md : exact module item names per area, grouped by std module
references/examples.md : minimal working example for each major area
references/anti-patterns.md : five-plus stdlib anti-patterns and their fixes
Approved sources
1---2name: rust-core-stdlib-overview3description: Use when the user needs a map of the Rust standard library: which std module provides what (collections, sync, io, fs, process, thread, time, path, env, ffi), the prelude, the core / alloc / std split, no_std switch, hash-DoS resilience. Prevents reaching for an external crate when std already has it, missing the no_std implications of using std::collections, or ignoring HashMap's RandomState hash-DoS protection. Covers: std::collections (Vec / HashMap / BTreeMap / VecDeque / HashSet / BTreeSet / BinaryHeap), std::sync (Arc / Mutex / RwLock / atomic / Once / OnceLock 1.70 / LazyLock 1.80 / Barrier / Condvar), std::io (Read / Write / BufReader / stdin / stdout / stderr), std::fs, std::process (Command), std::thread (spawn / scope 1.63+), std::time, std::path, std::env, std::ffi (CString / OsString), prelude, core / alloc / std split, hashbrown. Keywords: stdlib, standard library, prelude, no_std, alloc, core, collections, HashMap, Vec, BTreeMap, Arc, Mutex, RwLock, atomic, LazyLock, OnceLock, Read trait, Write4license: MIT5---67# rust-core-stdlib-overview89A tour of the Rust standard library. This skill is a **map**, not a tutorial: it tells you which `std` module provides which capability, what the `prelude` auto-imports, how `core` / `alloc` / `std` are layered, and when to drop to `no_std`. Deep mechanics live in cross-referenced skills.1011Cross-references: [[rust-impl-no-std]] [[rust-impl-concurrency]] [[rust-impl-channels]] [[rust-core-async-runtime]] [[rust-impl-async-tokio]]1213---1415## When to use this skill1617- User asks "is there a standard library type for X" or "do I need a crate for this"18- User asks "what does the prelude import", "what is `std::prelude::v1`"19- User asks "what is the difference between `core`, `alloc`, and `std`"20- User asks "how do I make my crate `no_std`" at the map level (mechanics live in `rust-impl-no-std`)21- User confused about which `std::sync` primitive to pick at the catalogue level22- User asks "which `std::collections` type should I use" at the catalogue level23- User asks "where is X in `std`" and you need the module location2425For deep mechanics of any module (lock poisoning, async runtimes, lifetime rules of `&Path`), refer to the cross-referenced skills.2627---2829## Layering: core, alloc, std3031`std` is built on two lower layers. ALWAYS understand which layer you depend on before writing portable code.3233| Layer | What it provides | Requires |34|-------|------------------|----------|35| `core` | Primitives, traits, `Option`, `Result`, `Iterator`, formatting, atomics, `Future`, `Pin`. No allocation, no OS. | Always available, including bare-metal `no_std`. |36| `alloc` | `Box`, `Vec`, `String`, `Rc`, `Arc`, `BTreeMap`, `BTreeSet`, `VecDeque`, `BinaryHeap`, `LinkedList`. | A global allocator. Available on `no_std` with `extern crate alloc;`. |37| `std` | Everything in `core` and `alloc` plus OS-dependent: `std::fs`, `std::io`, `std::net`, `std::process`, `std::thread`, `std::env`, `std::sync::Mutex`, `HashMap`, `HashSet`. | An operating system. |3839ALWAYS note: `HashMap` and `HashSet` are in `std`, NOT in `alloc`, because they depend on `RandomState` for hash-DoS resilience which is seeded from the OS RNG. NEVER assume you can use `HashMap` on `no_std`; use the `hashbrown` crate directly with a manual hasher.4041ALWAYS note: `std::collections` re-exports the `alloc::collections` types (`BTreeMap`, `BTreeSet`, `VecDeque`, `BinaryHeap`, `LinkedList`) plus the `std`-only types (`HashMap`, `HashSet`). Switching to `no_std + alloc` loses the hash-based types.4243---4445## The prelude4647The **prelude** is the set of names automatically imported into every module of every crate. Edition 2024 adds two items.4849| Item | Prelude version |50|------|-----------------|51| `Copy`, `Clone`, `Drop`, `Sized`, `Send`, `Sync`, `Unpin` | v1 (all editions) |52| `Option`, `Some`, `None`, `Result`, `Ok`, `Err` | v1 (all editions) |53| `Box`, `String`, `ToString`, `Vec`, `ToOwned` | v1 (all editions) |54| `Default`, `From`, `Into`, `TryFrom`, `TryInto` | v1 (all editions) |55| `Iterator`, `IntoIterator`, `DoubleEndedIterator`, `ExactSizeIterator`, `Extend` | v1 (all editions) |56| `AsRef`, `AsMut` | v1 (all editions) |57| `Debug`, `Eq`, `Hash`, `Ord`, `PartialEq`, `PartialOrd` | v1 (all editions) |58| `Fn`, `FnMut`, `FnOnce` | v1 (all editions) |59| `Future`, `IntoFuture` | edition 2024 prelude addition |6061ALWAYS access the prelude as `std::prelude::v1` (or `core::prelude::v1` / `alloc::prelude::v1` for the layered preludes). NEVER assume non-prelude items like `std::collections::HashMap` are auto-imported; you must `use` them.6263---6465## Decision table: I need X to do Y, which std module6667| I need to ... | Use this `std` module | Key type or function |68|---------------|------------------------|----------------------|69| Store a growable list | `std::vec` | `Vec<T>` |70| Look up by key (unordered) | `std::collections` | `HashMap<K, V>` |71| Look up by key (sorted) | `std::collections` | `BTreeMap<K, V>` |72| Queue / double-ended queue | `std::collections` | `VecDeque<T>` |73| Set of unique values (unordered) | `std::collections` | `HashSet<T>` |74| Set of unique values (sorted) | `std::collections` | `BTreeSet<T>` |75| Max-heap priority queue | `std::collections` | `BinaryHeap<T>` |76| Share data across threads | `std::sync` | `Arc<T>` |77| Mutual exclusion lock | `std::sync` | `Mutex<T>` |78| Multi-reader / single-writer lock | `std::sync` | `RwLock<T>` |79| Lock-free counter / flag | `std::sync::atomic` | `AtomicUsize`, `AtomicBool`, `Ordering` |80| One-time initialization (thread-safe, returns reference) | `std::sync` | `OnceLock<T>` (since 1.70) |81| Lazy global (thread-safe, holds closure) | `std::sync` | `LazyLock<T, F>` (since 1.80) |82| Wait for N threads | `std::sync` | `Barrier` |83| Condition variable | `std::sync` | `Condvar` |84| Read or write a file | `std::fs` + `std::io` | `File::open`, `File::create`, `fs::read_to_string`, `fs::write` |85| Buffered I/O | `std::io` | `BufReader<R>`, `BufWriter<W>` |86| Read stdin / write stdout | `std::io` | `io::stdin`, `io::stdout`, `io::stderr` |87| Spawn an OS thread | `std::thread` | `thread::spawn`, `thread::scope` (since 1.63) |88| Run a subprocess | `std::process` | `Command::new(...).output()` |89| Sleep / measure elapsed time | `std::time` + `std::thread` | `thread::sleep`, `Instant::now`, `Duration::from_*` |90| Wall-clock time | `std::time` | `SystemTime::now` |91| Manipulate filesystem paths | `std::path` | `Path`, `PathBuf` |92| Read environment variables / args | `std::env` | `env::args`, `env::var`, `env::vars`, `env::current_dir` |93| FFI string with C (NUL-terminated) | `std::ffi` | `CString`, `CStr` |94| FFI string with OS (platform-native) | `std::ffi` | `OsString`, `OsStr` |95| Format a string | `std::fmt` | `format!`, `write!`, `Debug`, `Display` |96| Pin a value | `std::pin` | `Pin<P>`, `pin!` macro |97| Channel between threads | `std::sync::mpsc` | `channel`, `Sender`, `Receiver` |9899ALWAYS check this table before reaching for an external crate. NEVER add a dependency for capabilities that `std` already provides at acceptable quality.100101---102103## std::collections at a glance104105`std::collections` is the catalogue of generic containers. Selection rules:106107- ALWAYS default to `Vec<T>` for sequences. It is the most efficient choice for almost every use case.108- ALWAYS prefer `HashMap<K, V>` for unordered key-value lookup when keys implement `Hash + Eq`.109- ALWAYS use `BTreeMap<K, V>` when you need ordered iteration, range queries, or deterministic iteration order (HashMap iteration order is intentionally randomised).110- ALWAYS use `VecDeque<T>` for FIFO queues; `Vec::remove(0)` is O(n), `VecDeque::pop_front` is O(1).111- ALWAYS use `BinaryHeap<T>` for priority queues; it is a max-heap, use `std::cmp::Reverse` for a min-heap.112- NEVER reach for `LinkedList<T>`; its only honest use case is constant-time splicing of large lists, which is almost never the bottleneck. `Vec` or `VecDeque` is faster in practice due to cache locality.113114### HashMap and hash-DoS resilience115116`HashMap` uses `RandomState` as its default hasher. `RandomState` is seeded from the OS RNG at creation time. This is a deliberate hash-DoS protection: an attacker who can choose keys cannot force pathological O(n) collisions in the table.117118Consequences:119120- ALWAYS expect iteration order to differ between runs and between insertions. NEVER rely on `HashMap` iteration order for any logic.121- For deterministic order, use `BTreeMap` or wrap with `IndexMap` (external crate `indexmap`).122- For maximum speed when keys are trusted (internal benchmark, fixed dataset), use `HashMap` with a non-random hasher such as `FxHashMap` (external crate `rustc-hash`) or `AHashMap` (external crate `ahash`). ALWAYS document the threat model when removing DoS protection.123- The underlying implementation of `HashMap` is the `hashbrown` crate, which is the Swiss-table design used by ABSL. In `no_std + alloc` you depend on `hashbrown` directly.124125---126127## std::sync at a glance128129`std::sync` collects the synchronization primitives.130131- `Arc<T>` : atomic reference count, thread-safe shared ownership. ALWAYS use `Arc`, NEVER `Rc`, when sharing across threads.132- `Mutex<T>` : exclusive lock. Returns `LockResult<MutexGuard<T>>`; `Err` indicates **poisoning** from a panic while locked. ALWAYS handle poisoning explicitly or call `.unwrap()` only when the panic is unrecoverable.133- `RwLock<T>` : many readers OR one writer. ALWAYS prefer `Mutex` for write-heavy workloads; `RwLock` overhead beats `Mutex` only when reads dominate.134- `atomic` (`AtomicUsize`, `AtomicBool`, `AtomicPtr`, `AtomicI32`, etc.) : lock-free integer / pointer operations with explicit `Ordering`. ALWAYS pick `Ordering::Relaxed` for counters with no cross-thread observation requirements; `Ordering::Acquire` / `Ordering::Release` for synchronization; `Ordering::SeqCst` only when you have proven a need.135- `Once` : run a closure exactly once across threads. Legacy; ALWAYS prefer `OnceLock` or `LazyLock` for new code.136- `OnceLock<T>` (since 1.70) : one-time initialization that returns `&T`. Replaces `lazy_static` for non-closure cases.137- `LazyLock<T, F>` (since 1.80) : `static` lazily initialized by a closure on first access. Replaces `lazy_static` for closure cases.138- `Barrier` : block N threads until all arrive.139- `Condvar` : condition variable, used with `Mutex<bool>` or `Mutex<Queue>` for "wait until predicate holds" patterns.140- `mpsc` (sub-module): multi-producer, single-consumer channel. `channel()` returns `(Sender<T>, Receiver<T>)`; `sync_channel(bound)` for bounded backpressure.141142NEVER use `std::sync::Mutex` inside `async` code (holding the guard across `.await` blocks the runtime worker). Use `tokio::sync::Mutex` or similar runtime-specific async locks. See [[rust-core-async-runtime]].143144---145146## std::io at a glance147148`std::io` defines the I/O traits and helpers. Almost all `Read` / `Write` consumers are generic over the trait, not concrete types.149150| Item | Purpose |151|------|---------|152| `Read` | `read(&mut self, buf: &mut [u8]) -> io::Result<usize>` |153| `Write` | `write(&mut self, buf: &[u8]) -> io::Result<usize>`, plus `write_all`, `flush` |154| `BufRead` | `read_line`, `lines()`, `fill_buf` |155| `Seek` | `seek(SeekFrom)` |156| `BufReader<R>` | Wraps a `Read` with an in-memory buffer; ALWAYS wrap raw `File` reads in `BufReader` unless you are doing one big read |157| `BufWriter<W>` | Wraps a `Write` with an in-memory buffer; flush on drop (errors are swallowed; flush explicitly to detect them) |158| `io::stdin()`, `io::stdout()`, `io::stderr()` | Handles to the standard streams; each acquires a lock per call (prefer `.lock()` for tight loops) |159| `io::Result<T>` | Alias for `Result<T, io::Error>` |160| `io::Error`, `io::ErrorKind` | Error type and discriminant; use `ErrorKind::NotFound`, `WouldBlock`, etc. for matching |161| `io::copy(&mut R, &mut W)` | Copy bytes between any `Read` and any `Write` |162163ALWAYS check the return of `Write::write`: a partial write is legal. Use `write_all` to loop until done, or handle the partial yourself.164165NEVER call `stdout().write_all(...)` in a tight loop without locking once via `stdout().lock()`; each `stdout()` call acquires the lock and is significantly slower.166167---168169## std::fs and std::path at a glance170171`std::fs` covers filesystem operations; `std::path` covers cross-platform path manipulation.172173Key items:174175- `File::open(path)` opens read-only; `File::create(path)` opens write-only-truncate; `OpenOptions::new().read(true).write(true).create(true).append(true).open(path)` for full control.176- `fs::read_to_string(path)` reads an entire file into a `String`; `fs::write(path, contents)` writes a slice or string.177- `fs::metadata(path)` returns `Metadata` (file size, mtime, permissions).178- `fs::create_dir`, `fs::create_dir_all`, `fs::remove_file`, `fs::remove_dir`, `fs::remove_dir_all`, `fs::rename`, `fs::copy`.179- `fs::read_dir(path)` returns an iterator of `io::Result<DirEntry>`.180181`Path` is the **borrowed** unsized type (analogous to `&str`); `PathBuf` is the **owned** growable type (analogous to `String`).182183- ALWAYS accept `&Path` (or generically `impl AsRef<Path>`) in function parameters, NEVER `&PathBuf`.184- ALWAYS use `Path::join`, `Path::with_extension`, `Path::file_name`, `Path::components` for manipulation; NEVER concatenate strings.185- NEVER assume paths are valid UTF-8; on Unix they are arbitrary bytes, on Windows they are arbitrary UTF-16. Use `Path::display()` for human output and `OsStr` for byte-level work.186187NEVER use blocking `std::fs` calls inside an async runtime (Tokio, async-std, smol); the runtime worker stalls. Use `tokio::fs` or wrap in `tokio::task::spawn_blocking`. See [[rust-impl-async-tokio]].188189---190191## std::process at a glance192193`std::process::Command` is the builder for spawning subprocesses.194195```rust196use std::process::{Command, Stdio};197198let output = Command::new("ls")199 .arg("-la")200 .arg("/tmp")201 .env("LC_ALL", "C")202 .stdout(Stdio::piped())203 .output()?; // io::Result<Output>204205assert!(output.status.success());206let stdout = String::from_utf8_lossy(&output.stdout);207```208209Key API:210211- `Command::new(program)` ; chained `.arg`, `.args`, `.env`, `.env_clear`, `.env_remove`, `.current_dir`, `.stdin`, `.stdout`, `.stderr`.212- `.output()` runs to completion and collects `Output { status, stdout, stderr }`.213- `.status()` runs to completion and returns only the exit status.214- `.spawn()` returns `Child` for streaming I/O; ALWAYS call `.wait()` or `.wait_with_output()` to reap the process.215- `process::exit(code)` terminates the current process without unwinding (Drop is NOT run).216- `process::abort()` aborts (no destructors, signal SIGABRT on Unix).217218NEVER pass user-controlled strings through a shell. ALWAYS use `Command::arg` per argument; arguments are passed directly to the OS without shell interpretation.219220---221222## std::thread at a glance223224`std::thread` is the OS-thread API.225226- `thread::spawn(|| { ... })` returns a `JoinHandle<T>`; closure must be `'static + Send`, return type must be `Send`.227- `thread::scope(|s| { s.spawn(|| { ... }); ... })` (since 1.63) creates **scoped threads** that can borrow non-`'static` data; all scoped threads must finish before the scope returns. ALWAYS prefer `thread::scope` over `thread::spawn` when you need to borrow stack data.228- `JoinHandle::join()` waits for the thread and returns `Result<T, Box<dyn Any + Send>>`; `Err` indicates the thread panicked.229- `thread::Builder::new().name("worker").stack_size(8 * 1024 * 1024).spawn(...)` configures a thread before spawning.230- `thread::current()` returns the current thread handle; `thread::sleep(Duration)`; `thread::park()` / `Thread::unpark()`.231- `thread_local!` macro declares per-thread static storage.232233ALWAYS join spawned threads, NEVER let them detach silently unless you genuinely have a fire-and-forget background task.234235---236237## std::time at a glance238239| Type | Purpose |240|------|---------|241| `Duration` | Span of time; constructors `Duration::from_secs`, `from_millis`, `from_micros`, `from_nanos`. Arithmetic via `+`, `-`, `*`, `/`. |242| `Instant` | Monotonic clock; `Instant::now()`, `Instant::elapsed`, `Instant::duration_since`. ALWAYS use for measuring elapsed time. |243| `SystemTime` | Wall-clock time; `SystemTime::now()`, `SystemTime::UNIX_EPOCH`. NEVER use for measuring elapsed time; the wall clock can jump backwards. |244245`thread::sleep(Duration::from_millis(100))` sleeps the current thread.246247For async sleep, use `tokio::time::sleep` ; NEVER use `thread::sleep` inside an async runtime.248249---250251## std::env at a glance252253| Function | Returns |254|----------|---------|255| `env::args()` | `Args` iterator over `String` command-line arguments (panics on non-UTF-8 on Unix; use `env::args_os()` for `OsString`) |256| `env::var("NAME")` | `Result<String, VarError>`; UTF-8 only |257| `env::var_os("NAME")` | `Option<OsString>`; any bytes |258| `env::vars()` | Iterator over `(String, String)` pairs (UTF-8 only) |259| `env::current_dir()` | `io::Result<PathBuf>` |260| `env::set_current_dir(path)` | `io::Result<()>` ; process-wide, NOT thread-local |261| `env::current_exe()` | `io::Result<PathBuf>` ; path of the running binary |262| `env::set_var(k, v)` / `env::remove_var(k)` | Modifies the process environment (since 1.85: unsafe-marked; calling concurrently from multiple threads is undefined behavior) |263264ALWAYS use `env::args_os()` when arguments may contain non-UTF-8 (filenames on Unix). NEVER mutate environment variables (`set_var` / `remove_var`) from inside a library or from a multi-threaded program without external synchronization; libc `setenv` is not thread-safe.265266---267268## std::ffi at a glance269270Two pairs of borrowed/owned string types, with different invariants.271272| Type | Purpose |273|------|---------|274| `CStr` | Borrowed NUL-terminated C string. Unsized, like `str`. |275| `CString` | Owned NUL-terminated C string. Constructed via `CString::new(...)`. |276| `OsStr` | Borrowed platform-native string. Unsized. |277| `OsString` | Owned platform-native string. |278279ALWAYS use `CString` / `CStr` for FFI with C APIs (`extern "C"` functions that take `*const c_char`). NEVER pass `&str` directly; `&str` is not NUL-terminated.280281ALWAYS use `OsString` / `OsStr` for paths and environment variables that may contain non-UTF-8 bytes (Unix paths, Windows UTF-16 paths).282283Conversion: `CString::new("hello")?` returns `Result<CString, NulError>`; the error fires if the input contains an interior NUL byte.284285See [[rust-impl-ffi-bindgen]] for full FFI mechanics.286287---288289## The no_std switch290291To make a crate compile without `std`, add `#![no_std]` to `src/lib.rs`. Consequences:292293- You lose `std::fs`, `std::io`, `std::net`, `std::process`, `std::thread`, `std::env`, `std::sync::Mutex`, `HashMap`, `HashSet`, the standard `println!` macro that targets stdout.294- You keep all of `core` : `Option`, `Result`, `Iterator`, traits, atomics, formatting machinery (but no default output target).295- ALWAYS add `extern crate alloc;` if you want `Box`, `Vec`, `String`, `Rc`, `Arc`, `BTreeMap`. Then `use alloc::vec::Vec;`, etc.296- ALWAYS provide a `#[panic_handler]` somewhere in the crate graph (typically in the binary or board crate, not in the library).297- For hash maps without `std`, use the `hashbrown` crate directly with `BuildHasherDefault<FxHasher>` or a fixed seed.298299See [[rust-impl-no-std]] for the full `no_std` workflow.300301---302303## Common cross-references304305- For ownership and borrowing rules used throughout the stdlib API: see [[rust-syntax-ownership]] and [[rust-syntax-borrowing]].306- For deeper async runtime semantics (when `std` blocking calls are forbidden): see [[rust-core-async-runtime]] and [[rust-impl-async-tokio]].307- For lock-free programming with `std::sync::atomic`: see [[rust-impl-concurrency]].308- For channel patterns built on `std::sync::mpsc`: see [[rust-impl-channels]].309- For the `no_std` workflow end to end: see [[rust-impl-no-std]].310311---312313## Reference files314315- `references/methods.md` : exact module item names per area, grouped by `std` module316- `references/examples.md` : minimal working example for each major area317- `references/anti-patterns.md` : five-plus stdlib anti-patterns and their fixes318319---320321## Approved sources322323- Rust Standard Library (root): https://doc.rust-lang.org/std/324- std::collections : https://doc.rust-lang.org/std/collections/index.html325- std::sync : https://doc.rust-lang.org/std/sync/index.html326- std::io : https://doc.rust-lang.org/std/io/index.html327- std::fs : https://doc.rust-lang.org/std/fs/index.html328- std::thread : https://doc.rust-lang.org/std/thread/index.html329- std::time : https://doc.rust-lang.org/std/time/index.html330- std::path : https://doc.rust-lang.org/std/path/index.html331- std::env : https://doc.rust-lang.org/std/env/index.html332- std::ffi : https://doc.rust-lang.org/std/ffi/index.html333- std::process : https://doc.rust-lang.org/std/process/index.html334- Rust 1.70 release (OnceLock) : https://blog.rust-lang.org/2023/06/01/Rust-1.70.0/335- Rust 1.80 release (LazyLock) : https://blog.rust-lang.org/2024/07/25/Rust-1.80.0/336- Rust 1.63 release (scoped threads) : https://blog.rust-lang.org/2022/08/11/Rust-1.63.0/