# Nuclei: everything > Proactive async runtime for Rust. A task hands its IO to the driver and gets the result back completed, one shard per core, on io_uring, epoll, kqueue and I/O completion ports. Nuclei 0.5.3 needs Rust 1.99 or newer. Add it to Cargo.toml: ```toml [dependencies] nuclei = "0.5.3" ``` These files are built from commit 522f3a61affd58eb53d8a4d5a9505eff201b07a7 of github.com/vertexclique/nuclei with the site, on every push to master, so they describe the code as it is there. The Learn chapters teach the crate from the first program to production, with a program that compiles and runs for every idea; the API reference holds every public item. What follows: the Learn index, the 17 Learn chapters in order, the API reference, and the changelog. # Learn Nuclei From the first line in Cargo.toml to a server in production, one idea at a time. The page: https://nuclei.rs/learn/ Nuclei is a proactive async runtime for Rust. A task hands its IO to the driver of its core and gets the result back completed; every core runs a shard of its own, with its tasks, timers, buffers and driver. The chapters follow the path below: start, the core ideas, then each area of the crate. > **Every example runs** > > Each program on these pages is a file the site's build compiles, lints and runs on Linux, on io_uring and on epoll, before every deploy. The ones that need Unix (Unix sockets, signals, programs such as `sort`) say so. ## Where to start - **New to async Rust:** read in order. [Setup](https://nuclei.rs/learn/setup.html), [How it works](https://nuclei.rs/learn/proactive.html), [Runtime](https://nuclei.rs/learn/runtime.html) and [Tasks](https://nuclei.rs/learn/tasks.html) are the core. - **Coming from a readiness-based runtime:** start with [Migrate](https://nuclei.rs/learn/migrate.html). Most names carry over; dropping a task handle and a write's completion behave differently. - **Looking for one item:** press `Ctrl K` (`⌘ K` on a Mac) to search these pages and the [API reference](https://nuclei.rs/api/nuclei/). ## Start [01SetupAdd Nuclei, run a first program, pick features, see which backend runs.](https://nuclei.rs/learn/setup.html)[02How it worksShards, the proactor and its buffers: the few ideas the rest builds on.](https://nuclei.rs/learn/proactive.html) ## Core [03RuntimeEnter the runtime: the attribute, block_on, a runtime of your own and its workers.](https://nuclei.rs/learn/runtime.html)[04TasksSpawn, join, cancel and name tasks; local, blocking and task-local work.](https://nuclei.rs/learn/tasks.html)[05Select and joinWait on several futures in one task: join!, try_join! and select!.](https://nuclei.rs/learn/select.html) ## IO [06NetworkingTCP, UDP and Unix sockets, names, socket options, halves, ending a stream and pipes.](https://nuclei.rs/learn/net.html)[07IO utilitiesRead and write helpers, copies, buffers you lend, in-memory pipes and the standard streams.](https://nuclei.rs/learn/io.html)[08ReadinessReadiness waits, the try_ calls, and system calls of your own.](https://nuclei.rs/learn/readiness.html)[09FilesFiles, IO at an offset and direct IO, syncs, locks, metadata and directories.](https://nuclei.rs/learn/fs.html) ## Building blocks [10TimeSleeps to the millisecond or the microsecond, timeouts, intervals, and a clock tests can stop.](https://nuclei.rs/learn/time.html)[11SyncLocks, semaphores, notifications, once-cells, lock-free structures and their one-shard twins.](https://nuclei.rs/learn/sync.html)[12Channelsmpsc, oneshot, broadcast and watch channels, meshes between workers, and cancellation tokens.](https://nuclei.rs/learn/channels.html)[13ProcessesChild processes with async pipes, and signals as streams.](https://nuclei.rs/learn/processes.html) ## Ship it [14ProductionEvery runtime setting, hooks, counters, shutdown, tests and allocation.](https://nuclei.rs/learn/production.html)[15Backendsio_uring, epoll, kqueue and IOCP: how one is picked and what differs.](https://nuclei.rs/learn/backends.html)[16ErrorsThe messages you may meet, what each means, and the fix.](https://nuclei.rs/learn/errors.html)[17MigrateComing from a readiness-based runtime: the map and the pitfalls.](https://nuclei.rs/learn/migrate.html) # Setup Add Nuclei, run a first program, and see which kernel interface it picked. Chapter 1 of 17. The page: https://nuclei.rs/learn/setup.html ## What you need Rust 1.99 or later. Nuclei is written in the 2024 edition; your crate may use any edition. Each system runs on its own kernel interface: | System | Backend | | --- | --- | | Linux, Android | io_uring where the kernel (6.1 or later) and the sandbox allow it, else epoll | | illumos | epoll | | macOS, iOS, FreeBSD, NetBSD, OpenBSD, DragonFly | kqueue | | Windows | I/O completion ports | ## Add it ```sh cargo add nuclei ``` or in `Cargo.toml`: `Cargo.toml`: ```toml [dependencies] nuclei = "0.5" ``` Nothing else is needed: the read and write helpers, the stream traits and the macros all come with the crate. ## A first program `src/main.rs`: ```rust #[nuclei::main] async fn main() { let answer = nuclei::spawn(async { 6 * 7 }).await; println!("the answer is {answer}"); } ``` Output: ``` the answer is 42 ``` `#[nuclei::main]` runs the async `main` on the runtime, and `nuclei::spawn` places a task on one of its shards; awaiting the task gives its output. There is nothing to configure: the first `spawn` or `block_on` starts the default runtime, with one worker per core the process may run on. ## Features | Feature | Default | What it gives | | --- | --- | --- | | `epoll` | on | Names epoll beside `iouring`. Epoll is built on Linux either way. | | `iouring` | on | The io_uring driver, on Linux and Android. Without it those systems run on epoll. | | `attributes` | on | `#[nuclei::main]`, `#[nuclei::test]` and `#[nuclei::bench]`. | | `recycle` | off | Node memory of the lock-free queues, maps and channels underneath, from a per-thread cache instead of the global allocator. | | `io-stats` | off | Each worker's IO in `stats`: counts of its operations and bytes, and IO latencies when recorded ([Production](https://nuclei.rs/learn/production.html#io-stats)). Off by default; without it no IO path carries counting or timing code. | `recycle` is for applications: cargo turns a feature on for every user of a crate in a build, so a library that enabled it would enable it for all of them. `Cargo.toml`: ```toml [dependencies] # Linux on epoll only, keeping the attribute macros: nuclei = { version = "0.5", default-features = false, features = ["attributes"] } ``` ## Which backend runs `src/main.rs`: ```rust fn main() { nuclei::block_on(async { println!("IO runs on {:?}", nuclei::Proactor::backend()); }); } ``` With nothing set, Nuclei takes io_uring where the kernel lets the process have the rings its shards use, and the platform's poller otherwise. The probe is safe, even under a seccomp filter that kills a process for calling `io_uring_setup`. `NUCLEI_BACKEND` picks one by hand: `auto`, `io_uring` or `epoll` on Linux, `kqueue` on macOS and the BSDs, `iocp` on Windows. ```sh NUCLEI_BACKEND=epoll cargo run ``` A backend named by hand that the process cannot have is an error with the reason, never a silent fallback. [Backends](https://nuclei.rs/learn/backends.html) has the details, [Errors](https://nuclei.rs/learn/errors.html#backend-io-uring) the messages. # How it works Shards, a driver that completes the IO, and buffers it keeps: the ideas the other chapters build on. Chapter 2 of 17. The page: https://nuclei.rs/learn/proactive.html ## One shard per core A runtime starts one worker thread per core, and each runs a **shard**: a run queue, a timer wheel, a buffer pool and a **driver**, its own handle on the kernel's IO interface. On Linux each worker is pinned to its core. - **A task stays where it was placed.** Nothing steals it: no lock or cache line is shared to move it, and its timers and IO stay on one core. - **Placement keeps work near.** A task spawned on a worker stays on that worker while it is no busier than the others (a margin you can set); the first spawn from another thread picks the less loaded of two shards. - **A task that blocks holds up only itself.** A poll that runs past [`handoff_after`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.handoff_after) (10 ms by default) hands the shard, with its other tasks, timers and IO, to another thread on the same core ([Tasks](https://nuclei.rs/learn/tasks.html#handoff)). The blocked thread still shares that core, so give long work to [the blocking pool](https://nuclei.rs/learn/tasks.html#blocking), or split it with [yields](https://nuclei.rs/learn/tasks.html#yield). ## The driver completes the IO A readiness-based runtime tells a task when a socket may be ready, and the task then makes the read or write call itself; if another reader got there first, the call would block and the task waits again. Nuclei is a **proactor**: the task hands its operation to its shard's driver, and the operation completes for it. Only the driver touches a descriptor. | Backend | How an operation completes | | --- | --- | | io_uring | The driver submits it to the shard's ring, and the kernel performs it. | | I/O completion ports | It is issued as an overlapped call; the kernel completes it, and the shard takes the completion from its port. | | epoll, kqueue | The driver makes the call: at once when the socket may be ready, otherwise on its next edge. | The task's side is the same on all four: it asks, and later takes the result. ## Where the bytes go The kernel may hold an operation's memory after the future that asked is gone, so Nuclei never lends the kernel memory a future borrows: - **Reads land in the shard's pool.** The driver reads ahead into a pool buffer; `recv` or `read` copies into your slice. - **Writes go to a write-behind.** A write is copied into the stream's write-behind buffer and taken at once; the driver writes it out, in order, as the socket takes it. - **The pool has a ceiling.** Each worker's buffers hold at most [`io_buffer_cap`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.io_buffer_cap) bytes. At the cap, IO waits for buffers to come back, so IO memory never grows past it. So a write that returned means the bytes are Nuclei's to deliver, not that the kernel has them. `flush` waits until the kernel has every byte and reports a write that failed; `shutdown` flushes, then ends the write side so the peer sees the end of the stream. `src/main.rs`: ```rust use nuclei::io::{AsyncReadExt, AsyncWriteExt}; use nuclei::net::{TcpListener, TcpStream}; #[nuclei::main] async fn main() -> std::io::Result<()> { let listener = TcpListener::bind("127.0.0.1:0").await?; let addr = listener.local_addr()?; let reader = nuclei::spawn(async move { let (mut stream, _) = listener.accept().await?; let mut all = Vec::new(); stream.read_to_end(&mut all).await?; std::io::Result::Ok(all.len()) }); let mut stream = TcpStream::connect(addr).await?; // Each write is copied into the stream's write-behind and taken at once. for _ in 0..1000 { stream.write_all(&[b'x'; 1024]).await?; } // flush waits until the kernel has every byte, and reports a failed write. stream.flush().await?; // shutdown flushes, then ends the write side: the reader sees the end. stream.shutdown().await?; assert_eq!(reader.await?, 1000 * 1024); Ok(()) } ``` A write that fails keeps its error: later writes fail with it until a flush reports it. Bytes written behind are delivered even if the handle is dropped first: a task sends them on the handle's own descriptor, for at most [`write_behind_linger`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.write_behind_linger) (one minute by default, [every setting](https://nuclei.rs/learn/production.html#builder)), and then closes it. Past that the rest is given up, and a TCP stream's connection is reset, so the peer reads `ConnectionReset` rather than a cut stream that looks whole. `abort` resets a TCP stream at once ([Networking](https://nuclei.rs/learn/net.html#shut)). A runtime's drop waits for these tasks, running them for at most the same time. One it has not finished by then goes on, on a thread of its own, to its own deadline, as do the ones handed over after the drop. ## Lending a buffer Where the copy matters, lend the driver a buffer of your own. `read_owned` reads into its spare capacity and gives it back with the count; `write_owned` writes all of it and gives it back once the kernel took the last byte. Each takes any buffer type that implements [`IoBuf`](https://nuclei.rs/learn/io.html#owned) (writes) or `IoBufMut` (reads), a `Vec` among them, and gives the same type back. TCP and Unix streams, pipes and files have both, and `read_vectored_owned` and `write_vectored_owned` lend several buffers in one call ([IO utilities](https://nuclei.rs/learn/io.html#vectored)). `src/main.rs`: ```rust use nuclei::net::{TcpListener, TcpStream}; #[nuclei::main] async fn main() -> std::io::Result<()> { let listener = TcpListener::bind("127.0.0.1:0").await?; let addr = listener.local_addr()?; let server = nuclei::spawn(async move { let (stream, _) = listener.accept().await?; // Lend the driver this vector: the kernel reads into its spare capacity. let (n, buf) = stream.read_owned(Vec::with_capacity(64)).await; n?; // Lend it again for the reply; it comes back once the kernel took it all. let (sent, _buf) = stream.write_owned(buf).await; sent }); let client = TcpStream::connect(addr).await?; let (sent, _) = client.write_owned(b"lent, not copied".to_vec()).await; sent?; let (n, reply) = client.read_owned(Vec::with_capacity(64)).await; assert_eq!(&reply[..n?], b"lent, not copied"); server.await?; Ok(()) } ``` ## Dropping a future halfway Async code drops futures all the time: a timeout fires, a token is cancelled, a `select!` takes another branch. No byte is lost when it does: - A read dropped halfway leaves what the driver already read for the next read. - A lent read (`read_owned`) dropped halfway hands the bytes read into its buffer to the next read, ahead of anything after them. - A lent write (`write_owned`) dropped halfway reaches the stream whole or not at all: withdrawn if none of it went out, finished by the driver if some did. On Windows a TCP write is always finished. ## No allocation in steady state Once warm, these operations make no call into the allocator. The crate's tests measure it with a counting allocator (`tests/zero_alloc.rs`), on a runtime that runs everything on one thread: - a TCP round trip; UDP datagrams, to an address and on a connected socket; file reads and writes; - a local spawn; a spawn onto a worker, on the spawning thread; a job on the blocking pool; - a `JoinSet` spawn and join; a oneshot channel. A timer takes a slot of its shard's wheel, and arming and cancelling reuse the slots once the wheel has grown to the most timers alive at once. ## Checked, not assumed The concurrent protocols are model-checked with TLA+: the task's states, the park and wake handshake, an IO source's sides, the ring's operations and the sync primitives' queues. TLC tries every order of every thread's steps for small sizes, and each model has mutations that must break it. Lean proves the arithmetic under them (counts, state words, generations) for every size. Loom runs the real code under every interleaving it reaches, and CI runs the suite under AddressSanitizer on io_uring and on epoll. [`proofs/README.md`](https://github.com/vertexclique/nuclei/blob/master/proofs/README.md) says what each check covers and what it leaves out. # Runtime The ways into the runtime: the attribute, block_on, and runtimes of your own. Chapter 3 of 17. The page: https://nuclei.rs/learn/runtime.html ## The attribute `#[nuclei::main]` turns an async `main` into a program: its body runs in `block_on` on the default runtime. It may return anything `main` may, such as `std::io::Result<()>`. Its options, comma separated: - `threads = N`: a runtime of its own with N workers; `0` runs every task on the thread inside `block_on`. - `start_paused = true`: a runtime of its own whose clock starts paused (see [Time](https://nuclei.rs/learn/time.html#paused)). - `builder = "path"`: a runtime of its own, built from the `Builder` the function at `path` returns; `threads` and `start_paused`, when given, apply on top of it. - `crate = "path"`: where the crate is, for code that re-exports it. `src/main.rs`: ```rust #[nuclei::main(threads = 2)] async fn main() { let stats = nuclei::stats(); let workers = stats.shards.iter().filter(|s| s.worker.is_some()).count(); println!("{workers} worker shards"); } ``` Output: ``` 2 worker shards ``` With `builder`, every setting comes from a function of your own: `src/main.rs`: ```rust // The runtime's settings, from a function of the program's own. fn runtime() -> nuclei::Builder { nuclei::Builder::new() .worker_threads(2) .thread_name("server") } #[nuclei::main(builder = "runtime")] async fn main() { let thread = nuclei::spawn(async { std::thread::current().name().map(str::to_owned) }); assert_eq!(thread.await.as_deref(), Some("server")); } ``` ## block_on `nuclei::block_on` runs a future to its end on the calling thread. The first call, or the first `spawn`, starts the default runtime, so a plain `fn main` needs nothing else. (`nuclei::drive` is the same call under the name earlier versions used.) `src/main.rs`: ```rust use std::time::Duration; fn main() { // The first call starts the default runtime: one worker shard per core. let sum = nuclei::block_on(async { nuclei::time::sleep(Duration::from_millis(10)).await; (1..=10).sum::() }); assert_eq!(sum, 55); } ``` ## block_on nests `block_on` works anywhere, inside a task too. There it nests: the shard keeps running its other tasks, timers and IO until the future completes, so synchronous code deep in a call stack can wait on a future without holding the shard. `src/main.rs`: ```rust /// A synchronous helper, deep in a call stack, that needs a future's output. fn lookup(key: u32) -> u32 { nuclei::block_on(async move { key * 2 }) } #[nuclei::main] async fn main() { let task = nuclei::spawn(async { // block_on nests: the shard runs its other tasks while it waits. lookup(21) }); assert_eq!(task.await, 42); } ``` Two rules come with it. The task that called `block_on` is not polled again until the call returns, so a future that waits for that very task never completes. And each level runs on the thread's stack, so the depth is bounded by [`max_nesting`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.max_nesting); one level more panics with a message that says so. ## A runtime of your own `Runtime::new()` starts one with every setting at its default; `Runtime::builder()` sets them ([every setting](https://nuclei.rs/learn/production.html#builder)). A runtime spawns, runs `block_on` and runs blocking work, as the free functions do on the default runtime. `src/main.rs`: ```rust use std::time::Duration; use nuclei::runtime::Runtime; fn main() -> std::io::Result<()> { let runtime = Runtime::builder() .worker_threads(4) .thread_name("api-worker") .max_blocking_threads(64) .build()?; let task = runtime.spawn(async { "served" }); assert_eq!(runtime.block_on(task), "served"); // Stop the workers, waiting for them one second at most. runtime.shutdown_timeout(Duration::from_secs(1)); Ok(()) } ``` Dropping a `Runtime` stops its workers, drops the tasks they still hold, and waits for the threads to exit. Bytes that dropped handles wrote behind still go out, each for at most [`write_behind_linger`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.write_behind_linger); one still under way when the drop is done carries on on a thread of its own. `shutdown_timeout` bounds the whole wait; `shutdown_background` does not wait at all. `build` checks every setting first: a value no runtime can work with, or two that do not fit together, fails with `InvalidInput` naming the setting, its value and what it must be ([Errors](https://nuclei.rs/learn/errors.html#setting)). ## Handles and entering `runtime.handle()` gives a `RuntimeHandle`: cheap to clone, usable from any thread to spawn on that runtime or to `block_on`. A handle does not keep its runtime running. `src/main.rs`: ```rust use nuclei::runtime::{Runtime, RuntimeHandle}; fn main() -> std::io::Result<()> { let runtime = Runtime::new()?; let handle = runtime.handle(); // A plain thread hands work to the runtime through its handle. let thread = std::thread::spawn(move || handle.block_on(handle.spawn(async { 2 + 2 }))); assert_eq!(thread.join().unwrap(), 4); // Outside block_on this thread is inside no runtime... assert!(RuntimeHandle::try_current().is_err()); { // ...until enter sets one: the free functions use it while the guard lives. let _guard = runtime.enter(); assert_eq!(RuntimeHandle::try_current().unwrap().id(), runtime.id()); let task = nuclei::spawn(async { "on the entered runtime" }); assert_eq!(runtime.block_on(task), "on the entered runtime"); } Ok(()) } ``` - `RuntimeHandle::current()`: the runtime this thread is inside, or the default one. - `RuntimeHandle::try_current()`: the runtime this thread is inside, or an error; it never starts the default one. - `runtime.enter()`: makes the free functions (`spawn`, `spawn_blocking`, ...) use this runtime on this thread until the guard drops. - `id()`: a `RuntimeId`, different for every runtime of the process. ## Choosing the worker `spawn` picks the shard for you. To pick it yourself, name the worker: indices run from 0 to [`workers()`](https://nuclei.rs/api/nuclei/runtime/struct.RuntimeHandle.html#method.workers), and `worker_index()` says which one the calling code runs on. `src/main.rs`: ```rust use std::rc::Rc; use nuclei::runtime::{Runtime, worker_index}; fn main() -> std::io::Result<()> { let runtime = Runtime::builder().worker_threads(2).build()?; let handle = runtime.handle(); assert_eq!(handle.workers(), 2); // A task placed on worker 1 runs there for its whole life. let task = handle.spawn_on_worker(1, async { worker_index() })?; assert_eq!(runtime.block_on(task), Some(1)); // One task per worker, its future made there: it need not be Send. let each = handle.on_each_worker(|| async { let here = Rc::new(worker_index()); nuclei::task::yield_now().await; *here }); let mut seen = runtime.block_on(each.join_all()); seen.sort(); assert_eq!(seen, [Some(0), Some(1)]); // A worker the runtime does not have is refused. assert!(handle.spawn_on_worker(2, async {}).is_err()); Ok(()) } ``` - [`spawn_on_worker(k, future)`](https://nuclei.rs/api/nuclei/runtime/struct.RuntimeHandle.html#method.spawn_on_worker) places a task on worker `k`, where it stays for its whole life: a [handoff](https://nuclei.rs/learn/tasks.html#handoff) moves the worker's shard to another thread with its tasks, and `worker_index()` still answers `k`. - [`spawn_local_on_worker(k, make)`](https://nuclei.rs/api/nuclei/runtime/struct.RuntimeHandle.html#method.spawn_local_on_worker) runs `make` on worker `k` and spawns the future it makes there, so the future need not be `Send`. - [`on_each_worker(make)`](https://nuclei.rs/api/nuclei/runtime/struct.RuntimeHandle.html#method.on_each_worker) does that once on every worker that takes tasks and gives a `JoinSet` with one task per worker: a listener per core, a cache per core, a [mesh](https://nuclei.rs/learn/channels.html#mesh) of channels between them. - [`task::Builder::worker(k)`](https://nuclei.rs/api/nuclei/task/struct.Builder.html#method.worker) places a task spawned with options the same way. A worker the runtime does not have, or one that stopped, refuses the task with `InvalidInput`; a task it took is never dropped unrun. ## A value per worker [`shard_local!`](https://nuclei.rs/api/nuclei/macro.shard_local.html) declares a static, a [`ShardLocal`](https://nuclei.rs/api/nuclei/runtime/struct.ShardLocal.html), that holds one value per worker, made on its first use there: a counter, a cache or a buffer that the worker's tasks share without a lock. The value lives in the worker's shard, not in its thread, so it moves with the shard on a handoff and the worker's tasks always see the same one. `src/main.rs`: ```rust use std::cell::Cell; use nuclei::runtime::Runtime; nuclei::shard_local! { // One counter per worker, made on its first use there. static SERVED: Cell = Cell::new(0); } fn main() -> std::io::Result<()> { let runtime = Runtime::builder().worker_threads(2).build()?; let handle = runtime.handle(); for worker in [0, 0, 0, 1] { let served = handle.spawn_on_worker(worker, async { SERVED.with(|n| n.set(n.get() + 1)); })?; runtime.block_on(served); } // Each worker reads its own counter. let counts = handle.on_each_worker(|| async { SERVED.with(Cell::get) }); let mut counts = runtime.block_on(counts.join_all()); counts.sort(); assert_eq!(counts, [1, 3]); // Code that runs on no worker has no value. assert!(SERVED.try_with(Cell::get).is_err()); Ok(()) } ``` [`with`](https://nuclei.rs/api/nuclei/runtime/struct.ShardLocal.html#method.with) runs a closure on this worker's value, and the shard stays on the thread while it runs: keep the closure short. Only code on a worker reaches one: off the workers (in `block_on`'s own thread, on the blocking pool, on another thread) [`try_with`](https://nuclei.rs/api/nuclei/runtime/struct.ShardLocal.html#method.try_with) answers a `ShardAccessError` and `with` panics. ## The default runtime, configured The free functions use the runtime the calling thread is inside, or else the default runtime. To configure the default one, build it with `build_global` before anything starts it. `src/main.rs`: ```rust fn main() -> std::io::Result<()> { // Configure the default runtime before anything starts it. nuclei::Builder::new().worker_threads(2).build_global()?; // From here on the free functions use it. let task = nuclei::spawn(async { "on the default runtime" }); assert_eq!(nuclei::block_on(task), "on the default runtime"); Ok(()) } ``` `build_global` fails with [the default runtime is already running](https://nuclei.rs/learn/errors.html#already-running) once a free function, the attribute or an earlier `build_global` started it: call it first thing in `main`. # Tasks Spawn work, wait for it, cancel it, and run what is not Send or not async. Chapter 4 of 17. The page: https://nuclei.rs/learn/tasks.html ## Spawn and await `nuclei::spawn` takes a future that is `Send + 'static` and returns a `Task`. A task is a future itself: awaiting it gives the task's output. If the task panics, awaiting it resumes the panic. `src/main.rs`: ```rust #[nuclei::main] async fn main() { // Each task is placed on a shard, and there it stays. let tasks: Vec<_> = (0..8u64) .map(|n| nuclei::spawn(async move { n * n })) .collect(); let mut total = 0; for task in tasks { total += task.await; } assert_eq!(total, 140); } ``` ## Dropping, detaching, cancelling A `Task` owns its task: **dropping it cancels the task**. To let a task run on with nobody waiting for it, call `detach`. `src/main.rs`: ```rust use std::time::Duration; use nuclei::time::sleep; #[nuclei::main] async fn main() { // Dropping a Task cancels it: this one never prints. let dropped = nuclei::spawn(async { sleep(Duration::from_millis(50)).await; println!("never printed"); }); drop(dropped); // detach lets a task run to its end with no handle. nuclei::spawn(async { println!("detached, and it runs") }).detach(); // cancel stops a task, and gives its output back if it had finished. let slow = nuclei::spawn(async { sleep(Duration::from_secs(10)).await; 1 }); assert_eq!(slow.cancel().await, None); // abort cancels without waiting; an AbortHandle does it from anywhere. let stuck = nuclei::spawn(std::future::pending::<()>()); let abort = stuck.abort_handle(); abort.abort(); assert!(stuck.join().await.unwrap_err().is_cancelled()); sleep(Duration::from_millis(100)).await; } ``` | Call | What it does | | --- | --- | | `detach()` | The task runs to its end; its output is dropped. | | `cancel().await` | Cancels and waits until the future is dropped; gives the output back if the task had finished. | | `abort()` | Cancels without waiting. `abort_handle()` gives an `AbortHandle` that does it from anywhere and outlives the task. | | `is_finished()` | Whether the task completed or was cancelled. | > **The most common surprise** > > A server loop that spawns a task per connection and drops each handle cancels every connection at once. Write `nuclei::spawn(handler).detach()`, or keep the tasks in a [JoinSet](https://nuclei.rs/learn/tasks.html#join-set). ## Why a task gave no output Awaiting a task panics where it has no output to give. `join()` gives a `Result` instead: the output, or a `JoinError` that says the task was cancelled or panicked (with the panic's payload). `fallible()` gives an `Option`. `src/main.rs`: ```rust #[nuclei::main] async fn main() { // join gives the output, or a JoinError that says why there is none. let ok = nuclei::spawn(async { 7 }).join().await; assert_eq!(ok.unwrap(), 7); let failed = nuclei::spawn(async { if true { panic!("the task gave up"); } }) .join() .await; let error = failed.unwrap_err(); assert!(error.is_panic()); let message = error.into_panic(); assert_eq!(message.downcast_ref::<&str>(), Some(&"the task gave up")); // fallible: None where awaiting the Task would panic. let done = nuclei::spawn(async { 1 }).fallible(); assert_eq!(done.await, Some(1)); } ``` ## Many tasks: JoinSet A `JoinSet` holds tasks and gives their outputs in the order they finish. Dropping the set cancels whatever is still in it, so no task outlives the code that owns it. `src/main.rs`: ```rust use std::time::Duration; use nuclei::task::JoinSet; use nuclei::time::sleep; #[nuclei::main] async fn main() { let mut set = JoinSet::new(); for n in [30u64, 10, 20] { set.spawn(async move { sleep(Duration::from_millis(n)).await; n }); } // Joined in the order they finish, not the order they were spawned. let mut order = Vec::new(); while let Some(done) = set.join_next().await { order.push(done.unwrap()); } assert_eq!(order, [10, 20, 30]); // Dropping the set, or shutdown, cancels whatever is still in it. set.spawn(std::future::pending()); set.shutdown().await; assert!(set.is_empty()); } ``` `join_next_with_id` says which task finished, `try_join_next` never waits, `join_all` collects every output, and `abort_all`, `detach_all` and `shutdown` end or release them all. ## Ids and names Every task has an `Id`, unique in the process and never reused: `task.id()` from the handle, `task::id()` from inside it, and the [task hooks](https://nuclei.rs/learn/production.html#hooks) are given it too. `task::Builder` spawns with options and answers an `io::Result`: a `name`, which the hooks read with `TaskMeta::name`, and a `worker` to place the task on ([Runtime](https://nuclei.rs/learn/runtime.html#workers)). `src/main.rs`: ```rust use nuclei::task; #[nuclei::main] async fn main() -> std::io::Result<()> { // A task spawned with options: a name. let worker = task::Builder::new() .name("checksum") .spawn(async { task::id() })?; let id = worker.id(); // Inside the task, task::id() is the same id the handle reports. assert_eq!(worker.await, id); // Outside any task there is none. assert!(task::try_id().is_none()); Ok(()) } ``` ## Tasks that are not Send `nuclei::spawn_local` takes a future that need not be `Send` and keeps it on the calling thread's shard. There is no local set to create first. `src/main.rs`: ```rust use std::cell::RefCell; use std::rc::Rc; #[nuclei::main] async fn main() { // Rc is not Send: these tasks stay on the thread that spawned them. let log = Rc::new(RefCell::new(Vec::new())); let tasks: Vec<_> = (0..3) .map(|n| { let log = Rc::clone(&log); nuclei::spawn_local(async move { log.borrow_mut().push(n) }) }) .collect(); for task in tasks { task.await; } assert_eq!(log.borrow().len(), 3); } ``` ## Work that blocks A blocking call (a synchronous library, a long computation) would hold its shard and every task on it. `nuclei::spawn_blocking` runs a closure on the runtime's blocking pool instead and returns a `Task` for its result. The pool grows on demand up to [`max_blocking_threads`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.max_blocking_threads), and idle threads leave after [`thread_keep_alive`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.thread_keep_alive). `src/main.rs`: ```rust #[nuclei::main] async fn main() -> std::io::Result<()> { // Blocking calls go to the blocking pool, so no shard waits on them. let entries = nuclei::spawn_blocking(|| std::fs::read_dir(".").map(|dir| dir.count())).await?; println!("{entries} entries here"); let digest = nuclei::spawn_blocking(|| (0..1_000_000u64).fold(0u64, |h, n| h.rotate_left(5) ^ n)).await; println!("digest {digest:x}"); Ok(()) } ``` ## A poll that blocks anyway Blocking code finds its way into tasks: a lock of a synchronous library, a slow system call, a loop longer than planned. When one poll of a task runs past [`handoff_after`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.handoff_after) (10 ms by default), the task holds up only itself: its worker's shard, with every other task, timer and IO of it, goes on on another thread on the same core, and the blocked task carries on once its poll returns. A task placed on a worker stays on that worker through it. - The blocked thread still shares the core, so a handoff is a rescue, not a place to run work: give long work to `spawn_blocking` or break it up with yields. - Tasks that `spawn_local` keeps on the blocked thread, and a nested `block_on` there, wait for it and finish on that thread. - [`on_long_poll`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.on_long_poll) names the task that blocked ([Production](https://nuclei.rs/learn/production.html#hooks)), and `stats()` counts each worker's `handoffs` and its `longest_poll`. - Watching costs each poll two plain stores and a load, and each call a task makes into its worker (a wake, a spawn, a send or a receive) two loads and two stores: on io_uring a 64-byte TCP round trip runs 12% more instructions with it, a spawn and its join 25% more. `handoff_after(None)` turns it off. ## Task-local values `task_local!` declares a key whose value belongs to one task: `scope` runs a future with it set, and any code that future runs reads it with `get`, `with` or `try_with`. `src/main.rs`: ```rust nuclei::task_local! { static REQUEST: u64; } async fn handle() -> String { // Any code the task runs reads the value its scope set. format!("request {}", REQUEST.get()) } #[nuclei::main] async fn main() { let first = nuclei::spawn(REQUEST.scope(1, handle())); let second = nuclei::spawn(REQUEST.scope(2, handle())); assert_eq!(first.await, "request 1"); assert_eq!(second.await, "request 2"); // Read where no scope set it, try_with answers an error instead of panicking. assert!(REQUEST.try_with(|id| *id).is_err()); } ``` ## Yielding and the budget Each poll of a task may complete a budget of operations ([`coop::BUDGET`](https://nuclei.rs/api/nuclei/task/coop/constant.BUDGET.html)) before it yields, so one busy task cannot hold its shard. IO that completes spends one, and so does a receive, an acquire or a lock of [`nuclei::sync`](https://nuclei.rs/learn/sync.html#budget) that completes without waiting, so a loop over a channel that is never empty yields too. A loop that awaits nothing else can spend the budget itself with `coop::consume_budget()`; `task::yield_now()` gives the other tasks a turn at once, and `coop::unconstrained` runs a future with no budget. `src/main.rs`: ```rust use nuclei::task::{self, coop}; #[nuclei::main] async fn main() { let busy = nuclei::spawn(async { let mut sum = 0u64; for n in 0..100_000u64 { sum += n; // A long loop that awaits nothing else spends the budget, so the // shard's other tasks get their turns. coop::consume_budget().await; } sum }); // yield_now: a turn for the other tasks of this shard, at once. task::yield_now().await; assert_eq!(busy.await, 4_999_950_000); } ``` # Select and join Wait on several futures at once, inside one task. Chapter 5 of 17. The page: https://nuclei.rs/learn/select.html ## join! and try_join! `nuclei::join!` polls every future given, all at once, in the task that awaits it, and gives their outputs as a tuple in the order written. `nuclei::try_join!` does the same with futures that give a `Result`: it gives `Ok` with every output, or the first error at once, dropping the rest. `src/main.rs`: ```rust use std::time::Duration; use nuclei::time::sleep; async fn fetch(name: &'static str, ms: u64) -> &'static str { sleep(Duration::from_millis(ms)).await; name } async fn parse(text: &str) -> Result { text.parse() } #[nuclei::main] async fn main() { // join! runs both at once in this task: about 30 ms, not 50. let (user, orders) = nuclei::join!(fetch("user", 30), fetch("orders", 20)); assert_eq!((user, orders), ("user", "orders")); // try_join! gives every output, or the first error. let both = nuclei::try_join!(parse("4"), parse("2")); assert_eq!(both, Ok((4, 2))); assert!(nuclei::try_join!(parse("4"), parse("x")).is_err()); } ``` The futures run concurrently, not in parallel: they share the task. To use more cores, [spawn](https://nuclei.rs/learn/tasks.html#spawn) them. Each poll starts one future later than the last, so a future that is always ready cannot starve the others; `biased;` as the first argument polls in the order written. ## select! `nuclei::select!` waits on several branches and runs the handler of the first to finish, dropping the other futures. Each branch is `pattern = future => handler`. `src/main.rs`: ```rust use std::time::Duration; use nuclei::sync::mpsc; use nuclei::time::sleep; #[nuclei::main] async fn main() { let (tx, mut jobs) = mpsc::channel::(8); nuclei::spawn(async move { for job in 1..=3 { tx.send(job).await.unwrap(); } }) .detach(); let mut done = Vec::new(); loop { // The first branch to finish runs; the other futures are dropped. nuclei::select! { Some(job) = jobs.recv() => done.push(job), _ = sleep(Duration::from_secs(1)) => break, // Every branch disabled (the channel closed and gave None): else. else => break, } } assert_eq!(done, [1, 2, 3]); } ``` - **Patterns filter.** A future whose output does not match its pattern disables its branch, and the others go on: `Some(job) = jobs.recv()` stops matching once the channel closes. - **`else` ends it.** When every branch is disabled, the `else` branch runs; without one, `select!` panics. - **Preconditions.** `pattern = future, if condition => handler` leaves a branch out when the condition is false. - **Fair by default.** Polling starts at a random branch; `biased;` first polls in the order written. - **Handlers are plain code.** They run after the futures are dropped, so `return`, `?`, `break` and `continue` act on the code around the `select!`. > **What a losing branch loses** > > A branch that loses is dropped where it stood. Nuclei's IO loses no byte when dropped (see [How it works](https://nuclei.rs/learn/proactive.html#cancel)), and a sync wait or a channel receive withdraws without losing a value or a wakeup; a `Barrier` wait is the one exception, its arrival stays counted. State a future of your own holds halfway is dropped with it. # Networking TCP, UDP and Unix sockets, addresses and names, socket options, halves and pipes. Chapter 6 of 17. The page: https://nuclei.rs/learn/net.html ## TCP `nuclei::net` has the socket types: `TcpListener`, `TcpStream`, `UdpSocket` and, on Unix, `UnixListener`, `UnixStream` and `UnixDatagram`. Each is std's own socket in a [`Handle`](https://nuclei.rs/api/nuclei/io/struct.Handle.html): the handle adds the async calls, and std's methods (`local_addr`, `peer_addr`, `set_ttl`, ...) work through it. `src/main.rs`: ```rust use nuclei::io::{AsyncReadExt, AsyncWriteExt}; use nuclei::net::{TcpListener, TcpStream}; #[nuclei::main] async fn main() -> std::io::Result<()> { // Port 0: the system picks a free one. let listener = TcpListener::bind("127.0.0.1:0").await?; let addr = listener.local_addr()?; // The server echoes every byte back until the client ends its side. let server = nuclei::spawn(async move { let (stream, peer) = listener.accept().await?; println!("connection from {}", peer.ip()); let mut buf = [0u8; 1024]; loop { let n = stream.recv(&mut buf).await?; if n == 0 { break; } stream.send(&buf[..n]).await?; } std::io::Result::Ok(()) }); // The client uses the same stream through the read and write helpers. let mut client = TcpStream::connect(addr).await?; client.write_all(b"hello").await?; client.shutdown().await?; let mut reply = String::new(); client.read_to_string(&mut reply).await?; assert_eq!(reply, "hello"); server.await?; Ok(()) } ``` - `bind` and `connect` are async, since a name may need looking up. Each takes the first address that works. - `recv` and `send` work on a shared reference; the stream is also `AsyncRead` and `AsyncWrite`, on the handle and on `&` the handle, so one task can read while another writes. - `incoming()` gives the connections as a stream. `accept_multi()` gives a stream that owns a copy of the listener, so it may outlive the handle; on io_uring one accept stays armed for every connection that comes. - `read_owned` and `write_owned` lend the driver a buffer of yours, and `read_vectored_owned` and `write_vectored_owned` lend several in one call ([IO utilities](https://nuclei.rs/learn/io.html#vectored)). ## Addresses and names Every call that takes an address takes anything [`ToSocketAddrs`](https://nuclei.rs/api/nuclei/net/trait.ToSocketAddrs.html) accepts: a `SocketAddr`, an `(ip, port)` pair, a `"host:port"` string, a `(host, port)` pair, or a slice of addresses. Numbers are used at once; a name is looked up on the blocking pool, so no shard waits on the resolver. `net::lookup_host` looks one up alone. `src/main.rs`: ```rust use std::net::{Ipv4Addr, SocketAddr}; use nuclei::net::{self, TcpListener}; #[nuclei::main] async fn main() -> std::io::Result<()> { // A name is looked up on the blocking pool, so no shard waits on the resolver. let found: Vec = net::lookup_host("localhost:8080").await?.collect(); assert!(found.iter().all(|addr| addr.port() == 8080)); // Every call that takes an address takes any of these forms. let a = TcpListener::bind("127.0.0.1:0").await?; let b = TcpListener::bind(("127.0.0.1", 0)).await?; let c = TcpListener::bind((Ipv4Addr::LOCALHOST, 0)).await?; let d = TcpListener::bind(SocketAddr::from(([127, 0, 0, 1], 0))).await?; for listener in [a, b, c, d] { assert!(listener.local_addr()?.ip().is_loopback()); } Ok(()) } ``` ## UDP A bound socket sends datagrams to any address and receives them with their sender's; a connected one talks to one peer. A datagram larger than the buffer is cut to fit. `src/main.rs`: ```rust use nuclei::net::UdpSocket; #[nuclei::main] async fn main() -> std::io::Result<()> { let server = UdpSocket::bind("127.0.0.1:0").await?; let server_addr = server.local_addr()?; // Datagrams to an address, and received with their sender's address. let client = UdpSocket::bind("127.0.0.1:0").await?; client.send_to(b"ping", server_addr).await?; let mut buf = [0u8; 64]; let (n, from) = server.recv_from(&mut buf).await?; assert_eq!((&buf[..n], from), (&b"ping"[..], client.local_addr()?)); // A connected socket sends to, and receives from, its one peer. let peer = UdpSocket::connect(server_addr).await?; peer.send(b"hi").await?; let (_, from) = server.recv_from(&mut buf).await?; server.send_to(b"hello", from).await?; let n = peer.recv(&mut buf).await?; assert_eq!(&buf[..n], b"hello"); Ok(()) } ``` `peek` and `peek_from` look at the next datagram without taking it, `peek_sender` names its sender without copying a byte, and `recv_buf` and `recv_buf_from` receive into a [`ReadBuf`](https://nuclei.rs/api/nuclei/io/struct.ReadBuf.html) that need not be initialized. ## Unix sockets Streams and datagrams over a path in the file system, or a connected pair. A stream knows its peer: `peer_cred` gives the user and group, and the process where the system tells it (Linux, Android, macOS, iOS). `src/main.rs`: ```rust use nuclei::io::{AsyncReadExt, AsyncWriteExt}; use nuclei::net::{UnixDatagram, UnixListener, UnixStream}; #[nuclei::main] async fn main() -> std::io::Result<()> { let dir = std::env::temp_dir().join(format!("learn-unix-{}", std::process::id())); std::fs::create_dir_all(&dir)?; let path = dir.join("server.sock"); // Streams over a path in the file system. let listener = UnixListener::bind(&path)?; let mut client = UnixStream::connect(&path).await?; let (mut server, _) = listener.accept().await?; client.write_all(b"over a path").await?; let mut buf = [0u8; 11]; server.read_exact(&mut buf).await?; assert_eq!(&buf, b"over a path"); // Who is at the other end: user, group and, where the system says, process. let peer = server.peer_cred()?; assert_eq!(peer.pid(), Some(std::process::id() as i32)); // A connected pair, and datagrams from a socket bound to no address. let (a, b) = UnixStream::pair()?; a.send(b"paired").await?; assert_eq!(b.recv(&mut buf).await?, 6); let inbox = UnixDatagram::bind(dir.join("inbox.sock"))?; let sender = UnixDatagram::unbound()?; sender.send_to(b"note", dir.join("inbox.sock")).await?; assert_eq!(inbox.recv(&mut buf).await?, 4); std::fs::remove_dir_all(&dir) } ``` A connect to a listener whose backlog is full waits until the listener takes it, as std's blocking connect does. Linux answers such a connect at once, so the connect tries again on its own socket after a pause on a timer (1 ms, doubled up to 64 ms). No thread waits for it, the options set on the socket stay, and dropping the future frees everything. On Linux a socket may also take a name in the abstract namespace, with no file behind it: `bind_addr` and `connect_addr` take std's `SocketAddr`, made with `from_abstract_name`. `src/main.rs`: ```rust use std::os::linux::net::SocketAddrExt; use std::os::unix::net::SocketAddr; use nuclei::net::{UnixListener, UnixStream}; #[nuclei::main] async fn main() -> std::io::Result<()> { // Linux: a name in the abstract namespace, with no file behind it. let name = format!("learn-{}", std::process::id()); let addr = SocketAddr::from_abstract_name(name.as_bytes())?; let listener = UnixListener::bind_addr(&addr)?; let client = UnixStream::connect_addr(&addr).await?; let (server, _) = listener.accept().await?; client.send(b"no file").await?; let mut buf = [0u8; 7]; assert_eq!(server.recv(&mut buf).await?, 7); Ok(()) } ``` ## Socket options A socket to set up before it listens or connects is a [`TcpSocket`](https://nuclei.rs/api/nuclei/net/struct.TcpSocket.html): buffer sizes, address and port reuse, keepalive, `TCP_NODELAY`, linger, the type of service or traffic class, `IPV6_V6ONLY`, and on Linux the network interface (`bind_device`). Then `listen` or `connect` turns it into a listener or a stream. A stream that is connected already sets linger and no-delay on the handle. The [TCP options](https://nuclei.rs/learn/net.html#keepalive) below go further. `src/main.rs`: ```rust use std::time::Duration; use nuclei::net::TcpSocket; #[nuclei::main] async fn main() -> std::io::Result<()> { // Set a socket up before it listens... let socket = TcpSocket::new_v4()?; socket.set_reuseaddr(true)?; socket.set_recv_buffer_size(256 * 1024)?; socket.bind("127.0.0.1:0".parse().unwrap())?; let listener = socket.listen(1024)?; let addr = listener.local_addr()?; // ...or before it connects. let socket = TcpSocket::new_v4()?; socket.set_nodelay(true)?; socket.set_keepalive(true)?; let stream = socket.connect(addr).await?; assert!(stream.nodelay()?); // Options of a stream that is connected already: linger on close. let (accepted, _) = listener.accept().await?; accepted.set_linger(Some(Duration::from_secs(1)))?; assert_eq!(accepted.linger()?, Some(Duration::from_secs(1))); Ok(()) } ``` [`UnixSocket`](https://nuclei.rs/api/nuclei/net/struct.UnixSocket.html) is the same for Unix sockets: `new_stream` or `new_datagram`, `bind`, then `listen`, `connect` or `datagram`. ## TCP options A [`TcpKeepalive`](https://nuclei.rs/api/nuclei/net/struct.TcpKeepalive.html) times the keepalive probes: `time` idle before the first, `interval` between them, and `retries` unanswered before the connection drops. A field left `None` keeps the system's value; times are whole seconds. `set_keepalive_timing` turns the probes on with that timing, on a `TcpSocket` or on a connected stream, and `keepalive_timing` reads it back. `src/main.rs`: ```rust use std::time::Duration; use nuclei::io::AsyncWriteExt; use nuclei::net::{TcpKeepalive, TcpSocket}; #[nuclei::main] async fn main() -> std::io::Result<()> { // A listener's options, set before it listens; incoming_cpu and defer_accept are Linux's. let socket = TcpSocket::new_v4()?; socket.set_reuseport(true)?; socket.set_incoming_cpu(0)?; socket.set_defer_accept(Some(Duration::from_secs(1)))?; socket.bind("127.0.0.1:0".parse().unwrap())?; let listener = socket.listen(128)?; // Probes after a minute idle, then every 10 seconds; 5 unanswered drop the connection. let socket = TcpSocket::new_v4()?; socket.set_keepalive_timing(TcpKeepalive { time: Some(Duration::from_secs(60)), interval: Some(Duration::from_secs(10)), retries: Some(5), })?; // Sent bytes may go unacknowledged for 30 seconds before the connection drops. socket.set_user_timeout(Some(Duration::from_secs(30)))?; let mut client = socket.connect(listener.local_addr()?).await?; assert_eq!(client.keepalive_timing()?.retries, Some(5)); assert_eq!(client.user_timeout()?, Some(Duration::from_secs(30))); // With defer_accept, the connection is handed to accept once its first bytes came. client.write_all(b"hello").await?; client.flush().await?; let (server, _) = listener.accept().await?; server.set_quickack(true)?; Ok(()) } ``` | Option | What it sets | | --- | --- | | [`set_keepalive_timing`](https://nuclei.rs/api/nuclei/net/struct.TcpSocket.html#method.set_keepalive_timing) | Turns keepalive probes on (SO_KEEPALIVE), timed as keepalive says (TCP_KEEPIDLE, TCP_KEEPINTVL, TCP_KEEPCNT; macOS calls the first TCP_KEEPALIVE). | | [`set_user_timeout`](https://nuclei.rs/api/nuclei/net/struct.TcpSocket.html#method.set_user_timeout) | Sets TCP_USER_TIMEOUT (Linux): how long sent bytes may go unacknowledged before the connection is dropped, in whole milliseconds; None or zero leaves it to the system. | | [`set_incoming_cpu`](https://nuclei.rs/api/nuclei/net/struct.TcpSocket.html#method.set_incoming_cpu) | Sets SO_INCOMING_CPU (Linux): the CPU whose connections this listener takes among listeners sharing a port with SO_REUSEPORT, so each core accepts the connections its own queues received. | | [`set_fastopen`](https://nuclei.rs/api/nuclei/net/struct.TcpSocket.html#method.set_fastopen) | Sets TCP_FASTOPEN on a socket that will listen: connections may bring data with their handshake. Linux keeps up to queue such handshakes waiting; macOS, FreeBSD and Windows take it as on (above zero) or off. | | [`set_defer_accept`](https://nuclei.rs/api/nuclei/net/struct.TcpSocket.html#method.set_defer_accept) | Sets TCP_DEFER_ACCEPT (Linux) on a socket that will listen: a connection is handed to accept only once its first data came, or wait passed (whole seconds, which the kernel rounds up to its retransmission steps); None hands each over at once. | | [`set_only_v6`](https://nuclei.rs/api/nuclei/net/struct.TcpSocket.html#method.set_only_v6) | Sets IPV6_V6ONLY on an IPv6 socket: with true it takes IPv6 alone, else IPv4 too, through addresses mapped into IPv6. | | [`set_quickack`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.set_quickack) | Sets TCP_QUICKACK (Linux): with true the stream acknowledges at once rather than waiting to send it with data. The kernel turns it off again as it sees fit, so it is set again where it matters. | A connected TCP stream also has `set_keepalive_timing` and `set_user_timeout`. Each option has its getter (`user_timeout`, `incoming_cpu`, `fastopen`, ...). An option the system does not have answers `Unsupported`, so code for several systems can try it and go on. ## A UDP socket set up first Some options only a socket that is not bound yet takes. [`UdpSocketBuilder`](https://nuclei.rs/api/nuclei/net/struct.UdpSocketBuilder.html) is that socket: `new_v4` or `new_v6`, then address and port reuse, buffer sizes, the type of service (`IP_TOS`) or the traffic class (`IPV6_TCLASS`), `set_only_v6`, and on Linux the network interface (`bind_device`). `bind` turns it into a `UdpSocket`. `src/main.rs`: ```rust use nuclei::net::{UdpSocket, UdpSocketBuilder}; #[nuclei::main] async fn main() -> std::io::Result<()> { // Options a UDP socket takes before it binds. let builder = UdpSocketBuilder::new_v4()?; builder.set_reuseport(true)?; builder.set_recv_buffer_size(256 * 1024)?; builder.set_tos(0x10)?; assert!(builder.recv_buffer_size()? >= 256 * 1024); let server = builder.bind("127.0.0.1:0".parse().unwrap())?; let addr = server.local_addr()?; // SO_REUSEPORT on both lets a second socket bind the same port. let second = UdpSocketBuilder::new_v4()?; second.set_reuseport(true)?; let second = second.bind(addr)?; assert_eq!(second.local_addr()?, addr); drop(second); // Bound, it is a UdpSocket like any other. let client = UdpSocket::bind("127.0.0.1:0").await?; client.send_to(b"ping", addr).await?; let mut buf = [0u8; 16]; let (n, from) = server.recv_from(&mut buf).await?; assert_eq!((&buf[..n], from), (&b"ping"[..], client.local_addr()?)); Ok(()) } ``` ## Two halves A TCP or Unix stream splits into a read half and a write half: `split()` borrows the stream and allocates nothing; `into_split()` gives owned halves that move into tasks of their own, and `reunite` puts them back together. `src/main.rs`: ```rust use nuclei::io::{AsyncReadExt, AsyncWriteExt}; use nuclei::net::{TcpListener, TcpStream}; #[nuclei::main] async fn main() -> std::io::Result<()> { let listener = TcpListener::bind("127.0.0.1:0").await?; let mut client = TcpStream::connect(listener.local_addr()?).await?; let (stream, _) = listener.accept().await?; // Owned halves: the read half and the write half go to tasks of their own. let (mut read, mut write) = stream.into_split(); let reader = nuclei::spawn(async move { let mut got = [0u8; 4]; read.read_exact(&mut got).await?; std::io::Result::Ok((read, got)) }); let writer = nuclei::spawn(async move { write.write_all(b"pong").await?; write.flush().await?; std::io::Result::Ok(write) }); client.write_all(b"ping").await?; let mut reply = [0u8; 4]; client.read_exact(&mut reply).await?; assert_eq!(&reply, b"pong"); // The two halves go back together into the stream. let (read, got) = reader.await?; assert_eq!(&got, b"ping"); let stream = read.reunite(writer.await?).expect("halves of one stream"); assert_eq!(stream.peer_addr()?, client.local_addr()?); Ok(()) } ``` ## Ending a stream A stream ends in one of three ways, each telling the peer something different: - `shutdown().await`, from [`AsyncWriteExt`](https://nuclei.rs/learn/io.html#traits), flushes and ends the write side: the peer reads every byte, then the end. - [`shut(how)`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.shut), on a TCP or Unix stream, is std's `shutdown` made once the bytes written behind reached the kernel. `Shutdown::Write` and `Both` wait for those bytes, so the peer reads them all before the end; `Read` leaves the writes alone. Where the calling thread's shard runs io_uring, the reading half is shut through the ring. - [`abort()`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.abort) closes a TCP stream now: `SO_LINGER` goes to zero, the bytes written behind are dropped, and the peer's reads fail with `ConnectionReset`. `src/main.rs`: ```rust use std::io::ErrorKind; use std::net::Shutdown; use nuclei::io::{AsyncReadExt, AsyncWriteExt}; use nuclei::net::{TcpListener, TcpStream}; #[nuclei::main] async fn main() -> std::io::Result<()> { let listener = TcpListener::bind("127.0.0.1:0").await?; let addr = listener.local_addr()?; // shut waits until the kernel has the bytes written behind, then ends the write side. let mut client = TcpStream::connect(addr).await?; let (mut server, _) = listener.accept().await?; client.write_all(b"every byte").await?; client.shut(Shutdown::Write).await?; let mut got = Vec::new(); server.read_to_end(&mut got).await?; assert_eq!(got, b"every byte"); // abort drops what is behind and resets the connection: the peer reads an error. let client = TcpStream::connect(addr).await?; let (server, _) = listener.accept().await?; client.abort()?; let mut buf = [0u8; 16]; let reset = server.recv(&mut buf).await.unwrap_err(); assert_eq!(reset.kind(), ErrorKind::ConnectionReset); Ok(()) } ``` After `shut(Read)` or `shut(Both)`, reads answer as std's do on each system: Linux hands out what came before, then the end; macOS and Windows end at once, so there the handle drops what it read ahead too. The call is not named `shutdown`, so `stream.shutdown(how)` still reaches std's own through the handle, which shuts the halves at once: bytes still behind then never reach the peer. A stream that is only dropped still delivers its bytes behind and ends cleanly. One whose time for that runs out resets the connection, as `abort` does ([How it works](https://nuclei.rs/learn/proactive.html#buffers)). ## Files and large writes [`send_file(&file, offset, len)`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.send_file) sends a range of a file to a TCP or Unix stream. Where the system has `sendfile(2)` or `TransmitFile`, the bytes go from the page cache to the socket inside the kernel; elsewhere they are read and written, which works the same. Each call runs on the blocking pool and sends at most [`send_file_chunk`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.send_file_chunk) bytes (1 MiB by default), so a cold page holds a pool thread for one chunk at most. [`write_zero_copy`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.write_zero_copy) writes a lent buffer as `write_owned` does, and asks the kernel not to copy it either. The write ends once the kernel took the last byte; the buffer comes back through a [`Released`](https://nuclei.rs/api/nuclei/net/struct.Released.html) once the peer acknowledged every byte. Only io_uring sends zero-copy, on the runtime's workers, and only while the write has at least [`zero_copy_threshold`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.zero_copy_threshold) bytes left (1 MiB by default). Below it, and on the other backends, the kernel copies and the `Released` is ready at once. `src/main.rs`: ```rust use std::net::Shutdown; use nuclei::fs::File; use nuclei::io::AsyncReadExt; use nuclei::net::{TcpListener, TcpStream}; #[nuclei::main] async fn main() -> std::io::Result<()> { nuclei::fs::write("page.html", vec![b'x'; 64 * 1024]).await?; let listener = TcpListener::bind("127.0.0.1:0").await?; let addr = listener.local_addr()?; let reader = nuclei::spawn(async move { let (mut stream, _) = listener.accept().await?; let mut all = Vec::new(); stream.read_to_end(&mut all).await?; std::io::Result::Ok(all.len()) }); let stream = TcpStream::connect(addr).await?; // send_file: the kernel sends from the page cache, the bytes never pass through the program. let file = File::open("page.html").await?; assert_eq!(stream.send_file(&file, 0, 64 * 1024).await?, 64 * 1024); // write_zero_copy: the kernel sends from the buffer, which comes back once it let go. let (written, released) = stream.write_zero_copy(vec![b'y'; 2 * 1024 * 1024]).await; assert_eq!(written?, 2 * 1024 * 1024); let buf = released.await; assert_eq!(buf.len(), 2 * 1024 * 1024); stream.shut(Shutdown::Write).await?; assert_eq!(reader.await?, 64 * 1024 + 2 * 1024 * 1024); nuclei::fs::remove_file("page.html").await } ``` ## Pipes and FIFOs `net::unix::pipe::pipe()` makes an anonymous pipe: a `Sender` and a `Receiver`, async streams like any other. A named pipe in the file system opens with [`pipe::OpenOptions`](https://nuclei.rs/api/nuclei/net/unix/pipe/struct.OpenOptions.html), as a receiver or a sender. `src/main.rs`: ```rust use nuclei::io::{AsyncReadExt, AsyncWriteExt}; use nuclei::net::unix::pipe; #[nuclei::main] async fn main() -> std::io::Result<()> { // An anonymous pipe: what goes into the sender comes out of the receiver. let (mut sender, mut receiver) = pipe::pipe()?; let writer = nuclei::spawn(async move { sender.write_all(b"through a pipe").await?; // Dropping the sender ends the stream for the reader. drop(sender); std::io::Result::Ok(()) }); let mut text = String::new(); receiver.read_to_string(&mut text).await?; assert_eq!(text, "through a pipe"); writer.await } ``` ## std's calls through the handle std's methods reach the socket through the handle, and the handle's own methods of the same name take their place where it has them (`connect`, `send`, `linger`, ...). A few of std's go around the bytes the handle read ahead and wrote behind, or block its shard: - `shutdown(how)` shuts the halves at once, ahead of the bytes still behind; [`shut`](https://nuclei.rs/learn/net.html#shut) waits for them. - `set_nonblocking(false)` makes the driver's own calls on the socket block the shard's thread, and every task of the shard with them. - `take_error` takes the socket's pending error, which the handle's connect in progress or its next operation would have answered. - std's `Read` and `Write` on a shared reference to the socket read past the bytes read ahead, write ahead of the bytes written behind, and answer `WouldBlock` where the handle's own calls wait. - `UdpSocket::connect(addr)` makes a new connected socket. `socket.connect(addr)` on a socket you have is std's: it connects that socket in place and looks a name up with a blocking call on the shard's thread, so give it a numeric address, or look the name up first with `net::lookup_host`. The [`Handle`](https://nuclei.rs/api/nuclei/io/struct.Handle.html) reference has the details. # IO utilities The helpers every stream gets: reads and writes as futures, copies, buffers, in-memory pipes. Chapter 7 of 17. The page: https://nuclei.rs/learn/io.html ## Reads and writes as futures Streams implement the `futures-io` traits (`AsyncRead`, `AsyncWrite`, `AsyncBufRead`, `AsyncSeek`), so code written against them works unchanged. `nuclei::io` adds the calls you await, in four extension traits: | Trait | Calls | | --- | --- | | [`AsyncReadExt`](https://nuclei.rs/api/nuclei/io/trait.AsyncReadExt.html) | `read`, `read_exact`, `read_to_end`, `read_to_string`, `read_buf`, `read_u32` and every number (big-endian, or `_le`), `take`, `chain` | | [`AsyncWriteExt`](https://nuclei.rs/api/nuclei/io/trait.AsyncWriteExt.html) | `write`, `write_all`, `write_vectored`, `write_u32` and every number, `flush`, `shutdown` | | [`AsyncBufReadExt`](https://nuclei.rs/api/nuclei/io/trait.AsyncBufReadExt.html) | `read_line`, `read_until`, `lines`, `split`, `fill_buf`, `consume` | | [`AsyncSeekExt`](https://nuclei.rs/api/nuclei/io/trait.AsyncSeekExt.html) | `seek`, `rewind`, `stream_position` | `src/main.rs`: ```rust use nuclei::io::{self, AsyncReadExt, AsyncWriteExt}; #[nuclei::main] async fn main() -> std::io::Result<()> { // Two connected in-memory streams, 64 bytes of buffer each way. let (mut client, mut server) = io::duplex(64); // A frame: a length, big-endian, then that many bytes. let body = b"framed"; client.write_u32(body.len() as u32).await?; client.write_all(body).await?; let len = server.read_u32().await?; let mut frame = vec![0u8; len as usize]; server.read_exact(&mut frame).await?; assert_eq!(frame, body); // Ending one side ends the other's reads. drop(client); let mut rest = Vec::new(); assert_eq!(server.read_to_end(&mut rest).await?, 0); Ok(()) } ``` ## Lines and buffers `BufReader` puts a buffer in front of a reader, so small reads and line reads take from memory; `BufWriter` gathers small writes into one; `BufStream` is both, for a stream that reads and writes. `src/main.rs`: ```rust use nuclei::io::{self, AsyncBufReadExt, AsyncWriteExt, BufReader}; #[nuclei::main] async fn main() -> std::io::Result<()> { let (rx, mut tx) = io::simplex(1024); tx.write_all(b"GET /\nHost: nuclei.rs\n\nbody").await?; drop(tx); // A buffer in front of the reader, then a line at a time. let mut lines = BufReader::new(rx).lines(); let mut head = Vec::new(); while let Some(line) = lines.next_line().await? { if line.is_empty() { break; } head.push(line); } assert_eq!(head, ["GET /", "Host: nuclei.rs"]); Ok(()) } ``` `src/main.rs`: ```rust use nuclei::io::{AsyncReadExt, AsyncWriteExt, BufWriter}; use nuclei::net::{TcpListener, TcpStream}; #[nuclei::main] async fn main() -> std::io::Result<()> { let listener = TcpListener::bind("127.0.0.1:0").await?; let stream = TcpStream::connect(listener.local_addr()?).await?; let (mut server, _) = listener.accept().await?; // Many small writes gather in the buffer and go out as one. let mut out = BufWriter::new(stream); for word in ["one ", "two ", "three"] { out.write_all(word.as_bytes()).await?; } out.flush().await?; out.shutdown().await?; let mut text = String::new(); server.read_to_string(&mut text).await?; assert_eq!(text, "one two three"); Ok(()) } ``` ## Copies `io::copy` moves everything a reader gives into a writer, then flushes; `copy_buf` does it from a buffered reader's own buffer. `copy_bidirectional` runs both directions between two streams at once, the heart of a proxy, and answers the bytes moved each way. `src/main.rs`: ```rust use nuclei::io::{self, AsyncReadExt, AsyncWriteExt}; #[nuclei::main] async fn main() -> std::io::Result<()> { // copy: everything a reader gives, into a writer, then a flush. let mut source = io::repeat(b'x').take(1 << 20); let copied = io::copy(&mut source, &mut io::sink()).await?; assert_eq!(copied, 1 << 20); // copy_bidirectional: a proxy between two streams, both ways at once. let (mut client, mut front) = io::duplex(1024); let (mut back, mut backend) = io::duplex(1024); let proxy = nuclei::spawn(async move { io::copy_bidirectional(&mut front, &mut back).await }); client.write_all(b"request").await?; let mut buf = [0u8; 7]; backend.read_exact(&mut buf).await?; backend.write_all(b"reply").await?; let mut reply = [0u8; 5]; client.read_exact(&mut reply).await?; assert_eq!(&reply, b"reply"); // Each side that ends ends its direction; the proxy answers both counts. drop(client); drop(backend); assert_eq!(proxy.await?, (7, 5)); Ok(()) } ``` ## Buffers you lend The owned calls (`read_owned`, `write_owned`, `write_zero_copy`, and the datagram and file forms) lend the driver your buffer and give it back, so the kernel reads into and writes from your memory and no byte is copied ([How it works](https://nuclei.rs/learn/proactive.html#lending)). A write takes any [`IoBuf`](https://nuclei.rs/api/nuclei/io/trait.IoBuf.html) and a read any [`IoBufMut`](https://nuclei.rs/api/nuclei/io/trait.IoBufMut.html), and each gives back the same type: a `Vec` in, a `Vec` out. `src/main.rs`: ```rust use std::sync::Arc; use nuclei::io::{AlignedBuf, IoBuf}; use nuclei::net::{TcpListener, TcpStream}; // A message in a shared allocation, sent to many peers without a copy. #[derive(Default)] struct Shared(Arc<[u8]>); // SAFETY: the bytes live in the Arc's allocation, which stays in place when // the value moves, and every one of them is initialized. unsafe impl IoBuf for Shared { fn stable_ptr(&self) -> *const u8 { self.0.as_ptr() } fn bytes_init(&self) -> usize { self.0.len() } fn bytes_total(&self) -> usize { self.0.len() } } #[nuclei::main] async fn main() -> std::io::Result<()> { let listener = TcpListener::bind("127.0.0.1:0").await?; let client = TcpStream::connect(listener.local_addr()?).await?; let (server, _) = listener.accept().await?; // A buffer of your own type goes in, and the same value comes back. let news: Arc<[u8]> = Arc::from(&b"shared, not copied"[..]); let (sent, back) = server.write_owned(Shared(Arc::clone(&news))).await; assert_eq!(sent?, news.len()); assert!(Arc::ptr_eq(&back.0, &news)); // An AlignedBuf fills like a vector: its room, up to its capacity. let room = AlignedBuf::new(64, 64)?; let (n, got) = client.read_owned(room).await; assert_eq!(&got[..n?], &news[..]); assert_eq!(got.as_ptr() as usize % 64, 0); Ok(()) } ``` - [`AlignedBuf`](https://nuclei.rs/api/nuclei/io/struct.AlignedBuf.html) is a buffer of a fixed capacity at an address of the alignment you choose, made by a safe constructor (`new` or `zeroed`): the buffer for a file opened for [direct IO](https://nuclei.rs/learn/fs.html#direct). Its memory is yours, not charged to the runtime's [`io_buffer_cap`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.io_buffer_cap). - A type of your own (a shared byte buffer, memory of a registered region) implements the two traits. They are unsafe: the memory must stay in place while the runtime holds the value, even when the value moves. - The runtime keeps a `Vec` or an `AlignedBuf` as it is while a call has it, and boxes a buffer of any other type once. - Where the compiler cannot see the buffer's type, write it: `Vec::::new()`, not `Vec::new().into()` or `Default::default()`, and `send_to_owned::` where you name the address type. ## Several buffers in one call `write_vectored_owned` writes every buffer of an [`IoVecBuf`](https://nuclei.rs/api/nuclei/io/trait.IoVecBuf.html) in order as one write: no other write of the handle comes between two of them. `read_vectored_owned` fills the room of each buffer of an [`IoVecBufMut`](https://nuclei.rs/api/nuclei/io/trait.IoVecBufMut.html) before the next one's. Both take a `Vec` or an array of any owned buffer type and give the buffers back together. TCP and Unix streams, pipes and files have both. `src/main.rs`: ```rust use nuclei::fs::File; use nuclei::io::AsyncSeekExt; #[nuclei::main] async fn main() -> std::io::Result<()> { let mut file = File::create_new("record.bin").await?; // A header and a body from two buffers, as one write: nothing comes between. let parts = vec![b"LEN=4;".to_vec(), b"body".to_vec()]; let (written, parts) = file.write_vectored_owned(parts).await; assert_eq!(written?, 10); // Both buffers come back, for the next record. assert_eq!(parts.len(), 2); // Read it back into two rooms: the first fills before the second. file.rewind().await?; let rooms = [Vec::::with_capacity(6), Vec::with_capacity(64)]; let (n, [header, body]) = file.read_vectored_owned(rooms).await; assert_eq!(n?, 10); assert_eq!((&header[..], &body[..]), (&b"LEN=4;"[..], &b"body"[..])); nuclei::fs::remove_file("record.bin").await } ``` Each call of the kernel takes every buffer at once: `writev` and `readv`, or a `sendmsg` and `recvmsg` of several buffers, on epoll and kqueue; their ring operations on io_uring; a `WSASend` or `WSARecv` of several buffers on I/O completion ports; `pwritev` and `preadv` for files. A call the kernel takes part of goes on from the byte it stopped at. Where the system has no vectored call of the kind, the buffers go one call each, in order: a buffered file on Windows does so, and a Windows handle that is not a socket writes that way and reads into its first buffer only. ## In memory Streams with no socket behind them, for tests and for joining parts of a program: - `duplex(n)`: two connected streams, `n` bytes of buffer each way. `simplex(n)`: one pipe, a reader and a writer. - `io::split(stream)`: a read half and a write half of any stream, put back with `unsplit`. - `empty()`, `repeat(byte)`, `sink()`: a reader at its end, a reader without end, a writer that keeps nothing. ## The standard streams `io::stdin()`, `io::stdout()` and `io::stderr()` are the process's own, as async streams. `src/main.rs`: ```rust use nuclei::io::{self, AsyncWriteExt}; #[nuclei::main] async fn main() -> std::io::Result<()> { let mut out = io::stdout(); out.write_all(b"written to stdout\n").await?; out.flush().await?; Ok(()) } ``` Output: ``` written to stdout ``` ## Any std object The socket and file types are `Handle`s over std's own objects, and `Handle::new` takes over any other one: on Unix anything with a file descriptor, on Windows sockets, files and a child's pipes. `get_ref` reaches the object; `into_inner` gives it back once the bytes written behind went out. `src/main.rs`: ```rust use nuclei::Handle; #[nuclei::main] async fn main() -> std::io::Result<()> { // Any std socket or file, taken over: Handle::new makes its IO async. let std_listener = std::net::TcpListener::bind("127.0.0.1:0")?; let listener = Handle::new(std_listener)?; let addr = listener.get_ref().local_addr()?; let client = Handle::new(std::net::TcpStream::connect(addr)?)?; let (server, _) = listener.accept().await?; client.send(b"hi").await?; let mut buf = [0u8; 2]; server.recv(&mut buf).await?; // into_inner gives std's object back once the bytes written behind went out. let std_stream: std::net::TcpStream = client.into_inner(); assert_eq!(std_stream.peer_addr()?, addr); Ok(()) } ``` # Readiness Wait until a socket may be ready, try a call without waiting, and make calls of your own. Chapter 8 of 17. The page: https://nuclei.rs/learn/readiness.html ## Readiness on a proactor The driver completes IO for the task ([How it works](https://nuclei.rs/learn/proactive.html#proactor)), so most code never asks whether a socket is ready: it awaits `recv` or `read`. Readiness is for code that wants to try first and wait only when it must, and for calls the driver does not make. On a Nuclei socket: - **A read is ready** when the handle holds bytes the driver read ahead, or the stream ended. - **A write is ready** when the stream's write-behind has room. ## Wait, then try `readable()`, `writable()` and `ready(interest)` wait until a read or a write would end at once; the `try_` calls make it without waiting, or answer `WouldBlock`. They answer from the handle's own read-ahead and write-behind, which the driver keeps filling and draining: a `try_read` that finds nothing leaves the driver reading, so a later one finds what came. `src/main.rs`: ```rust use std::io::ErrorKind; use nuclei::io::{Interest, Ready}; use nuclei::net::{TcpListener, TcpStream}; #[nuclei::main] async fn main() -> std::io::Result<()> { let listener = TcpListener::bind("127.0.0.1:0").await?; let client = TcpStream::connect(listener.local_addr()?).await?; let (server, _) = listener.accept().await?; // try_write hands bytes to the write-behind, or says WouldBlock when it is full. client.writable().await?; assert_eq!(client.try_write(b"ready")?, 5); // try_read answers from what the driver read ahead, never waiting. let mut buf = [0u8; 16]; let n = loop { server.readable().await?; match server.try_read(&mut buf) { Ok(n) => break n, // Nothing read ahead yet: wait for readiness again. Err(e) if e.kind() == ErrorKind::WouldBlock => continue, Err(e) => return Err(e), } }; assert_eq!(&buf[..n], b"ready"); // ready waits for either, and says which it found. let found: Ready = server .ready(Interest::READABLE | Interest::WRITABLE) .await?; assert!(found.is_writable()); Ok(()) } ``` Streams have `try_read`, `try_read_vectored`, `try_write` and `try_write_vectored`. A `try_` call after a wait can still answer `WouldBlock`, when another task got there first: wait again, as the loop does. ## Datagrams Datagram sockets have `try_send`, `try_send_to`, `try_recv` and `try_recv_from` the same way, and UDP sockets `try_peek` and `try_peek_from` too. `src/main.rs`: ```rust use std::io::ErrorKind; use nuclei::net::UdpSocket; #[nuclei::main] async fn main() -> std::io::Result<()> { let a = UdpSocket::bind("127.0.0.1:0").await?; let b = UdpSocket::bind("127.0.0.1:0").await?; // Nothing came yet: the try_ call answers at once instead of waiting. let mut buf = [0u8; 64]; let empty = b.try_recv_from(&mut buf).unwrap_err(); assert_eq!(empty.kind(), ErrorKind::WouldBlock); a.try_send_to(b"datagram", b.local_addr()?)?; // peek_sender names who sent the next datagram, which stays to be received. assert_eq!(b.peek_sender().await?, a.local_addr()?); b.readable().await?; let (n, from) = b.try_recv_from(&mut buf)?; assert_eq!((&buf[..n], from), (&b"datagram"[..], a.local_addr()?)); Ok(()) } ``` ## For futures of your own A future or stream written by hand polls instead: `poll_accept`, `poll_peek`, `poll_read_ready`, `poll_write_ready`, and for datagrams `poll_recv_ready`, `poll_send_ready` and `poll_peek_sender`. Each keeps the waker of its `Context` until the answer is ready. `src/main.rs`: ```rust use std::future::poll_fn; use nuclei::io::ReadBuf; use nuclei::net::{TcpListener, TcpStream}; #[nuclei::main] async fn main() -> std::io::Result<()> { let listener = TcpListener::bind("127.0.0.1:0").await?; let client = nuclei::spawn(TcpStream::connect(listener.local_addr()?)); // poll_accept: the accept as a poll, for a future or a stream of your own. let (server, _) = poll_fn(|cx| listener.poll_accept(cx)).await?; let client = client.await?; client.send(b"peek").await?; // poll_peek: the bytes the next receive gives, left where they are. let mut storage = [0u8; 4]; let mut buf = ReadBuf::new(&mut storage); let n = poll_fn(|cx| server.poll_peek(cx, &mut buf)).await?; assert_eq!(n, 4); assert_eq!(buf.filled(), b"peek"); Ok(()) } ``` A UDP socket also polls its datagrams themselves: [`poll_recv_from`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.poll_recv_from) receives one into a `ReadBuf` and answers its sender, cutting what does not fit, and [`poll_send_to`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.poll_send_to) sends one to an address. `src/main.rs`: ```rust use std::future::poll_fn; use nuclei::io::ReadBuf; use nuclei::net::UdpSocket; #[nuclei::main] async fn main() -> std::io::Result<()> { let server = UdpSocket::bind("127.0.0.1:0").await?; let client = UdpSocket::bind("127.0.0.1:0").await?; let to = server.local_addr()?; // poll_send_to: a datagram's send as a poll. let sent = poll_fn(|cx| client.poll_send_to(cx, b"ping", to)).await?; assert_eq!(sent, 4); // poll_recv_from: the datagram fills the ReadBuf, and the answer is its sender. let mut storage = [0u8; 16]; let mut buf = ReadBuf::new(&mut storage); let from = poll_fn(|cx| server.poll_recv_from(cx, &mut buf)).await?; assert_eq!((buf.filled(), from), (&b"ping"[..], client.local_addr()?)); Ok(()) } ``` ## Calls of your own on a socket For a socket option or a system call Nuclei does not make, `async_io(interest, f)` runs `f`, your own call on the socket, each time it may be ready, until it answers other than `WouldBlock`; `try_io` runs it once, now (Unix). `src/main.rs`: ```rust use std::io::ErrorKind; use nuclei::io::Interest; use nuclei::net::UdpSocket; #[nuclei::main] async fn main() -> std::io::Result<()> { let a = UdpSocket::bind("127.0.0.1:0").await?; let b = UdpSocket::bind("127.0.0.1:0").await?; let to = b.local_addr()?; // A call of your own on the socket, made when it may be ready. The socket // is non-blocking, so a call that cannot go on answers WouldBlock and the // wait goes on. let sent = a .async_io(Interest::WRITABLE, || a.get_ref().send_to(b"own call", to)) .await?; assert_eq!(sent, 8); let mut buf = [0u8; 64]; let n = b .async_io(Interest::READABLE, || b.get_ref().recv(&mut buf)) .await?; assert_eq!(&buf[..n], b"own call"); // try_io makes the call once, now, or answers WouldBlock. let again = b.try_io(Interest::READABLE, || b.get_ref().recv(&mut buf)); assert_eq!(again.unwrap_err().kind(), ErrorKind::WouldBlock); Ok(()) } ``` Nothing is reordered around your call. Bytes the handle wrote behind go out before it, and a read of your own while the handle holds bytes it read ahead answers `ResourceBusy`: read those first. ## A descriptor of your own `nuclei::io::unix::AsyncFd` drives any descriptor you own by readiness: an eventfd, a device, a socket of a kind Nuclei does not wrap. Wait with `readable` or `writable`, then make your call through the guard's `try_io`; a call that answers `WouldBlock` clears the readiness, and the next wait lasts until the driver says so again. The descriptor must be in non-blocking mode. `src/main.rs`: ```rust use std::io::{Read, Write}; use std::os::unix::net::UnixStream; use nuclei::io::unix::AsyncFd; #[nuclei::main] async fn main() -> std::io::Result<()> { // A descriptor of your own (here a std socket), in non-blocking mode. let (mine, mut theirs) = UnixStream::pair()?; mine.set_nonblocking(true)?; let fd = AsyncFd::new(mine)?; theirs.write_all(b"edge")?; let mut buf = [0u8; 4]; let n = loop { // Wait until the driver says it may be readable... let mut guard = fd.readable().await?; // ...then make the call; WouldBlock clears the readiness and waits again. match guard.try_io(|inner| inner.get_ref().read(&mut buf)) { Ok(result) => break result?, Err(_would_block) => continue, } }; assert_eq!(&buf[..n], b"edge"); Ok(()) } ``` # Files Files and directories, as async calls that never hold a shard. Chapter 9 of 17. The page: https://nuclei.rs/learn/fs.html ## Whole files `nuclei::fs` mirrors `std::fs`, with each call a future: `read`, `read_to_string`, `write`, `copy`, `rename`, `remove_file`, `metadata`, `try_exists` and the rest take a path and do the whole job. `src/main.rs`: ```rust use nuclei::fs; #[nuclei::main] async fn main() -> std::io::Result<()> { // Whole files in one call each. fs::write("notes.txt", "first line\n").await?; let text = fs::read_to_string("notes.txt").await?; assert_eq!(text, "first line\n"); fs::copy("notes.txt", "copy.txt").await?; fs::rename("copy.txt", "moved.txt").await?; assert!(fs::try_exists("moved.txt").await?); assert_eq!(fs::read("moved.txt").await?, b"first line\n"); let meta = fs::metadata("moved.txt").await?; assert!(meta.is_file()); assert_eq!(meta.len(), 11); fs::remove_file("moved.txt").await?; fs::remove_file("notes.txt").await } ``` ## Opening a file A [`File`](https://nuclei.rs/api/nuclei/fs/type.File.html) is std's file in a `Handle`: `File::open` reads, `File::create` writes (creating or cutting the file), `File::create_new` creates a file to read and write and fails if it exists, and [`OpenOptions`](https://nuclei.rs/api/nuclei/fs/struct.OpenOptions.html) sets the rest (append, truncate, the mode and the open flags on Unix). A file reads and writes through the [IO helpers](https://nuclei.rs/learn/io.html#traits) and has a cursor that `seek` moves. `src/main.rs`: ```rust use std::io::SeekFrom; use nuclei::fs::{File, OpenOptions}; use nuclei::io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt}; #[nuclei::main] async fn main() -> std::io::Result<()> { let mut file = File::create("log.txt").await?; file.write_all(b"one\n").await?; // flush hands the bytes to the system; sync_all puts them on the device. file.flush().await?; file.sync_all().await?; drop(file); // Open for appending: every write lands at the end. let mut log = OpenOptions::new().append(true).open("log.txt").await?; log.write_all(b"two\n").await?; log.flush().await?; drop(log); let mut file = File::open("log.txt").await?; let mut text = String::new(); file.read_to_string(&mut text).await?; assert_eq!(text, "one\ntwo\n"); // A file has a cursor: seek moves it. file.seek(SeekFrom::Start(4)).await?; let mut second = String::new(); file.read_to_string(&mut second).await?; assert_eq!(second, "two\n"); nuclei::fs::remove_file("log.txt").await } ``` - `flush` waits until the system has the bytes written behind; `sync_all` and `sync_data` put them on the device ([Surviving a crash](https://nuclei.rs/learn/fs.html#durable)). - `metadata`, `set_len`, `set_permissions`, `set_times` and `set_modified` work on the open file; `try_clone` gives a second handle with a cursor of its own. - A read at the cursor sees the changes made beside it: bytes it read ahead before a positional write, a cut by `set_len`, an `allocate` or a copy into the file are never handed out after the change. ## Lending buffers As on streams ([How it works](https://nuclei.rs/learn/proactive.html#lending)), `read_owned` and `write_owned` take your buffer and give it back, so no byte is copied. The buffer is a `Vec`, an `AlignedBuf`, or a type of your own ([IO utilities](https://nuclei.rs/learn/io.html#owned)). `src/main.rs`: ```rust use nuclei::fs::File; #[nuclei::main] async fn main() -> std::io::Result<()> { // Lend a vector to the write: the bytes are written from it, no copy. let file = File::create("lent.bin").await?; let (written, _buf) = file.write_owned(vec![7u8; 4096]).await; assert_eq!(written?, 4096); drop(file); // And to the read: they land in its spare capacity. let file = File::open("lent.bin").await?; let (n, buf) = file.read_owned(Vec::with_capacity(8192)).await; assert_eq!(n?, 4096); assert!(buf.iter().all(|&b| b == 7)); nuclei::fs::remove_file("lent.bin").await } ``` ## Reads and writes at an offset [`read_at`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.read_at) and [`write_at`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.write_at) read and write at an offset you give, on a shared reference to the handle, so any number of tasks may use one file at once. They never read or move the cursor. `read_exact_at` and `write_all_at` do the whole length, and `read_at_owned` and `write_at_owned` lend your buffer. `src/main.rs`: ```rust use std::sync::Arc; use nuclei::fs::File; use nuclei::io::AsyncReadExt; #[nuclei::main] async fn main() -> std::io::Result<()> { // One handle shared by four tasks, each writing its record at its offset. let file = Arc::new(File::create_new("records.bin").await?); let writers: Vec<_> = (0..4u8) .map(|i| { let file = Arc::clone(&file); nuclei::spawn(async move { file.write_all_at(&[i; 16], u64::from(i) * 16).await }) }) .collect(); for writer in writers { writer.await?; } let mut record = [0u8; 16]; file.read_exact_at(&mut record, 32).await?; assert_eq!(record, [2; 16]); // Many reads in one call, each into a buffer of its own, out together. let reads = (0..4u64) .map(|i| (Vec::::with_capacity(16), i * 16)) .collect(); for (i, (n, buf)) in (0u8..).zip(file.read_many_at(reads).await) { assert_eq!(n?, 16); assert!(buf.iter().all(|&b| b == i)); } // Positional calls never move the cursor: a read at it starts at 0. let mut all = Vec::new(); (&*file).read_to_end(&mut all).await?; assert_eq!(all.len(), 64); nuclei::fs::remove_file("records.bin").await } ``` - A positional call lands after every write accepted at the cursor before it, and a read sees every positional write that returned before it. Two positional writes running at once land in either order, as two threads' `pwrite` calls do. - A positional write whose future is dropped still lands, and every later call of the handle waits for it. - `read_at` and `write_at` go through a buffer of the runtime's pool, at most 64 KiB a call; the owned forms use your buffer itself. - [`read_many_at`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.read_many_at) makes many reads in one call and gives each buffer back in order with its result. On io_uring they go to the kernel together, at most 64 out at once. - These are the async calls, and they shadow std's `FileExt::read_at` and `write_at`, which the handle reaches through `Deref` and which block the worker. std's stay reachable as `(*file).read_at(..)`. ## Surviving a crash [`sync_all`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.sync_all) writes the file's data and metadata through to the device, and `sync_data` its data, once every write accepted before the call landed. A file's sync does not cover its name in its directory; [`fs::sync_dir`](https://nuclei.rs/api/nuclei/fs/fn.sync_dir.html) does. To replace a file so a crash leaves the old contents or the new and never a mix, write a temporary file in the same directory, sync it, rename it over the target, then sync the directory. `src/main.rs`: ```rust use nuclei::fs::{self, File}; use nuclei::io::AsyncWriteExt; #[nuclei::main] async fn main() -> std::io::Result<()> { fs::write("config.toml", "version = 1\n").await?; // Replace it so a crash leaves the old contents or the new, never a mix. let mut tmp = File::create("config.toml.tmp").await?; tmp.write_all(b"version = 2\n").await?; tmp.sync_all().await?; // the bytes, on the device drop(tmp); fs::rename("config.toml.tmp", "config.toml").await?; fs::sync_dir(".").await?; // the new name, on the device assert_eq!(fs::read_to_string("config.toml").await?, "version = 2\n"); fs::remove_file("config.toml").await } ``` Once a sync of a handle failed, every later sync of it fails with the same error, since the system reports a lost write-back only once. Open the file again to start over. ## Space, write-back and copies [`allocate`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.allocate) changes the space a range of the file uses, as its [`Allocate`](https://nuclei.rs/api/nuclei/fs/enum.Allocate.html) mode says: `Extend` reserves it and grows the file, `KeepSize` reserves it and keeps the length, `PunchHole` frees it, and `ZeroRange` makes it read as zeros. A system that cannot do a mode answers `Unsupported` (macOS cannot zero a range in place), and a file system may refuse one with its own error. [`sync_range`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.sync_range) writes a range back and waits for it; it writes no metadata, so it is not a durability guarantee. [`copy_range_to`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.copy_range_to) copies a range into another file, in the kernel where the system can, in chunks of at most 16 MiB, and moves neither cursor. `src/main.rs`: ```rust use nuclei::fs::{Allocate, File}; #[nuclei::main] async fn main() -> std::io::Result<()> { let log = File::create_new("log.bin").await?; // Reserve 1 MiB up front, so writes into it cannot run out of space. log.allocate(0, 1 << 20, Allocate::KeepSize).await?; assert_eq!(log.metadata().await?.len(), 0); log.write_all_at(b"entry", 0).await?; // Start writing the range back now; sync_data is what makes it durable. log.sync_range(0, 5).await?; // Copy the range into another file, in the kernel where it can. let copy = File::create_new("copy.bin").await?; assert_eq!(log.copy_range_to(©, 0, 0, 5).await?, 5); let mut back = [0u8; 5]; copy.read_exact_at(&mut back, 0).await?; assert_eq!(&back, b"entry"); nuclei::fs::remove_file("log.bin").await?; nuclei::fs::remove_file("copy.bin").await } ``` ## Locks [`lock_file`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.lock_file) takes an advisory lock on the whole file, shared or exclusive, and waits for it on the blocking pool so the worker runs on. A future dropped while it waits never leaves the file locked with nobody to release it. [`try_lock_file`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.try_lock_file) answers at once, with `WouldBlock` when another holder has the lock, and [`unlock_file`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.unlock_file) releases it once the writes before it landed. `src/main.rs`: ```rust use nuclei::fs::{File, TryLockError}; #[nuclei::main] async fn main() -> std::io::Result<()> { let holder = File::create("app.lock").await?; let other = File::open("app.lock").await?; // Wait for the lock on the blocking pool; the worker runs on meanwhile. holder.lock_file(false).await?; // While it is held, another handle cannot have it. let refused = other.try_lock_file(false).await; assert!(matches!(refused, Err(TryLockError::WouldBlock))); // Released once the writes before it landed; then free for the other. holder.unlock_file().await?; other.try_lock_file(true).await?; other.unlock_file().await?; nuclei::fs::remove_file("app.lock").await } ``` std's own `lock`, `try_lock` and `unlock` stay reachable through `Deref`; std's `lock` blocks the worker while it waits. ## Direct IO A file opened for direct IO (`O_DIRECT` on Linux, `FILE_FLAG_NO_BUFFERING` on Windows) skips the system's page cache. Nuclei reads and writes it with exactly your lengths and offsets, with no read-ahead and no write-behind, so the kernel's alignment rules apply to your calls as they would to your own system calls: the memory's address, the offset and the length are multiples of the device's block size. [`AlignedBuf`](https://nuclei.rs/api/nuclei/io/struct.AlignedBuf.html) gives memory at the alignment you ask for. `src/main.rs`: ```rust use nuclei::fs::OpenOptions; use nuclei::io::AlignedBuf; // Direct IO asks the memory, the offset and the length to be multiples of // the device's block size; 4096 meets that on the common ones. const BLOCK: usize = 4096; #[nuclei::main] async fn main() -> std::io::Result<()> { let file = OpenOptions::new() .read(true) .write(true) .create(true) .custom_flags(libc::O_DIRECT) .open("direct.bin") .await?; // Two blocks in memory aligned to a block, handed to the kernel as they are. let mut blocks = AlignedBuf::new(2 * BLOCK, BLOCK)?; blocks.extend_from_slice(&[7u8; 2 * BLOCK]); let (written, _blocks) = file.write_at_owned(blocks, 0).await; assert_eq!(written?, 2 * BLOCK); // The second block, read straight into an aligned buffer of its own. let room = AlignedBuf::new(BLOCK, BLOCK)?; let (n, block) = file.read_at_owned(room, BLOCK as u64).await; assert_eq!(n?, BLOCK); assert!(block.iter().all(|&b| b == 7)); nuclei::fs::remove_file("direct.bin").await } ``` ## Directories `create_dir`, `create_dir_all` and [`DirBuilder`](https://nuclei.rs/api/nuclei/fs/struct.DirBuilder.html) (recursive, with a mode on Unix) make them; `remove_dir` and `remove_dir_all` take them away. `read_dir` streams the entries a page at a time, so a directory of any size is read without holding it all. `src/main.rs`: ```rust use nuclei::fs::{self, DirBuilder}; #[nuclei::main] async fn main() -> std::io::Result<()> { fs::create_dir_all("site/assets/img").await?; DirBuilder::new() .recursive(true) .create("site/pages") .await?; fs::write("site/index.html", "

hi

").await?; // read_dir is a stream of entries, read a page at a time. let mut names = Vec::new(); let mut entries = fs::read_dir("site").await?; while let Some(entry) = entries.next_entry().await? { let mut name = entry.file_name().to_string_lossy().into_owned(); if entry.file_type().await?.is_dir() { name.push('/'); } names.push(name); } names.sort(); assert_eq!(names, ["assets/", "index.html", "pages/"]); fs::remove_dir_all("site").await } ``` Links: `hard_link`, `read_link` and `canonicalize`, `symlink` on Unix, `symlink_file` and `symlink_dir` on Windows. ## Where file IO runs A regular file is always ready to the kernel, so no poller can say when its IO would wait. On io_uring a file's reads and writes, at the cursor and at an offset, its syncs, `sync_range` and `allocate` are operations of the shard's ring; on the other backends each is a job of the blocking pool. Calls by path, `lock_file`, `copy_range_to` and the file's other calls run on the blocking pool; `try_lock_file` runs on the calling thread, since it never waits. On Linux, `File::open` opens a regular file on a local file system on the calling thread when the kernel's caches resolve its path at once (`openat2` with `RESOLVE_CACHED`, Linux 5.12), with no job; any other open, a FIFO, a device or a file on a network file system among them, goes to the blocking pool. A `File` that is not a regular file (a FIFO, a terminal, a pipe) is a byte stream the driver serves like a socket. # Time Sleeps to the millisecond or the microsecond, timeouts and intervals, and a clock that tests can stop. Chapter 10 of 17. The page: https://nuclei.rs/learn/time.html ## Sleeps and timeouts `src/main.rs`: ```rust use std::time::Duration; use nuclei::time::{self, Instant}; #[nuclei::main] async fn main() { let start = Instant::now(); time::sleep(Duration::from_millis(20)).await; assert!(start.elapsed() >= Duration::from_millis(20)); // A future that takes too long gives Elapsed. let slow = time::sleep(Duration::from_secs(5)); assert!( time::timeout(Duration::from_millis(10), slow) .await .is_err() ); // One that is ready in time gives its output. let quick = async { "in time" }; assert_eq!( time::timeout(Duration::from_secs(1), quick).await, Ok("in time") ); // The same against a deadline. let deadline = Instant::now() + Duration::from_millis(10); let never = std::future::pending::<()>(); assert!(time::timeout_at(deadline, never).await.is_err()); } ``` - `sleep(duration)` and `sleep_until(instant)` give a `Sleep`; `reset` moves its deadline, `deadline` and `is_elapsed` read it. - `timeout(duration, future)` and `timeout_at(deadline, future)` give `Ok(output)`, or `Err(Elapsed)` if the time ran out first. The future is polled before the clock is read, so one that is ready at once always wins. - Dropping a timer's future cancels it. ## The clock and the wheel Every shard has a timer wheel with millisecond slots, where sleeps, timeouts and intervals wait. Such a timer waits at least its duration, rounded up to the next millisecond, and fires on the shard that polls it; a shard busy with a task fires it once that task yields. Arming and cancelling take constant time. A timer polled on a thread that runs no shard (another runtime's) is fired for it by a shard of the current runtime, or of the default one. A sleep that needs a finer step [waits to the microsecond](https://nuclei.rs/learn/time.html#precise). `nuclei::time::Instant` is the runtime's clock. It reads the system's monotonic clock until it is paused. ## Sleeps to the microsecond [`sleep_precise(duration)`](https://nuclei.rs/api/nuclei/time/fn.sleep_precise.html) and [`sleep_until_precise(instant)`](https://nuclei.rs/api/nuclei/time/fn.sleep_until_precise.html) give a [`SleepPrecise`](https://nuclei.rs/api/nuclei/time/struct.SleepPrecise.html), which ends at its deadline to the microsecond. Its timer sits in the shard's microsecond wheel, and the shard's wait ends at the earliest deadline of both wheels through the backend's high-resolution timer: the wait's own timeout on io_uring and on Windows, a timerfd on epoll, and an `EVFILT_TIMER` in nanoseconds on kqueue. `src/main.rs`: ```rust use std::time::Duration; use nuclei::time::{self, Instant}; #[nuclei::main] async fn main() { // To the microsecond, where sleep would round up to the next millisecond. let start = Instant::now(); time::sleep_precise(Duration::from_micros(250)).await; assert!(start.elapsed() >= Duration::from_micros(250)); // A pacer: ten steps 100 microseconds apart, each deadline counted from // the last one, so a late wake does not push the rest back. let begin = Instant::now(); let mut next = begin; for _ in 0..10 { next += Duration::from_micros(100); time::sleep_until_precise(next).await; } assert!(begin.elapsed() >= Duration::from_millis(1)); } ``` - It waits at least its duration, rounded up to the microsecond, and ends as soon after that as the system's timer wakes the shard. A shard busy with a task runs it late by as long as that task takes to yield, as with any timer. - A precise deadline that is the shard's earliest costs the shard a timer of its own in the kernel, one more system call to arm on epoll. Sleeps on the millisecond wheel pay nothing for it, so keep `sleep` where a millisecond is fine. - Pick it for a pacer, a retry spaced in microseconds, or a deadline a protocol counts in microseconds. - `deadline`, `is_elapsed` and `reset` work as on a `Sleep`, and a paused clock moves to a precise deadline exactly. ## Intervals `interval(period)` ticks every period, the first tick at once; `interval_at(start, period)` starts at `start`. `tick().await` gives the instant the tick was due, and `poll_tick` is the same wait for a hand-written future. A period of zero panics. `src/main.rs`: ```rust use std::time::Duration; use nuclei::time::{self, MissedTickBehavior}; #[nuclei::main] async fn main() { let mut every = time::interval(Duration::from_millis(10)); // When polled late, skip the ticks that were missed instead of bursting them. every.set_missed_tick_behavior(MissedTickBehavior::Skip); let first = every.tick().await; // the first tick is at once for _ in 0..3 { every.tick().await; } assert!(first.elapsed() >= Duration::from_millis(30)); // reset: the next tick is one period from now. every.reset(); every.tick().await; assert_eq!(every.period(), Duration::from_millis(10)); } ``` | MissedTickBehavior | When the interval was polled late | | --- | --- | | `Burst` (the default) | Every missed tick fires at once, one after another, until the interval is back on its schedule. | | `Delay` | The next tick comes one period after the late one: the schedule moves. | | `Skip` | Missed ticks are skipped: the next tick is the next one on the original schedule after now. | ## Paused time Code that sleeps is slow to test. A paused clock stands still and moves only when asked, so an hour's timeout passes at once and the test still sees an hour on the clock. - `time::pause()` stops the clock of the runtime the code runs in. `Builder::start_paused(true)`, `#[nuclei::main(start_paused = true)]` and `#[nuclei::test(start_paused = true)]` start it stopped. - **It moves by itself when nothing else can.** Once every shard of the runtime is idle with a timer armed, the clock jumps to the earliest timer. - `time::advance(duration).await` moves it by hand and lets the timers that came due fire before it returns. - `time::resume()` starts it again from where it stands. `src/main.rs`: ```rust use std::time::Duration; use nuclei::time::{self, Instant}; #[nuclei::main(start_paused = true)] async fn main() { let start = Instant::now(); // Paused, the clock jumps to the next timer once every task waits: // an hour's sleep ends at once, and the clock says an hour passed. time::sleep(Duration::from_secs(3600)).await; assert_eq!(start.elapsed(), Duration::from_secs(3600)); // advance moves the clock by hand, firing the timers it passes. let timer = nuclei::spawn(time::sleep(Duration::from_secs(10))); time::advance(Duration::from_secs(10)).await; timer.await; assert_eq!(start.elapsed(), Duration::from_secs(3610)); // resume lets it run with the system's clock again. time::resume(); time::sleep(Duration::from_millis(1)).await; assert!(start.elapsed() > Duration::from_secs(3610)); } ``` A paused clock never goes backwards, on any thread, across a pause, a resume or an advance. While no runtime's clock is paused or advanced, reading it costs one load more than reading the system clock. # Sync Locks, semaphores, notifications, once-cells and lock-free structures for async code, and twins of them for one shard. Chapter 11 of 17. The page: https://nuclei.rs/learn/sync.html ## Futures and wakers, nothing else Every wait in `nuclei::sync` is a future built from futures and wakers alone, so it works under any executor, not only Nuclei's. A contended wait queues and returns `Pending`; it never blocks a thread. - **Familiar names.** `Mutex`, `RwLock`, `Semaphore`, `Notify`, `Barrier`, `OnceCell` and `SetOnce` keep the names, signatures and errors of the established async sync API: code written against it compiles after a change of import. - **Every wait has a `try_` form** that never waits, and a `blocking_` form for threads that may block. On a Nuclei shard a `blocking_` call nests a `block_on`, so the shard keeps running its other tasks. - **Dropping a wait loses nothing.** A dropped future withdraws its place in line and passes on what was handed to it, so no wakeup is lost. A `Barrier` wait is the one exception: an arrival that was counted stays counted. - **Fair to the shard.** On a Nuclei shard, a lock, an acquire or a receive that completes spends the task's [budget](https://nuclei.rs/learn/sync.html#budget), so a loop on one that is always ready still lets other tasks run. Under another executor there is no budget. ## Mutex `src/main.rs`: ```rust use std::sync::Arc; use nuclei::sync::Mutex; #[nuclei::main] async fn main() { let counter = Arc::new(Mutex::new(0u32)); let tasks: Vec<_> = (0..8) .map(|_| { let counter = Arc::clone(&counter); nuclei::spawn(async move { // lock waits as a future: the shard runs other tasks meanwhile. *counter.lock().await += 1; }) }) .collect(); for task in tasks { task.await; } assert_eq!(*counter.lock().await, 8); // An owned guard holds the lock by an Arc, so it can be moved into a task. let guard = Arc::clone(&counter).lock_owned().await; nuclei::spawn(async move { assert_eq!(*guard, 8) }).await; // try_lock never waits. assert!(counter.try_lock().is_ok()); } ``` Uncontended, taking and releasing the lock is one atomic operation each. It does not poison: a panic in a holder unlocks it. `lock_owned` holds the lock through an `Arc`, so the guard can move into a task; `MutexGuard::map` narrows a guard to a part of the value. ## RwLock Readers share the lock, a writer has it alone. An **upgradable read** sits beside plain readers (one at a time) and turns into a write without letting another writer in between: read, decide, then write. `src/main.rs`: ```rust use nuclei::sync::{RwLock, RwLockUpgradableReadGuard}; #[nuclei::main] async fn main() { let config = RwLock::new(String::from("v1")); // Readers share the lock. let a = config.read().await; let b = config.read().await; assert_eq!((a.as_str(), b.as_str()), ("v1", "v1")); drop((a, b)); // An upgradable read sits beside plain readers, and becomes a write // without letting another writer in between. let check = config.upgradable_read().await; if check.as_str() == "v1" { let mut write = RwLockUpgradableReadGuard::upgrade(check).await; write.push_str("+patch"); } assert_eq!(*config.read().await, "v1+patch"); } ``` A write guard `downgrade`s to a read guard, and `with_max_readers` bounds how many readers share it. ## Reentrant locks `ReentrantMutex` and `ReentrantRwLock` may be taken again by the holder that has them. The holder is an [`Owner`](https://nuclei.rs/api/nuclei/sync/struct.Owner.html) token, not a thread: a task can move between threads, and many tasks can share one. `src/main.rs`: ```rust use nuclei::sync::{Owner, ReentrantMutex}; #[nuclei::main] async fn main() { let state = ReentrantMutex::new(Vec::<&str>::new()); // The lock is held by an owner, not a thread: tasks move between threads. let me = Owner::new(); let outer = state.lock(&me).await; // The same owner takes it again without waiting for itself. let inner = state.lock(&me).await; assert!(inner.is_empty() && outer.is_empty()); drop(inner); drop(outer); // Another owner waits until every hold of the first is gone. let other = Owner::new(); assert!(state.try_lock(&other).is_some()); } ``` ## Semaphore A semaphore hands out permits; a permit goes back when it drops. It bounds how many tasks do something at once. `src/main.rs`: ```rust use std::sync::Arc; use std::time::Duration; use nuclei::sync::{Mutex, Semaphore}; use nuclei::time::sleep; #[nuclei::main] async fn main() { // At most two jobs at once, however many are spawned. let slots = Arc::new(Semaphore::new(2)); let running = Arc::new(Mutex::new((0u32, 0u32))); // (now, most at once) let jobs: Vec<_> = (0..6) .map(|_| { let (slots, running) = (Arc::clone(&slots), Arc::clone(&running)); nuclei::spawn(async move { let _permit = slots.acquire_owned().await.unwrap(); { let mut r = running.lock().await; r.0 += 1; r.1 = r.1.max(r.0); } sleep(Duration::from_millis(5)).await; running.lock().await.0 -= 1; // The permit goes back when it drops. }) }) .collect(); for job in jobs { job.await; } assert_eq!(running.lock().await.1, 2); assert_eq!(slots.available_permits(), 2); } ``` `acquire_many` takes several at once, `forget` keeps a permit from going back, `add_permits` adds more, and `close` makes every wait fail. ## Notify, Event, Latch, Barrier | Type | Waits end when | | --- | --- | | `Notify` | `notify_one` wakes the oldest waiter, or keeps one permit for the next when nobody waits; `notify_waiters` wakes every waiter there is. | | `Event` | it is set; it stays set, so later waits end at once. | | `Latch` | its count, counted down by `count_down`, reaches zero; it stays open. | | `Barrier` | `n` tasks wait at once; one of them is told it is the leader. | `src/main.rs`: ```rust use std::sync::Arc; use nuclei::sync::{Barrier, Event, Latch, Notify}; #[nuclei::main] async fn main() { // Notify: wake one waiter; a notify with nobody waiting is kept for the next. let notify = Arc::new(Notify::new()); let waiter = { let notify = Arc::clone(¬ify); nuclei::spawn(async move { notify.notified().await }) }; notify.notify_one(); waiter.await; // Event: set once, and every wait, now or later, ends. let ready = Arc::new(Event::new()); let watcher = { let ready = Arc::clone(&ready); nuclei::spawn(async move { ready.wait().await }) }; ready.set(); watcher.await; ready.wait().await; // Latch: waits end once the count reaches zero. let started = Arc::new(Latch::new(3)); for _ in 0..3 { let started = Arc::clone(&started); nuclei::spawn(async move { started.count_down() }).detach(); } started.wait().await; // Barrier: each wait ends once n tasks are waiting; one is the leader. let barrier = Arc::new(Barrier::new(2)); let other = { let barrier = Arc::clone(&barrier); nuclei::spawn(async move { barrier.wait().await.is_leader() }) }; let mine = barrier.wait().await.is_leader(); assert!(mine != other.await); } ``` ## Once-cells and lazy values `OnceCell` holds a value set once; `get_or_init` runs an async initializer, and callers that come meanwhile wait for it. `SetOnce` is set from anywhere, and `wait` waits until someone has. `Lazy` computes its value on first use. `src/main.rs`: ```rust use std::time::Duration; use nuclei::sync::{Lazy, OnceCell, SetOnce}; static TABLE: Lazy> = Lazy::new(|| (0..10).map(|n| n * n).collect()); static SETTINGS: OnceCell = OnceCell::const_new(); async fn load_settings() -> String { nuclei::time::sleep(Duration::from_millis(5)).await; "port=7000".to_string() } #[nuclei::main] async fn main() { // Lazy: computed on first use, the same value after. assert_eq!(TABLE[3], 9); // OnceCell: the first caller runs the async initializer; others wait for it. let (a, b) = nuclei::join!( SETTINGS.get_or_init(load_settings), SETTINGS.get_or_init(load_settings), ); assert!(std::ptr::eq(a, b)); // SetOnce: set once from anywhere; wait until someone has. let shutdown_reason = SetOnce::new(); shutdown_reason.set("maintenance").unwrap(); assert_eq!(*shutdown_reason.wait().await, "maintenance"); assert!(shutdown_reason.set("again").is_err()); } ``` ## Fast, and fair by count The locks and the semaphore let a caller take what is free even while others wait, so a release never waits for a sleeping task to run. A waiter that loses [`MAX_BYPASS`](https://nuclei.rs/api/nuclei/sync/constant.MAX_BYPASS.html) times is owed a handoff: nobody gets in ahead of it, and the next release goes to it directly. Fairness is counted, never timed. ## The task's budget On a Nuclei shard, a lock or a semaphore acquire that completes spends one operation of the task's [budget](https://nuclei.rs/learn/tasks.html#yield), as IO does, and so do a channel receive that completes and a bounded send that completes at its first try. Once the budget is spent the call completes nothing: it wakes its task and answers `Pending`, so the task goes behind the shard's other tasks. `src/main.rs`: ```rust use std::cell::Cell; use std::rc::Rc; use nuclei::sync::mpsc; #[nuclei::main] async fn main() { let (tx, mut rx) = mpsc::unbounded_channel(); for value in 0..1000u32 { tx.send(value).unwrap(); } drop(tx); let ran = Rc::new(Cell::new(false)); let other = nuclei::spawn_local({ let ran = Rc::clone(&ran); async move { ran.set(true) } }); // Every receive is ready at once, yet the loop yields when its budget is // spent, so the other task runs while values are still waiting. let (mut received, mut ran_after) = (0, None); while rx.recv().await.is_some() { received += 1; if ran.get() && ran_after.is_none() { ran_after = Some(received); } } assert!(ran_after.is_some_and(|n| n < 1000)); other.await; } ``` - A wait that queued and was then granted spends nothing, so it keeps what it waited for. - The `try_` forms never spend. `Notify`, `Event`, `Latch`, `Barrier` and the once-cells keep no budget. - Off a Nuclei shard, under another executor, there is no budget, and these calls never yield for it. - [`coop::unconstrained`](https://nuclei.rs/api/nuclei/task/coop/fn.unconstrained.html) runs a future with no budget, and [`budget_yields`](https://nuclei.rs/api/nuclei/stats/struct.ShardStats.html#structfield.budget_yields) counts how often a shard's tasks yielded for it. ## For the tasks of one shard [`nuclei::sync::local`](https://nuclei.rs/api/nuclei/sync/local/index.html) has twins of `mpsc`, `oneshot`, `Semaphore` and `Mutex` for tasks that share one thread: [`spawn_local`](https://nuclei.rs/learn/tasks.html#local) tasks, and the future `block_on` runs. Their state sits in an `Rc` and plain cells, so no path makes an atomic instruction or a fence, and a message between two tasks takes fewer instructions than on the shared channel (CI counts both, in the `mpsc` and `local_mpsc` rows of [`ci/op_budget.txt`](https://github.com/vertexclique/nuclei/blob/master/ci/op_budget.txt)). `src/main.rs`: ```rust use std::rc::Rc; use nuclei::sync::local::{Mutex, mpsc, oneshot}; #[nuclei::main] async fn main() { // Rc, not Arc: these tasks all stay on this thread's shard. let log = Rc::new(Mutex::new(Vec::new())); let (tx, mut rx) = mpsc::channel(2); for n in 1..=3u32 { let (tx, log) = (tx.clone(), Rc::clone(&log)); nuclei::spawn_local(async move { log.lock().await.push(n); tx.send(n).await.unwrap(); }) .detach(); } drop(tx); // A oneshot carries the sum back once every sender is gone. let (reply, sum) = oneshot::channel(); nuclei::spawn_local(async move { let mut total = 0; while let Some(n) = rx.recv().await { total += n; } reply.send(total).unwrap(); }) .detach(); assert_eq!(sum.await, Ok(6)); assert_eq!(log.lock().await.len(), 3); } ``` - **Not Send.** The types are neither `Send` nor `Sync`, so the compiler keeps them on the thread that made them. Share one between tasks with an `Rc`. - **The same names and errors.** Code switches by changing the path. Left out are the `blocking_` forms, which on one thread could only wait for themselves, and the weak sender. - **First come, first served.** Waiting sends, acquires and locks are served strictly in the order they came, and a `try_` form fails while anyone waits. The shared locks let a caller in ahead of a waiter ([fair by count](https://nuclei.rs/learn/sync.html#fairness)); these never do. - Dropping a wait loses nothing, and the [budget](https://nuclei.rs/learn/sync.html#budget) applies as it does to the shared ones. ## Lock-free maps and queues For state shared across threads without a lock at all: - [`HopscotchMap`](https://nuclei.rs/api/nuclei/sync/struct.HopscotchMap.html): a concurrent hash map; values are cloned out. - [`SegQueue`](https://nuclei.rs/api/nuclei/sync/struct.SegQueue.html): an unbounded queue. [`ArrayQueue`](https://nuclei.rs/api/nuclei/sync/struct.ArrayQueue.html): a bounded one whose push refuses when full. - [`Atom`](https://nuclei.rs/api/nuclei/sync/struct.Atom.html): a value read without a lock and replaced whole. `src/main.rs`: ```rust use std::sync::Arc; use nuclei::sync::{ArrayQueue, Atom, HopscotchMap, SegQueue}; #[nuclei::main] async fn main() { // A concurrent map: every operation is lock-free, values are cloned out. let sessions = Arc::new(HopscotchMap::new()); let writers: Vec<_> = (0..4u32) .map(|n| { let sessions = Arc::clone(&sessions); nuclei::spawn(async move { sessions.insert(n, format!("user-{n}")) }) }) .collect(); for writer in writers { writer.await; } assert_eq!(sessions.get(&2).as_deref(), Some("user-2")); assert_eq!(sessions.len(), 4); // Queues: unbounded, and bounded with a push that refuses when full. let work = SegQueue::new(); work.push("job"); assert_eq!(work.pop(), Some("job")); let ring = ArrayQueue::new(1); assert!(ring.push(1).is_ok()); assert_eq!(ring.push(2), Err(2)); // Atom: a value read without a lock and replaced whole. let config = Atom::new(String::from("v1")); config.store(String::from("v2")); assert_eq!(config.load_clone(), "v2"); } ``` # Channels Send values between tasks, and tell many tasks to stop. Chapter 12 of 17. The page: https://nuclei.rs/learn/channels.html ## Which channel | Channel | For | | --- | --- | | `mpsc::channel(n)` | Many senders, one receiver, at most `n` messages waiting: a send waits for room, so a fast sender cannot run away. | | `mpsc::unbounded_channel()` | The same with no bound: a send never waits. | | `oneshot::channel()` | One value, once: a reply to a request. | | `broadcast::channel(n)` | Every receiver sees every message; one that falls `n` behind is told how many it missed. | | `watch::channel(v)` | One value many tasks read, and the news that it changed. | | `local::mpsc::channel(n)`, `local::oneshot::channel()` | mpsc and oneshot for the tasks of one shard: not `Send`, with no atomic instruction on any path ([Sync](https://nuclei.rs/learn/sync.html#local)). | | `mesh::mesh(n, capacity)` | A bounded mpsc channel between every pair of `n` parties, such as one party per worker ([below](https://nuclei.rs/learn/channels.html#mesh)). | Like everything in [`nuclei::sync`](https://nuclei.rs/learn/sync.html#model), they work under any executor, and their receives are safe to drop halfway. On a Nuclei shard a receive that completes spends one operation of the task's [budget](https://nuclei.rs/learn/sync.html#budget), so a loop on a channel that is never empty still lets the shard's other tasks run. ## mpsc Senders clone; the channel closes when the last one drops, and `recv` then gives `None`. `recv_many` takes up to a limit at once; the receiver's `close` stops new sends and lets it drain what is there. `src/main.rs`: ```rust use nuclei::sync::mpsc; #[nuclei::main] async fn main() { // Bounded: a send waits while the channel holds 16 messages. let (tx, mut rx) = mpsc::channel::(16); for worker in 0..3 { let tx = tx.clone(); nuclei::spawn(async move { tx.send(format!("hello from {worker}")).await.unwrap(); }) .detach(); } // The channel closes when the last sender drops, and recv gives None. drop(tx); let mut got = Vec::new(); while let Some(message) = rx.recv().await { got.push(message); } got.sort(); assert_eq!(got, ["hello from 0", "hello from 1", "hello from 2"]); } ``` ## Permits, timeouts, weak senders `reserve` takes a slot before the value exists, so the send that uses the permit cannot fail; `reserve_many` takes several, `reserve_owned` one that moves. `try_send` never waits, and `send_timeout` gives up after a while and gives the value back. A weak sender does not keep the channel open. `src/main.rs`: ```rust use std::time::Duration; use nuclei::sync::mpsc::{self, error::TrySendError}; #[nuclei::main] async fn main() { let (tx, mut rx) = mpsc::channel::(1); // reserve takes a slot first; the send that uses it cannot fail. let permit = tx.reserve().await.unwrap(); permit.send(1); // The one slot is taken: try_send says so instead of waiting. assert!(matches!(tx.try_send(2), Err(TrySendError::Full(2)))); // send_timeout gives up after a while, and gives the value back. let late = tx.send_timeout(3, Duration::from_millis(10)).await; assert_eq!(late.unwrap_err().into_inner(), 3); assert_eq!(rx.recv().await, Some(1)); // A weak sender does not keep the channel open. let weak = tx.downgrade(); drop(tx); assert!(weak.upgrade().is_none()); assert_eq!(rx.recv().await, None); } ``` ## oneshot `src/main.rs`: ```rust use nuclei::sync::oneshot; #[nuclei::main] async fn main() { // One value, once: a reply to a request. let (reply, answer) = oneshot::channel::(); nuclei::spawn(async move { let _ = reply.send(6 * 7); }) .detach(); assert_eq!(answer.await.unwrap(), 42); // A sender dropped before it sent: the receiver gets an error. let (reply, answer) = oneshot::channel::(); drop(reply); assert!(answer.await.is_err()); } ``` The sender can wait for the receiver to go away (`closed`), to stop work nobody will read. ## broadcast `src/main.rs`: ```rust use nuclei::sync::broadcast::{self, error::RecvError}; #[nuclei::main] async fn main() { // Every receiver sees every message sent after it subscribed. let (tx, mut first) = broadcast::channel::<&str>(2); let mut second = tx.subscribe(); tx.send("deploy").unwrap(); assert_eq!(first.recv().await, Ok("deploy")); assert_eq!(second.recv().await, Ok("deploy")); // A receiver that falls more than the capacity behind is told how far. for event in ["a", "b", "c"] { tx.send(event).unwrap(); } assert_eq!(first.recv().await, Err(RecvError::Lagged(1))); assert_eq!(first.recv().await, Ok("b")); // A weak sender: it can send again once upgraded, while a strong one lives. let weak = tx.downgrade(); assert!(weak.upgrade().is_some()); drop(tx); assert!(weak.upgrade().is_none()); } ``` `subscribe` on the sender, and `resubscribe` on a receiver, add a receiver that takes what is sent from then on. A `WeakSender` sends only once upgraded, and does not keep the channel open. ## watch `src/main.rs`: ```rust use nuclei::sync::watch; #[nuclei::main] async fn main() { // One value, read by many; each receiver sees the latest. let (tx, mut rx) = watch::channel(1u32); let watcher = nuclei::spawn(async move { // changed waits for a value this receiver has not seen. rx.changed().await.unwrap(); *rx.borrow_and_update() }); tx.send_modify(|v| *v += 1); assert_eq!(watcher.await, 2); assert_eq!(*tx.borrow(), 2); } ``` `borrow` reads the current value; `changed` waits for one this receiver has not seen, and `wait_for` for one that passes a test. `send_modify` changes the value in place, and `send_if_modified` tells the receivers only when the change says so. ## A mesh between workers [`mesh(n, capacity)`](https://nuclei.rs/api/nuclei/sync/mesh/fn.mesh.html) joins `n` parties, each ordered pair by a bounded `mpsc` channel of `capacity` messages, and gives each its [`Party`](https://nuclei.rs/api/nuclei/sync/mesh/struct.Party.html): its senders to every party and its receivers from every party, indexed by party. A party may send to itself, so a send to whoever owns a key needs no special case. The mesh only builds channels: put each party in a task of its own, here one per worker with [`spawn_on_worker`](https://nuclei.rs/learn/runtime.html#workers). `src/main.rs`: ```rust use nuclei::RuntimeHandle; use nuclei::sync::mesh::mesh; #[nuclei::main(threads = 3)] async fn main() -> std::io::Result<()> { let runtime = RuntimeHandle::current(); // One party per worker, each pair joined by a channel of 8 messages each way. let parties = mesh::(runtime.workers(), 8); let mut tasks = Vec::new(); for (worker, mut party) in parties.into_iter().enumerate() { tasks.push(runtime.spawn_on_worker(worker, async move { // Every party sends its index to every party, itself included. for to in 0..party.parties() { party.send_to(to, party.index()).await.unwrap(); } // recv ends once every party, this one too, has closed its senders. party.close_senders(); let mut heard = Vec::new(); while let Some((from, index)) = party.recv().await { assert_eq!(from, index); heard.push(from); } heard.sort_unstable(); heard })?); } for task in tasks { assert_eq!(task.await, [0, 1, 2]); } Ok(()) } ``` - `send_to(to, value)` waits for room on the channel to `to` alone: a full channel holds up no other pair. `try_send_to` never waits. - `recv()` takes from any party, with its index, round robin from the one after the last that delivered, so a party that floods cannot starve a quiet one. `recv_from(from)` takes from one party. - `recv()` ends once every channel into the party has ended. The party's sender to itself keeps one open, so a party calls `close_senders` when it is done sending. - `n` parties make `n * n` channels. ## Cancellation tokens A [`CancellationToken`](https://nuclei.rs/api/nuclei/sync/struct.CancellationToken.html) tells any number of tasks to stop. Clones share one state; a child token is cancelled with its parent, and on its own without touching the parent. `src/main.rs`: ```rust use std::time::Duration; use nuclei::sync::CancellationToken; use nuclei::time::sleep; #[nuclei::main] async fn main() { let shutdown = CancellationToken::new(); // A child token is cancelled with its parent, and alone too. let worker_token = shutdown.child_token(); let worker = nuclei::spawn(async move { // The work, or None once the token is cancelled first. worker_token .run_until_cancelled(sleep(Duration::from_secs(60))) .await }); shutdown.cancel(); assert_eq!(worker.await, None); assert!(shutdown.is_cancelled()); // A drop guard cancels its token when it drops, on every way out of a scope. let token = CancellationToken::new(); { let _guard = token.clone().drop_guard(); } token.cancelled().await; } ``` - `cancelled().await` waits for it; `is_cancelled()` checks. - `run_until_cancelled(future)` gives `Some(output)`, or `None` once the token is cancelled first, dropping the future. - `drop_guard()` cancels the token when the guard drops, however the scope ends. [A clean shutdown](https://nuclei.rs/learn/production.html#shutdown) puts it to work. # Processes Run programs with async pipes, and take signals as streams. Chapter 13 of 17. The page: https://nuclei.rs/learn/processes.html ## Running a program [`nuclei::process::Command`](https://nuclei.rs/api/nuclei/process/struct.Command.html) is shaped like std's: arguments, environment, working directory and standard streams, then `output` (collect what it printed), `status` (only the exit) or `spawn` (a `Child` to talk to). The examples run Unix programs. `src/main.rs`: ```rust use nuclei::process::Command; #[nuclei::main] async fn main() -> std::io::Result<()> { // Run a program to its end and collect what it printed. let output = Command::new("echo").arg("hello").output().await?; assert!(output.status.success()); assert_eq!(output.stdout, b"hello\n"); // Or just its exit status, its streams left as they are. let status = Command::new("true").status().await?; assert_eq!(status.code(), Some(0)); Ok(()) } ``` A shard's driver watches each child's exit (a pidfd on Linux, a process event on kqueue, a wait on the process handle on Windows) and reaps it, so a wait holds no thread, and a child whose `Child` was dropped leaves no zombie behind. ## Talking to a child Piped streams are async: write to `stdin`, read `stdout` and `stderr` with the [IO helpers](https://nuclei.rs/learn/io.html#traits). Dropping `stdin` ends the child's input; `wait` closes it first too, so a child that reads to the end can exit. `src/main.rs`: ```rust use nuclei::io::{AsyncReadExt, AsyncWriteExt}; use nuclei::process::{Command, Stdio}; #[nuclei::main] async fn main() -> std::io::Result<()> { let mut child = Command::new("sort") .stdin(Stdio::piped()) .stdout(Stdio::piped()) .spawn()?; // The pipes are async streams. let mut stdin = child.stdin.take().expect("piped"); stdin.write_all(b"pear\napple\nfig\n").await?; // Dropping stdin ends the child's input, so sort can finish. drop(stdin); let mut stdout = child.stdout.take().expect("piped"); let mut sorted = String::new(); stdout.read_to_string(&mut sorted).await?; assert_eq!(sorted, "apple\nfig\npear\n"); assert!(child.wait().await?.success()); Ok(()) } ``` ## Ending a child `src/main.rs`: ```rust use nuclei::process::Command; #[nuclei::main] async fn main() -> std::io::Result<()> { // kill ends the child and waits for it to go. let mut child = Command::new("sleep").arg("60").spawn()?; child.kill().await?; assert!(!child.wait().await?.success()); // start_kill only starts it; wait to see it go. let mut child = Command::new("sleep").arg("60").spawn()?; child.start_kill()?; child.wait().await?; // kill_on_drop: dropping the Child ends the process too. let child = Command::new("sleep").arg("60").kill_on_drop(true).spawn()?; drop(child); Ok(()) } ``` - `kill().await` ends the child (SIGKILL on Unix, TerminateProcess on Windows) and waits for its exit; `start_kill()` only starts it. - `kill_on_drop(true)` ends the child when its `Child` is dropped before it exits. By default a dropped child runs on. - `try_wait()` gives the status if the child exited, without waiting. - For what `Command` does not mirror, `as_std_mut` reaches std's command underneath, `spawn_with` starts the child through your own code, and `into_std` takes std's command back. ## Ctrl-C `nuclei::signal::ctrl_c()` completes when the process gets a Ctrl-C: SIGINT on Unix, the console's CTRL_C_EVENT on Windows. Listening starts with its first poll, and replaces the default action, which would end the process. `src/main.rs`: ```rust use std::time::Duration; use nuclei::time::sleep; #[nuclei::main] async fn main() { nuclei::select! { _ = nuclei::signal::ctrl_c() => println!("stopping on Ctrl-C"), _ = sleep(Duration::from_millis(100)) => println!("the work finished first"), } } ``` Output: ``` the work finished first ``` ## Unix signals `signal::unix::signal(kind)` listens to one signal from then on, as a stream: `recv().await` ends once it was delivered, once or more, since the last `recv`. `SignalKind` names the usual ones (`hangup`, `terminate`, `user_defined1`, ...) and `from_raw` any other. `src/main.rs`: ```rust use nuclei::process::Command; use nuclei::signal::unix::{SignalKind, signal}; #[nuclei::main] async fn main() -> std::io::Result<()> { // Listening starts here; the signal's default action is replaced. let mut reload = signal(SignalKind::user_defined1())?; let mut hangup = signal(SignalKind::hangup())?; // Send this process SIGUSR1, as an operator would with `kill -USR1`. let pid = std::process::id().to_string(); Command::new("kill").args(["-USR1", &pid]).status().await?; nuclei::select! { _ = reload.recv() => println!("reloading"), _ = hangup.recv() => println!("hung up"), } Ok(()) } ``` Output: ``` reloading ``` ## Windows console events `signal::windows` has `ctrl_c`, `ctrl_break`, `ctrl_close`, `ctrl_logoff` and `ctrl_shutdown`, each a `CtrlEvent` whose `recv().await` ends at the next such event. # Production Every runtime setting, the hooks, the counters, a clean shutdown, and tests. Chapter 14 of 17. The page: https://nuclei.rs/learn/production.html ## Every runtime setting Every setting is optional, and an unset one takes a default that needs no configuration to work well. Set them on a `Builder`, then `build` a runtime of your own or `build_global` the default one ([Runtime](https://nuclei.rs/learn/runtime.html#default)). `build` checks them all before it starts a thread: a value outside what the runtime can work with fails with `InvalidInput` naming the setting, its value and the range it must be in ([Errors](https://nuclei.rs/learn/errors.html#setting)). `src/main.rs`: ```rust use std::time::Duration; use nuclei::runtime::{RngSeed, UnhandledPanic}; use nuclei::{Builder, IoBackend}; fn main() -> std::io::Result<()> { let backend = if cfg!(target_os = "linux") { IoBackend::Epoll } else { nuclei::Proactor::backend() }; let runtime = Builder::new() .worker_threads(4) // default: one per core .max_worker_threads(8) // default: four times worker_threads .pin_workers(true) // Linux; default true .thread_name("edge") // default nuclei-worker, nuclei-blocking .thread_stack_size(2 * 1024 * 1024) // default 8 MiB .max_nesting(64) // default 256 .max_blocking_threads(128) // default 512 .thread_keep_alive(Duration::from_secs(5)) // default 10 seconds .local_spawn_margin(16) // default 32 .handoff_after(Some(Duration::from_millis(20))) // default 10 ms .io_buffer_cap(32 * 1024 * 1024) // default 64 MiB per worker .write_behind_linger(Duration::from_secs(5)) // default one minute .event_interval(31) // default 61 .global_queue_interval(15) // default 31 .max_io_events_per_tick(256) // default: all that are ready .disable_lifo_slot() .rng_seed(RngSeed::from_bytes(b"replay")) .unhandled_panic(UnhandledPanic::ShutdownRuntime) .backend(backend) // default: the process's choice .build()?; let used = runtime.block_on(runtime.spawn(async { nuclei::Proactor::backend() })); println!("workers run {used:?}"); runtime.shutdown_timeout(Duration::from_secs(1)); Ok(()) } ``` | Setting | What it sets (its default) | | --- | --- | | [`worker_threads`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.worker_threads) | Worker threads, each running one shard. The default is one per core of worker_cores when it is set, else one per core the process may run on, held to max_worker_threads when that is set. Zero runs every task on the thread that spawns it, while that thread is inside block_on. | | [`max_worker_threads`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.max_worker_threads) | The most worker threads the runtime may start over its life, the ones it starts with included (default four times the workers it starts with): what spawn_more_threads may add up to. A stopped worker’s place is not taken again. Below an explicit worker_threads, build fails with InvalidInput; with worker_threads unset, the runtime starts with at most this many. | | [`pin_workers`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.pin_workers) | Whether each worker thread is pinned to its own core (Linux and Windows; default true). A pinned shard keeps its cache warm; unpinned, the scheduler may move it. With worker_cores set, each worker is pinned to its core of that list, or, unpinned, runs on any core of the list. | | [`worker_cores`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.worker_cores) | The cores the workers run on, in the order the workers take them: worker k runs on cores[k % cores.len()], pinned to it, or, with pin_workers(false), on any core of the list. The worker count defaults to the list’s length. Every core must be one the process may run on and the list must not be empty; build fails with InvalidInput otherwise. Pinning takes effect on Linux and Windows; elsewhere the list sets the worker count and is checked against the cores the machine has. | | [`blocking_cores`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.blocking_cores) | The cores the blocking pool’s threads run on, any of them (default: the cores of the thread that builds the runtime). Checked as worker_cores are, and in effect on Linux and Windows. | | [`thread_name`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.thread_name) | The name of every thread the runtime starts (default nuclei-worker and nuclei-blocking). | | [`thread_name_fn`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.thread_name_fn) | A function naming each thread the runtime starts. | | [`thread_stack_size`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.thread_stack_size) | The stack size of every thread the runtime starts, in bytes (default 8 MiB). At least 128 KiB; build fails with InvalidInput below. | | [`max_nesting`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.max_nesting) | How deep block_on may nest on one thread (default 256). A call one level deeper panics instead of running the thread out of stack. At least 1; build fails with InvalidInput below. | | [`max_blocking_threads`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.max_blocking_threads) | The most threads the blocking pool runs at once (default 512). At least 1; build fails with InvalidInput below. | | [`thread_keep_alive`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.thread_keep_alive) | How long an idle blocking thread waits for work before it exits (default 10 seconds). | | [`local_spawn_margin`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.local_spawn_margin) | How many more live tasks than another shard a spawning thread’s shard may hold and still take a task it spawns (default 32). A task spawned on a worker stays on it (so a task that waits for what it spawned keeps it on its own thread), and a task spawned on any other thread goes to that thread’s home shard (where its spawns went last), unless that shard holds that many more tasks than a shard picked at random; then it goes to the other, which becomes the home. Zero balances strictly; a larger margin keeps more work together. | | [`handoff_after`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.handoff_after) | How long one poll of a task may run on a worker before the worker’s other tasks go on without it (default 10 ms; None: never). | | [`io_buffer_cap`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.io_buffer_cap) | The most bytes each worker’s IO buffers hold (default 64 MiB). Reads that had to wait land in these buffers, and writes that had to wait are copied into them; at the cap, IO waits for buffers to come back, so a worker’s IO memory never grows past it. On io_uring the worker’s receive buffers count against the cap too (recv_buffers of recv_buffer_size bytes, 4 MiB by default, with their descriptors), and the rest is left for the others. A cap that leaves less than 512 bytes beside the receive buffers is refused with InvalidInput when the worker starts; otherwise any value is accepted, and a request that cannot fit under a cap too small for it fails with an error that names this setting. | | [`write_behind_linger`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.write_behind_linger) | How long the bytes a dropped handle wrote behind may take to reach the kernel (default one minute): a task delivers them after the drop, as the kernel delivers what a closed socket holds. Past it the rest is given up, and a TCP stream’s connection is reset, so its peer reads an error rather than the end of a stream cut short. get_mut and into_inner wait for the bytes as long at most, and the runtime’s drop waits for the tasks. More than zero; build fails with InvalidInput at zero. | | [`zero_copy_threshold`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.zero_copy_threshold) | The least a write_zero_copy must have left to send for its next send to go zero-copy, in bytes (default 1 MiB): below it, the kernel copies the bytes, as it does for every write. Copying costs less than pinning the pages for small writes; where the threshold pays depends on the machine and its network. Only io_uring sends zero-copy, on the runtime’s workers: every value is accepted, and 0 sends every write zero-copy, usize::MAX none. | | [`send_file_chunk`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.send_file_chunk) | The most bytes one call of a send_file sends (default 1 MiB). Each call runs on the blocking pool and may stall on a cold page there, so this bounds how long a pool thread is held, and how much a cancelled send_file still sends after its future went; where the system has no call for it, each chunk is read into a buffer of this size. From 1 byte to 0x7ffff000 (what one sendfile(2) sends); build fails with InvalidInput outside. | | [`event_interval`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.event_interval) | Task runs between a worker’s looks at its timers and IO when it is busy (default 61): lower answers IO sooner, higher runs tasks with fewer interruptions. At least 1; build fails with InvalidInput at 0. | | [`global_queue_interval`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.global_queue_interval) | Task runs between the times a worker takes from its inbox (tasks woken by other threads) before its own queue (default 31). At least 1; build fails with InvalidInput at 0. | | [`max_io_events_per_tick`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.max_io_events_per_tick) | The most IO events a worker takes from its driver in one look (default: all that are ready). At least 1; build fails with InvalidInput at 0. | | [`disable_lifo_slot`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.disable_lifo_slot) | Turns off each worker’s LIFO slot, where a task woken by the task running on the worker goes to run next. Without it the woken task goes to the back of the worker’s queue: fairer when the queue is long, slower for a task that hands work to another and waits for it. | | [`rng_seed`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.rng_seed) | Seeds the runtime’s random choices, so that they repeat run after run; see RngSeed. | | [`unhandled_panic`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.unhandled_panic) | What the runtime does when one of its tasks panics (default UnhandledPanic::Ignore: the panic goes to the task’s handle). | | [`start_paused`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.start_paused) | Whether the runtime’s clock starts paused (default false): see time::pause. Its tasks then see time move only as they advance it, or as it jumps to the next timer whenever every shard of the runtime is idle. | | [`backend`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.backend) | The kernel interface the workers run their IO on. Unset, it is the process’s: the backend of NucleiConfig, or io_uring where the kernel lets this process have it and the platform’s poller otherwise. A backend this process cannot have makes build fail with the reason. A non-empty NUCLEI_BACKEND overrides it. | | [`io_uring`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.io_uring) | The settings the workers’ io_uring rings are made with, for this runtime alone (default: the process’s, from Proactor::with_config). Checked in build, which fails with InvalidInput naming the setting a ring cannot work with, on every platform; only the workers of a runtime whose IO runs on io_uring make rings. Whether io_uring is chosen when no backend is named is decided with these settings. The shard of a thread inside block_on keeps the process’s settings: it serves every runtime the thread enters. | | [`record_latencies`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.record_latencies) | Counts how long each task poll runs, and (with the io-stats feature) how long each IO operation waits for the kernel, by kind, in log2 histograms each worker’s ShardStats carries (default false: no clock is read for it). The poll times cost two clock reads and a call around every poll, of every runtime of the process while one records them; the IO latencies two clock reads per operation of this runtime’s workers. | A busy worker looks at its timers and IO every `event_interval` task runs, and also, checked every 16 runs, whenever its last look is more than a millisecond old, so a run of slow tasks cannot keep IO waiting for long. ## Hooks A runtime calls hooks of yours on its threads and around its tasks: for metrics, tracing or thread setup. Each task hook is given the task's `Id`. `src/main.rs`: ```rust use std::sync::Arc; use std::sync::atomic::{AtomicUsize, Ordering}; use nuclei::Builder; fn main() -> std::io::Result<()> { let spawned = Arc::new(AtomicUsize::new(0)); let polls = Arc::new(AtomicUsize::new(0)); let runtime = Builder::new() .worker_threads(2) .on_thread_start(|| println!("worker up")) .on_task_spawn({ let spawned = Arc::clone(&spawned); move |_task| { spawned.fetch_add(1, Ordering::Relaxed); } }) .on_before_task_poll({ let polls = Arc::clone(&polls); move |_task| { polls.fetch_add(1, Ordering::Relaxed); } }) .build()?; runtime.block_on(async { for n in 0..10 { nuclei::spawn(async move { n }).await; } }); assert_eq!(spawned.load(Ordering::Relaxed), 10); assert!(polls.load(Ordering::Relaxed) >= 10); Ok(()) } ``` | Hook | When it is called | | --- | --- | | [`on_thread_start`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.on_thread_start) | Called on each thread the runtime starts (workers and blocking-pool threads), on that thread, before it does anything else. | | [`on_thread_stop`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.on_thread_stop) | Called on each thread the runtime starts, on that thread, as it ends (after a panic too). | | [`on_thread_park`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.on_thread_park) | Called on a worker thread just before it sleeps with nothing to run. | | [`on_thread_unpark`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.on_thread_unpark) | Called on a worker thread just after it wakes from a sleep. | | [`on_task_spawn`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.on_task_spawn) | Called with each task this runtime spawns (not the blocking pool’s jobs), on the spawning thread, once the task exists. | | [`on_before_task_poll`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.on_before_task_poll) | Called just before each poll of a task of this runtime, on the thread that polls it. | | [`on_after_task_poll`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.on_after_task_poll) | Called just after each poll of a task of this runtime, on the thread that polled it. | | [`on_task_terminate`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.on_task_terminate) | Called when a task of this runtime is done with: its future completed or was dropped by a cancel, on the thread that dropped it. | | [`on_long_poll`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.on_long_poll) | Called with each poll of a task of this runtime that its worker’s watch sees run past handoff_after, on the watch’s own thread: the task’s id and name say which one holds its worker up. The task is the innermost one whose poll was running when the watch looked; the poll may have ended by the time the hook runs. A poll is told once, unless a block_on inside it ran a long poll of its own and the shard stayed on that thread: the outer poll may then be told again as it goes on. The shard is handed on first, so a slow hook delays no rescue, but every other worker waits for its next look while the hook runs: keep it short. A panic in it is caught (after the panic hook reported it) and the watch goes on. Only workers are watched; with handoff_after(None) build fails with InvalidInput. | A hook runs in the middle of the runtime's work: keep it short, and never panic in one. Task hooks get a `TaskMeta`: the task's `id()`, and its `name()` when `task::Builder` gave one. `on_long_poll` finds the task that holds a worker up: it is called, on the watch's own thread, for each poll that runs past `handoff_after` ([Tasks](https://nuclei.rs/learn/tasks.html#handoff)). `src/main.rs`: ```rust use std::sync::mpsc; use std::time::Duration; use nuclei::{Builder, task}; fn main() -> std::io::Result<()> { let (told, heard) = mpsc::channel(); let runtime = Builder::new() .worker_threads(1) .handoff_after(Some(Duration::from_millis(10))) // Called on the watch's thread for a poll that runs past the handoff. .on_long_poll(move |task| { let _ = told.send(task.name().map(str::to_owned)); }) .build()?; let name = runtime.block_on(async move { let blocker = task::Builder::new() .name("report") .worker(0) .spawn(async move { // A blocking call inside a poll, on purpose: it waits for the report of itself. heard.recv_timeout(Duration::from_secs(10)) })?; Ok::<_, std::io::Error>(blocker.await) })?; assert_eq!(name, Ok(Some("report".to_owned()))); Ok(()) } ``` ## The io_uring configuration The rings are configured once per process, before any IO, with `Proactor::with_config`: every runtime starts from these settings. A second call, or one after IO has started (which configures the defaults), panics. [`Builder::io_uring`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.io_uring) gives one runtime's workers ring settings of their own instead, and `build` answers a setting a ring cannot work with as an error rather than a panic. `src/main.rs`: ```rust use nuclei::Proactor; use nuclei::config::{IoUringConfiguration, NucleiConfig}; fn main() { // Once, before any IO: the io_uring settings of every shard. Proactor::with_config(NucleiConfig { iouring: IoUringConfiguration { queue_len: 4096, recv_buffers: 512, recv_buffer_size: 16 * 1024, ..IoUringConfiguration::default() }, backend: None, // io_uring where this process may have it, else the poller }); nuclei::block_on(async { println!("IO runs on {:?}", Proactor::backend()); }); } ``` | Field | What it sets (its default) | | --- | --- | | [`queue_len`](https://nuclei.rs/api/nuclei/config/struct.IoUringConfiguration.html#structfield.queue_len) | Entries in each ring’s submission queue (default 2048); the completion queue holds twice as many. | | [`recv_buffers`](https://nuclei.rs/api/nuclei/config/struct.IoUringConfiguration.html#structfield.recv_buffers) | Buffers in each shard’s group for multishot receives (default 256, or queue_len rounded up to a power of two when that is fewer): the kernel fills one as bytes arrive, so a stream’s receive stays armed for every arrival and a receive that waits holds no buffer of its own. | | [`recv_buffer_size`](https://nuclei.rs/api/nuclei/config/struct.IoUringConfiguration.html#structfield.recv_buffer_size) | The size in bytes of each of those buffers (default 16384); for UDP, one that holds the largest datagram expected. | | [`sqpoll_wake_interval`](https://nuclei.rs/api/nuclei/config/struct.IoUringConfiguration.html#structfield.sqpoll_wake_interval) | With Some(ms), a kernel thread polls the submission queue and sleeps after that many idle milliseconds: fewer system calls for more CPU (default None: no polling thread). | | [`iopoll_enabled`](https://nuclei.rs/api/nuclei/config/struct.IoUringConfiguration.html#structfield.iopoll_enabled) | Busy-waits for file completions instead of taking interrupts (default false): lower latency for more CPU, and only for files opened with O_DIRECT on file systems that support polling. | | [`per_numa_bounded_worker_count`](https://nuclei.rs/api/nuclei/config/struct.IoUringConfiguration.html#structfield.per_numa_bounded_worker_count) | The most io_uring worker threads per NUMA node for IO bound in time, on regular files and block devices (default Some(256)). | | [`per_numa_unbounded_worker_count`](https://nuclei.rs/api/nuclei/config/struct.IoUringConfiguration.html#structfield.per_numa_unbounded_worker_count) | The most io_uring worker threads per NUMA node for IO that may never complete, such as on sockets (default Some(512)). | | [`aggressive_poll`](https://nuclei.rs/api/nuclei/config/struct.IoUringConfiguration.html#structfield.aggressive_poll) | Has no effect, and is kept so code written against earlier versions builds (default false). Every shard already looks at its ring’s completions while it spins before it sleeps, and a kernel thread that polls the submission queue is sqpoll_wake_interval; no third kind of polling is left for this flag to turn on. | Four presets fill the struct from a queue length: `interrupt_driven` (the one to pick when unsure), `low_latency_driven` and `kernel_poll_only` (a kernel submission thread), and `io_poll`. `NucleiConfig::backend` is the backend of every runtime that names none. The sizes are checked where they take effect: `queue_len` at least 64, `recv_buffers` 0 or a power of two below twice `queue_len`, and `recv_buffer_size` from 512 bytes to 1 GiB while there are receive buffers. A value outside fails the first runtime built with it, with `InvalidInput` naming the setting. ## Counters `nuclei::stats()` takes a snapshot of every shard alive in the process (each runtime's workers, then the shard of each thread in `block_on`) and of the blocking pools; `Runtime::stats` takes one of a single runtime's workers and pool. It reads the shards without stopping them; most counts are published by a shard as it is about to wait for work, and by a busy one every few hundred task runs. `src/main.rs`: ```rust #[nuclei::main] async fn main() { nuclei::spawn(async {}).await; let stats = nuclei::stats(); for shard in &stats.shards { println!( "{:?} on {:?}: {} tasks, {} polls, {} IO in flight, {} of {} buffer bytes", shard.worker, shard.backend, shard.tasks, shard.polls, shard.ops_in_flight, shard.buffer_bytes, shard.buffer_cap, ); for (kind, count) in shard.errors.iter() { println!(" {count} errors of kind {kind:?}"); } } println!("{} blocking threads", stats.blocking_threads); } ``` | Field | What it counts | | --- | --- | | [`worker`](https://nuclei.rs/api/nuclei/stats/struct.ShardStats.html#structfield.worker) | The shard’s place among its runtime’s workers; None for the shard of a thread that runs block_on. | | [`runtime`](https://nuclei.rs/api/nuclei/stats/struct.ShardStats.html#structfield.runtime) | The runtime the shard is a worker of; None for the shard of a thread that runs block_on, which serves every runtime the thread enters. | | [`backend`](https://nuclei.rs/api/nuclei/stats/struct.ShardStats.html#structfield.backend) | The kernel interface the shard’s IO runs on. | | [`tasks`](https://nuclei.rs/api/nuclei/stats/struct.ShardStats.html#structfield.tasks) | Tasks placed on the shard and not done yet. | | [`polls`](https://nuclei.rs/api/nuclei/stats/struct.ShardStats.html#structfield.polls) | Task polls the shard has run (published). | | [`queue_depth`](https://nuclei.rs/api/nuclei/stats/struct.ShardStats.html#structfield.queue_depth) | Runnables waiting in the shard’s own queue, its LIFO slot included (published). | | [`remote_wakes`](https://nuclei.rs/api/nuclei/stats/struct.ShardStats.html#structfield.remote_wakes) | Runnables of the shard’s tasks it took from other threads: a task woken there, or spawned onto it from there (published). | | [`parks`](https://nuclei.rs/api/nuclei/stats/struct.ShardStats.html#structfield.parks) | Times the shard slept with nothing to run (published). | | [`parked`](https://nuclei.rs/api/nuclei/stats/struct.ShardStats.html#structfield.parked) | Time the shard spent asleep, in all (published). | | [`busy`](https://nuclei.rs/api/nuclei/stats/struct.ShardStats.html#structfield.busy) | Time since the shard was made that it did not spend asleep: running tasks, driving its IO and timers, spinning before a park (from the published time asleep). | | [`ops_in_flight`](https://nuclei.rs/api/nuclei/stats/struct.ShardStats.html#structfield.ops_in_flight) | IO operations the shard handed to the kernel that have not ended: on io_uring the operations submitted, on IOCP the ones issued. A readiness poller (epoll, kqueue) hands the kernel none, as its driver makes each call once the descriptor is ready: 0 there (published). | | [`cq_overflows`](https://nuclei.rs/api/nuclei/stats/struct.ShardStats.html#structfield.cq_overflows) | Times the shard found completions the kernel was holding for want of room in the ring’s completion queue (none is lost: the kernel keeps them until there is room); 0 on other backends (published). | | [`buffer_bytes`](https://nuclei.rs/api/nuclei/stats/struct.ShardStats.html#structfield.buffer_bytes) | Bytes the shard’s IO buffers hold: its pool’s, in use and free, and on io_uring its receive buffers’ (published). | | [`buffer_cap`](https://nuclei.rs/api/nuclei/stats/struct.ShardStats.html#structfield.buffer_cap) | The most bytes the shard’s IO buffers may hold, its receive buffers included (Builder::io_buffer_cap). | | [`buffer_exhausted`](https://nuclei.rs/api/nuclei/stats/struct.ShardStats.html#structfield.buffer_exhausted) | Times a buffer was wanted while every byte under the pool’s cap was in use; the IO waits for one to come back (published). | | [`timers`](https://nuclei.rs/api/nuclei/stats/struct.ShardStats.html#structfield.timers) | Timers armed on the shard (published). | | [`handoffs`](https://nuclei.rs/api/nuclei/stats/struct.ShardStats.html#structfield.handoffs) | Times the shard went to another thread because the thread running it stayed in one poll past Builder::handoff_after. | | [`longest_poll`](https://nuclei.rs/api/nuclei/stats/struct.ShardStats.html#structfield.longest_poll) | The longest poll the runtime saw on the shard, at the resolution of its watch (a quarter of the handoff threshold); zero when no poll lasted that long, or with the handoff off. | | [`budget_yields`](https://nuclei.rs/api/nuclei/stats/struct.ShardStats.html#structfield.budget_yields) | Times a task’s poll on the shard spent its budget of operations and yielded to the shard’s other tasks (see task::coop). | | [`poll_times`](https://nuclei.rs/api/nuclei/stats/struct.ShardStats.html#structfield.poll_times) | How long each task poll on the shard ran, while its runtime records it (Builder::record_latencies); None when it does not, which is not a shard with no polls. | | [`errors`](https://nuclei.rs/api/nuclei/stats/struct.ShardStats.html#structfield.errors) | Errors of IO run on the shard. | `Stats` also has `blocking_threads` and `blocking_queue_depth`, `off_shard_errors` for IO run on threads that run no shard, and `receive_buffers_missing` for shards that started without the io_uring receive buffers they asked for. ## IO counts and latencies A runtime built with `record_latencies(true)` keeps a log2 [`Histogram`](https://nuclei.rs/api/nuclei/stats/struct.Histogram.html) of how long each task poll ran, in `ShardStats::poll_times`. With the `io-stats` feature ([Setup](https://nuclei.rs/learn/setup.html#features)) it can also count and time each worker's IO: - `Builder::count_io(true)` fills `ShardStats::io`, an `IoCounts`: reads and writes with the bytes of each, and accepts. - `record_latencies(true)` also fills `ShardStats::io_latencies`, an `IoLatencies`: the time from submission to completion of reads, writes, accepts, connects and file calls. On epoll and kqueue it is `None`: the driver makes each call once the kernel says it is ready, so there is no wait in the kernel to time. `src/main.rs`: ```rust use std::time::Duration; use nuclei::Builder; use nuclei::io::{AsyncReadExt, AsyncWriteExt}; use nuclei::net::{TcpListener, TcpStream}; fn main() -> std::io::Result<()> { let runtime = Builder::new() .worker_threads(1) .count_io(true) // the io-stats feature .record_latencies(true) // poll times; with io-stats, IO latencies too .build()?; runtime.block_on(runtime.spawn(async { let listener = TcpListener::bind("127.0.0.1:0").await?; let mut client = TcpStream::connect(listener.local_addr()?).await?; let (mut server, _) = listener.accept().await?; client.write_all(b"ping").await?; client.flush().await?; let mut buf = [0u8; 4]; server.read_exact(&mut buf).await?; Ok::<_, std::io::Error>(()) }))?; // A worker publishes its counts each time it looks at its IO and timers: a sleep makes it look. runtime.block_on(runtime.spawn(nuclei::time::sleep(Duration::from_millis(1)))); let stats = runtime.stats(); let worker = &stats.shards[0]; let io = worker.io.unwrap(); assert_eq!((io.accepts, io.bytes_read, io.bytes_written), (1, 4, 4)); let polls = worker.poll_times.as_ref().unwrap(); for (from, until, samples) in polls.buckets() { println!("{samples} polls of {from:?} to {until:?}"); } // Readiness backends (epoll, kqueue) have no wait in the kernel to time. if let Some(io) = &worker.io_latencies { let timed = [&io.reads, &io.writes, &io.accepts, &io.connects, &io.files]; println!( "{} IO operations timed", timed.iter().map(|h| h.count()).sum::() ); } Ok(()) } ``` Without the feature, no IO path carries counting or timing code, and these items do not exist. With it, every IO call costs a few instructions, counted or not, so leave it off where nobody reads the counts. The API reference here is built with `io-stats` on, so it lists them; they exist only with `io-stats` on. ## A clean shutdown A server stops taking connections when asked, lets the open ones finish, and gives up after a deadline. A `CancellationToken` carries the request to every task, Ctrl-C raises it, a `JoinSet` holds the connections, and `timeout` bounds the drain. `src/main.rs`: ```rust use std::time::Duration; use nuclei::net::{TcpListener, TcpStream}; use nuclei::sync::CancellationToken; use nuclei::task::JoinSet; use nuclei::time::timeout; async fn serve(listener: TcpListener, shutdown: CancellationToken) -> std::io::Result<()> { let mut connections = JoinSet::new(); // Take connections until the token is cancelled. while let Some(accepted) = shutdown.run_until_cancelled(listener.accept()).await { let (stream, _) = accepted?; let stop = shutdown.child_token(); connections.spawn(async move { let mut buf = [0u8; 1024]; while let Some(Ok(n @ 1..)) = stop.run_until_cancelled(stream.recv(&mut buf)).await { let _ = stream.send(&buf[..n]).await; } }); } // Let the open connections finish, for five seconds at most. let drained = timeout(Duration::from_secs(5), connections.join_all()).await; if drained.is_err() { eprintln!("some connections did not finish in time"); } Ok(()) } #[nuclei::main] async fn main() -> std::io::Result<()> { let listener = TcpListener::bind("127.0.0.1:0").await?; let addr = listener.local_addr()?; let shutdown = CancellationToken::new(); // Ctrl-C cancels the token. let on_ctrl_c = shutdown.clone(); nuclei::spawn(async move { if nuclei::signal::ctrl_c().await.is_ok() { on_ctrl_c.cancel(); } }) .detach(); let server = nuclei::spawn(serve(listener, shutdown.clone())); // Here a client comes and goes, then the program asks for the shutdown itself. let client = TcpStream::connect(addr).await?; client.send(b"hi").await?; let mut buf = [0u8; 2]; client.recv(&mut buf).await?; shutdown.cancel(); server.await } ``` ## Tests `#[nuclei::test]` makes an async test: its body runs in `block_on` on the default runtime, or on a runtime of its own with `threads = N` or `start_paused = true` ([paused time](https://nuclei.rs/learn/time.html#paused)). A test may return a `Result`, like any test. `tests/echo.rs`: ```rust use std::time::Duration; use nuclei::net::{TcpListener, TcpStream}; use nuclei::time::{self, Instant}; #[nuclei::test] async fn echoes_a_message() -> std::io::Result<()> { let listener = TcpListener::bind("127.0.0.1:0").await?; let addr = listener.local_addr()?; nuclei::spawn(async move { let (stream, _) = listener.accept().await?; let mut buf = [0u8; 64]; let n = stream.recv(&mut buf).await?; stream.send(&buf[..n]).await?; std::io::Result::Ok(()) }) .detach(); let client = TcpStream::connect(addr).await?; client.send(b"ping").await?; let mut buf = [0u8; 4]; client.recv(&mut buf).await?; assert_eq!(&buf, b"ping"); Ok(()) } // A runtime of its own with one worker, for a test that needs a known shape. #[nuclei::test(threads = 1)] async fn times_out() { let never = std::future::pending::<()>(); assert!( time::timeout(Duration::from_millis(10), never) .await .is_err() ); } // A paused clock: the day-long timeout passes at once. #[nuclei::test(start_paused = true)] async fn a_day_passes_at_once() { let start = Instant::now(); let never = std::future::pending::<()>(); assert!( time::timeout(Duration::from_secs(86_400), never) .await .is_err() ); assert_eq!(start.elapsed(), Duration::from_secs(86_400)); } ``` `#[nuclei::bench]` does the same for a benchmark on the nightly test harness. ## The earlier entry points Programs written against earlier versions set up the default runtime with `init` or `init_with_config`; both still work, on the shards. `GlobalExecutorConfig` sets the workers to start (`with_min_threads`, or from an environment variable with `with_env_var`), the most to run (`with_max_threads`) and their names. `spawn_more_threads` starts more workers, up to the maximum, and `stop_thread` drains one: it takes no new task and exits once its tasks are done. `src/main.rs`: ```rust use nuclei::GlobalExecutorConfig; fn main() { // The default runtime, set up the way earlier versions of nuclei did it. nuclei::init_with_config( GlobalExecutorConfig::default() .with_env_var("APP_WORKERS") // read the worker count from here first .with_min_threads(2) .with_max_threads(4), ); nuclei::block_on(async { let started = nuclei::spawn_more_threads(2).await.expect("workers start"); println!("started {started} more workers"); let stopped = nuclei::stop_thread().await; println!("stopped one: {stopped}"); }); } ``` Code that drove the proactor by hand still can: `Proactor::get().wait(max_events, timeout)` drives the calling thread's shard once, and `wake` ends every wait in progress. # Backends io_uring, epoll, kqueue and I/O completion ports: how one is picked, and what each does. Chapter 15 of 17. The page: https://nuclei.rs/learn/backends.html ## How the backend is picked The first of these that says something decides, when a runtime's first shard starts: 1. `NUCLEI_BACKEND`, when set and not empty: `auto`, `io_uring`, or the platform's poller by name (`epoll`, `kqueue`, `iocp`). 2. The runtime's own `Builder::backend`. 3. `NucleiConfig::backend`, the process's choice for every runtime that names none. 4. `auto`: io_uring where the kernel lets the process have the rings its shards use, the platform's poller otherwise. A backend named in any of these ways that the process cannot have fails with the reason; it never falls back. `Proactor::backend()` says which one the calling thread's shard runs. `src/main.rs`: ```rust use nuclei::{Builder, IoBackend, Proactor}; fn main() -> std::io::Result<()> { // What the process picked: NUCLEI_BACKEND if set, else io_uring where it may, else the poller. println!("default: {:?}", Proactor::backend()); // One runtime on the platform's poller, whatever the default is. let poller = if cfg!(target_os = "linux") { IoBackend::Epoll } else if cfg!(windows) { IoBackend::Iocp } else { IoBackend::Kqueue }; let runtime = Builder::new().worker_threads(1).backend(poller).build()?; let used = runtime.block_on(runtime.spawn(async { Proactor::backend() })); // It runs the poller, unless NUCLEI_BACKEND names another: the variable wins. if std::env::var_os("NUCLEI_BACKEND").is_none_or(|v| v.is_empty()) { assert_eq!(used, poller); } Ok(()) } ``` ## io_uring - Linux and Android 6.1 or later, with the `iouring` feature (on by default). The ring is Nuclei's own, on `libc` alone. - The probe is safe even under a seccomp filter that kills a process for calling `io_uring_setup`; where io_uring is refused (an older kernel, a container's policy), `auto` runs epoll. - Each shard owns one ring. A worker's ring takes submissions from whichever thread runs its shard, one at a time, since a [handoff](https://nuclei.rs/learn/tasks.html#handoff) may move the shard; the shard of a thread in `block_on`, and a worker with `handoff_after(None)`, use a single-issuer ring with deferred task work. A kernel submission thread (`sqpoll_wake_interval`) replaces both. - A stream keeps one multishot receive armed, and `accept_multi` one multishot accept, filled from the shard's receive group ([`recv_buffers`, `recv_buffer_size`](https://nuclei.rs/learn/production.html#iouring)). The group fits in half the completion queue, and an armed receive or accept that waits on an idle connection takes no room from other operations. - Regular files are read, written, synced and allocated with ring operations, at the handle's cursor or at an offset ([Files](https://nuclei.rs/learn/fs.html#positional)). A `write_zero_copy` of at least `zero_copy_threshold` bytes is sent without a copy. ## epoll - Linux, Android and illumos. On Linux it is what `auto` picks where io_uring cannot be had. - A readiness poller: the shard's driver makes each call when the descriptor may be ready, into the shard's buffers. Your code sees the same completion API. - Regular files run as jobs on the blocking pool: `pread` and `pwrite` (`preadv` and `pwritev` for several buffers), syncs and the space calls. A child's exit comes through its pidfd. ## kqueue - macOS, iOS, FreeBSD, NetBSD, OpenBSD and DragonFly. - A readiness poller, served like epoll; a child's exit comes through `EVFILT_PROC`, wakes through `EVFILT_USER`. - Regular files run on the blocking pool. ## I/O completion ports - Windows. One completion port per shard; operations are overlapped calls the kernel completes. - A handle takes std's TCP and UDP sockets, files, and a child's pipes. There are no Unix sockets on Windows. - A pipe or console opened for synchronous IO cannot complete on a port, so its calls run as jobs of the blocking pool and come back to the shard like the kernel's completions. - A TCP write, once issued, is always finished: a cancelled send there may have handed bytes to the network stack while saying it took none. - Timed waits use a high-resolution waitable timer where the system offers one, so timers are not rounded to the 15.6 ms system tick, and the handoff's watch acts at its threshold. ## What is tested where CI runs the suite on io_uring and on epoll on Linux 6.1, 6.6 and 6.12 and on the runner's own kernel, on kqueue on macOS, and on completion ports on Windows; it runs it under AddressSanitizer on both Linux backends. The examples on these pages run on Linux, on io_uring and on epoll. # Errors The messages you may meet, what each means, and the fix. Chapter 16 of 17. The page: https://nuclei.rs/learn/errors.html ## A spawned task never ran, or stopped halfway No message at all: the `Task` was dropped, and dropping a task cancels it. A loop that spawns per connection and throws the handle away cancels every connection at once. **Fix:** call `.detach()` on tasks nobody waits for, keep them in a `JoinSet`, or keep the handles and await them. See [Tasks](https://nuclei.rs/learn/tasks.html#lifetime). ## the task has no output `panic`: ``` the task has no output: it was cancelled or its runtime shut down before it completed, or it was awaited again after completing ``` A `Task` was awaited where it has no output to give: it was aborted, or its runtime was dropped before it completed. **Fix:** keep the runtime alive until its tasks are done, or await `task.join()` (a `JoinError` says why) or `task.fallible()` (`None`) instead. ## names no backend of this platform `panic`: ``` the default runtime could not start: NUCLEI_BACKEND=kqueue names no backend of this platform (use auto, epoll or io_uring) ``` `NUCLEI_BACKEND` holds a name this system has no backend for. The message lists the names that work here. **Fix:** set one of the names listed, or unset the variable. ## asks for io_uring, but `panic`: ``` the default runtime could not start: NUCLEI_BACKEND=io_uring asks for io_uring, but this build has no io_uring; leave it unset to use the poller ``` io_uring was asked for by name (`NUCLEI_BACKEND`, `Builder::backend` or `NucleiConfig`) and this process cannot have it; the reason follows *but*. Here the crate was built without the `iouring` feature; elsewhere it may be the kernel or a sandbox refusing the ring. A backend named by hand never falls back. **Fix:** leave the backend unset, so `auto` picks io_uring where it can; turn the `iouring` feature back on; or run where io_uring is allowed (Linux 6.1 or later, and a sandbox that permits it). ## the proactor is configured already `panic`: ``` the proactor is configured already: call `with_config` once, before any IO ``` `Proactor::with_config` was called twice, or after the first IO, `spawn` or `block_on`, which configures the defaults. **Fix:** call it once, first thing in a plain `fn main`, then enter the runtime with `nuclei::block_on`, as in [Production](https://nuclei.rs/learn/production.html#iouring). Under `#[nuclei::main]` the body already runs on the runtime. ## the default runtime is already running `error`: ``` the default runtime is already running ``` `Builder::build_global` returned this: a free function, the attribute or an earlier `build_global` started the default runtime first. **Fix:** call `build_global` before anything spawns, or build a `Runtime` of your own and use its methods. ## a setting is out of range `error`: ``` io_uring queue_len is 32; it must be at least 64 ``` `Builder::build` (or `build_global`) returned this as `InvalidInput`: a setting holds a value no runtime can work with, or one that does not fit with another (`max_worker_threads` below `worker_threads`, `on_long_poll` with `handoff_after(None)`). The message names the setting, the value and what it must be. The io_uring sizes set with `Proactor::with_config` are checked by the first runtime built with them. **Fix:** set a value in the range the message gives, or leave the setting unset for its default. [Every setting](https://nuclei.rs/learn/production.html#builder) states its range. ## worker does not exist `error`: ``` worker 4 does not exist: the runtime has started 4 workers ``` `spawn_on_worker`, `spawn_local_on_worker` or `task::Builder::worker` named a worker the runtime does not have; a worker that stopped answers *has stopped and takes no new task*. Both are `InvalidInput`, and the task was not spawned. **Fix:** name a worker from 0 to `workers()` less one, or use `on_each_worker` to reach every worker there is. See [Runtime](https://nuclei.rs/learn/runtime.html#workers). ## no shard-local value `panic`: ``` this code runs on no worker, so it has no shard-local value: use it in a task ``` A `shard_local!` value was used off the workers: in `block_on`'s own future, on the blocking pool, or on a thread of its own. Each worker has its own value and these places have none. `with` panics with this message; `try_with` answers it as a `ShardAccessError`. **Fix:** use the value in a task spawned on the runtime, or handle the error of `try_with`. See [Runtime](https://nuclei.rs/learn/runtime.html#shard-local). ## block_on is nested too deep `panic`: ``` block_on is nested 2 deep on one thread, the most allowed: each level runs on the thread's stack (raise the limit with `Builder::max_nesting`) ``` (Here the limit was set to 2.) Each nested `block_on` runs on the thread's stack, and one level past the limit panics before the stack would overflow. **Fix:** await instead of nesting where you can; raise `Builder::max_nesting` where you cannot. ## block_on never returns No message: a task called `block_on` on a future that waits for that very task. The task is not polled again until the call returns, so neither can finish. **Fix:** inside a task, wait for the other work with `.await`, not with `block_on`. ## Data seems lost, or an error came late Writes are taken into the stream's write-behind and sent by the driver, so a failed write can surface on a later write or on `flush`. **Fix:** `flush().await` (or `shutdown().await`) where you need to know the bytes reached the kernel. See [How it works](https://nuclei.rs/learn/proactive.html#buffers). ## A call of your own answers ResourceBusy `try_io` or `async_io` on a socket found bytes the handle had read ahead: a read of your own would skip them. **Fix:** read what the handle holds first (`try_read` until `WouldBlock`), then make your call. See [Readiness](https://nuclei.rs/learn/readiness.html#own-calls). ## A child's wait fails with ECHILD Something other than Nuclei reaped the child: the program ignores `SIGCHLD`, or calls `waitpid` itself. **Fix:** leave `SIGCHLD` at its default and let `Child::wait` reap your children. # Migrate Coming from a readiness-based runtime: where each piece is, and what behaves differently. Chapter 17 of 17. The page: https://nuclei.rs/learn/migrate.html ## The map Most names carry over; the import path changes. The last column is what to watch. | What you use today | In Nuclei | Mind | | --- | --- | --- | | An attribute on an async main or test | `#[nuclei::main]`, `#[nuclei::test]` | `threads = N` and `start_paused = true` give a runtime of its own. | | Run a future from synchronous code | `nuclei::block_on` | Allowed inside a task too: it nests and keeps the shard running. | | Spawn and keep a join handle | `nuclei::spawn` gives a `Task` | Awaiting gives `T` itself; `join()` gives `Result`. | | Drop the handle to let the task run on | `.detach()` | **Dropping a `Task` cancels it.** | | Abort a task, a join set | `abort()`, `abort_handle()`, `nuclei::task::JoinSet` | `cancel().await` also gives back an output that was ready. | | Blocking work, tasks that are not Send | `spawn_blocking`, `spawn_local` | No local set to create: a local task runs on the calling thread's shard. | | Spawn on a chosen worker, or on each | `RuntimeHandle::spawn_on_worker`, `on_each_worker` | A placed task stays on its worker for its whole life. See [Runtime](https://nuclei.rs/learn/runtime.html#workers). | | A value per worker thread | `nuclei::shard_local!` | It lives in the worker's shard and moves with it on a handoff; off the workers there is none. | | Task-local values, yielding, the budget | `nuclei::task_local!`, `task::yield_now`, `task::coop` | A task-local value is set with `scope` around the task's future. | | A runtime builder and handle | `nuclei::Builder`, `RuntimeHandle` | A handle does not keep the runtime running. See [every setting](https://nuclei.rs/learn/production.html#builder). | | TCP, UDP and Unix socket types | `nuclei::net` | std's own sockets inside; std's methods work through them. | | Socket builders, stream halves | `TcpSocket`, `UdpSocketBuilder`, `UnixSocket`, `split`, `into_split` | A shared reference to a stream reads and writes too. | | Shut one direction of a stream | `shut(how)`, `abort()` | `stream.shutdown(how)` is std's call through the handle, which goes around the bytes written behind. See [Networking](https://nuclei.rs/learn/net.html#shut). | | Read and write extension traits, copies, buffers | `nuclei::io` | On the `futures-io` traits; closing a write side is `shutdown`. | | Wait until readable, then try a read | `readable()`, `try_read()` | Rarely needed: `recv().await` completes the read for you. | | A descriptor of your own, by readiness | `nuclei::io::unix::AsyncFd` | The descriptor must be in non-blocking mode. | | Files and directories | `nuclei::fs` | `read_dir` gives entries with `next_entry().await`. | | Reads and writes at an offset | `read_at`, `write_at` on `&File` | The handle's own calls are async; std's `FileExt` calls through it block the worker. See [Files](https://nuclei.rs/learn/fs.html#positional). | | Sleep, timeout, interval, paused time | `nuclei::time` | A millisecond wheel; missed ticks burst by default. | | Locks, semaphores, channels, a cancellation token | `nuclei::sync` | The established names and signatures; they work under any executor. | | Channels and locks for tasks of one thread | `nuclei::sync::local` | Not `Send`, and cheaper for it: for `spawn_local` tasks of one shard. See [Sync](https://nuclei.rs/learn/sync.html#local). | | select!, join!, try_join! | `nuclei::select!`, `join!`, `try_join!` | `select!` starts at a random branch unless `biased;`. | | Ctrl-C, Unix signals, child processes | `nuclei::signal`, `nuclei::process` | A signal is a stream: `recv().await`. | ## Pitfalls ### Dropping a task cancels it The most common bug after a move. A task whose `Task` is dropped stops at its next `.await`, and never runs if it had not started. Every fire-and-forget spawn needs `.detach()`. See [Tasks](https://nuclei.rs/learn/tasks.html#lifetime). ### A write is taken, not delivered A write returns once its bytes are copied into the stream's write-behind. Code that writes and then exits, or expects an error right away, should `flush().await` or `shutdown().await`. See [How it works](https://nuclei.rs/learn/proactive.html#buffers). ### No work stealing A task stays on its shard, and no idle core takes work from a busy one. A poll that runs past `handoff_after` (10 ms by default) has the shard's other tasks go on on another thread of the same core ([Tasks](https://nuclei.rs/learn/tasks.html#handoff)), but the long poll still shares that core: give such work to `spawn_blocking`, or break it up. ### Buffers are copied, unless you lend them `recv` and `read` copy from the shard's buffer into your slice; writes copy into the write-behind. Where the copy matters, `read_owned` and `write_owned` lend the driver your own buffer, a vector or any [`IoBuf`](https://nuclei.rs/learn/io.html#owned). ### std's calls through the handle A socket or file is std's own object in a `Handle`, so std's methods are reachable through it. The ones that read, write or shut a stream go around the bytes the handle read ahead and wrote behind, and the blocking ones block the worker. Use the handle's own calls; [Networking](https://nuclei.rs/learn/net.html#std-calls) lists what each of std's does. ### Configure io_uring before any IO `Proactor::with_config` runs once, before the first IO, `spawn` or `block_on`; it panics otherwise. Configure from a plain `fn main`, then enter the runtime. # Nuclei 0.5.3: API reference Every public item of the crate `nuclei` with its definition and documentation, and every method, associated constant, variant and field with its signature and documentation; for traits, their implementors; for types, the traits they implement. Read from the rustdoc of commit 522f3a61affd58eb53d8a4d5a9505eff201b07a7 (x86_64-unknown-linux-gnu, default features), which is also served as HTML at https://nuclei.rs/api/nuclei/. ## Crate `nuclei` https://nuclei.rs/api/nuclei/index.html **Nuclei** A proactive async runtime: thread-per-core shards that run tasks and drive their own IO, timers and buffers. Every operation is completed for the task that asked for it; no task waits for readiness and then makes the call itself. IO runs on io_uring on Linux where the kernel allows it, else on epoll; on kqueue on macOS and the BSDs; and on I/O completion ports on Windows. [`spawn`](https://nuclei.rs/api/nuclei/runtime/fn.spawn.html), [`block_on`](https://nuclei.rs/api/nuclei/runtime/fn.block_on.html) and the rest place work on the process default [`Runtime`](https://nuclei.rs/api/nuclei/runtime/struct.Runtime.html), which starts on first use with no configuration; a [`Builder`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html) sets every setting for a runtime of one’s own. **What is where** - [`runtime`](https://nuclei.rs/api/nuclei/runtime/index.html): runtimes, their builder and handles, `block_on`, tasks placed on a worker one names ([`RuntimeHandle::spawn_on_worker`](https://nuclei.rs/api/nuclei/runtime/struct.RuntimeHandle.html#method.spawn_on_worker), [`RuntimeHandle::on_each_worker`](https://nuclei.rs/api/nuclei/runtime/struct.RuntimeHandle.html#method.on_each_worker)) and values kept per worker ([`shard_local!`](https://nuclei.rs/api/nuclei/macro.shard_local.html)). - [`task`](https://nuclei.rs/api/nuclei/task/index.html): spawning, [`JoinSet`](https://nuclei.rs/api/nuclei/task/struct.JoinSet.html), abort handles, ids and names, task-local values and yielding. - [`net`](https://nuclei.rs/api/nuclei/net/index.html): TCP, UDP and Unix sockets, names, socket options and builders, stream halves, `shut` and `abort`, and pipes. - [`io`](https://nuclei.rs/api/nuclei/io/index.html): [`Handle`](https://nuclei.rs/api/nuclei/io/struct.Handle.html), async operations on std’s own IO objects, and the helpers every stream gets: reads and writes as futures, copies, buffers, in-memory pipes, the standard streams and readiness; and the buffers the owned calls lend the driver ([`io::IoBuf`](https://nuclei.rs/api/nuclei/io/trait.IoBuf.html), [`io::AlignedBuf`](https://nuclei.rs/api/nuclei/io/struct.AlignedBuf.html), [`io::IoVecBuf`](https://nuclei.rs/api/nuclei/io/trait.IoVecBuf.html)). - [`fs`](https://nuclei.rs/api/nuclei/fs/index.html): files, whole-file calls, metadata and directories; IO at an offset, direct IO, syncs, the space calls and advisory locks. - [`time`](https://nuclei.rs/api/nuclei/time/index.html): sleeps on a millisecond wheel or to the microsecond, timeouts, intervals and a clock tests can pause. - [`sync`](https://nuclei.rs/api/nuclei/sync/index.html): locks, semaphores, notifications, once-cells, channels and cancellation tokens, for any executor; [`sync::local`](https://nuclei.rs/api/nuclei/sync/local/index.html), their cheaper twins for the tasks of one shard; and [`sync::mesh`](https://nuclei.rs/api/nuclei/sync/mesh/index.html), channels between every pair of a set of parties. - [`process`](https://nuclei.rs/api/nuclei/process/index.html) and [`signal`](https://nuclei.rs/api/nuclei/signal/index.html): child processes, signals and console events. - [`stats()`](https://nuclei.rs/api/nuclei/stats/fn.stats.html): a snapshot of what every shard is doing, with poll times when recorded and, with the `io-stats` feature, its IO counts and latencies. - [`select!`](https://nuclei.rs/api/nuclei/macro.select.html), [`join!`](https://nuclei.rs/api/nuclei/macro.join.html) and [`try_join!`](https://nuclei.rs/api/nuclei/macro.try_join.html) wait on several futures in one task; `#[nuclei::main]`, `#[nuclei::test]` and `#[nuclei::bench]` run an async function in the runtime. A call that needs the default runtime or the calling thread’s shard panics if that cannot start (the system refused its poller: no descriptors or memory left); [`Builder::build`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.build) and [`task::Builder`](https://nuclei.rs/api/nuclei/task/struct.Builder.html) answer the error instead. [`Builder::build`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.build) also checks every setting first, and answers one out of range as `InvalidInput` naming it. The guide, a path from the first program to production with an example that runs for every idea, is at [https://nuclei.rs/learn/](https://nuclei.rs/learn/). ```rust use nuclei::net::TcpListener; #[nuclei::main] async fn main() -> std::io::Result<()> { let listener = TcpListener::bind("127.0.0.1:7000").await?; loop { let (stream, _) = listener.accept().await?; nuclei::spawn(async move { let mut buf = [0u8; 1024]; while let Ok(n @ 1..) = stream.recv(&mut buf).await { if stream.send(&buf[..n]).await.is_err() { break; } } }) .detach(); } } ``` ### Re-exports - `pub use io::Handle;` - `pub use io::IoObject;` - `pub use net::TcpStreamGenerator;` - `pub use runtime::Builder;` - `pub use runtime::FallibleTask;` - `pub use runtime::Runtime;` - `pub use runtime::RuntimeHandle;` - `pub use runtime::Task;` - `pub use runtime::block_on;` - `pub use runtime::spawn;` - `pub use runtime::spawn_blocking;` - `pub use runtime::spawn_local;` - `pub use stats::stats;` - `pub use time::sleep;` - `pub use time::timeout;` ### Modules - [config](https://nuclei.rs/api/nuclei/config/index.html): The proactor’s configuration: the io_uring settings of every shard and the default backend. - [fs](https://nuclei.rs/api/nuclei/fs/index.html): The file system: files as [`File`](https://nuclei.rs/api/nuclei/fs/type.File.html) (std’s file in a [`Handle`](https://nuclei.rs/api/nuclei/io/struct.Handle.html)), [`OpenOptions`](https://nuclei.rs/api/nuclei/fs/struct.OpenOptions.html), the calls by path ([`read`](https://nuclei.rs/api/nuclei/fs/fn.read.html), [`write`](https://nuclei.rs/api/nuclei/fs/fn.write.html), [`metadata`](https://nuclei.rs/api/nuclei/fs/fn.metadata.html), [`rename`](https://nuclei.rs/api/nuclei/fs/fn.rename.html), [`copy`](https://nuclei.rs/api/nuclei/fs/fn.copy.html), …), directories ([`create_dir_all`](https://nuclei.rs/api/nuclei/fs/fn.create_dir_all.html), [`DirBuilder`](https://nuclei.rs/api/nuclei/fs/struct.DirBuilder.html), [`read_dir`](https://nuclei.rs/api/nuclei/fs/fn.read_dir.html) streamed a page at a time) and links. Calls by path, and a regular file’s calls beside its reads, writes, syncs and [`Handle::allocate`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.allocate), run on the blocking pool; [`Handle::try_lock_file`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.try_lock_file), which never waits, runs on the calling thread, and so does `File::open` on Linux for a regular file on a local file system whose path the kernel’s caches resolve at once. - [io](https://nuclei.rs/api/nuclei/io/index.html): IO: [`Handle`](https://nuclei.rs/api/nuclei/io/struct.Handle.html) (async operations on std’s sockets and files), the `futures-io` traits, and the utilities every stream gets: the reads and writes of [`AsyncReadExt`](https://nuclei.rs/api/nuclei/io/trait.AsyncReadExt.html), [`AsyncWriteExt`](https://nuclei.rs/api/nuclei/io/trait.AsyncWriteExt.html), [`AsyncBufReadExt`](https://nuclei.rs/api/nuclei/io/trait.AsyncBufReadExt.html) and [`AsyncSeekExt`](https://nuclei.rs/api/nuclei/io/trait.AsyncSeekExt.html) as futures, [`ReadBuf`](https://nuclei.rs/api/nuclei/io/struct.ReadBuf.html), [`copy`](https://nuclei.rs/api/nuclei/io/fn.copy.html) and [`copy_bidirectional`](https://nuclei.rs/api/nuclei/io/fn.copy_bidirectional.html), [`BufReader`](https://nuclei.rs/api/nuclei/io/struct.BufReader.html), [`BufWriter`](https://nuclei.rs/api/nuclei/io/struct.BufWriter.html) and [`BufStream`](https://nuclei.rs/api/nuclei/io/struct.BufStream.html), the in-memory pipes [`duplex`](https://nuclei.rs/api/nuclei/io/fn.duplex.html) and [`simplex`](https://nuclei.rs/api/nuclei/io/fn.simplex.html), [`split`](https://nuclei.rs/api/nuclei/io/fn.split.html), [`empty`](https://nuclei.rs/api/nuclei/io/fn.empty.html), [`repeat`](https://nuclei.rs/api/nuclei/io/fn.repeat.html) and [`sink`](https://nuclei.rs/api/nuclei/io/fn.sink.html), the process’s [`stdin`](https://nuclei.rs/api/nuclei/io/fn.stdin.html), [`stdout`](https://nuclei.rs/api/nuclei/io/fn.stdout.html) and [`stderr`](https://nuclei.rs/api/nuclei/io/fn.stderr.html), what the sockets’ readiness calls take and answer ([`Interest`](https://nuclei.rs/api/nuclei/io/struct.Interest.html), [`Ready`](https://nuclei.rs/api/nuclei/io/struct.Ready.html)), the caller’s own buffers the owned calls take and give back ([`IoBuf`](https://nuclei.rs/api/nuclei/io/trait.IoBuf.html), [`IoBufMut`](https://nuclei.rs/api/nuclei/io/trait.IoBufMut.html), [`IoVecBuf`](https://nuclei.rs/api/nuclei/io/trait.IoVecBuf.html), [`IoVecBufMut`](https://nuclei.rs/api/nuclei/io/trait.IoVecBufMut.html), [`AlignedBuf`](https://nuclei.rs/api/nuclei/io/struct.AlignedBuf.html)), and on unix [`AsyncFd`](https://nuclei.rs/api/nuclei/io/unix/struct.AsyncFd.html), a caller’s own descriptor driven by readiness. - [net](https://nuclei.rs/api/nuclei/net/index.html): Sockets: TCP, UDP and Unix domain, as [`Handle`](https://nuclei.rs/api/nuclei/io/struct.Handle.html)s. - [process](https://nuclei.rs/api/nuclei/process/index.html): Child processes: spawn one, wait for its exit and talk to it through async pipes. Child processes: a [`Command`](https://nuclei.rs/api/nuclei/process/struct.Command.html) spawns one, and its [`Child`](https://nuclei.rs/api/nuclei/process/struct.Child.html) waits for the exit without holding a thread and talks to it through async pipes. - [runtime](https://nuclei.rs/api/nuclei/runtime/index.html): nuclei’s own runtime: shards, tasks, `block_on`, `spawn` and the blocking pool. nuclei’s own runtime: thread-per-core shards that run tasks, a blocking pool, and the functions that place work on them. - [signal](https://nuclei.rs/api/nuclei/signal/index.html): Signals (unix) and console control events (Windows), as streams. Signals: a stream of the deliveries of one signal (unix) or console control event (Windows), and [`ctrl_c`](https://nuclei.rs/api/nuclei/signal/fn.ctrl_c.html). - [stats](https://nuclei.rs/api/nuclei/stats/index.html): What the runtime is doing: a snapshot of every shard’s counters, taken by [`stats()`](https://nuclei.rs/api/nuclei/stats/fn.stats.html), or of one runtime’s by [`Runtime::stats`](https://nuclei.rs/api/nuclei/runtime/struct.Runtime.html#method.stats). A runtime built with [`Builder::record_latencies`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.record_latencies) adds a [`Histogram`](https://nuclei.rs/api/nuclei/stats/struct.Histogram.html) of its poll times, and with the `io-stats` feature each worker’s IO counts and latencies. - [sync](https://nuclei.rs/api/nuclei/sync/index.html): Runtime-independent synchronization primitives: futures and wakers only, usable from any executor. Nuclei’s runtime-independent synchronization primitives: locks, a semaphore, events, a barrier, once-cells and channels that never block a thread. - [task](https://nuclei.rs/api/nuclei/task/index.html): Tasks: spawning, their handles and ids, cancellation from anywhere, and yielding. Tasks: spawning (named, or on a worker the caller names, or neither), their handles and ids, cancellation from anywhere, and yielding to the other tasks of the shard. - [time](https://nuclei.rs/api/nuclei/time/index.html): Time: sleeping, timeouts and intervals on the shard’s timer wheel. Time: sleeping, timeouts and intervals, on the timer wheel of the shard that polls them, and the runtime’s clock they read. ### Macros - [join](https://nuclei.rs/api/nuclei/macro.join.html): Waits on every future given, all at once, and gives their outputs as a tuple in the order written. - [select](https://nuclei.rs/api/nuclei/macro.select.html): Waits on several branches at once and runs the handler of the first to finish, dropping the others. - [shard_local](https://nuclei.rs/api/nuclei/macro.shard_local.html): Declares shard-local statics, each a [`ShardLocal`](https://nuclei.rs/api/nuclei/runtime/struct.ShardLocal.html) made with the expression given on its first use on each worker. - [task_local](https://nuclei.rs/api/nuclei/macro.task_local.html): Declares task-local keys, each a [`LocalKey`](https://nuclei.rs/api/nuclei/task/struct.LocalKey.html). - [try_join](https://nuclei.rs/api/nuclei/macro.try_join.html): Waits on every future given, all at once, each giving a `Result` with the same error type, and gives `Ok` with their outputs as a tuple in the order written, or the first error. ### Structs - [GlobalExecutorConfig](https://nuclei.rs/api/nuclei/struct.GlobalExecutorConfig.html): How the process default runtime is set up by [`init_with_config`](https://nuclei.rs/api/nuclei/fn.init_with_config.html). - [Proactor](https://nuclei.rs/api/nuclei/struct.Proactor.html): The process’s proactor: its configuration, and the IO of the calling thread’s shard. ### Enums - [IoBackend](https://nuclei.rs/api/nuclei/enum.IoBackend.html): Which kernel interface nuclei’s IO runs on. ### Functions - [drive](https://nuclei.rs/api/nuclei/fn.drive.html): Runs `future` to its end on the calling thread, driving its shard’s IO meanwhile: [`block_on`](https://nuclei.rs/api/nuclei/runtime/fn.block_on.html). - [init](https://nuclei.rs/api/nuclei/fn.init.html): Starts the process default runtime now, with every setting at its default, unless it is running already. - [init_with_config](https://nuclei.rs/api/nuclei/fn.init_with_config.html): Starts the process default runtime now, as `config` says, unless it is running already (then `config` is not used). - [spawn_more_threads](https://nuclei.rs/api/nuclei/fn.spawn_more_threads.html): Starts up to `count` more workers on the runtime this thread is inside (or the default one), within its maximum; returns how many started. - [stop_current_thread](https://nuclei.rs/api/nuclei/fn.stop_current_thread.html): Stops the worker this task runs on, as [`stop_thread`](https://nuclei.rs/api/nuclei/fn.stop_thread.html) stops one: false on a thread that is not a worker of its runtime, or when only the minimum runs. - [stop_thread](https://nuclei.rs/api/nuclei/fn.stop_thread.html): Stops one worker of the runtime this thread is inside (or the default one), unless only the runtime’s minimum runs: it takes no new task from now on and exits once the tasks it has are done. The task completes with whether a worker was stopped, once it takes no new task. ### Attribute Macros - [bench](https://nuclei.rs/api/nuclei/attr.bench.html): Enables an async benchmark function. - [main](https://nuclei.rs/api/nuclei/attr.main.html): Enables an async main function. - [test](https://nuclei.rs/api/nuclei/attr.test.html): Enables an async test function. ### macro `nuclei::join` https://nuclei.rs/api/nuclei/macro.join.html ```rust macro_rules! join { () => { ... }; (biased; $($future:expr),+ $(,)?) => { ... }; ($($future:expr),+ $(,)?) => { ... }; } ``` Waits on every future given, all at once, and gives their outputs as a tuple in the order written. The futures run concurrently in the task that awaits `join!`, not in tasks of their own: [`spawn`](https://nuclei.rs/api/nuclei/runtime/fn.spawn.html) them for parallelism. Each argument is an [`IntoFuture`](https://doc.rust-lang.org/1.99.1/core/future/into_future/trait.IntoFuture.html). Each poll polls the unfinished futures, starting one later each time; after `biased;` they are polled in the order written. `join!()` is `()`. **Examples** ```rust use nuclei::sync::oneshot; let (tx, rx) = oneshot::channel::(); // Each needs the other: only a concurrent wait finishes. let (sent, got) = nuclei::join!(async { tx.send(7) }, rx); assert!(sent.is_ok()); assert_eq!(got.unwrap(), 7); ``` ### macro `nuclei::select` https://nuclei.rs/api/nuclei/macro.select.html ```rust macro_rules! select { (biased;) => { ... }; (biased; $($branches:tt)+) => { ... }; () => { ... }; ($($branches:tt)+) => { ... }; } ``` Waits on several branches at once and runs the handler of the first to finish, dropping the others. Each branch is ` = (, if )? => `, with commas between the branches (optional after a block handler), and an `else => ` branch may come last. `select!`: 1. Evaluates every precondition; a branch whose precondition is `false` is disabled. 2. Evaluates every future expression (of disabled branches too), each an [`IntoFuture`](https://doc.rust-lang.org/1.99.1/core/future/into_future/trait.IntoFuture.html). 3. Polls the futures of the enabled branches, starting at a random one so no branch is favoured, or in the order written after `biased;`. 4. When a future finishes, its branch is disabled. If the output matches the branch’s pattern, the other futures are dropped and the handler runs with the pattern’s bindings; if not, the output is dropped and the other branches go on. 5. When every branch is disabled, the `else` expression is the value. The value of `select!` is the value of the handler that ran, so every handler and `else` has the same type. A `select!` takes at most 64 branches. **Panics** When every branch is disabled and there is no `else` branch. **Examples** ```rust use nuclei::sync::mpsc; let (tx, mut numbers) = mpsc::unbounded_channel::(); let (tick_tx, mut ticks) = mpsc::unbounded_channel::<()>(); tx.send(1).unwrap(); tx.send(2).unwrap(); tick_tx.send(()).unwrap(); drop((tx, tick_tx)); let (mut seen, mut ticked) = (Vec::new(), 0); // Each closed channel gives `None`, which disables its branch; once // both are closed, `else` ends the loop. loop { nuclei::select! { Some(n) = numbers.recv() => seen.push(n), Some(()) = ticks.recv() => ticked += 1, else => break, } } assert_eq!(seen, [1, 2]); assert_eq!(ticked, 1); ``` Patterns bind as written, `mut`, `ref` and `&` included, in every edition: ```rust let label = String::from("one"); let n = nuclei::select! { (mut n, ref name) = async { (1u32, &label) } => { n += name.len() as u32; n } }; assert_eq!(n, 4); ``` ### macro `nuclei::shard_local` https://nuclei.rs/api/nuclei/macro.shard_local.html ```rust macro_rules! shard_local { () => { ... }; ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr; $($rest:tt)*) => { ... }; ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr) => { ... }; } ``` Declares shard-local statics, each a [`ShardLocal`](https://nuclei.rs/api/nuclei/runtime/struct.ShardLocal.html) made with the expression given on its first use on each worker. ```rust use std::cell::Cell; nuclei::shard_local! { static REQUESTS: Cell = Cell::new(0); } let rt = nuclei::Runtime::builder().worker_threads(1).build().unwrap(); let count = rt.block_on(rt.spawn(async { REQUESTS.with(|n| n.set(n.get() + 1)); REQUESTS.with(Cell::get) })); assert_eq!(count, 1); ``` ### macro `nuclei::task_local` https://nuclei.rs/api/nuclei/macro.task_local.html ```rust macro_rules! task_local { () => { ... }; ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty; $($rest:tt)*) => { ... }; ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty) => { ... }; } ``` Declares task-local keys, each a [`LocalKey`](https://nuclei.rs/api/nuclei/task/struct.LocalKey.html). ```rust nuclei::task_local! { static REQUEST_ID: u64; } REQUEST_ID .scope(7, async { assert_eq!(REQUEST_ID.get(), 7); }) .await; ``` ### macro `nuclei::try_join` https://nuclei.rs/api/nuclei/macro.try_join.html ```rust macro_rules! try_join { () => { ... }; (biased; $($future:expr),+ $(,)?) => { ... }; ($($future:expr),+ $(,)?) => { ... }; } ``` Waits on every future given, all at once, each giving a `Result` with the same error type, and gives `Ok` with their outputs as a tuple in the order written, or the first error. On the first `Err`, `try_join!` gives it at once and drops the other futures. Otherwise it runs as [`join!`](https://nuclei.rs/api/nuclei/macro.join.html) does: concurrently, in the awaiting task, polled from one later each time or in order after `biased;`. `try_join!()` is `Ok(())`. **Examples** ```rust let ok: Result<(u8, u16), &str> = nuclei::try_join!(async { Ok(1) }, async { Ok(2) }); assert_eq!(ok, Ok((1, 2))); let failed: Result<(u8, ()), &str> = nuclei::try_join!(async { Err("first") }, std::future::pending::>()); assert_eq!(failed, Err("first")); ``` ### struct `nuclei::GlobalExecutorConfig` https://nuclei.rs/api/nuclei/struct.GlobalExecutorConfig.html ```rust pub struct GlobalExecutorConfig { /* private fields */ } ``` How the process default runtime is set up by [`init_with_config`](https://nuclei.rs/api/nuclei/fn.init_with_config.html). #### Implementations `impl GlobalExecutorConfig` ```rust pub fn with_env_var(self, env_var: &'static str) -> Self ``` Reads the number of workers to start from the environment variable `env_var`, before [`with_min_threads`](https://nuclei.rs/api/nuclei/struct.GlobalExecutorConfig.html#method.with_min_threads). ```rust pub fn with_min_threads(self, min_threads: usize) -> Self ``` Starts this many workers (default: one per core), the fewest [`stop_thread`](https://nuclei.rs/api/nuclei/fn.stop_thread.html) leaves running. ```rust pub fn with_max_threads(self, max_threads: usize) -> Self ``` The most workers the runtime may run, [`spawn_more_threads`](https://nuclei.rs/api/nuclei/fn.spawn_more_threads.html) included (default: four times the minimum). Zero runs every task on the thread inside `block_on`, with no worker at all. ```rust pub fn with_thread_name_fn( self, thread_name_fn: impl Fn() -> String + Send + Sync + 'static, ) -> Self ``` Names each worker thread. #### Trait Implementations - `impl Debug for GlobalExecutorConfig` - `impl Default for GlobalExecutorConfig` #### Auto Trait Implementations - `impl !RefUnwindSafe for GlobalExecutorConfig` - `impl !UnwindSafe for GlobalExecutorConfig` - `impl Freeze for GlobalExecutorConfig` - `impl Send for GlobalExecutorConfig` - `impl Sync for GlobalExecutorConfig` - `impl Unpin for GlobalExecutorConfig` - `impl UnsafeUnpin for GlobalExecutorConfig` ### struct `nuclei::Proactor` https://nuclei.rs/api/nuclei/struct.Proactor.html ```rust pub struct Proactor { /* private fields */ } ``` The process’s proactor: its configuration, and the IO of the calling thread’s shard. #### Implementations `impl Proactor` ```rust pub fn get() -> &'static Proactor ``` The proactor, with the default configuration unless [`with_config`](https://nuclei.rs/api/nuclei/struct.Proactor.html#method.with_config) set one first. ```rust pub fn with_config(config: NucleiConfig) -> &'static Proactor ``` Sets the proactor’s configuration, and returns the proactor. It is the default every runtime starts from; [`Builder::io_uring`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.io_uring) gives one runtime ring settings of its own, checked when it is built. **Panics** When the proactor was configured already, or used (which configures it with the defaults): a configuration is set once, before any IO. The signature returns the proactor itself, so it has no error to answer; `Builder::io_uring` answers its error instead. ```rust pub fn config(&self) -> &NucleiConfig ``` The configuration in place. ```rust pub fn wake(&self) ``` Ends every [`wait`](https://nuclei.rs/api/nuclei/struct.Proactor.html#method.wait) in progress at once. ```rust pub fn wait( &self, max_event_size: usize, duration: Option, ) -> Result ``` Drives the calling thread’s shard once: runs its ready tasks, waits for IO (up to `duration`; `None` until some comes or [`wake`](https://nuclei.rs/api/nuclei/struct.Proactor.html#method.wake)), handling at most `max_event_size` events, and runs the tasks the IO woke. Returns how many IO events it handled. **Errors** When the thread’s shard cannot start, or its poller fails. ```rust pub fn backend() -> IoBackend ``` The backend the calling thread’s shard runs its IO on; on a thread that runs none, the one of every runtime that names none (the platform’s poller when the backend named cannot be had: the shards then fail with the reason). #### Trait Implementations - `impl Debug for Proactor` #### Auto Trait Implementations - `impl Freeze for Proactor` - `impl RefUnwindSafe for Proactor` - `impl Send for Proactor` - `impl Sync for Proactor` - `impl Unpin for Proactor` - `impl UnsafeUnpin for Proactor` - `impl UnwindSafe for Proactor` ### enum `nuclei::IoBackend` https://nuclei.rs/api/nuclei/enum.IoBackend.html ```rust pub enum IoBackend { Kqueue, Epoll, IoUring, Iocp, } ``` Which kernel interface nuclei’s IO runs on. #### Variants ```rust Kqueue ``` kqueue (macOS and the BSDs). ```rust Epoll ``` epoll (Linux). ```rust IoUring ``` io_uring (Linux). ```rust Iocp ``` I/O completion ports (Windows). #### Trait Implementations - `impl Clone for IoBackend` - `impl Copy for IoBackend` - `impl Debug for IoBackend` - `impl Eq for IoBackend` - `impl Hash for IoBackend` - `impl PartialEq for IoBackend` - `impl StructuralPartialEq for IoBackend` #### Auto Trait Implementations - `impl Freeze for IoBackend` - `impl RefUnwindSafe for IoBackend` - `impl Send for IoBackend` - `impl Sync for IoBackend` - `impl Unpin for IoBackend` - `impl UnsafeUnpin for IoBackend` - `impl UnwindSafe for IoBackend` ### fn `nuclei::drive` https://nuclei.rs/api/nuclei/fn.drive.html ```rust pub fn drive(future: impl Future) -> T ``` Runs `future` to its end on the calling thread, driving its shard’s IO meanwhile: [`block_on`](https://nuclei.rs/api/nuclei/runtime/fn.block_on.html). ### fn `nuclei::init` https://nuclei.rs/api/nuclei/fn.init.html ```rust pub fn init() ``` Starts the process default runtime now, with every setting at its default, unless it is running already. ### fn `nuclei::init_with_config` https://nuclei.rs/api/nuclei/fn.init_with_config.html ```rust pub fn init_with_config(config: GlobalExecutorConfig) ``` Starts the process default runtime now, as `config` says, unless it is running already (then `config` is not used). A runtime that cannot start is reported at the `error` level of the [`log`](https://docs.rs/log) facade, and the default runtime stays unstarted: the next call that needs it starts it with every setting at its default. [`Builder::build_global`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.build_global) answers the error instead. ### fn `nuclei::spawn_more_threads` https://nuclei.rs/api/nuclei/fn.spawn_more_threads.html ```rust pub async fn spawn_more_threads(count: usize) -> Result ``` Starts up to `count` more workers on the runtime this thread is inside (or the default one), within its maximum; returns how many started. **Errors** When a worker’s poller cannot be made or its thread cannot start. ### fn `nuclei::stop_current_thread` https://nuclei.rs/api/nuclei/fn.stop_current_thread.html ```rust pub fn stop_current_thread() -> Task ``` Stops the worker this task runs on, as [`stop_thread`](https://nuclei.rs/api/nuclei/fn.stop_thread.html) stops one: false on a thread that is not a worker of its runtime, or when only the minimum runs. ### fn `nuclei::stop_thread` https://nuclei.rs/api/nuclei/fn.stop_thread.html ```rust pub fn stop_thread() -> Task ``` Stops one worker of the runtime this thread is inside (or the default one), unless only the runtime’s minimum runs: it takes no new task from now on and exits once the tasks it has are done. The task completes with whether a worker was stopped, once it takes no new task. ### attr `nuclei::bench` https://nuclei.rs/api/nuclei/attr.bench.html ```rust #[bench] ``` Enables an async benchmark function. The harness times runs of the body of the async function, each on the runtime’s `block_on` (with `threads = N` the runtime is built once, before the first); the benchmark function itself takes the harness, so the annotated function takes no parameters. Benchmarks need the nightly test harness: write `#![feature(test)]` and `extern crate test;` at the crate root (so the example is not compiled here). **Examples** ```rust #[nuclei::bench] async fn spawns_one() { nuclei::spawn(async {}).detach(); } ``` ### attr `nuclei::main` https://nuclei.rs/api/nuclei/attr.main.html ```rust #[main] ``` Enables an async main function. The body of the async function runs on the runtime’s `block_on`; with `threads = N` the runtime is built with N worker threads, where 0 runs everything on the `block_on` thread. **Examples** ```rust #[nuclei::main] async fn main() -> std::io::Result<()> { Ok(()) } ``` ### attr `nuclei::test` https://nuclei.rs/api/nuclei/attr.test.html ```rust #[test] ``` Enables an async test function. The body of the async function runs on the runtime’s `block_on`; with `threads = N` the test builds its own runtime with N worker threads, where 0 runs everything on the `block_on` thread. **Examples** ```rust #[nuclei::test] async fn adds_up() -> std::io::Result<()> { assert_eq!(2 + 2, 4); Ok(()) } ``` ## Module `nuclei::config` https://nuclei.rs/api/nuclei/config/index.html The proactor’s configuration: the io_uring settings of every shard and the default backend. ### Structs - [IoUringConfiguration](https://nuclei.rs/api/nuclei/config/struct.IoUringConfiguration.html): The settings of every shard’s io_uring ring (Linux 6.1 or later). - [NucleiConfig](https://nuclei.rs/api/nuclei/config/struct.NucleiConfig.html): Nuclei’s proactor configuration: the io_uring settings of every shard, and the backend of every runtime that names none. It is set once, before any IO, with [`Proactor::with_config`](https://nuclei.rs/api/nuclei/struct.Proactor.html#method.with_config); a runtime with io_uring settings of its own takes them from [`Builder::io_uring`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.io_uring) instead. ### struct `nuclei::config::IoUringConfiguration` https://nuclei.rs/api/nuclei/config/struct.IoUringConfiguration.html ```rust pub struct IoUringConfiguration { pub queue_len: u32, pub sqpoll_wake_interval: Option, pub per_numa_bounded_worker_count: Option, pub per_numa_unbounded_worker_count: Option, pub aggressive_poll: bool, pub iopoll_enabled: bool, pub recv_buffers: u16, pub recv_buffer_size: u32, } ``` The settings of every shard’s io_uring ring (Linux 6.1 or later). The default is [`interrupt_driven`](https://nuclei.rs/api/nuclei/config/struct.IoUringConfiguration.html#method.interrupt_driven) with 2048 queue entries and the io-wq worker limits `Some(256)` and `Some(512)`. #### Fields `queue_len: u32` Entries in each ring’s submission queue (default 2048); the completion queue holds twice as many. At least 64, the floor a ring is shrunk to when the system has no memory for more; a smaller value is refused as the configuration’s mistake when the first shard starts. The kernel rounds the count up to a power of two and clamps it to its own maximum (32768 on current kernels), so a larger value is accepted and gets what the kernel allows. `sqpoll_wake_interval: Option` With `Some(ms)`, a kernel thread polls the submission queue and sleeps after that many idle milliseconds: fewer system calls for more CPU (default `None`: no polling thread). Before version 5.11 of the Linux kernel, to successfully use this feature, the application must register a set of files to be used for IO through io_uring_register(2) using the `IORING_REGISTER_FILES` opcode. Failure to do so will result in submitted IO being errored with EBADF. The presence of this feature can be detected by the `IORING_FEAT_SQPOLL_NONFIXED` feature flag. In version 5.11 and later, it is no longer necessary to register files to use this feature. 5.11 also allows using this as non-root, if the user has the CAP_SYS_NICE capability. In 5.13 this requirement was also relaxed, and no special privileges are needed for SQPOLL in newer kernels. Certain stable kernels older than 5.13 may also support unprivileged SQPOLL. A shorter interval keeps the kernel thread awake more, for more CPU; a longer one lets it sleep, and a submission after it slept wakes it. `per_numa_bounded_worker_count: Option` The most io_uring worker threads per NUMA node for IO bound in time, on regular files and block devices (default `Some(256)`). `Some(0)` leaves the kernel’s limit as it is; with `None` the kernel limits them to the ring’s submission entries or four times the online CPUs, whichever is smaller. `per_numa_unbounded_worker_count: Option` The most io_uring worker threads per NUMA node for IO that may never complete, such as on sockets (default `Some(512)`). `Some(0)` leaves the kernel’s limit as it is; with `None` the process’s task limit (`RLIMIT_NPROC`) bounds them. `aggressive_poll: bool` Has no effect, and is kept so code written against earlier versions builds (default `false`). Every shard already looks at its ring’s completions while it spins before it sleeps, and a kernel thread that polls the submission queue is [`sqpoll_wake_interval`](https://nuclei.rs/api/nuclei/config/struct.IoUringConfiguration.html#structfield.sqpoll_wake_interval); no third kind of polling is left for this flag to turn on. `iopoll_enabled: bool` Busy-waits for file completions instead of taking interrupts (default `false`): lower latency for more CPU, and only for files opened with `O_DIRECT` on file systems that support polling. `recv_buffers: u16` Buffers in each shard’s group for multishot receives (default 256, or [`queue_len`](https://nuclei.rs/api/nuclei/config/struct.IoUringConfiguration.html#structfield.queue_len) rounded up to a power of two when that is fewer): the kernel fills one as bytes arrive, so a stream’s receive stays armed for every arrival and a receive that waits holds no buffer of its own. The buffers, with their descriptors, count against the shard’s [`io_buffer_cap`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.io_buffer_cap) for as long as the shard lives, and the shard’s own pool gets the rest; a group that leaves the pool less than 512 bytes is refused as the configuration’s mistake when the shard starts, and one the system has no memory for fails the shard’s start with `OutOfMemory`. 0 turns multishot receives off, and each read then takes a buffer of the shard’s own pool for its receive. Otherwise a power of two from 1 to 32768 and below twice `queue_len`, so the group never takes more than half the completion queue (twice `queue_len`, rounded up to a power of two); any other value is refused as the configuration’s mistake when the first shard starts. A ring the system could only make with fewer entries than `queue_len` (it had no memory for more) gets a group cut to the same rule. A kernel that refuses provided buffer rings makes the default backend choice pick the poller; 0 keeps io_uring there. Ubuntu’s 6.8 kernels from 6.8.0-136 on refuse every valid registration: a backport inverted the check of its reserved words ([https://bugs.launchpad.net/ubuntu/+source/linux/+bug/2162843](https://bugs.launchpad.net/ubuntu/+source/linux/+bug/2162843)). `recv_buffer_size: u32` The size in bytes of each of those buffers (default 16384); for UDP, one that holds the largest datagram expected. From 512 (smaller buffers split a stream into chunks of a few packets each) to 1 GiB; a value outside is refused as the configuration’s mistake when the first shard starts. Not checked while `recv_buffers` is 0. `recv_buffers` buffers of this size count against the shard’s [`io_buffer_cap`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.io_buffer_cap), as said there. A receive is stopped once the bytes it handed out and its reader has not taken pass an eighth of the group (at least one buffer), and asked for again when its reader catches up. What the kernel took for it before the stop stays with it, so a reader with a long backlog may hold more until it reads; other receives take buffers of the shard’s own pool meanwhile. #### Implementations `impl IoUringConfiguration` ```rust pub fn interrupt_driven(queue_len: u32) -> Self ``` No polling: a completion wakes its shard by interrupt. The one to pick when unsure. ```rust pub fn low_latency_driven(queue_len: u32) -> Self ``` A kernel thread polls the submission queue and sleeps after 2 idle milliseconds: lower latency under steady traffic, for more CPU. ```rust pub fn kernel_poll_only(queue_len: u32) -> Self ``` A kernel thread polls the submission queue and sleeps after 2 idle milliseconds, as [`low_latency_driven`](https://nuclei.rs/api/nuclei/config/struct.IoUringConfiguration.html#method.low_latency_driven). ```rust pub fn io_poll(queue_len: u32) -> Self ``` Busy-waits for file completions ([`iopoll_enabled`](https://nuclei.rs/api/nuclei/config/struct.IoUringConfiguration.html#structfield.iopoll_enabled)): low-latency IO on files opened with `O_DIRECT`. #### Trait Implementations - `impl Clone for IoUringConfiguration` - `impl Debug for IoUringConfiguration` - `impl Default for IoUringConfiguration` #### Auto Trait Implementations - `impl Freeze for IoUringConfiguration` - `impl RefUnwindSafe for IoUringConfiguration` - `impl Send for IoUringConfiguration` - `impl Sync for IoUringConfiguration` - `impl Unpin for IoUringConfiguration` - `impl UnsafeUnpin for IoUringConfiguration` - `impl UnwindSafe for IoUringConfiguration` ### struct `nuclei::config::NucleiConfig` https://nuclei.rs/api/nuclei/config/struct.NucleiConfig.html ```rust pub struct NucleiConfig { pub iouring: IoUringConfiguration, pub backend: Option, } ``` Nuclei’s proactor configuration: the io_uring settings of every shard, and the backend of every runtime that names none. It is set once, before any IO, with [`Proactor::with_config`](https://nuclei.rs/api/nuclei/struct.Proactor.html#method.with_config); a runtime with io_uring settings of its own takes them from [`Builder::io_uring`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.io_uring) instead. #### Fields `iouring: IoUringConfiguration` The settings every shard’s io_uring ring is made with. `backend: Option` The kernel interface every runtime that names none runs its IO on ([`Builder::backend`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.backend) names one for one runtime). `None` (the default) picks io_uring where the kernel lets this process have it, and the platform’s poller otherwise. Having it means every kernel feature a shard’s ring needs with this configuration: the buffer ring for multishot receives while [`recv_buffers`](https://nuclei.rs/api/nuclei/config/struct.IoUringConfiguration.html#structfield.recv_buffers) is not 0, and the table of fixed files. A backend named here that this process cannot have makes the first shard fail with the reason. A non-empty `NUCLEI_BACKEND` overrides it. #### Trait Implementations - `impl Clone for NucleiConfig` - `impl Debug for NucleiConfig` - `impl Default for NucleiConfig` #### Auto Trait Implementations - `impl Freeze for NucleiConfig` - `impl RefUnwindSafe for NucleiConfig` - `impl Send for NucleiConfig` - `impl Sync for NucleiConfig` - `impl Unpin for NucleiConfig` - `impl UnsafeUnpin for NucleiConfig` - `impl UnwindSafe for NucleiConfig` ## Module `nuclei::fs` https://nuclei.rs/api/nuclei/fs/index.html The file system: files as [`File`](https://nuclei.rs/api/nuclei/fs/type.File.html) (std’s file in a [`Handle`](https://nuclei.rs/api/nuclei/io/struct.Handle.html)), [`OpenOptions`](https://nuclei.rs/api/nuclei/fs/struct.OpenOptions.html), the calls by path ([`read`](https://nuclei.rs/api/nuclei/fs/fn.read.html), [`write`](https://nuclei.rs/api/nuclei/fs/fn.write.html), [`metadata`](https://nuclei.rs/api/nuclei/fs/fn.metadata.html), [`rename`](https://nuclei.rs/api/nuclei/fs/fn.rename.html), [`copy`](https://nuclei.rs/api/nuclei/fs/fn.copy.html), …), directories ([`create_dir_all`](https://nuclei.rs/api/nuclei/fs/fn.create_dir_all.html), [`DirBuilder`](https://nuclei.rs/api/nuclei/fs/struct.DirBuilder.html), [`read_dir`](https://nuclei.rs/api/nuclei/fs/fn.read_dir.html) streamed a page at a time) and links. Calls by path, and a regular file’s calls beside its reads, writes, syncs and [`Handle::allocate`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.allocate), run on the blocking pool; [`Handle::try_lock_file`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.try_lock_file), which never waits, runs on the calling thread, and so does `File::open` on Linux for a regular file on a local file system whose path the kernel’s caches resolve at once. A regular file’s reads and writes, at the handle’s own cursor or at an offset of the caller’s ([`Handle::read_at`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.read_at), [`Handle::write_at`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.write_at) and their forms, which many tasks may make at once on one handle, and [`Handle::read_many_at`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.read_many_at), many reads in one call), its syncs ([`Handle::sync_all`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.sync_all), [`Handle::sync_data`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.sync_data), [`Handle::sync_range`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.sync_range)) and [`Handle::allocate`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.allocate) are operations of the shard’s ring on io_uring and jobs of the blocking pool on the other backends (see `file`). A file opened for direct IO (`O_DIRECT`, `FILE_FLAG_NO_BUFFERING`) is read and written with exactly the caller’s lengths and offsets, never through the handle’s read-ahead or write-behind. A `File` that is not a regular file (a FIFO, a terminal, a pipe) is a byte stream the shard’s driver serves like a socket (on Windows, through the completion port, or through jobs of the blocking pool for a handle opened for synchronous IO). Reads and writes at the cursor are `AsyncRead` and `AsyncWrite` on the handle and on a shared reference to it (both share the cursor, as `&File` shares its offset); `AsyncBufRead` and `AsyncSeek` are on the handle. `read_owned`, `write_owned`, `read_at_owned`, `write_at_owned` and the vectored `read_vectored_owned` and `write_vectored_owned` take the caller’s buffers (any [`IoBuf`](https://nuclei.rs/api/nuclei/io/trait.IoBuf.html) or [`IoBufMut`](https://nuclei.rs/api/nuclei/io/trait.IoBufMut.html), an [`AlignedBuf`](https://nuclei.rs/api/nuclei/io/struct.AlignedBuf.html) for direct IO) and give them back, so the bytes are read into them and written from them with no copy. Beside those, a regular file can be asked to change the space a range uses ([`Handle::allocate`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.allocate): reserve, keep the length, punch a hole, zero), to write a range back ([`Handle::sync_range`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.sync_range)), to copy a range into another file in the kernel where the system can ([`Handle::copy_range_to`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.copy_range_to)), and to take an advisory lock without blocking the worker ([`Handle::lock_file`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.lock_file), [`Handle::try_lock_file`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.try_lock_file), [`Handle::unlock_file`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.unlock_file)). A file’s name in its directory needs [`sync_dir`](https://nuclei.rs/api/nuclei/fs/fn.sync_dir.html) to survive a crash. To replace a file atomically: write a temporary file in the same directory, `sync_all` it, [`rename`](https://nuclei.rs/api/nuclei/fs/fn.rename.html) it over the target, then [`sync_dir`](https://nuclei.rs/api/nuclei/fs/fn.sync_dir.html) the directory. ### Structs - [DirBuilder](https://nuclei.rs/api/nuclei/fs/struct.DirBuilder.html): How to create a directory: recursively or not, and with which mode. - [DirEntry](https://nuclei.rs/api/nuclei/fs/struct.DirEntry.html): An entry of a directory. - [FileTimes](https://nuclei.rs/api/nuclei/fs/struct.FileTimes.html): Representation of the various timestamps on a file. - [FileType](https://nuclei.rs/api/nuclei/fs/struct.FileType.html): A structure representing a type of file with accessors for each file type. It is returned by [`Metadata::file_type`](https://nuclei.rs/api/nuclei/fs/struct.Metadata.html#method.file_type) method. - [Metadata](https://nuclei.rs/api/nuclei/fs/struct.Metadata.html): Metadata information about a file. - [OpenOptions](https://nuclei.rs/api/nuclei/fs/struct.OpenOptions.html): How to open a file: the options of std’s `OpenOptions`, opened on the blocking pool into a [`Handle`](https://nuclei.rs/api/nuclei/io/struct.Handle.html). - [Permissions](https://nuclei.rs/api/nuclei/fs/struct.Permissions.html): Representation of the various permissions on a file. - [ReadDir](https://nuclei.rs/api/nuclei/fs/struct.ReadDir.html): A directory’s entries, read a page at a time. ### Enums - [Allocate](https://nuclei.rs/api/nuclei/fs/enum.Allocate.html): How a call to [`File::allocate`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.allocate) changes the space a range of a file uses. - [TryLockError](https://nuclei.rs/api/nuclei/fs/enum.TryLockError.html): An enumeration of possible errors which can occur while trying to acquire a lock from the [`try_lock`](https://doc.rust-lang.org/1.99.1/std/fs/struct.File.html#method.try_lock) method and [`try_lock_shared`](https://doc.rust-lang.org/1.99.1/std/fs/struct.File.html#method.try_lock_shared) method on a [`File`](https://doc.rust-lang.org/1.99.1/std/fs/struct.File.html). ### Functions - [canonicalize](https://nuclei.rs/api/nuclei/fs/fn.canonicalize.html): The absolute path of `path`, every link and `..` resolved. - [copy](https://nuclei.rs/api/nuclei/fs/fn.copy.html): Copies the file `from` to `to`, with its permissions; answers the bytes copied. - [create_dir](https://nuclei.rs/api/nuclei/fs/fn.create_dir.html): Creates the directory `path`; its parent must exist. - [create_dir_all](https://nuclei.rs/api/nuclei/fs/fn.create_dir_all.html): Creates the directory `path` and every missing parent. - [hard_link](https://nuclei.rs/api/nuclei/fs/fn.hard_link.html): Makes `link` a new name of the file `original` (a hard link). - [metadata](https://nuclei.rs/api/nuclei/fs/fn.metadata.html): The metadata of what `path` names, through links. - [read](https://nuclei.rs/api/nuclei/fs/fn.read.html): The whole file at `path`. - [read_dir](https://nuclei.rs/api/nuclei/fs/fn.read_dir.html): The entries of the directory at `path`, through [`ReadDir::next_entry`](https://nuclei.rs/api/nuclei/fs/struct.ReadDir.html#method.next_entry) or as a [`Stream`]. - [read_link](https://nuclei.rs/api/nuclei/fs/fn.read_link.html): Where the symbolic link `path` points. - [read_to_string](https://nuclei.rs/api/nuclei/fs/fn.read_to_string.html): The whole file at `path`, which must be UTF-8. - [remove_dir](https://nuclei.rs/api/nuclei/fs/fn.remove_dir.html): Removes the empty directory at `path`. - [remove_dir_all](https://nuclei.rs/api/nuclei/fs/fn.remove_dir_all.html): Removes the directory at `path` and everything in it. - [remove_file](https://nuclei.rs/api/nuclei/fs/fn.remove_file.html): Removes the file at `path`. - [rename](https://nuclei.rs/api/nuclei/fs/fn.rename.html): Renames `from` to `to`, replacing `to` if it is a file. - [set_permissions](https://nuclei.rs/api/nuclei/fs/fn.set_permissions.html): Sets the permissions of what `path` names. - [symlink](https://nuclei.rs/api/nuclei/fs/fn.symlink.html): Makes `link` a symbolic link to `original`. - [symlink_metadata](https://nuclei.rs/api/nuclei/fs/fn.symlink_metadata.html): The metadata of what `path` names, a link itself rather than its target. - [sync_dir](https://nuclei.rs/api/nuclei/fs/fn.sync_dir.html): Writes the entries of the directory at `path` through to the device: the names created, removed or renamed in it before the call survive a crash. A file’s own `sync_all` does not cover its name in the directory, so the name needs this call. It runs on the blocking pool. - [try_exists](https://nuclei.rs/api/nuclei/fs/fn.try_exists.html): Whether `path` names something: `Ok(false)` when it does not, an error when that cannot be told (no permission, for one). - [write](https://nuclei.rs/api/nuclei/fs/fn.write.html): Writes `contents` as the whole file at `path`, creating it or cutting it down first. ### Type Aliases - [File](https://nuclei.rs/api/nuclei/fs/type.File.html): A file: std’s `File` in a [`Handle`](https://nuclei.rs/api/nuclei/io/struct.Handle.html), with async reads, writes, seeks and calls. ### struct `nuclei::fs::DirBuilder` https://nuclei.rs/api/nuclei/fs/struct.DirBuilder.html ```rust pub struct DirBuilder { /* private fields */ } ``` How to create a directory: recursively or not, and with which mode. #### Implementations `impl DirBuilder` ```rust pub fn new() -> Self ``` Creates one directory, with the default mode. ```rust pub fn recursive(&mut self, recursive: bool) -> &mut Self ``` Creates every missing parent too. ```rust pub fn mode(&mut self, mode: u32) -> &mut Self ``` The mode bits the directories get (before the umask). ```rust pub async fn create(&self, path: impl AsRef) -> Result<()> ``` Creates the directory `path`. #### Trait Implementations - `impl Debug for DirBuilder` - `impl Default for DirBuilder` #### Auto Trait Implementations - `impl Freeze for DirBuilder` - `impl RefUnwindSafe for DirBuilder` - `impl Send for DirBuilder` - `impl Sync for DirBuilder` - `impl Unpin for DirBuilder` - `impl UnsafeUnpin for DirBuilder` - `impl UnwindSafe for DirBuilder` ### struct `nuclei::fs::DirEntry` https://nuclei.rs/api/nuclei/fs/struct.DirEntry.html ```rust pub struct DirEntry { /* private fields */ } ``` An entry of a directory. #### Implementations `impl DirEntry` ```rust pub fn path(&self) -> PathBuf ``` The entry’s full path: the directory’s path joined with its name. ```rust pub fn file_name(&self) -> OsString ``` The entry’s name in its directory. ```rust pub fn ino(&self) -> u64 ``` The entry’s inode number. ```rust pub async fn file_type(&self) -> Result ``` What kind of file the entry is, without following a link. ```rust pub async fn metadata(&self) -> Result ``` The entry’s metadata, without following a link. #### Trait Implementations - `impl Debug for DirEntry` #### Auto Trait Implementations - `impl Freeze for DirEntry` - `impl RefUnwindSafe for DirEntry` - `impl Send for DirEntry` - `impl Sync for DirEntry` - `impl Unpin for DirEntry` - `impl UnsafeUnpin for DirEntry` - `impl UnwindSafe for DirEntry` ### struct `nuclei::fs::FileTimes` https://nuclei.rs/api/nuclei/fs/struct.FileTimes.html ```rust pub struct FileTimes(/* private fields */); ``` Representation of the various timestamps on a file. #### Implementations `impl FileTimes` ```rust pub fn new() -> FileTimes ``` Creates a new `FileTimes` with no times set. Using the resulting `FileTimes` in [`File::set_times`](https://doc.rust-lang.org/1.99.1/std/fs/struct.File.html#method.set_times) will not modify any timestamps. ```rust pub fn set_accessed(self, t: SystemTime) -> FileTimes ``` Set the last access time of a file. ```rust pub fn set_modified(self, t: SystemTime) -> FileTimes ``` Set the last modified time of a file. #### Trait Implementations - `impl Clone for FileTimes` - `impl Copy for FileTimes` - `impl Debug for FileTimes` - `impl Default for FileTimes` #### Auto Trait Implementations - `impl Freeze for FileTimes` - `impl RefUnwindSafe for FileTimes` - `impl Send for FileTimes` - `impl Sync for FileTimes` - `impl Unpin for FileTimes` - `impl UnsafeUnpin for FileTimes` - `impl UnwindSafe for FileTimes` ### struct `nuclei::fs::FileType` https://nuclei.rs/api/nuclei/fs/struct.FileType.html ```rust pub struct FileType(/* private fields */); ``` A structure representing a type of file with accessors for each file type. It is returned by [`Metadata::file_type`](https://nuclei.rs/api/nuclei/fs/struct.Metadata.html#method.file_type) method. #### Implementations `impl FileType` ```rust pub fn is_dir(&self) -> bool ``` Tests whether this file type represents a directory. The result is mutually exclusive to the results of [`is_file`](https://nuclei.rs/api/nuclei/fs/struct.FileType.html#method.is_file) and [`is_symlink`](https://nuclei.rs/api/nuclei/fs/struct.FileType.html#method.is_symlink); only zero or one of these tests may pass. **Examples** ```rust fn main() -> std::io::Result<()> { use std::fs; let metadata = fs::metadata("foo.txt")?; let file_type = metadata.file_type(); assert_eq!(file_type.is_dir(), false); Ok(()) } ``` ```rust pub fn is_file(&self) -> bool ``` Tests whether this file type represents a regular file. The result is mutually exclusive to the results of [`is_dir`](https://nuclei.rs/api/nuclei/fs/struct.FileType.html#method.is_dir) and [`is_symlink`](https://nuclei.rs/api/nuclei/fs/struct.FileType.html#method.is_symlink); only zero or one of these tests may pass. When the goal is simply to read from (or write to) the source, the most reliable way to test the source can be read (or written to) is to open it. Only using `is_file` can break workflows like `diff <( prog_a )` on a Unix-like system for example. See [`File::open`](https://doc.rust-lang.org/1.99.1/std/fs/struct.File.html#method.open) or [`OpenOptions::open`](https://doc.rust-lang.org/1.99.1/std/fs/struct.OpenOptions.html#method.open) for more information. **Examples** ```rust fn main() -> std::io::Result<()> { use std::fs; let metadata = fs::metadata("foo.txt")?; let file_type = metadata.file_type(); assert_eq!(file_type.is_file(), true); Ok(()) } ``` ```rust pub fn is_symlink(&self) -> bool ``` Tests whether this file type represents a symbolic link. The result is mutually exclusive to the results of [`is_dir`](https://nuclei.rs/api/nuclei/fs/struct.FileType.html#method.is_dir) and [`is_file`](https://nuclei.rs/api/nuclei/fs/struct.FileType.html#method.is_file); only zero or one of these tests may pass. The underlying [`Metadata`](https://nuclei.rs/api/nuclei/fs/struct.Metadata.html) struct needs to be retrieved with the [`fs::symlink_metadata`](https://doc.rust-lang.org/1.99.1/std/fs/fn.symlink_metadata.html) function and not the [`fs::metadata`](https://doc.rust-lang.org/1.99.1/std/fs/fn.metadata.html) function. The [`fs::metadata`](https://doc.rust-lang.org/1.99.1/std/fs/fn.metadata.html) function follows symbolic links, so [`is_symlink`](https://nuclei.rs/api/nuclei/fs/struct.FileType.html#method.is_symlink) would always return `false` for the target file. **Examples** ```rust use std::fs; fn main() -> std::io::Result<()> { let metadata = fs::symlink_metadata("foo.txt")?; let file_type = metadata.file_type(); assert_eq!(file_type.is_symlink(), false); Ok(()) } ``` #### Trait Implementations - `impl Clone for FileType` - `impl Copy for FileType` - `impl Debug for FileType` - `impl Eq for FileType` - `impl FileTypeExt for FileType` - `impl Hash for FileType` - `impl PartialEq for FileType` - `impl StructuralPartialEq for FileType` #### Auto Trait Implementations - `impl Freeze for FileType` - `impl RefUnwindSafe for FileType` - `impl Send for FileType` - `impl Sync for FileType` - `impl Unpin for FileType` - `impl UnsafeUnpin for FileType` - `impl UnwindSafe for FileType` ### struct `nuclei::fs::Metadata` https://nuclei.rs/api/nuclei/fs/struct.Metadata.html ```rust pub struct Metadata(/* private fields */); ``` Metadata information about a file. This structure is returned from the [`metadata`](https://doc.rust-lang.org/1.99.1/std/fs/fn.metadata.html) or [`symlink_metadata`](https://doc.rust-lang.org/1.99.1/std/fs/fn.symlink_metadata.html) function or method and represents known metadata about a file such as its permissions, size, modification times, etc. #### Implementations `impl Metadata` ```rust pub fn file_type(&self) -> FileType ``` Returns the file type for this metadata. **Examples** ```rust fn main() -> std::io::Result<()> { use std::fs; let metadata = fs::metadata("foo.txt")?; println!("{:?}", metadata.file_type()); Ok(()) } ``` ```rust pub fn is_dir(&self) -> bool ``` Returns `true` if this metadata is for a directory. The result is mutually exclusive to the result of [`Metadata::is_file`](https://nuclei.rs/api/nuclei/fs/struct.Metadata.html#method.is_file), and will be false for symlink metadata obtained from [`symlink_metadata`](https://doc.rust-lang.org/1.99.1/std/fs/fn.symlink_metadata.html). **Examples** ```rust fn main() -> std::io::Result<()> { use std::fs; let metadata = fs::metadata("foo.txt")?; assert!(!metadata.is_dir()); Ok(()) } ``` ```rust pub fn is_file(&self) -> bool ``` Returns `true` if this metadata is for a regular file. The result is mutually exclusive to the result of [`Metadata::is_dir`](https://nuclei.rs/api/nuclei/fs/struct.Metadata.html#method.is_dir), and will be false for symlink metadata obtained from [`symlink_metadata`](https://doc.rust-lang.org/1.99.1/std/fs/fn.symlink_metadata.html). When the goal is simply to read from (or write to) the source, the most reliable way to test the source can be read (or written to) is to open it. Only using `is_file` can break workflows like `diff <( prog_a )` on a Unix-like system for example. See [`File::open`](https://doc.rust-lang.org/1.99.1/std/fs/struct.File.html#method.open) or [`OpenOptions::open`](https://doc.rust-lang.org/1.99.1/std/fs/struct.OpenOptions.html#method.open) for more information. **Examples** ```rust use std::fs; fn main() -> std::io::Result<()> { let metadata = fs::metadata("foo.txt")?; assert!(metadata.is_file()); Ok(()) } ``` ```rust pub fn is_symlink(&self) -> bool ``` Returns `true` if this metadata is for a symbolic link. **Examples** ```rust use std::fs; use std::path::Path; use std::os::unix::fs::symlink; fn main() -> std::io::Result<()> { let link_path = Path::new("link"); symlink("/origin_does_not_exist/", link_path)?; let metadata = fs::symlink_metadata(link_path)?; assert!(metadata.is_symlink()); Ok(()) } ``` ```rust pub fn len(&self) -> u64 ``` Returns the size of the file, in bytes, this metadata is for. **Examples** ```rust use std::fs; fn main() -> std::io::Result<()> { let metadata = fs::metadata("foo.txt")?; assert_eq!(0, metadata.len()); Ok(()) } ``` ```rust pub fn permissions(&self) -> Permissions ``` Returns the permissions of the file this metadata is for. **Examples** ```rust use std::fs; fn main() -> std::io::Result<()> { let metadata = fs::metadata("foo.txt")?; assert!(!metadata.permissions().readonly()); Ok(()) } ``` ```rust pub fn modified(&self) -> Result ``` Returns the last modification time listed in this metadata. The returned value corresponds to the `mtime` field of `stat` on Unix platforms and the `ftLastWriteTime` field on Windows platforms. **Errors** This field might not be available on all platforms, and will return an `Err` on platforms where it is not available. **Examples** ```rust use std::fs; fn main() -> std::io::Result<()> { let metadata = fs::metadata("foo.txt")?; if let Ok(time) = metadata.modified() { println!("{time:?}"); } else { println!("Not supported on this platform"); } Ok(()) } ``` ```rust pub fn accessed(&self) -> Result ``` Returns the last access time of this metadata. The returned value corresponds to the `atime` field of `stat` on Unix platforms and the `ftLastAccessTime` field on Windows platforms. Note that not all platforms will keep this field update in a file’s metadata, for example Windows has an option to disable updating this time when files are accessed and Linux similarly has `noatime`. **Errors** This field might not be available on all platforms, and will return an `Err` on platforms where it is not available. **Examples** ```rust use std::fs; fn main() -> std::io::Result<()> { let metadata = fs::metadata("foo.txt")?; if let Ok(time) = metadata.accessed() { println!("{time:?}"); } else { println!("Not supported on this platform"); } Ok(()) } ``` ```rust pub fn created(&self) -> Result ``` Returns the creation time listed in this metadata. The returned value corresponds to the `btime` field of `statx` on Linux kernel starting from to 4.11, the `birthtime` field of `stat` on other Unix platforms, and the `ftCreationTime` field on Windows platforms. **Errors** This field might not be available on all platforms, and will return an `Err` on platforms or filesystems where it is not available. **Examples** ```rust use std::fs; fn main() -> std::io::Result<()> { let metadata = fs::metadata("foo.txt")?; if let Ok(time) = metadata.created() { println!("{time:?}"); } else { println!("Not supported on this platform or filesystem"); } Ok(()) } ``` #### Trait Implementations - `impl Clone for Metadata` - `impl Debug for Metadata` - `impl MetadataExt for Metadata` - `impl MetadataExt for Metadata` #### Auto Trait Implementations - `impl Freeze for Metadata` - `impl RefUnwindSafe for Metadata` - `impl Send for Metadata` - `impl Sync for Metadata` - `impl Unpin for Metadata` - `impl UnsafeUnpin for Metadata` - `impl UnwindSafe for Metadata` ### struct `nuclei::fs::OpenOptions` https://nuclei.rs/api/nuclei/fs/struct.OpenOptions.html ```rust pub struct OpenOptions(/* private fields */); ``` How to open a file: the options of std’s `OpenOptions`, opened on the blocking pool into a [`Handle`](https://nuclei.rs/api/nuclei/io/struct.Handle.html). #### Implementations `impl OpenOptions` ```rust pub fn new() -> Self ``` No option set: neither read nor write. ```rust pub fn read(&mut self, read: bool) -> &mut Self ``` Opens for reading. ```rust pub fn write(&mut self, write: bool) -> &mut Self ``` Opens for writing. ```rust pub fn append(&mut self, append: bool) -> &mut Self ``` Opens for writing at the end, whatever the cursor. ```rust pub fn truncate(&mut self, truncate: bool) -> &mut Self ``` Cuts an existing file down to nothing when it opens. ```rust pub fn create(&mut self, create: bool) -> &mut Self ``` Creates the file if it does not exist. ```rust pub fn create_new(&mut self, create_new: bool) -> &mut Self ``` Creates the file, failing if it exists. ```rust pub fn mode(&mut self, mode: u32) -> &mut Self ``` The mode bits a created file gets (before the umask). ```rust pub fn custom_flags(&mut self, flags: i32) -> &mut Self ``` Flags passed to `open` beside the ones the options set. ```rust pub async fn open(&self, path: impl AsRef) -> Result> ``` Opens the file at `path` with these options. #### Trait Implementations - `impl Clone for OpenOptions` - `impl Debug for OpenOptions` - `impl Default for OpenOptions` - `impl From for OpenOptions` #### Auto Trait Implementations - `impl Freeze for OpenOptions` - `impl RefUnwindSafe for OpenOptions` - `impl Send for OpenOptions` - `impl Sync for OpenOptions` - `impl Unpin for OpenOptions` - `impl UnsafeUnpin for OpenOptions` - `impl UnwindSafe for OpenOptions` ### struct `nuclei::fs::Permissions` https://nuclei.rs/api/nuclei/fs/struct.Permissions.html ```rust pub struct Permissions(/* private fields */); ``` Representation of the various permissions on a file. This module only currently provides one bit of information, [`Permissions::readonly`](https://nuclei.rs/api/nuclei/fs/struct.Permissions.html#method.readonly), which is exposed on all currently supported platforms. Unix-specific functionality, such as mode bits, is available through the [`PermissionsExt`](https://doc.rust-lang.org/1.99.1/std/os/unix/fs/trait.PermissionsExt.html) trait. #### Implementations `impl Permissions` ```rust pub fn readonly(&self) -> bool ``` Returns `true` if these permissions describe a readonly (unwritable) file. **Note** This function does not take Access Control Lists (ACLs), Unix group membership and other nuances into account. Therefore the return value of this function cannot be relied upon to predict whether attempts to read or write the file will actually succeed. **Windows** On Windows this returns [`FILE_ATTRIBUTE_READONLY`](https://docs.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants). If `FILE_ATTRIBUTE_READONLY` is set then writes to the file will fail but the user may still have permission to change this flag. If `FILE_ATTRIBUTE_READONLY` is *not* set then writes may still fail due to lack of write permission. The behavior of this attribute for directories depends on the Windows version. **Unix (including macOS)** On Unix-based platforms this checks if *any* of the owner, group or others write permission bits are set. It does not consider anything else, including: - Whether the current user is in the file’s assigned group. - Permissions granted by ACL. - That `root` user can write to files that do not have any write bits set. - Writable files on a filesystem that is mounted read-only. The [`PermissionsExt`](https://doc.rust-lang.org/1.99.1/std/os/unix/fs/trait.PermissionsExt.html) trait gives direct access to the permission bits but also does not read ACLs. **Examples** ```rust use std::fs::File; fn main() -> std::io::Result<()> { let mut f = File::create("foo.txt")?; let metadata = f.metadata()?; assert_eq!(false, metadata.permissions().readonly()); Ok(()) } ``` ```rust pub fn set_readonly(&mut self, readonly: bool) ``` Modifies the readonly flag for this set of permissions. If the `readonly` argument is `true`, using the resulting `Permission` will update file permissions to forbid writing. Conversely, if it’s `false`, using the resulting `Permission` will update file permissions to allow writing. This operation does **not** modify the files attributes. This only changes the in-memory value of these attributes for this `Permissions` instance. To modify the files attributes use the [`set_permissions`](https://doc.rust-lang.org/1.99.1/std/fs/fn.set_permissions.html) function which commits these attribute changes to the file. **Note** `set_readonly(false)` makes the file *world-writable* on Unix. You can use the [`PermissionsExt`](https://doc.rust-lang.org/1.99.1/std/os/unix/fs/trait.PermissionsExt.html) trait on Unix to avoid this issue. It also does not take Access Control Lists (ACLs) or Unix group membership into account. **Windows** On Windows this sets or clears [`FILE_ATTRIBUTE_READONLY`](https://docs.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants). If `FILE_ATTRIBUTE_READONLY` is set then writes to the file will fail but the user may still have permission to change this flag. If `FILE_ATTRIBUTE_READONLY` is *not* set then the write may still fail if the user does not have permission to write to the file. In Windows 7 and earlier this attribute prevents deleting empty directories. It does not prevent modifying the directory contents. On later versions of Windows this attribute is ignored for directories. **Unix (including macOS)** On Unix-based platforms this sets or clears the write access bit for the owner, group *and* others, equivalent to `chmod a+w ` or `chmod a-w ` respectively. The latter will grant write access to all users! You can use the [`PermissionsExt`](https://doc.rust-lang.org/1.99.1/std/os/unix/fs/trait.PermissionsExt.html) trait on Unix to avoid this issue. **Examples** ```rust use std::fs::File; fn main() -> std::io::Result<()> { let f = File::create("foo.txt")?; let metadata = f.metadata()?; let mut permissions = metadata.permissions(); permissions.set_readonly(true); // filesystem doesn't change, only the in memory state of the // readonly permission assert_eq!(false, metadata.permissions().readonly()); // just this particular `permissions`. assert_eq!(true, permissions.readonly()); Ok(()) } ``` #### Trait Implementations - `impl Clone for Permissions` - `impl Debug for Permissions` - `impl Eq for Permissions` - `impl PartialEq for Permissions` - `impl PermissionsExt for Permissions` - `impl StructuralPartialEq for Permissions` #### Auto Trait Implementations - `impl Freeze for Permissions` - `impl RefUnwindSafe for Permissions` - `impl Send for Permissions` - `impl Sync for Permissions` - `impl Unpin for Permissions` - `impl UnsafeUnpin for Permissions` - `impl UnwindSafe for Permissions` ### struct `nuclei::fs::ReadDir` https://nuclei.rs/api/nuclei/fs/struct.ReadDir.html ```rust pub struct ReadDir { /* private fields */ } ``` A directory’s entries, read a page at a time. #### Implementations `impl ReadDir` ```rust pub async fn next_entry(&mut self) -> Result> ``` The next entry, `None` at the end. ```rust pub fn poll_next_entry( &mut self, cx: &mut Context<'_>, ) -> Poll>> ``` Polls for the next entry. #### Trait Implementations - `impl Debug for ReadDir` - `impl Stream for ReadDir` #### Auto Trait Implementations - `impl !RefUnwindSafe for ReadDir` - `impl !UnwindSafe for ReadDir` - `impl Freeze for ReadDir` - `impl Send for ReadDir` - `impl Sync for ReadDir` - `impl Unpin for ReadDir` - `impl UnsafeUnpin for ReadDir` ### enum `nuclei::fs::Allocate` https://nuclei.rs/api/nuclei/fs/enum.Allocate.html ```rust pub enum Allocate { Extend, KeepSize, PunchHole, ZeroRange, } ``` How a call to [`File::allocate`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.allocate) changes the space a range of a file uses. #### Variants ```rust Extend ``` Reserves disk space for the range, so a later write into it does not run out of space, and grows the file to cover the range when the range ends past its end. The new part reads as zeros. ```rust KeepSize ``` Reserves disk space for the range and leaves the file’s length as it is. ```rust PunchHole ``` Frees the disk space of the range, which then reads as zeros, and leaves the file’s length as it is. A range that ends past the end of the file does not grow it. ```rust ZeroRange ``` Makes the range read as zeros, without a write of zeros, and grows the file to cover the range when it ends past the end, as a write of zeros would. #### Trait Implementations - `impl Clone for Allocate` - `impl Copy for Allocate` - `impl Debug for Allocate` - `impl Eq for Allocate` - `impl PartialEq for Allocate` - `impl StructuralPartialEq for Allocate` #### Auto Trait Implementations - `impl Freeze for Allocate` - `impl RefUnwindSafe for Allocate` - `impl Send for Allocate` - `impl Sync for Allocate` - `impl Unpin for Allocate` - `impl UnsafeUnpin for Allocate` - `impl UnwindSafe for Allocate` ### enum `nuclei::fs::TryLockError` https://nuclei.rs/api/nuclei/fs/enum.TryLockError.html ```rust pub enum TryLockError { Error(Error), WouldBlock, } ``` An enumeration of possible errors which can occur while trying to acquire a lock from the [`try_lock`](https://doc.rust-lang.org/1.99.1/std/fs/struct.File.html#method.try_lock) method and [`try_lock_shared`](https://doc.rust-lang.org/1.99.1/std/fs/struct.File.html#method.try_lock_shared) method on a [`File`](https://doc.rust-lang.org/1.99.1/std/fs/struct.File.html). #### Variants ```rust Error(Error) ``` The lock could not be acquired due to an I/O error on the file. The standard library will not return an [`ErrorKind::WouldBlock`](https://doc.rust-lang.org/1.99.1/core/io/error/enum.ErrorKind.html#variant.WouldBlock) error inside [`TryLockError::Error`](https://nuclei.rs/api/nuclei/fs/enum.TryLockError.html#variant.Error) ```rust WouldBlock ``` The lock could not be acquired at this time because it is held by another handle/process. #### Trait Implementations - `impl Debug for TryLockError` - `impl Display for TryLockError` - `impl Error for TryLockError` #### Auto Trait Implementations - `impl !RefUnwindSafe for TryLockError` - `impl !UnwindSafe for TryLockError` - `impl Freeze for TryLockError` - `impl Send for TryLockError` - `impl Sync for TryLockError` - `impl Unpin for TryLockError` - `impl UnsafeUnpin for TryLockError` ### fn `nuclei::fs::canonicalize` https://nuclei.rs/api/nuclei/fs/fn.canonicalize.html ```rust pub async fn canonicalize(path: impl AsRef) -> Result ``` The absolute path of `path`, every link and `..` resolved. ### fn `nuclei::fs::copy` https://nuclei.rs/api/nuclei/fs/fn.copy.html ```rust pub async fn copy(from: impl AsRef, to: impl AsRef) -> Result ``` Copies the file `from` to `to`, with its permissions; answers the bytes copied. ### fn `nuclei::fs::create_dir` https://nuclei.rs/api/nuclei/fs/fn.create_dir.html ```rust pub async fn create_dir(path: impl AsRef) -> Result<()> ``` Creates the directory `path`; its parent must exist. ### fn `nuclei::fs::create_dir_all` https://nuclei.rs/api/nuclei/fs/fn.create_dir_all.html ```rust pub async fn create_dir_all(path: impl AsRef) -> Result<()> ``` Creates the directory `path` and every missing parent. ### fn `nuclei::fs::hard_link` https://nuclei.rs/api/nuclei/fs/fn.hard_link.html ```rust pub async fn hard_link( original: impl AsRef, link: impl AsRef, ) -> Result<()> ``` Makes `link` a new name of the file `original` (a hard link). ### fn `nuclei::fs::metadata` https://nuclei.rs/api/nuclei/fs/fn.metadata.html ```rust pub async fn metadata(path: impl AsRef) -> Result ``` The metadata of what `path` names, through links. ### fn `nuclei::fs::read` https://nuclei.rs/api/nuclei/fs/fn.read.html ```rust pub async fn read(path: impl AsRef) -> Result> ``` The whole file at `path`. ### fn `nuclei::fs::read_dir` https://nuclei.rs/api/nuclei/fs/fn.read_dir.html ```rust pub async fn read_dir(path: impl AsRef) -> Result ``` The entries of the directory at `path`, through [`ReadDir::next_entry`](https://nuclei.rs/api/nuclei/fs/struct.ReadDir.html#method.next_entry) or as a [`Stream`]. ### fn `nuclei::fs::read_link` https://nuclei.rs/api/nuclei/fs/fn.read_link.html ```rust pub async fn read_link(path: impl AsRef) -> Result ``` Where the symbolic link `path` points. ### fn `nuclei::fs::read_to_string` https://nuclei.rs/api/nuclei/fs/fn.read_to_string.html ```rust pub async fn read_to_string(path: impl AsRef) -> Result ``` The whole file at `path`, which must be UTF-8. ### fn `nuclei::fs::remove_dir` https://nuclei.rs/api/nuclei/fs/fn.remove_dir.html ```rust pub async fn remove_dir(path: impl AsRef) -> Result<()> ``` Removes the empty directory at `path`. ### fn `nuclei::fs::remove_dir_all` https://nuclei.rs/api/nuclei/fs/fn.remove_dir_all.html ```rust pub async fn remove_dir_all(path: impl AsRef) -> Result<()> ``` Removes the directory at `path` and everything in it. ### fn `nuclei::fs::remove_file` https://nuclei.rs/api/nuclei/fs/fn.remove_file.html ```rust pub async fn remove_file(path: impl AsRef) -> Result<()> ``` Removes the file at `path`. ### fn `nuclei::fs::rename` https://nuclei.rs/api/nuclei/fs/fn.rename.html ```rust pub async fn rename(from: impl AsRef, to: impl AsRef) -> Result<()> ``` Renames `from` to `to`, replacing `to` if it is a file. ### fn `nuclei::fs::set_permissions` https://nuclei.rs/api/nuclei/fs/fn.set_permissions.html ```rust pub async fn set_permissions( path: impl AsRef, perm: Permissions, ) -> Result<()> ``` Sets the permissions of what `path` names. ### fn `nuclei::fs::symlink` https://nuclei.rs/api/nuclei/fs/fn.symlink.html ```rust pub async fn symlink( original: impl AsRef, link: impl AsRef, ) -> Result<()> ``` Makes `link` a symbolic link to `original`. ### fn `nuclei::fs::symlink_metadata` https://nuclei.rs/api/nuclei/fs/fn.symlink_metadata.html ```rust pub async fn symlink_metadata(path: impl AsRef) -> Result ``` The metadata of what `path` names, a link itself rather than its target. ### fn `nuclei::fs::sync_dir` https://nuclei.rs/api/nuclei/fs/fn.sync_dir.html ```rust pub async fn sync_dir(path: impl AsRef) -> Result<()> ``` Writes the entries of the directory at `path` through to the device: the names created, removed or renamed in it before the call survive a crash. A file’s own `sync_all` does not cover its name in the directory, so the name needs this call. It runs on the blocking pool. To replace a file `target` atomically, so a crash leaves either the old contents or the new and never a mix: 1. write the new contents to a temporary file in the same directory, 2. [`sync_all`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.sync_all) the temporary file, 3. [`rename`](https://nuclei.rs/api/nuclei/fs/fn.rename.html) it over `target`, 4. `sync_dir` the directory they are in. On Windows the directory is opened with backup semantics for reading and writing and flushed (`FlushFileBuffers`); on Apple’s systems a full flush of a directory the system refuses is made with `fsync`. **Errors** The system’s own: `path` does not exist, cannot be opened, or is not something the system lets be synced. A path that is not a directory gets the answer the system gives for it. ### fn `nuclei::fs::try_exists` https://nuclei.rs/api/nuclei/fs/fn.try_exists.html ```rust pub async fn try_exists(path: impl AsRef) -> Result ``` Whether `path` names something: `Ok(false)` when it does not, an error when that cannot be told (no permission, for one). ### fn `nuclei::fs::write` https://nuclei.rs/api/nuclei/fs/fn.write.html ```rust pub async fn write( path: impl AsRef, contents: impl AsRef<[u8]>, ) -> Result<()> ``` Writes `contents` as the whole file at `path`, creating it or cutting it down first. ### type `nuclei::fs::File` https://nuclei.rs/api/nuclei/fs/type.File.html ```rust pub type File = Handle; ``` A file: std’s `File` in a [`Handle`](https://nuclei.rs/api/nuclei/io/struct.Handle.html), with async reads, writes, seeks and calls. #### Aliased Type ```rust pub struct File { /* private fields */ } ``` ## Module `nuclei::io` https://nuclei.rs/api/nuclei/io/index.html IO: [`Handle`](https://nuclei.rs/api/nuclei/io/struct.Handle.html) (async operations on std’s sockets and files), the `futures-io` traits, and the utilities every stream gets: the reads and writes of [`AsyncReadExt`](https://nuclei.rs/api/nuclei/io/trait.AsyncReadExt.html), [`AsyncWriteExt`](https://nuclei.rs/api/nuclei/io/trait.AsyncWriteExt.html), [`AsyncBufReadExt`](https://nuclei.rs/api/nuclei/io/trait.AsyncBufReadExt.html) and [`AsyncSeekExt`](https://nuclei.rs/api/nuclei/io/trait.AsyncSeekExt.html) as futures, [`ReadBuf`](https://nuclei.rs/api/nuclei/io/struct.ReadBuf.html), [`copy`](https://nuclei.rs/api/nuclei/io/fn.copy.html) and [`copy_bidirectional`](https://nuclei.rs/api/nuclei/io/fn.copy_bidirectional.html), [`BufReader`](https://nuclei.rs/api/nuclei/io/struct.BufReader.html), [`BufWriter`](https://nuclei.rs/api/nuclei/io/struct.BufWriter.html) and [`BufStream`](https://nuclei.rs/api/nuclei/io/struct.BufStream.html), the in-memory pipes [`duplex`](https://nuclei.rs/api/nuclei/io/fn.duplex.html) and [`simplex`](https://nuclei.rs/api/nuclei/io/fn.simplex.html), [`split`](https://nuclei.rs/api/nuclei/io/fn.split.html), [`empty`](https://nuclei.rs/api/nuclei/io/fn.empty.html), [`repeat`](https://nuclei.rs/api/nuclei/io/fn.repeat.html) and [`sink`](https://nuclei.rs/api/nuclei/io/fn.sink.html), the process’s [`stdin`](https://nuclei.rs/api/nuclei/io/fn.stdin.html), [`stdout`](https://nuclei.rs/api/nuclei/io/fn.stdout.html) and [`stderr`](https://nuclei.rs/api/nuclei/io/fn.stderr.html), what the sockets’ readiness calls take and answer ([`Interest`](https://nuclei.rs/api/nuclei/io/struct.Interest.html), [`Ready`](https://nuclei.rs/api/nuclei/io/struct.Ready.html)), the caller’s own buffers the owned calls take and give back ([`IoBuf`](https://nuclei.rs/api/nuclei/io/trait.IoBuf.html), [`IoBufMut`](https://nuclei.rs/api/nuclei/io/trait.IoBufMut.html), [`IoVecBuf`](https://nuclei.rs/api/nuclei/io/trait.IoVecBuf.html), [`IoVecBufMut`](https://nuclei.rs/api/nuclei/io/trait.IoVecBufMut.html), [`AlignedBuf`](https://nuclei.rs/api/nuclei/io/struct.AlignedBuf.html)), and on unix [`AsyncFd`](https://nuclei.rs/api/nuclei/io/unix/struct.AsyncFd.html), a caller’s own descriptor driven by readiness. Inside, the shards’ half of IO: sources, the drivers’ half of every handle, and the system calls they make. A handle’s IO object stays its own (std’s sockets and files); its source is what the shard’s driver reaches. The driver completes every operation, into and out of the pool’s buffers, at once when it can and on readiness otherwise, and wakes the task, which takes the result. ### Modules - [unix](https://nuclei.rs/api/nuclei/io/unix/index.html): Unix’s own: [`AsyncFd`](https://nuclei.rs/api/nuclei/io/unix/struct.AsyncFd.html), a caller’s descriptor driven by readiness, and its guards. ### Structs - [AlignedBuf](https://nuclei.rs/api/nuclei/io/struct.AlignedBuf.html): A buffer of a fixed capacity whose memory starts at an address that is a multiple of a chosen alignment: the buffer a file opened for direct IO (`O_DIRECT`, `FILE_FLAG_NO_BUFFERING`) is read into and written from by the owned calls ([`Handle::read_at_owned`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.read_at_owned), [`Handle::write_at_owned`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.write_at_owned) and the others), which hand its memory to the kernel as it is. - [BufReader](https://nuclei.rs/api/nuclei/io/struct.BufReader.html): A reader with a buffer in front: small reads take from the buffer, which is filled by large reads of the reader. Writes, if the reader is also a writer, go straight through. - [BufStream](https://nuclei.rs/api/nuclei/io/struct.BufStream.html): A stream with a read buffer and a write buffer in front: a [`BufReader`](https://nuclei.rs/api/nuclei/io/struct.BufReader.html) around a [`BufWriter`](https://nuclei.rs/api/nuclei/io/struct.BufWriter.html). - [BufWriter](https://nuclei.rs/api/nuclei/io/struct.BufWriter.html): A writer with a buffer in front: small writes gather in the buffer, which goes to the writer when full, on a flush, or on a close. Reads, if the writer is also a reader, go straight through. Dropping it loses what is still buffered: flush or close it first. - [Chain](https://nuclei.rs/api/nuclei/io/struct.Chain.html): A reader that reads one to its end, then another; made by [`chain`](https://nuclei.rs/api/nuclei/io/trait.AsyncReadExt.html#method.chain). - [DuplexStream](https://nuclei.rs/api/nuclei/io/struct.DuplexStream.html): One end of a [`duplex`](https://nuclei.rs/api/nuclei/io/fn.duplex.html) pair: what it writes the other reads, and what the other writes it reads. Dropping it ends the other’s reads (after what is left) and fails the other’s writes. - [Empty](https://nuclei.rs/api/nuclei/io/struct.Empty.html): A reader at its end at once, and a writer that takes every byte and keeps none. Made by [`empty`](https://nuclei.rs/api/nuclei/io/fn.empty.html). - [FillBuf](https://nuclei.rs/api/nuclei/io/struct.FillBuf.html): The future of [`fill_buf`](https://nuclei.rs/api/nuclei/io/trait.AsyncBufReadExt.html#method.fill_buf). - [Flush](https://nuclei.rs/api/nuclei/io/struct.Flush.html): The future of [`flush`](https://nuclei.rs/api/nuclei/io/trait.AsyncWriteExt.html#method.flush). - [Handle](https://nuclei.rs/api/nuclei/io/struct.Handle.html): An IO object (a socket, a pipe, a file) whose operations run on nuclei’s shards. - [Interest](https://nuclei.rs/api/nuclei/io/struct.Interest.html): What a readiness call waits for: reading, writing, or either. - [Lines](https://nuclei.rs/api/nuclei/io/struct.Lines.html): The lines of a buffered reader; made by [`lines`](https://nuclei.rs/api/nuclei/io/trait.AsyncBufReadExt.html#method.lines). - [Read](https://nuclei.rs/api/nuclei/io/struct.Read.html): The future of [`read`](https://nuclei.rs/api/nuclei/io/trait.AsyncReadExt.html#method.read). - [ReadBuf](https://nuclei.rs/api/nuclei/io/struct.ReadBuf.html): A buffer being filled by reads: its first `filled` bytes hold data, its first `initialized` bytes are initialized (`filled <= initialized`), and the rest may be uninitialized memory that a read may write into. - [ReadBufFuture](https://nuclei.rs/api/nuclei/io/struct.ReadBufFuture.html): The future of [`read_buf`](https://nuclei.rs/api/nuclei/io/trait.AsyncReadExt.html#method.read_buf). - [ReadExact](https://nuclei.rs/api/nuclei/io/struct.ReadExact.html): The future of [`read_exact`](https://nuclei.rs/api/nuclei/io/trait.AsyncReadExt.html#method.read_exact). - [ReadHalf](https://nuclei.rs/api/nuclei/io/struct.ReadHalf.html): The read half of a stream [`split`](https://nuclei.rs/api/nuclei/io/fn.split.html) in two. - [ReadLine](https://nuclei.rs/api/nuclei/io/struct.ReadLine.html): The future of [`read_line`](https://nuclei.rs/api/nuclei/io/trait.AsyncBufReadExt.html#method.read_line). - [ReadNumber](https://nuclei.rs/api/nuclei/io/struct.ReadNumber.html): The future of a typed read ([`read_u32`](https://nuclei.rs/api/nuclei/io/trait.AsyncReadExt.html#method.read_u32) and the like). - [ReadToEnd](https://nuclei.rs/api/nuclei/io/struct.ReadToEnd.html): The future of [`read_to_end`](https://nuclei.rs/api/nuclei/io/trait.AsyncReadExt.html#method.read_to_end). - [ReadToString](https://nuclei.rs/api/nuclei/io/struct.ReadToString.html): The future of [`read_to_string`](https://nuclei.rs/api/nuclei/io/trait.AsyncReadExt.html#method.read_to_string). - [ReadUntil](https://nuclei.rs/api/nuclei/io/struct.ReadUntil.html): The future of [`read_until`](https://nuclei.rs/api/nuclei/io/trait.AsyncBufReadExt.html#method.read_until). - [Ready](https://nuclei.rs/api/nuclei/io/struct.Ready.html): What a readiness call found. - [Repeat](https://nuclei.rs/api/nuclei/io/struct.Repeat.html): A reader that gives one byte over and over, without end. Made by [`repeat`](https://nuclei.rs/api/nuclei/io/fn.repeat.html). - [Seek](https://nuclei.rs/api/nuclei/io/struct.Seek.html): The future of [`seek`](https://nuclei.rs/api/nuclei/io/trait.AsyncSeekExt.html#method.seek) and the seeks built on it. - [Shutdown](https://nuclei.rs/api/nuclei/io/struct.Shutdown.html): The future of [`shutdown`](https://nuclei.rs/api/nuclei/io/trait.AsyncWriteExt.html#method.shutdown). - [SimplexReader](https://nuclei.rs/api/nuclei/io/struct.SimplexReader.html): The reading end of a [`simplex`](https://nuclei.rs/api/nuclei/io/fn.simplex.html) pipe. Dropping it fails the writer’s next write. - [SimplexWriter](https://nuclei.rs/api/nuclei/io/struct.SimplexWriter.html): The writing end of a [`simplex`](https://nuclei.rs/api/nuclei/io/fn.simplex.html) pipe. Dropping it (or closing it) ends the reader’s reads after what is left. - [Sink](https://nuclei.rs/api/nuclei/io/struct.Sink.html): A writer that takes every byte and keeps none. Made by [`sink`](https://nuclei.rs/api/nuclei/io/fn.sink.html). - [Split](https://nuclei.rs/api/nuclei/io/struct.Split.html): The segments of a buffered reader between a byte; made by [`split`](https://nuclei.rs/api/nuclei/io/trait.AsyncBufReadExt.html#method.split). - [Stderr](https://nuclei.rs/api/nuclei/io/struct.Stderr.html): The process’s standard error: writes run on the blocking pool, one at a time. - [Stdin](https://nuclei.rs/api/nuclei/io/struct.Stdin.html): The process’s standard input: reads run on the blocking pool. - [Stdout](https://nuclei.rs/api/nuclei/io/struct.Stdout.html): The process’s standard output: writes run on the blocking pool, one at a time; flush before the process exits to see the last one done. - [Take](https://nuclei.rs/api/nuclei/io/struct.Take.html): A reader that ends after a number of bytes of another; made by [`take`](https://nuclei.rs/api/nuclei/io/trait.AsyncReadExt.html#method.take). - [Write](https://nuclei.rs/api/nuclei/io/struct.Write.html): The future of [`write`](https://nuclei.rs/api/nuclei/io/trait.AsyncWriteExt.html#method.write). - [WriteAll](https://nuclei.rs/api/nuclei/io/struct.WriteAll.html): The future of [`write_all`](https://nuclei.rs/api/nuclei/io/trait.AsyncWriteExt.html#method.write_all). - [WriteHalf](https://nuclei.rs/api/nuclei/io/struct.WriteHalf.html): The write half of a stream [`split`](https://nuclei.rs/api/nuclei/io/fn.split.html) in two. - [WriteNumber](https://nuclei.rs/api/nuclei/io/struct.WriteNumber.html): The future of a typed write ([`write_u32`](https://nuclei.rs/api/nuclei/io/trait.AsyncWriteExt.html#method.write_u32) and the like). - [WriteVectored](https://nuclei.rs/api/nuclei/io/struct.WriteVectored.html): The future of [`write_vectored`](https://nuclei.rs/api/nuclei/io/trait.AsyncWriteExt.html#method.write_vectored). ### Traits - [AsyncBufRead](https://nuclei.rs/api/nuclei/io/trait.AsyncBufRead.html): Read bytes asynchronously. - [AsyncBufReadExt](https://nuclei.rs/api/nuclei/io/trait.AsyncBufReadExt.html): Reads on any [`AsyncBufRead`](https://nuclei.rs/api/nuclei/io/trait.AsyncBufRead.html): up to a delimiter, a line, the lines or the segments one by one. - [AsyncRead](https://nuclei.rs/api/nuclei/io/trait.AsyncRead.html): Read bytes asynchronously. - [AsyncReadExt](https://nuclei.rs/api/nuclei/io/trait.AsyncReadExt.html): Reads on any [`AsyncRead`](https://nuclei.rs/api/nuclei/io/trait.AsyncRead.html): into a slice, a [`ReadBuf`](https://nuclei.rs/api/nuclei/io/struct.ReadBuf.html), to the end, as typed numbers in big or little endian. - [AsyncSeek](https://nuclei.rs/api/nuclei/io/trait.AsyncSeek.html): Seek bytes asynchronously. - [AsyncSeekExt](https://nuclei.rs/api/nuclei/io/trait.AsyncSeekExt.html): Seeks on any [`AsyncSeek`](https://nuclei.rs/api/nuclei/io/trait.AsyncSeek.html). - [AsyncWrite](https://nuclei.rs/api/nuclei/io/trait.AsyncWrite.html): Write bytes asynchronously. - [AsyncWriteExt](https://nuclei.rs/api/nuclei/io/trait.AsyncWriteExt.html): Writes on any [`AsyncWrite`](https://nuclei.rs/api/nuclei/io/trait.AsyncWrite.html): a slice, all of a slice, typed numbers in big or little endian; and its flush and shutdown. - [IoBuf](https://nuclei.rs/api/nuclei/io/trait.IoBuf.html): A buffer an owned write takes: memory at an address that does not move while the runtime holds the buffer, whose first [`bytes_init`](https://nuclei.rs/api/nuclei/io/trait.IoBuf.html#tymethod.bytes_init) bytes are written. - [IoBufMut](https://nuclei.rs/api/nuclei/io/trait.IoBufMut.html): A buffer an owned read fills: an [`IoBuf`](https://nuclei.rs/api/nuclei/io/trait.IoBuf.html) whose memory past the bytes it holds may be written, and told how many hold data after a read. - [IoObject](https://nuclei.rs/api/nuclei/io/trait.IoObject.html): An IO object a [`Handle`](https://nuclei.rs/api/nuclei/io/struct.Handle.html) takes over: on unix anything with a file descriptor; on Windows std’s `TcpStream`, `TcpListener`, `UdpSocket` and `File`. - [IoVecBuf](https://nuclei.rs/api/nuclei/io/trait.IoVecBuf.html): The buffers of an owned vectored write: each one’s bytes, in order, go out as one write. Implemented for `Vec` and `[B; N]` of any [`IoBuf`](https://nuclei.rs/api/nuclei/io/trait.IoBuf.html), `Vec>` among them. - [IoVecBufMut](https://nuclei.rs/api/nuclei/io/trait.IoVecBufMut.html): The buffers of an owned vectored read: the bytes read fill each one’s spare capacity in order. Implemented for `Vec` and `[B; N]` of any [`IoBufMut`](https://nuclei.rs/api/nuclei/io/trait.IoBufMut.html). ### Functions - [copy](https://nuclei.rs/api/nuclei/io/fn.copy.html): Copies everything `reader` gives into `writer`, then flushes it; answers the bytes copied. - [copy_bidirectional](https://nuclei.rs/api/nuclei/io/fn.copy_bidirectional.html): Copies `a` into `b` and `b` into `a` at once, in the calling task, each direction through a buffer of 8 KiB; a direction whose reader ends closes its writer. Answers the bytes copied each way, `(a to b, b to a)`, once both ended; the first error ends both. - [copy_bidirectional_with_sizes](https://nuclei.rs/api/nuclei/io/fn.copy_bidirectional_with_sizes.html): [`copy_bidirectional`](https://nuclei.rs/api/nuclei/io/fn.copy_bidirectional.html) with a buffer of `a_to_b` bytes for one direction and of `b_to_a` bytes for the other. - [copy_buf](https://nuclei.rs/api/nuclei/io/fn.copy_buf.html): Copies everything a buffered `reader` gives into `writer` from the reader’s own buffer, then flushes it; answers the bytes copied. - [duplex](https://nuclei.rs/api/nuclei/io/fn.duplex.html): Two connected in-memory streams, each direction a pipe of `max_buf_size` bytes: a write waits while its pipe is full. - [empty](https://nuclei.rs/api/nuclei/io/fn.empty.html): A reader at its end at once, and a writer that takes every byte and keeps none. - [repeat](https://nuclei.rs/api/nuclei/io/fn.repeat.html): A reader that gives `byte` over and over, without end. - [simplex](https://nuclei.rs/api/nuclei/io/fn.simplex.html): One in-memory pipe of `max_buf_size` bytes: what the writer writes, the reader reads. - [sink](https://nuclei.rs/api/nuclei/io/fn.sink.html): A writer that takes every byte and keeps none. - [split](https://nuclei.rs/api/nuclei/io/fn.split.html): Splits `stream` into a read half and a write half; [`ReadHalf::unsplit`](https://nuclei.rs/api/nuclei/io/struct.ReadHalf.html#method.unsplit) puts them back together. - [stderr](https://nuclei.rs/api/nuclei/io/fn.stderr.html): The process’s standard error, as an async stream (see [`Stderr`](https://nuclei.rs/api/nuclei/io/struct.Stderr.html)). - [stdin](https://nuclei.rs/api/nuclei/io/fn.stdin.html): The process’s standard input, as an async stream (see [`Stdin`](https://nuclei.rs/api/nuclei/io/struct.Stdin.html)). - [stdout](https://nuclei.rs/api/nuclei/io/fn.stdout.html): The process’s standard output, as an async stream (see [`Stdout`](https://nuclei.rs/api/nuclei/io/struct.Stdout.html)). ### struct `nuclei::io::AlignedBuf` https://nuclei.rs/api/nuclei/io/struct.AlignedBuf.html ```rust pub struct AlignedBuf { /* private fields */ } ``` A buffer of a fixed capacity whose memory starts at an address that is a multiple of a chosen alignment: the buffer a file opened for direct IO (`O_DIRECT`, `FILE_FLAG_NO_BUFFERING`) is read into and written from by the owned calls ([`Handle::read_at_owned`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.read_at_owned), [`Handle::write_at_owned`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.write_at_owned) and the others), which hand its memory to the kernel as it is. The kernel’s alignment rules for direct IO ask the memory’s address, the file offset and the length to be multiples of the device’s logical block size (512 or 4096 bytes on most devices); a buffer aligned to 4096 with a capacity of a multiple of 4096 meets them on all of them. It holds its first [`len`](https://nuclei.rs/api/nuclei/io/struct.AlignedBuf.html#method.len) bytes, as a `Vec` does, and never grows past its capacity. Its memory is the caller’s: it is not charged to the runtime’s IO buffer cap. #### Implementations `impl AlignedBuf` ```rust pub fn new(capacity: usize, align: usize) -> Result ``` An empty buffer with room for `capacity` bytes, its memory aligned to `align` bytes. **Errors** `InvalidInput` when `align` is not a power of two, or `capacity` rounded up to it is past what memory can hold; `OutOfMemory` when the allocator has no memory for it. ```rust pub fn zeroed(len: usize, align: usize) -> Result ``` A buffer of `len` zeroed bytes, its memory aligned to `align` bytes, with room for exactly `len`. **Errors** As [`new`](https://nuclei.rs/api/nuclei/io/struct.AlignedBuf.html#method.new). ```rust pub fn len(&self) -> usize ``` How many bytes it holds. ```rust pub fn is_empty(&self) -> bool ``` Whether it holds no byte. ```rust pub fn capacity(&self) -> usize ``` How many bytes its memory has room for. ```rust pub fn alignment(&self) -> usize ``` The alignment of its memory’s address. ```rust pub fn as_ptr(&self) -> *const u8 ``` The address of its first byte. ```rust pub fn as_mut_ptr(&mut self) -> *mut u8 ``` The address of its first byte, for writing. ```rust pub fn clear(&mut self) ``` Holds no byte any more; the memory stays. ```rust pub fn truncate(&mut self, len: usize) ``` Keeps only its first `len` bytes (all of them if it holds fewer). ```rust pub fn extend_from_slice(&mut self, bytes: &[u8]) -> usize ``` Copies as much of `bytes` as its room holds onto its end and returns how many: it never grows past its capacity. ```rust pub fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit] ``` Its memory past the bytes it holds. ```rust pub unsafe fn set_len(&mut self, len: usize) ``` Sets how many bytes it holds to `len`. **Safety** `len <= capacity()`, and the first `len` bytes are initialized. #### Methods from Deref ```rust pub fn is_ascii(&self) -> bool ``` Checks if all bytes in this slice are within the ASCII range. An empty slice returns `true`. ```rust pub fn as_ascii(&self) -> Option<&[AsciiChar]> ``` 🔬This is a nightly-only experimental API. (`ascii_char`) If this slice [`is_ascii`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.is_ascii), returns it as a slice of [ASCII characters](https://doc.rust-lang.org/1.99.1/core/ascii/ascii_char/enum.AsciiChar.html), otherwise returns `None`. ```rust pub unsafe fn as_ascii_unchecked(&self) -> &[AsciiChar] ``` 🔬This is a nightly-only experimental API. (`ascii_char`) Converts this slice of bytes into a slice of ASCII characters, without checking whether they’re valid. **Safety** Every byte in the slice must be in `0..=127`, or else this is UB. ```rust pub fn eq_ignore_ascii_case(&self, other: &[u8]) -> bool ``` Checks that two slices are an ASCII case-insensitive match. Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`, but without allocating and copying temporaries. ```rust pub fn make_ascii_uppercase(&mut self) ``` Converts this slice to its ASCII upper case equivalent in-place. ASCII letters ‘a’ to ‘z’ are mapped to ‘A’ to ‘Z’, but non-ASCII letters are unchanged. To return a new uppercased value without modifying the existing one, use [`to_ascii_uppercase`](https://nuclei.rs/api/nuclei/io/struct.AlignedBuf.html#method.to_ascii_uppercase). ```rust pub fn make_ascii_lowercase(&mut self) ``` Converts this slice to its ASCII lower case equivalent in-place. ASCII letters ‘A’ to ‘Z’ are mapped to ‘a’ to ‘z’, but non-ASCII letters are unchanged. To return a new lowercased value without modifying the existing one, use [`to_ascii_lowercase`](https://nuclei.rs/api/nuclei/io/struct.AlignedBuf.html#method.to_ascii_lowercase). ```rust pub fn escape_ascii(&self) -> EscapeAscii<'_> ``` Returns an iterator that produces an escaped version of this slice, treating it as an ASCII string. **Examples** ```rust let s = b"0\t\r\n'\"\\\x9d"; let escaped = s.escape_ascii().to_string(); assert_eq!(escaped, "0\\t\\r\\n\\'\\\"\\\\\\x9d"); ``` ```rust pub fn trim_ascii_start(&self) -> &[u8] ``` Returns a byte slice with leading ASCII whitespace bytes removed. ‘Whitespace’ refers to the definition used by [`u8::is_ascii_whitespace`](https://doc.rust-lang.org/1.99.1/std/primitive.u8.html#method.is_ascii_whitespace). Importantly, this definition excludes the `\0x0B` byte even though it has the Unicode [`White_Space`](https://www.unicode.org/reports/tr44/#White_Space) property and is removed by [`str::trim_start`](https://doc.rust-lang.org/1.99.1/std/primitive.str.html#method.trim_start). **Examples** ```rust assert_eq!(b" \t hello world\n".trim_ascii_start(), b"hello world\n"); assert_eq!(b" ".trim_ascii_start(), b""); assert_eq!(b"".trim_ascii_start(), b""); ``` ```rust pub fn trim_ascii_end(&self) -> &[u8] ``` Returns a byte slice with trailing ASCII whitespace bytes removed. ‘Whitespace’ refers to the definition used by [`u8::is_ascii_whitespace`](https://doc.rust-lang.org/1.99.1/std/primitive.u8.html#method.is_ascii_whitespace). Importantly, this definition excludes the `\0x0B` byte even though it has the Unicode [`White_Space`](https://www.unicode.org/reports/tr44/#White_Space) property and is removed by [`str::trim_end`](https://doc.rust-lang.org/1.99.1/std/primitive.str.html#method.trim_end). **Examples** ```rust assert_eq!(b"\r hello world\n ".trim_ascii_end(), b"\r hello world"); assert_eq!(b" ".trim_ascii_end(), b""); assert_eq!(b"".trim_ascii_end(), b""); ``` ```rust pub fn trim_ascii(&self) -> &[u8] ``` Returns a byte slice with leading and trailing ASCII whitespace bytes removed. ‘Whitespace’ refers to the definition used by [`u8::is_ascii_whitespace`](https://doc.rust-lang.org/1.99.1/std/primitive.u8.html#method.is_ascii_whitespace). Importantly, this definition excludes the `\0x0B` byte even though it has the Unicode [`White_Space`](https://www.unicode.org/reports/tr44/#White_Space) property and is removed by [`str::trim`](https://doc.rust-lang.org/1.99.1/std/primitive.str.html#method.trim). **Examples** ```rust assert_eq!(b"\r hello world\n ".trim_ascii(), b"hello world"); assert_eq!(b" ".trim_ascii(), b""); assert_eq!(b"".trim_ascii(), b""); ``` ```rust pub fn len(&self) -> usize ``` Returns the number of elements in the slice. **Examples** ```rust let a = [1, 2, 3]; assert_eq!(a.len(), 3); ``` ```rust pub fn is_empty(&self) -> bool ``` Returns `true` if the slice has a length of 0. **Examples** ```rust let a = [1, 2, 3]; assert!(!a.is_empty()); let b: &[i32] = &[]; assert!(b.is_empty()); ``` ```rust pub fn first(&self) -> Option<&T> ``` Returns the first element of the slice, or `None` if it is empty. **Examples** ```rust let v = [10, 40, 30]; assert_eq!(Some(&10), v.first()); let w: &[i32] = &[]; assert_eq!(None, w.first()); ``` ```rust pub fn first_mut(&mut self) -> Option<&mut T> ``` Returns a mutable reference to the first element of the slice, or `None` if it is empty. **Examples** ```rust let x = &mut [0, 1, 2]; if let Some(first) = x.first_mut() { *first = 5; } assert_eq!(x, &[5, 1, 2]); let y: &mut [i32] = &mut []; assert_eq!(None, y.first_mut()); ``` ```rust pub fn split_first(&self) -> Option<(&T, &[T])> ``` Returns the first and all the rest of the elements of the slice, or `None` if it is empty. **Examples** ```rust let x = &[0, 1, 2]; if let Some((first, elements)) = x.split_first() { assert_eq!(first, &0); assert_eq!(elements, &[1, 2]); } ``` ```rust pub fn split_first_mut(&mut self) -> Option<(&mut T, &mut [T])> ``` Returns the first and all the rest of the elements of the slice, or `None` if it is empty. **Examples** ```rust let x = &mut [0, 1, 2]; if let Some((first, elements)) = x.split_first_mut() { *first = 3; elements[0] = 4; elements[1] = 5; } assert_eq!(x, &[3, 4, 5]); ``` ```rust pub fn split_last(&self) -> Option<(&T, &[T])> ``` Returns the last and all the rest of the elements of the slice, or `None` if it is empty. **Examples** ```rust let x = &[0, 1, 2]; if let Some((last, elements)) = x.split_last() { assert_eq!(last, &2); assert_eq!(elements, &[0, 1]); } ``` ```rust pub fn split_last_mut(&mut self) -> Option<(&mut T, &mut [T])> ``` Returns the last and all the rest of the elements of the slice, or `None` if it is empty. **Examples** ```rust let x = &mut [0, 1, 2]; if let Some((last, elements)) = x.split_last_mut() { *last = 3; elements[0] = 4; elements[1] = 5; } assert_eq!(x, &[4, 5, 3]); ``` ```rust pub fn last(&self) -> Option<&T> ``` Returns the last element of the slice, or `None` if it is empty. **Examples** ```rust let v = [10, 40, 30]; assert_eq!(Some(&30), v.last()); let w: &[i32] = &[]; assert_eq!(None, w.last()); ``` ```rust pub fn last_mut(&mut self) -> Option<&mut T> ``` Returns a mutable reference to the last item in the slice, or `None` if it is empty. **Examples** ```rust let x = &mut [0, 1, 2]; if let Some(last) = x.last_mut() { *last = 10; } assert_eq!(x, &[0, 1, 10]); let y: &mut [i32] = &mut []; assert_eq!(None, y.last_mut()); ``` ```rust pub fn first_chunk(&self) -> Option<&[T; N]> ``` Returns an array reference to the first `N` items in the slice. If the slice is not at least `N` in length, this will return `None`. **Examples** ```rust let u = [10, 40, 30]; assert_eq!(Some(&[10, 40]), u.first_chunk::<2>()); let v: &[i32] = &[10]; assert_eq!(None, v.first_chunk::<2>()); let w: &[i32] = &[]; assert_eq!(Some(&[]), w.first_chunk::<0>()); ``` ```rust pub fn first_chunk_mut(&mut self) -> Option<&mut [T; N]> ``` Returns a mutable array reference to the first `N` items in the slice. If the slice is not at least `N` in length, this will return `None`. **Examples** ```rust let x = &mut [0, 1, 2]; if let Some(first) = x.first_chunk_mut::<2>() { first[0] = 5; first[1] = 4; } assert_eq!(x, &[5, 4, 2]); assert_eq!(None, x.first_chunk_mut::<4>()); ``` ```rust pub fn split_first_chunk(&self) -> Option<(&[T; N], &[T])> ``` Returns an array reference to the first `N` items in the slice and the remaining slice. If the slice is not at least `N` in length, this will return `None`. **Examples** ```rust let x = &[0, 1, 2]; if let Some((first, elements)) = x.split_first_chunk::<2>() { assert_eq!(first, &[0, 1]); assert_eq!(elements, &[2]); } assert_eq!(None, x.split_first_chunk::<4>()); ``` ```rust pub fn split_first_chunk_mut( &mut self, ) -> Option<(&mut [T; N], &mut [T])> ``` Returns a mutable array reference to the first `N` items in the slice and the remaining slice. If the slice is not at least `N` in length, this will return `None`. **Examples** ```rust let x = &mut [0, 1, 2]; if let Some((first, elements)) = x.split_first_chunk_mut::<2>() { first[0] = 3; first[1] = 4; elements[0] = 5; } assert_eq!(x, &[3, 4, 5]); assert_eq!(None, x.split_first_chunk_mut::<4>()); ``` ```rust pub fn split_last_chunk(&self) -> Option<(&[T], &[T; N])> ``` Returns an array reference to the last `N` items in the slice and the remaining slice. If the slice is not at least `N` in length, this will return `None`. **Examples** ```rust let x = &[0, 1, 2]; if let Some((elements, last)) = x.split_last_chunk::<2>() { assert_eq!(elements, &[0]); assert_eq!(last, &[1, 2]); } assert_eq!(None, x.split_last_chunk::<4>()); ``` ```rust pub fn split_last_chunk_mut( &mut self, ) -> Option<(&mut [T], &mut [T; N])> ``` Returns a mutable array reference to the last `N` items in the slice and the remaining slice. If the slice is not at least `N` in length, this will return `None`. **Examples** ```rust let x = &mut [0, 1, 2]; if let Some((elements, last)) = x.split_last_chunk_mut::<2>() { last[0] = 3; last[1] = 4; elements[0] = 5; } assert_eq!(x, &[5, 3, 4]); assert_eq!(None, x.split_last_chunk_mut::<4>()); ``` ```rust pub fn last_chunk(&self) -> Option<&[T; N]> ``` Returns an array reference to the last `N` items in the slice. If the slice is not at least `N` in length, this will return `None`. **Examples** ```rust let u = [10, 40, 30]; assert_eq!(Some(&[40, 30]), u.last_chunk::<2>()); let v: &[i32] = &[10]; assert_eq!(None, v.last_chunk::<2>()); let w: &[i32] = &[]; assert_eq!(Some(&[]), w.last_chunk::<0>()); ``` ```rust pub fn last_chunk_mut(&mut self) -> Option<&mut [T; N]> ``` Returns a mutable array reference to the last `N` items in the slice. If the slice is not at least `N` in length, this will return `None`. **Examples** ```rust let x = &mut [0, 1, 2]; if let Some(last) = x.last_chunk_mut::<2>() { last[0] = 10; last[1] = 20; } assert_eq!(x, &[0, 10, 20]); assert_eq!(None, x.last_chunk_mut::<4>()); ``` ```rust pub fn get(&self, index: I) -> Option<&>::Output> where I: SliceIndex<[T]> ``` Returns a reference to an element or subslice depending on the type of index. - If given a position, returns a reference to the element at that position or `None` if out of bounds. - If given a range, returns the subslice corresponding to that range, or `None` if out of bounds. **Examples** ```rust let v = [10, 40, 30]; assert_eq!(Some(&40), v.get(1)); assert_eq!(Some(&[10, 40][..]), v.get(0..2)); assert_eq!(None, v.get(3)); assert_eq!(None, v.get(0..4)); ``` ```rust pub fn get_mut( &mut self, index: I, ) -> Option<&mut >::Output> where I: SliceIndex<[T]> ``` Returns a mutable reference to an element or subslice depending on the type of index (see [`get`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.get)) or `None` if the index is out of bounds. **Examples** ```rust let x = &mut [0, 1, 2]; if let Some(elem) = x.get_mut(1) { *elem = 42; } assert_eq!(x, &[0, 42, 2]); ``` ```rust pub unsafe fn get_unchecked( &self, index: I, ) -> &>::Output where I: SliceIndex<[T]> ``` Returns a reference to an element or subslice, without doing bounds checking. For a safe alternative see [`get`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.get). **Safety** Calling this method with an out-of-bounds index is *[undefined behavior](https://doc.rust-lang.org/reference/behavior-considered-undefined.html)* even if the resulting reference is not used. You can think of this like `.get(index).unwrap_unchecked()`. It’s UB to call `.get_unchecked(len)`, even if you immediately convert to a pointer. And it’s UB to call `.get_unchecked(..len + 1)`, `.get_unchecked(..=len)`, or similar. **Examples** ```rust let x = &[1, 2, 4]; unsafe { assert_eq!(x.get_unchecked(1), &2); } ``` ```rust pub unsafe fn get_unchecked_mut( &mut self, index: I, ) -> &mut >::Output where I: SliceIndex<[T]> ``` Returns a mutable reference to an element or subslice, without doing bounds checking. For a safe alternative see [`get_mut`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.get_mut). **Safety** Calling this method with an out-of-bounds index is *[undefined behavior](https://doc.rust-lang.org/reference/behavior-considered-undefined.html)* even if the resulting reference is not used. You can think of this like `.get_mut(index).unwrap_unchecked()`. It’s UB to call `.get_unchecked_mut(len)`, even if you immediately convert to a pointer. And it’s UB to call `.get_unchecked_mut(..len + 1)`, `.get_unchecked_mut(..=len)`, or similar. **Examples** ```rust let x = &mut [1, 2, 4]; unsafe { let elem = x.get_unchecked_mut(1); *elem = 13; } assert_eq!(x, &[1, 13, 4]); ``` ```rust pub fn as_ptr(&self) -> *const T ``` Returns a raw pointer to the slice’s buffer. The caller must ensure that the slice outlives the pointer this function returns, or else it will end up dangling. The caller must also ensure that the memory the pointer (non-transitively) points to is never written to (except inside an `UnsafeCell`) using this pointer or any pointer derived from it. If you need to mutate the contents of the slice, use [`as_mut_ptr`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.as_mut_ptr). Modifying the container referenced by this slice may cause its buffer to be reallocated, which would also make any pointers to it invalid. **Examples** ```rust let x = &[1, 2, 4]; let x_ptr = x.as_ptr(); unsafe { for i in 0..x.len() { assert_eq!(x.get_unchecked(i), &*x_ptr.add(i)); } } ``` ```rust pub fn as_mut_ptr(&mut self) -> *mut T ``` Returns an unsafe mutable pointer to the slice’s buffer. The caller must ensure that the slice outlives the pointer this function returns, or else it will end up dangling. Modifying the container referenced by this slice may cause its buffer to be reallocated, which would also make any pointers to it invalid. **Examples** ```rust let x = &mut [1, 2, 4]; let x_ptr = x.as_mut_ptr(); unsafe { for i in 0..x.len() { *x_ptr.add(i) += 2; } } assert_eq!(x, &[3, 4, 6]); ``` ```rust pub fn as_ptr_range(&self) -> Range<*const T> ``` Returns the two raw pointers spanning the slice. The returned range is half-open, which means that the end pointer points *one past* the last element of the slice. This way, an empty slice is represented by two equal pointers, and the difference between the two pointers represents the size of the slice. See [`as_ptr`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.as_ptr) for warnings on using these pointers. The end pointer requires extra caution, as it does not point to a valid element in the slice. This function is useful for interacting with foreign interfaces which use two pointers to refer to a range of elements in memory, as is common in C++. It can also be useful to check if a pointer to an element refers to an element of this slice: ```rust let a = [1, 2, 3]; let x = &a[1] as *const _; let y = &5 as *const _; assert!(a.as_ptr_range().contains(&x)); assert!(!a.as_ptr_range().contains(&y)); ``` ```rust pub fn as_mut_ptr_range(&mut self) -> Range<*mut T> ``` Returns the two unsafe mutable pointers spanning the slice. The returned range is half-open, which means that the end pointer points *one past* the last element of the slice. This way, an empty slice is represented by two equal pointers, and the difference between the two pointers represents the size of the slice. See [`as_mut_ptr`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.as_mut_ptr) for warnings on using these pointers. The end pointer requires extra caution, as it does not point to a valid element in the slice. This function is useful for interacting with foreign interfaces which use two pointers to refer to a range of elements in memory, as is common in C++. ```rust pub fn as_array(&self) -> Option<&[T; N]> ``` Gets a reference to the underlying array. If `N` is not exactly equal to the length of `self`, then this method returns `None`. ```rust pub fn as_mut_array(&mut self) -> Option<&mut [T; N]> ``` Gets a mutable reference to the slice’s underlying array. If `N` is not exactly equal to the length of `self`, then this method returns `None`. ```rust pub fn swap(&mut self, a: usize, b: usize) ``` Swaps two elements in the slice. If `a` equals to `b`, it’s guaranteed that elements won’t change value. **Arguments** - a - The index of the first element - b - The index of the second element **Panics** Panics if `a` or `b` are out of bounds. **Examples** ```rust let mut v = ["a", "b", "c", "d", "e"]; v.swap(2, 4); assert!(v == ["a", "b", "e", "d", "c"]); ``` ```rust pub unsafe fn swap_unchecked(&mut self, a: usize, b: usize) ``` 🔬This is a nightly-only experimental API. (`slice_swap_unchecked`) Swaps two elements in the slice, without doing bounds checking. For a safe alternative see [`swap`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.swap). **Arguments** - a - The index of the first element - b - The index of the second element **Safety** Calling this method with an out-of-bounds index is *[undefined behavior](https://doc.rust-lang.org/reference/behavior-considered-undefined.html)*. The caller has to ensure that `a < self.len()` and `b < self.len()`. **Examples** ```rust #![feature(slice_swap_unchecked)] let mut v = ["a", "b", "c", "d"]; // SAFETY: we know that 1 and 3 are both indices of the slice unsafe { v.swap_unchecked(1, 3) }; assert!(v == ["a", "d", "c", "b"]); ``` ```rust pub fn reverse(&mut self) ``` Reverses the order of elements in the slice, in place. **Examples** ```rust let mut v = [1, 2, 3]; v.reverse(); assert!(v == [3, 2, 1]); ``` ```rust pub fn iter(&self) -> Iter<'_, T> ``` Returns an iterator over the slice. The iterator yields all items from start to end. **Examples** ```rust let x = &[1, 2, 4]; let mut iterator = x.iter(); assert_eq!(iterator.next(), Some(&1)); assert_eq!(iterator.next(), Some(&2)); assert_eq!(iterator.next(), Some(&4)); assert_eq!(iterator.next(), None); ``` ```rust pub fn iter_mut(&mut self) -> IterMut<'_, T> ``` Returns an iterator that allows modifying each value. The iterator yields all items from start to end. **Examples** ```rust let x = &mut [1, 2, 4]; for elem in x.iter_mut() { *elem += 2; } assert_eq!(x, &[3, 4, 6]); ``` ```rust pub fn windows(&self, size: usize) -> Windows<'_, T> ``` Returns an iterator over all contiguous windows of length `size`. The windows overlap. If the slice is shorter than `size`, the iterator returns no values. **Panics** Panics if `size` is zero. **Examples** ```rust let slice = ['l', 'o', 'r', 'e', 'm']; let mut iter = slice.windows(3); assert_eq!(iter.next().unwrap(), &['l', 'o', 'r']); assert_eq!(iter.next().unwrap(), &['o', 'r', 'e']); assert_eq!(iter.next().unwrap(), &['r', 'e', 'm']); assert!(iter.next().is_none()); ``` If the slice is shorter than `size`: ```rust let slice = ['f', 'o', 'o']; let mut iter = slice.windows(4); assert!(iter.next().is_none()); ``` Because the [Iterator](https://doc.rust-lang.org/1.99.1/core/iter/traits/iterator/trait.Iterator.html) trait cannot represent the required lifetimes, there is no `windows_mut` analog to `windows`; `[0,1,2].windows_mut(2).collect()` would violate [the rules of references](https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html#the-rules-of-references) (though a [LendingIterator](https://blog.rust-lang.org/2022/10/28/gats-stabilization.html) analog is possible). You can sometimes use [`Cell::as_slice_of_cells`](https://doc.rust-lang.org/1.99.1/core/cell/struct.Cell.html#method.as_slice_of_cells) in conjunction with `windows` instead: ```rust use std::cell::Cell; let mut array = ['R', 'u', 's', 't', ' ', '2', '0', '1', '5']; let slice = &mut array[..]; let slice_of_cells: &[Cell] = Cell::from_mut(slice).as_slice_of_cells(); for w in slice_of_cells.windows(3) { Cell::swap(&w[0], &w[2]); } assert_eq!(array, ['s', 't', ' ', '2', '0', '1', '5', 'u', 'R']); ``` ```rust pub fn chunks(&self, chunk_size: usize) -> Chunks<'_, T> ``` Returns an iterator over `chunk_size` elements of the slice at a time, starting at the beginning of the slice. The chunks are slices and do not overlap. If `chunk_size` does not divide the length of the slice, then the last chunk will not have length `chunk_size`. See [`chunks_exact`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.chunks_exact) for a variant of this iterator that returns chunks of always exactly `chunk_size` elements, and [`rchunks`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.rchunks) for the same iterator but starting at the end of the slice. If your `chunk_size` is a constant, consider using [`as_chunks`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.as_chunks) instead, which will give references to arrays of exactly that length, rather than slices. **Panics** Panics if `chunk_size` is zero. **Examples** ```rust let slice = ['l', 'o', 'r', 'e', 'm']; let mut iter = slice.chunks(2); assert_eq!(iter.next().unwrap(), &['l', 'o']); assert_eq!(iter.next().unwrap(), &['r', 'e']); assert_eq!(iter.next().unwrap(), &['m']); assert!(iter.next().is_none()); ``` ```rust pub fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut<'_, T> ``` Returns an iterator over `chunk_size` elements of the slice at a time, starting at the beginning of the slice. The chunks are mutable slices, and do not overlap. If `chunk_size` does not divide the length of the slice, then the last chunk will not have length `chunk_size`. See [`chunks_exact_mut`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.chunks_exact_mut) for a variant of this iterator that returns chunks of always exactly `chunk_size` elements, and [`rchunks_mut`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.rchunks_mut) for the same iterator but starting at the end of the slice. If your `chunk_size` is a constant, consider using [`as_chunks_mut`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.as_chunks_mut) instead, which will give references to arrays of exactly that length, rather than slices. **Panics** Panics if `chunk_size` is zero. **Examples** ```rust let v = &mut [0, 0, 0, 0, 0]; let mut count = 1; for chunk in v.chunks_mut(2) { for elem in chunk.iter_mut() { *elem += count; } count += 1; } assert_eq!(v, &[1, 1, 2, 2, 3]); ``` ```rust pub fn chunks_exact(&self, chunk_size: usize) -> ChunksExact<'_, T> ``` Returns an iterator over `chunk_size` elements of the slice at a time, starting at the beginning of the slice. The chunks are slices and do not overlap. If `chunk_size` does not divide the length of the slice, then the last up to `chunk_size-1` elements will be omitted and can be retrieved from the `remainder` function of the iterator. Due to each chunk having exactly `chunk_size` elements, the compiler can often optimize the resulting code better than in the case of [`chunks`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.chunks). See [`chunks`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.chunks) for a variant of this iterator that also returns the remainder as a smaller chunk, and [`rchunks_exact`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.rchunks_exact) for the same iterator but starting at the end of the slice. If your `chunk_size` is a constant, consider using [`as_chunks`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.as_chunks) instead, which will give references to arrays of exactly that length, rather than slices. **Panics** Panics if `chunk_size` is zero. **Examples** ```rust let slice = ['l', 'o', 'r', 'e', 'm']; let mut iter = slice.chunks_exact(2); assert_eq!(iter.next().unwrap(), &['l', 'o']); assert_eq!(iter.next().unwrap(), &['r', 'e']); assert!(iter.next().is_none()); assert_eq!(iter.remainder(), &['m']); ``` ```rust pub fn chunks_exact_mut(&mut self, chunk_size: usize) -> ChunksExactMut<'_, T> ``` Returns an iterator over `chunk_size` elements of the slice at a time, starting at the beginning of the slice. The chunks are mutable slices, and do not overlap. If `chunk_size` does not divide the length of the slice, then the last up to `chunk_size-1` elements will be omitted and can be retrieved from the `into_remainder` function of the iterator. Due to each chunk having exactly `chunk_size` elements, the compiler can often optimize the resulting code better than in the case of [`chunks_mut`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.chunks_mut). See [`chunks_mut`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.chunks_mut) for a variant of this iterator that also returns the remainder as a smaller chunk, and [`rchunks_exact_mut`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.rchunks_exact_mut) for the same iterator but starting at the end of the slice. If your `chunk_size` is a constant, consider using [`as_chunks_mut`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.as_chunks_mut) instead, which will give references to arrays of exactly that length, rather than slices. **Panics** Panics if `chunk_size` is zero. **Examples** ```rust let v = &mut [0, 0, 0, 0, 0]; let mut count = 1; for chunk in v.chunks_exact_mut(2) { for elem in chunk.iter_mut() { *elem += count; } count += 1; } assert_eq!(v, &[1, 1, 2, 2, 0]); ``` ```rust pub unsafe fn as_chunks_unchecked(&self) -> &[[T; N]] ``` Splits the slice into a slice of `N`-element arrays, assuming that there’s no remainder. This is the inverse operation to [`as_flattened`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.as_flattened). As this is `unsafe`, consider whether you could use [`as_chunks`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.as_chunks) or [`as_rchunks`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.as_rchunks) instead, perhaps via something like `if let (chunks, []) = slice.as_chunks()` or `let (chunks, []) = slice.as_chunks() else { unreachable!() };`. **Safety** This may only be called when - The slice splits exactly into `N`-element chunks (aka `self.len() % N == 0`). - `N != 0`. **Examples** ```rust let slice: &[char] = &['l', 'o', 'r', 'e', 'm', '!']; let chunks: &[[char; 1]] = // SAFETY: 1-element chunks never have remainder unsafe { slice.as_chunks_unchecked() }; assert_eq!(chunks, &[['l'], ['o'], ['r'], ['e'], ['m'], ['!']]); let chunks: &[[char; 3]] = // SAFETY: The slice length (6) is a multiple of 3 unsafe { slice.as_chunks_unchecked() }; assert_eq!(chunks, &[['l', 'o', 'r'], ['e', 'm', '!']]); // These would be unsound: // let chunks: &[[_; 5]] = slice.as_chunks_unchecked() // The slice length is not a multiple of 5 // let chunks: &[[_; 0]] = slice.as_chunks_unchecked() // Zero-length chunks are never allowed ``` ```rust pub fn as_chunks(&self) -> (&[[T; N]], &[T]) ``` Splits the slice into a slice of `N`-element arrays, starting at the beginning of the slice, and a remainder slice with length strictly less than `N`. The remainder is meaningful in the division sense. Given `let (chunks, remainder) = slice.as_chunks()`, then: - `chunks.len()` equals `slice.len() / N`, - `remainder.len()` equals `slice.len() % N`, and - `slice.len()` equals `chunks.len() * N + remainder.len()`. You can flatten the chunks back into a slice-of-`T` with [`as_flattened`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.as_flattened). **Panics** Panics if `N` is zero. Note that this check is against a const generic parameter, not a runtime value, and thus a particular monomorphization will either always panic or it will never panic. **Examples** ```rust let slice = ['l', 'o', 'r', 'e', 'm']; let (chunks, remainder) = slice.as_chunks(); assert_eq!(chunks, &[['l', 'o'], ['r', 'e']]); assert_eq!(remainder, &['m']); ``` If you expect the slice to be an exact multiple, you can combine `let`-`else` with an empty slice pattern: ```rust let slice = ['R', 'u', 's', 't']; let (chunks, []) = slice.as_chunks::<2>() else { panic!("slice didn't have even length") }; assert_eq!(chunks, &[['R', 'u'], ['s', 't']]); ``` ```rust pub fn as_rchunks(&self) -> (&[T], &[[T; N]]) ``` Splits the slice into a slice of `N`-element arrays, starting at the end of the slice, and a remainder slice with length strictly less than `N`. The remainder is meaningful in the division sense. Given `let (remainder, chunks) = slice.as_rchunks()`, then: - `remainder.len()` equals `slice.len() % N`, - `chunks.len()` equals `slice.len() / N`, and - `slice.len()` equals `chunks.len() * N + remainder.len()`. You can flatten the chunks back into a slice-of-`T` with [`as_flattened`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.as_flattened). **Panics** Panics if `N` is zero. Note that this check is against a const generic parameter, not a runtime value, and thus a particular monomorphization will either always panic or it will never panic. **Examples** ```rust let slice = ['l', 'o', 'r', 'e', 'm']; let (remainder, chunks) = slice.as_rchunks(); assert_eq!(remainder, &['l']); assert_eq!(chunks, &[['o', 'r'], ['e', 'm']]); ``` ```rust pub unsafe fn as_chunks_unchecked_mut( &mut self, ) -> &mut [[T; N]] ``` Splits the slice into a slice of `N`-element arrays, assuming that there’s no remainder. This is the inverse operation to [`as_flattened_mut`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.as_flattened_mut). As this is `unsafe`, consider whether you could use [`as_chunks_mut`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.as_chunks_mut) or [`as_rchunks_mut`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.as_rchunks_mut) instead, perhaps via something like `if let (chunks, []) = slice.as_chunks_mut()` or `let (chunks, []) = slice.as_chunks_mut() else { unreachable!() };`. **Safety** This may only be called when - The slice splits exactly into `N`-element chunks (aka `self.len() % N == 0`). - `N != 0`. **Examples** ```rust let slice: &mut [char] = &mut ['l', 'o', 'r', 'e', 'm', '!']; let chunks: &mut [[char; 1]] = // SAFETY: 1-element chunks never have remainder unsafe { slice.as_chunks_unchecked_mut() }; chunks[0] = ['L']; assert_eq!(chunks, &[['L'], ['o'], ['r'], ['e'], ['m'], ['!']]); let chunks: &mut [[char; 3]] = // SAFETY: The slice length (6) is a multiple of 3 unsafe { slice.as_chunks_unchecked_mut() }; chunks[1] = ['a', 'x', '?']; assert_eq!(slice, &['L', 'o', 'r', 'a', 'x', '?']); // These would be unsound: // let chunks: &[[_; 5]] = slice.as_chunks_unchecked_mut() // The slice length is not a multiple of 5 // let chunks: &[[_; 0]] = slice.as_chunks_unchecked_mut() // Zero-length chunks are never allowed ``` ```rust pub fn as_chunks_mut(&mut self) -> (&mut [[T; N]], &mut [T]) ``` Splits the slice into a slice of `N`-element arrays, starting at the beginning of the slice, and a remainder slice with length strictly less than `N`. The remainder is meaningful in the division sense. Given `let (chunks, remainder) = slice.as_chunks_mut()`, then: - `chunks.len()` equals `slice.len() / N`, - `remainder.len()` equals `slice.len() % N`, and - `slice.len()` equals `chunks.len() * N + remainder.len()`. You can flatten the chunks back into a slice-of-`T` with [`as_flattened_mut`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.as_flattened_mut). **Panics** Panics if `N` is zero. Note that this check is against a const generic parameter, not a runtime value, and thus a particular monomorphization will either always panic or it will never panic. **Examples** ```rust let v = &mut [0, 0, 0, 0, 0]; let mut count = 1; let (chunks, remainder) = v.as_chunks_mut(); remainder[0] = 9; for chunk in chunks { *chunk = [count; 2]; count += 1; } assert_eq!(v, &[1, 1, 2, 2, 9]); ``` ```rust pub fn as_rchunks_mut(&mut self) -> (&mut [T], &mut [[T; N]]) ``` Splits the slice into a slice of `N`-element arrays, starting at the end of the slice, and a remainder slice with length strictly less than `N`. The remainder is meaningful in the division sense. Given `let (remainder, chunks) = slice.as_rchunks_mut()`, then: - `remainder.len()` equals `slice.len() % N`, - `chunks.len()` equals `slice.len() / N`, and - `slice.len()` equals `chunks.len() * N + remainder.len()`. You can flatten the chunks back into a slice-of-`T` with [`as_flattened_mut`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.as_flattened_mut). **Panics** Panics if `N` is zero. Note that this check is against a const generic parameter, not a runtime value, and thus a particular monomorphization will either always panic or it will never panic. **Examples** ```rust let v = &mut [0, 0, 0, 0, 0]; let mut count = 1; let (remainder, chunks) = v.as_rchunks_mut(); remainder[0] = 9; for chunk in chunks { *chunk = [count; 2]; count += 1; } assert_eq!(v, &[9, 1, 1, 2, 2]); ``` ```rust pub fn array_windows(&self) -> ArrayWindows<'_, T, N> ``` Returns an iterator over overlapping windows of `N` elements of a slice, starting at the beginning of the slice. This is the const generic equivalent of [`windows`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.windows). If `N` is greater than the size of the slice, it will return no windows. **Panics** Panics if `N` is zero. Note that this check is against a const generic parameter, not a runtime value, and thus a particular monomorphization will either always panic or it will never panic. **Examples** ```rust let slice = [0, 1, 2, 3]; let mut iter = slice.array_windows(); assert_eq!(iter.next().unwrap(), &[0, 1]); assert_eq!(iter.next().unwrap(), &[1, 2]); assert_eq!(iter.next().unwrap(), &[2, 3]); assert!(iter.next().is_none()); ``` ```rust pub fn rchunks(&self, chunk_size: usize) -> RChunks<'_, T> ``` Returns an iterator over `chunk_size` elements of the slice at a time, starting at the end of the slice. The chunks are slices and do not overlap. If `chunk_size` does not divide the length of the slice, then the last chunk will not have length `chunk_size`. See [`rchunks_exact`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.rchunks_exact) for a variant of this iterator that returns chunks of always exactly `chunk_size` elements, and [`chunks`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.chunks) for the same iterator but starting at the beginning of the slice. If your `chunk_size` is a constant, consider using [`as_rchunks`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.as_rchunks) instead, which will give references to arrays of exactly that length, rather than slices. **Panics** Panics if `chunk_size` is zero. **Examples** ```rust let slice = ['l', 'o', 'r', 'e', 'm']; let mut iter = slice.rchunks(2); assert_eq!(iter.next().unwrap(), &['e', 'm']); assert_eq!(iter.next().unwrap(), &['o', 'r']); assert_eq!(iter.next().unwrap(), &['l']); assert!(iter.next().is_none()); ``` ```rust pub fn rchunks_mut(&mut self, chunk_size: usize) -> RChunksMut<'_, T> ``` Returns an iterator over `chunk_size` elements of the slice at a time, starting at the end of the slice. The chunks are mutable slices, and do not overlap. If `chunk_size` does not divide the length of the slice, then the last chunk will not have length `chunk_size`. See [`rchunks_exact_mut`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.rchunks_exact_mut) for a variant of this iterator that returns chunks of always exactly `chunk_size` elements, and [`chunks_mut`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.chunks_mut) for the same iterator but starting at the beginning of the slice. If your `chunk_size` is a constant, consider using [`as_rchunks_mut`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.as_rchunks_mut) instead, which will give references to arrays of exactly that length, rather than slices. **Panics** Panics if `chunk_size` is zero. **Examples** ```rust let v = &mut [0, 0, 0, 0, 0]; let mut count = 1; for chunk in v.rchunks_mut(2) { for elem in chunk.iter_mut() { *elem += count; } count += 1; } assert_eq!(v, &[3, 2, 2, 1, 1]); ``` ```rust pub fn rchunks_exact(&self, chunk_size: usize) -> RChunksExact<'_, T> ``` Returns an iterator over `chunk_size` elements of the slice at a time, starting at the end of the slice. The chunks are slices and do not overlap. If `chunk_size` does not divide the length of the slice, then the last up to `chunk_size-1` elements will be omitted and can be retrieved from the `remainder` function of the iterator. Due to each chunk having exactly `chunk_size` elements, the compiler can often optimize the resulting code better than in the case of [`rchunks`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.rchunks). See [`rchunks`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.rchunks) for a variant of this iterator that also returns the remainder as a smaller chunk, and [`chunks_exact`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.chunks_exact) for the same iterator but starting at the beginning of the slice. If your `chunk_size` is a constant, consider using [`as_rchunks`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.as_rchunks) instead, which will give references to arrays of exactly that length, rather than slices. **Panics** Panics if `chunk_size` is zero. **Examples** ```rust let slice = ['l', 'o', 'r', 'e', 'm']; let mut iter = slice.rchunks_exact(2); assert_eq!(iter.next().unwrap(), &['e', 'm']); assert_eq!(iter.next().unwrap(), &['o', 'r']); assert!(iter.next().is_none()); assert_eq!(iter.remainder(), &['l']); ``` ```rust pub fn rchunks_exact_mut(&mut self, chunk_size: usize) -> RChunksExactMut<'_, T> ``` Returns an iterator over `chunk_size` elements of the slice at a time, starting at the end of the slice. The chunks are mutable slices, and do not overlap. If `chunk_size` does not divide the length of the slice, then the last up to `chunk_size-1` elements will be omitted and can be retrieved from the `into_remainder` function of the iterator. Due to each chunk having exactly `chunk_size` elements, the compiler can often optimize the resulting code better than in the case of [`chunks_mut`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.chunks_mut). See [`rchunks_mut`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.rchunks_mut) for a variant of this iterator that also returns the remainder as a smaller chunk, and [`chunks_exact_mut`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.chunks_exact_mut) for the same iterator but starting at the beginning of the slice. If your `chunk_size` is a constant, consider using [`as_rchunks_mut`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.as_rchunks_mut) instead, which will give references to arrays of exactly that length, rather than slices. **Panics** Panics if `chunk_size` is zero. **Examples** ```rust let v = &mut [0, 0, 0, 0, 0]; let mut count = 1; for chunk in v.rchunks_exact_mut(2) { for elem in chunk.iter_mut() { *elem += count; } count += 1; } assert_eq!(v, &[0, 2, 2, 1, 1]); ``` ```rust pub fn chunk_by(&self, pred: F) -> ChunkBy<'_, T, F> where F: FnMut(&T, &T) -> bool ``` Returns an iterator over the slice producing non-overlapping runs of elements using the predicate to separate them. The predicate is called for every pair of consecutive elements, meaning that it is called on `slice[0]` and `slice[1]`, followed by `slice[1]` and `slice[2]`, and so on. **Examples** ```rust let slice = &[1, 1, 1, 3, 3, 2, 2, 2]; let mut iter = slice.chunk_by(|a, b| a == b); assert_eq!(iter.next(), Some(&[1, 1, 1][..])); assert_eq!(iter.next(), Some(&[3, 3][..])); assert_eq!(iter.next(), Some(&[2, 2, 2][..])); assert_eq!(iter.next(), None); ``` This method can be used to extract the sorted subslices: ```rust let slice = &[1, 1, 2, 3, 2, 3, 2, 3, 4]; let mut iter = slice.chunk_by(|a, b| a <= b); assert_eq!(iter.next(), Some(&[1, 1, 2, 3][..])); assert_eq!(iter.next(), Some(&[2, 3][..])); assert_eq!(iter.next(), Some(&[2, 3, 4][..])); assert_eq!(iter.next(), None); ``` ```rust pub fn chunk_by_mut(&mut self, pred: F) -> ChunkByMut<'_, T, F> where F: FnMut(&T, &T) -> bool ``` Returns an iterator over the slice producing non-overlapping mutable runs of elements using the predicate to separate them. The predicate is called for every pair of consecutive elements, meaning that it is called on `slice[0]` and `slice[1]`, followed by `slice[1]` and `slice[2]`, and so on. **Examples** ```rust let slice = &mut [1, 1, 1, 3, 3, 2, 2, 2]; let mut iter = slice.chunk_by_mut(|a, b| a == b); assert_eq!(iter.next(), Some(&mut [1, 1, 1][..])); assert_eq!(iter.next(), Some(&mut [3, 3][..])); assert_eq!(iter.next(), Some(&mut [2, 2, 2][..])); assert_eq!(iter.next(), None); ``` This method can be used to extract the sorted subslices: ```rust let slice = &mut [1, 1, 2, 3, 2, 3, 2, 3, 4]; let mut iter = slice.chunk_by_mut(|a, b| a <= b); assert_eq!(iter.next(), Some(&mut [1, 1, 2, 3][..])); assert_eq!(iter.next(), Some(&mut [2, 3][..])); assert_eq!(iter.next(), Some(&mut [2, 3, 4][..])); assert_eq!(iter.next(), None); ``` ```rust pub fn split_at(&self, mid: usize) -> (&[T], &[T]) ``` Divides one slice into two at an index. The first will contain all indices from `[0, mid)` (excluding the index `mid` itself) and the second will contain all indices from `[mid, len)` (excluding the index `len` itself). **Panics** Panics if `mid > len`. For a non-panicking alternative see [`split_at_checked`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.split_at_checked). **Examples** ```rust let v = ['a', 'b', 'c']; { let (left, right) = v.split_at(0); assert_eq!(left, []); assert_eq!(right, ['a', 'b', 'c']); } { let (left, right) = v.split_at(2); assert_eq!(left, ['a', 'b']); assert_eq!(right, ['c']); } { let (left, right) = v.split_at(3); assert_eq!(left, ['a', 'b', 'c']); assert_eq!(right, []); } ``` ```rust pub fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) ``` Divides one mutable slice into two at an index. The first will contain all indices from `[0, mid)` (excluding the index `mid` itself) and the second will contain all indices from `[mid, len)` (excluding the index `len` itself). **Panics** Panics if `mid > len`. For a non-panicking alternative see [`split_at_mut_checked`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.split_at_mut_checked). **Examples** ```rust let mut v = [1, 0, 3, 0, 5, 6]; let (left, right) = v.split_at_mut(2); assert_eq!(left, [1, 0]); assert_eq!(right, [3, 0, 5, 6]); left[1] = 2; right[1] = 4; assert_eq!(v, [1, 2, 3, 4, 5, 6]); ``` ```rust pub unsafe fn split_at_unchecked(&self, mid: usize) -> (&[T], &[T]) ``` Divides one slice into two at an index, without doing bounds checking. The first will contain all indices from `[0, mid)` (excluding the index `mid` itself) and the second will contain all indices from `[mid, len)` (excluding the index `len` itself). For a safe alternative see [`split_at`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.split_at). **Safety** Calling this method with an out-of-bounds index is *[undefined behavior](https://doc.rust-lang.org/reference/behavior-considered-undefined.html)* even if the resulting reference is not used. The caller has to ensure that `0 <= mid <= self.len()`. **Examples** ```rust let v = ['a', 'b', 'c']; unsafe { let (left, right) = v.split_at_unchecked(0); assert_eq!(left, []); assert_eq!(right, ['a', 'b', 'c']); } unsafe { let (left, right) = v.split_at_unchecked(2); assert_eq!(left, ['a', 'b']); assert_eq!(right, ['c']); } unsafe { let (left, right) = v.split_at_unchecked(3); assert_eq!(left, ['a', 'b', 'c']); assert_eq!(right, []); } ``` ```rust pub unsafe fn split_at_mut_unchecked( &mut self, mid: usize, ) -> (&mut [T], &mut [T]) ``` Divides one mutable slice into two at an index, without doing bounds checking. The first will contain all indices from `[0, mid)` (excluding the index `mid` itself) and the second will contain all indices from `[mid, len)` (excluding the index `len` itself). For a safe alternative see [`split_at_mut`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.split_at_mut). **Safety** Calling this method with an out-of-bounds index is *[undefined behavior](https://doc.rust-lang.org/reference/behavior-considered-undefined.html)* even if the resulting reference is not used. The caller has to ensure that `0 <= mid <= self.len()`. **Examples** ```rust let mut v = [1, 0, 3, 0, 5, 6]; // scoped to restrict the lifetime of the borrows unsafe { let (left, right) = v.split_at_mut_unchecked(2); assert_eq!(left, [1, 0]); assert_eq!(right, [3, 0, 5, 6]); left[1] = 2; right[1] = 4; } assert_eq!(v, [1, 2, 3, 4, 5, 6]); ``` ```rust pub fn split_at_checked(&self, mid: usize) -> Option<(&[T], &[T])> ``` Divides one slice into two at an index, returning `None` if the slice is too short. If `mid ≤ len` returns a pair of slices where the first will contain all indices from `[0, mid)` (excluding the index `mid` itself) and the second will contain all indices from `[mid, len)` (excluding the index `len` itself). Otherwise, if `mid > len`, returns `None`. **Examples** ```rust let v = [1, -2, 3, -4, 5, -6]; { let (left, right) = v.split_at_checked(0).unwrap(); assert_eq!(left, []); assert_eq!(right, [1, -2, 3, -4, 5, -6]); } { let (left, right) = v.split_at_checked(2).unwrap(); assert_eq!(left, [1, -2]); assert_eq!(right, [3, -4, 5, -6]); } { let (left, right) = v.split_at_checked(6).unwrap(); assert_eq!(left, [1, -2, 3, -4, 5, -6]); assert_eq!(right, []); } assert_eq!(None, v.split_at_checked(7)); ``` ```rust pub fn split_at_mut_checked( &mut self, mid: usize, ) -> Option<(&mut [T], &mut [T])> ``` Divides one mutable slice into two at an index, returning `None` if the slice is too short. If `mid ≤ len` returns a pair of slices where the first will contain all indices from `[0, mid)` (excluding the index `mid` itself) and the second will contain all indices from `[mid, len)` (excluding the index `len` itself). Otherwise, if `mid > len`, returns `None`. **Examples** ```rust let mut v = [1, 0, 3, 0, 5, 6]; if let Some((left, right)) = v.split_at_mut_checked(2) { assert_eq!(left, [1, 0]); assert_eq!(right, [3, 0, 5, 6]); left[1] = 2; right[1] = 4; } assert_eq!(v, [1, 2, 3, 4, 5, 6]); assert_eq!(None, v.split_at_mut_checked(7)); ``` ```rust pub fn split(&self, pred: F) -> Split<'_, T, F> where F: FnMut(&T) -> bool ``` Returns an iterator over subslices separated by elements that match `pred`. The matched element is not contained in the subslices. **Examples** ```rust let slice = [10, 40, 33, 20]; let mut iter = slice.split(|num| num % 3 == 0); assert_eq!(iter.next().unwrap(), &[10, 40]); assert_eq!(iter.next().unwrap(), &[20]); assert!(iter.next().is_none()); ``` If the first element is matched, an empty slice will be the first item returned by the iterator. Similarly, if the last element in the slice is matched, an empty slice will be the last item returned by the iterator: ```rust let slice = [10, 40, 33]; let mut iter = slice.split(|num| num % 3 == 0); assert_eq!(iter.next().unwrap(), &[10, 40]); assert_eq!(iter.next().unwrap(), &[]); assert!(iter.next().is_none()); ``` If two matched elements are directly adjacent, an empty slice will be present between them: ```rust let slice = [10, 6, 33, 20]; let mut iter = slice.split(|num| num % 3 == 0); assert_eq!(iter.next().unwrap(), &[10]); assert_eq!(iter.next().unwrap(), &[]); assert_eq!(iter.next().unwrap(), &[20]); assert!(iter.next().is_none()); ``` ```rust pub fn split_mut(&mut self, pred: F) -> SplitMut<'_, T, F> where F: FnMut(&T) -> bool ``` Returns an iterator over mutable subslices separated by elements that match `pred`. The matched element is not contained in the subslices. **Examples** ```rust let mut v = [10, 40, 30, 20, 60, 50]; for group in v.split_mut(|num| *num % 3 == 0) { group[0] = 1; } assert_eq!(v, [1, 40, 30, 1, 60, 1]); ``` ```rust pub fn split_inclusive(&self, pred: F) -> SplitInclusive<'_, T, F> where F: FnMut(&T) -> bool ``` Returns an iterator over subslices separated by elements that match `pred`. The matched element is contained in the end of the previous subslice as a terminator. **Examples** ```rust let slice = [10, 40, 33, 20]; let mut iter = slice.split_inclusive(|num| num % 3 == 0); assert_eq!(iter.next().unwrap(), &[10, 40, 33]); assert_eq!(iter.next().unwrap(), &[20]); assert!(iter.next().is_none()); ``` If the last element of the slice is matched, that element will be considered the terminator of the preceding slice. That slice will be the last item returned by the iterator. ```rust let slice = [3, 10, 40, 33]; let mut iter = slice.split_inclusive(|num| num % 3 == 0); assert_eq!(iter.next().unwrap(), &[3]); assert_eq!(iter.next().unwrap(), &[10, 40, 33]); assert!(iter.next().is_none()); ``` ```rust pub fn split_inclusive_mut(&mut self, pred: F) -> SplitInclusiveMut<'_, T, F> where F: FnMut(&T) -> bool ``` Returns an iterator over mutable subslices separated by elements that match `pred`. The matched element is contained in the previous subslice as a terminator. **Examples** ```rust let mut v = [10, 40, 30, 20, 60, 50]; for group in v.split_inclusive_mut(|num| *num % 3 == 0) { let terminator_idx = group.len()-1; group[terminator_idx] = 1; } assert_eq!(v, [10, 40, 1, 20, 1, 1]); ``` ```rust pub fn rsplit(&self, pred: F) -> RSplit<'_, T, F> where F: FnMut(&T) -> bool ``` Returns an iterator over subslices separated by elements that match `pred`, starting at the end of the slice and working backwards. The matched element is not contained in the subslices. **Examples** ```rust let slice = [11, 22, 33, 0, 44, 55]; let mut iter = slice.rsplit(|num| *num == 0); assert_eq!(iter.next().unwrap(), &[44, 55]); assert_eq!(iter.next().unwrap(), &[11, 22, 33]); assert_eq!(iter.next(), None); ``` As with `split()`, if the first or last element is matched, an empty slice will be the first (or last) item returned by the iterator. ```rust let v = &[0, 1, 1, 2, 3, 5, 8]; let mut it = v.rsplit(|n| *n % 2 == 0); assert_eq!(it.next().unwrap(), &[]); assert_eq!(it.next().unwrap(), &[3, 5]); assert_eq!(it.next().unwrap(), &[1, 1]); assert_eq!(it.next().unwrap(), &[]); assert_eq!(it.next(), None); ``` ```rust pub fn rsplit_mut(&mut self, pred: F) -> RSplitMut<'_, T, F> where F: FnMut(&T) -> bool ``` Returns an iterator over mutable subslices separated by elements that match `pred`, starting at the end of the slice and working backwards. The matched element is not contained in the subslices. **Examples** ```rust let mut v = [100, 400, 300, 200, 600, 500]; let mut count = 0; for group in v.rsplit_mut(|num| *num % 3 == 0) { count += 1; group[0] = count; } assert_eq!(v, [3, 400, 300, 2, 600, 1]); ``` ```rust pub fn splitn(&self, n: usize, pred: F) -> SplitN<'_, T, F> where F: FnMut(&T) -> bool ``` Returns an iterator over subslices separated by elements that match `pred`, limited to returning at most `n` items. The matched element is not contained in the subslices. The last element returned, if any, will contain the remainder of the slice. **Examples** Print the slice split once by numbers divisible by 3 (i.e., `[10, 40]`, `[20, 60, 50]`): ```rust let v = [10, 40, 30, 20, 60, 50]; for group in v.splitn(2, |num| *num % 3 == 0) { println!("{group:?}"); } ``` ```rust pub fn splitn_mut(&mut self, n: usize, pred: F) -> SplitNMut<'_, T, F> where F: FnMut(&T) -> bool ``` Returns an iterator over mutable subslices separated by elements that match `pred`, limited to returning at most `n` items. The matched element is not contained in the subslices. The last element returned, if any, will contain the remainder of the slice. **Examples** ```rust let mut v = [10, 40, 30, 20, 60, 50]; for group in v.splitn_mut(2, |num| *num % 3 == 0) { group[0] = 1; } assert_eq!(v, [1, 40, 30, 1, 60, 50]); ``` ```rust pub fn rsplitn(&self, n: usize, pred: F) -> RSplitN<'_, T, F> where F: FnMut(&T) -> bool ``` Returns an iterator over subslices separated by elements that match `pred` limited to returning at most `n` items. This starts at the end of the slice and works backwards. The matched element is not contained in the subslices. The last element returned, if any, will contain the remainder of the slice. **Examples** Print the slice split once, starting from the end, by numbers divisible by 3 (i.e., `[50]`, `[10, 40, 30, 20]`): ```rust let v = [10, 40, 30, 20, 60, 50]; for group in v.rsplitn(2, |num| *num % 3 == 0) { println!("{group:?}"); } ``` ```rust pub fn rsplitn_mut(&mut self, n: usize, pred: F) -> RSplitNMut<'_, T, F> where F: FnMut(&T) -> bool ``` Returns an iterator over subslices separated by elements that match `pred` limited to returning at most `n` items. This starts at the end of the slice and works backwards. The matched element is not contained in the subslices. The last element returned, if any, will contain the remainder of the slice. **Examples** ```rust let mut s = [10, 40, 30, 20, 60, 50]; for group in s.rsplitn_mut(2, |num| *num % 3 == 0) { group[0] = 1; } assert_eq!(s, [1, 40, 30, 20, 60, 1]); ``` ```rust pub fn split_once(&self, pred: F) -> Option<(&[T], &[T])> where F: FnMut(&T) -> bool ``` 🔬This is a nightly-only experimental API. (`slice_split_once`) Splits the slice on the first element that matches the specified predicate. If any matching elements are present in the slice, returns the prefix before the match and suffix after. The matching element itself is not included. If no elements match, returns `None`. **Examples** ```rust #![feature(slice_split_once)] let s = [1, 2, 3, 2, 4]; assert_eq!(s.split_once(|&x| x == 2), Some(( &[1][..], &[3, 2, 4][..] ))); assert_eq!(s.split_once(|&x| x == 0), None); ``` ```rust pub fn rsplit_once(&self, pred: F) -> Option<(&[T], &[T])> where F: FnMut(&T) -> bool ``` 🔬This is a nightly-only experimental API. (`slice_split_once`) Splits the slice on the last element that matches the specified predicate. If any matching elements are present in the slice, returns the prefix before the match and suffix after. The matching element itself is not included. If no elements match, returns `None`. **Examples** ```rust #![feature(slice_split_once)] let s = [1, 2, 3, 2, 4]; assert_eq!(s.rsplit_once(|&x| x == 2), Some(( &[1, 2, 3][..], &[4][..] ))); assert_eq!(s.rsplit_once(|&x| x == 0), None); ``` ```rust pub fn contains(&self, x: &T) -> bool where T: PartialEq ``` Returns `true` if the slice contains an element with the given value. This operation is *O*(*n*). Note that if you have a sorted slice, [`binary_search`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.binary_search) may be faster. **Examples** ```rust let v = [10, 40, 30]; assert!(v.contains(&30)); assert!(!v.contains(&50)); ``` If you do not have a `&T`, but some other value that you can compare with one (for example, `String` implements `PartialEq`), you can use `iter().any`: ```rust let v = [String::from("hello"), String::from("world")]; // slice of `String` assert!(v.iter().any(|e| e == "hello")); // search with `&str` assert!(!v.iter().any(|e| e == "hi")); ``` ```rust pub fn starts_with(&self, needle: &[T]) -> bool where T: PartialEq ``` Returns `true` if `needle` is a prefix of the slice or equal to the slice. **Examples** ```rust let v = [10, 40, 30]; assert!(v.starts_with(&[10])); assert!(v.starts_with(&[10, 40])); assert!(v.starts_with(&v)); assert!(!v.starts_with(&[50])); assert!(!v.starts_with(&[10, 50])); ``` Always returns `true` if `needle` is an empty slice: ```rust let v = &[10, 40, 30]; assert!(v.starts_with(&[])); let v: &[u8] = &[]; assert!(v.starts_with(&[])); ``` ```rust pub fn ends_with(&self, needle: &[T]) -> bool where T: PartialEq ``` Returns `true` if `needle` is a suffix of the slice or equal to the slice. **Examples** ```rust let v = [10, 40, 30]; assert!(v.ends_with(&[30])); assert!(v.ends_with(&[40, 30])); assert!(v.ends_with(&v)); assert!(!v.ends_with(&[50])); assert!(!v.ends_with(&[50, 30])); ``` Always returns `true` if `needle` is an empty slice: ```rust let v = &[10, 40, 30]; assert!(v.ends_with(&[])); let v: &[u8] = &[]; assert!(v.ends_with(&[])); ``` ```rust pub fn strip_prefix

(&self, prefix: &P) -> Option<&[T]> where P: SlicePattern + ?Sized, T: PartialEq ``` Returns a subslice with the prefix removed. If the slice starts with `prefix`, returns the subslice after the prefix, wrapped in `Some`. If `prefix` is empty, simply returns the original slice. If `prefix` is equal to the original slice, returns an empty slice. If the slice does not start with `prefix`, returns `None`. **Examples** ```rust let v = &[10, 40, 30]; assert_eq!(v.strip_prefix(&[10]), Some(&[40, 30][..])); assert_eq!(v.strip_prefix(&[10, 40]), Some(&[30][..])); assert_eq!(v.strip_prefix(&[10, 40, 30]), Some(&[][..])); assert_eq!(v.strip_prefix(&[50]), None); assert_eq!(v.strip_prefix(&[10, 50]), None); let prefix : &str = "he"; assert_eq!(b"hello".strip_prefix(prefix.as_bytes()), Some(b"llo".as_ref())); ``` ```rust pub fn strip_suffix

(&self, suffix: &P) -> Option<&[T]> where P: SlicePattern + ?Sized, T: PartialEq ``` Returns a subslice with the suffix removed. If the slice ends with `suffix`, returns the subslice before the suffix, wrapped in `Some`. If `suffix` is empty, simply returns the original slice. If `suffix` is equal to the original slice, returns an empty slice. If the slice does not end with `suffix`, returns `None`. **Examples** ```rust let v = &[10, 40, 30]; assert_eq!(v.strip_suffix(&[30]), Some(&[10, 40][..])); assert_eq!(v.strip_suffix(&[40, 30]), Some(&[10][..])); assert_eq!(v.strip_suffix(&[10, 40, 30]), Some(&[][..])); assert_eq!(v.strip_suffix(&[50]), None); assert_eq!(v.strip_suffix(&[50, 30]), None); ``` ```rust pub fn strip_circumfix(&self, prefix: &P, suffix: &S) -> Option<&[T]> where T: PartialEq, S: SlicePattern + ?Sized, P: SlicePattern + ?Sized ``` Returns a subslice with the prefix and suffix removed. If the slice starts with `prefix`, ends with `suffix`, and the prefix and suffix don’t overlap, returns the subslice after the prefix and before the suffix, wrapped in `Some`. If the slice does not start with `prefix`, does not end with `suffix`, or the prefix and suffix overlap in the slice, returns `None`. **Examples** ```rust let v = &[10, 50, 40, 30]; assert_eq!(v.strip_circumfix(&[10], &[30]), Some(&[50, 40][..])); assert_eq!(v.strip_circumfix(&[10], &[40, 30]), Some(&[50][..])); assert_eq!(v.strip_circumfix(&[10, 50], &[40, 30]), Some(&[][..])); assert_eq!(v.strip_circumfix(&[50], &[30]), None); assert_eq!(v.strip_circumfix(&[10], &[40]), None); assert_eq!(v.strip_circumfix(&[], &[40, 30]), Some(&[10, 50][..])); assert_eq!(v.strip_circumfix(&[10, 50], &[]), Some(&[40, 30][..])); assert_eq!(v.strip_circumfix(&[10, 50, 40], &[50, 40, 30]), None); ``` ```rust pub fn trim_prefix

(&self, prefix: &P) -> &[T] where P: SlicePattern + ?Sized, T: PartialEq ``` 🔬This is a nightly-only experimental API. (`trim_prefix_suffix`) Returns a subslice with the optional prefix removed. If the slice starts with `prefix`, returns the subslice after the prefix. If `prefix` is empty or the slice does not start with `prefix`, simply returns the original slice. If `prefix` is equal to the original slice, returns an empty slice. **Examples** ```rust #![feature(trim_prefix_suffix)] let v = &[10, 40, 30]; // Prefix present - removes it assert_eq!(v.trim_prefix(&[10]), &[40, 30][..]); assert_eq!(v.trim_prefix(&[10, 40]), &[30][..]); assert_eq!(v.trim_prefix(&[10, 40, 30]), &[][..]); // Prefix absent - returns original slice assert_eq!(v.trim_prefix(&[50]), &[10, 40, 30][..]); assert_eq!(v.trim_prefix(&[10, 50]), &[10, 40, 30][..]); let prefix : &str = "he"; assert_eq!(b"hello".trim_prefix(prefix.as_bytes()), b"llo".as_ref()); ``` ```rust pub fn trim_suffix

(&self, suffix: &P) -> &[T] where P: SlicePattern + ?Sized, T: PartialEq ``` 🔬This is a nightly-only experimental API. (`trim_prefix_suffix`) Returns a subslice with the optional suffix removed. If the slice ends with `suffix`, returns the subslice before the suffix. If `suffix` is empty or the slice does not end with `suffix`, simply returns the original slice. If `suffix` is equal to the original slice, returns an empty slice. **Examples** ```rust #![feature(trim_prefix_suffix)] let v = &[10, 40, 30]; // Suffix present - removes it assert_eq!(v.trim_suffix(&[30]), &[10, 40][..]); assert_eq!(v.trim_suffix(&[40, 30]), &[10][..]); assert_eq!(v.trim_suffix(&[10, 40, 30]), &[][..]); // Suffix absent - returns original slice assert_eq!(v.trim_suffix(&[50]), &[10, 40, 30][..]); assert_eq!(v.trim_suffix(&[50, 30]), &[10, 40, 30][..]); ``` ```rust pub fn binary_search(&self, x: &T) -> Result where T: Ord ``` Binary searches this slice for a given element. If the slice is not sorted, the returned result is unspecified and meaningless. If the value is found then [`Result::Ok`](https://doc.rust-lang.org/1.99.1/core/result/enum.Result.html#variant.Ok) is returned, containing the index of the matching element. If there are multiple matches, then any one of the matches could be returned. The index is chosen deterministically, but is subject to change in future versions of Rust. If the value is not found then [`Result::Err`](https://doc.rust-lang.org/1.99.1/core/result/enum.Result.html#variant.Err) is returned, containing the index where a matching element could be inserted while maintaining sorted order. See also [`binary_search_by`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.binary_search_by), [`binary_search_by_key`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.binary_search_by_key), and [`partition_point`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.partition_point). **Examples** Looks up a series of four elements. The first is found, with a uniquely determined position; the second and third are not found; the fourth could match any position in `[1, 4]`. ```rust let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; assert_eq!(s.binary_search(&13), Ok(9)); assert_eq!(s.binary_search(&4), Err(7)); assert_eq!(s.binary_search(&100), Err(13)); let r = s.binary_search(&1); assert!(match r { Ok(1..=4) => true, _ => false, }); ``` If you want to find that whole *range* of matching items, rather than an arbitrary matching one, that can be done using [`partition_point`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.partition_point): ```rust let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; let low = s.partition_point(|x| x < &1); assert_eq!(low, 1); let high = s.partition_point(|x| x <= &1); assert_eq!(high, 5); let r = s.binary_search(&1); assert!((low..high).contains(&r.unwrap())); assert!(s[..low].iter().all(|&x| x < 1)); assert!(s[low..high].iter().all(|&x| x == 1)); assert!(s[high..].iter().all(|&x| x > 1)); // For something not found, the "range" of equal items is empty assert_eq!(s.partition_point(|x| x < &11), 9); assert_eq!(s.partition_point(|x| x <= &11), 9); assert_eq!(s.binary_search(&11), Err(9)); ``` If you want to insert an item to a sorted vector, while maintaining sort order, consider using [`partition_point`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.partition_point): ```rust let mut s = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; let num = 42; let idx = s.partition_point(|&x| x <= num); // If `num` is unique, `s.partition_point(|&x| x < num)` (with `<`) is equivalent to // `s.binary_search(&num).unwrap_or_else(|x| x)`, but using `<=` will allow `insert` // to shift less elements. s.insert(idx, num); assert_eq!(s, [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]); ``` ```rust pub fn binary_search_by<'a, F>(&'a self, f: F) -> Result where F: FnMut(&'a T) -> Ordering ``` Binary searches this slice with a comparator function. The comparator function should return an order code that indicates whether its argument is `Less`, `Equal` or `Greater` the desired target. If the slice is not sorted or if the comparator function does not implement an order consistent with the sort order of the underlying slice, the returned result is unspecified and meaningless. If the value is found then [`Result::Ok`](https://doc.rust-lang.org/1.99.1/core/result/enum.Result.html#variant.Ok) is returned, containing the index of the matching element. If there are multiple matches, then any one of the matches could be returned. The index is chosen deterministically, but is subject to change in future versions of Rust. If the value is not found then [`Result::Err`](https://doc.rust-lang.org/1.99.1/core/result/enum.Result.html#variant.Err) is returned, containing the index where a matching element could be inserted while maintaining sorted order. See also [`binary_search`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.binary_search), [`binary_search_by_key`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.binary_search_by_key), and [`partition_point`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.partition_point). **Examples** Looks up a series of four elements. The first is found, with a uniquely determined position; the second and third are not found; the fourth could match any position in `[1, 4]`. ```rust let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; let seek = 13; assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Ok(9)); let seek = 4; assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Err(7)); let seek = 100; assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Err(13)); let seek = 1; let r = s.binary_search_by(|probe| probe.cmp(&seek)); assert!(match r { Ok(1..=4) => true, _ => false, }); ``` ```rust pub fn binary_search_by_key<'a, B, F>( &'a self, b: &B, f: F, ) -> Result where F: FnMut(&'a T) -> B, B: Ord ``` Binary searches this slice with a key extraction function. Assumes that the slice is sorted by the key, for instance with [`sort_by_key`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.sort_by_key) using the same key extraction function. If the slice is not sorted by the key, the returned result is unspecified and meaningless. If the value is found then [`Result::Ok`](https://doc.rust-lang.org/1.99.1/core/result/enum.Result.html#variant.Ok) is returned, containing the index of the matching element. If there are multiple matches, then any one of the matches could be returned. The index is chosen deterministically, but is subject to change in future versions of Rust. If the value is not found then [`Result::Err`](https://doc.rust-lang.org/1.99.1/core/result/enum.Result.html#variant.Err) is returned, containing the index where a matching element could be inserted while maintaining sorted order. See also [`binary_search`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.binary_search), [`binary_search_by`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.binary_search_by), and [`partition_point`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.partition_point). **Examples** Looks up a series of four elements in a slice of pairs sorted by their second elements. The first is found, with a uniquely determined position; the second and third are not found; the fourth could match any position in `[1, 4]`. ```rust let s = [(0, 0), (2, 1), (4, 1), (5, 1), (3, 1), (1, 2), (2, 3), (4, 5), (5, 8), (3, 13), (1, 21), (2, 34), (4, 55)]; assert_eq!(s.binary_search_by_key(&13, |&(a, b)| b), Ok(9)); assert_eq!(s.binary_search_by_key(&4, |&(a, b)| b), Err(7)); assert_eq!(s.binary_search_by_key(&100, |&(a, b)| b), Err(13)); let r = s.binary_search_by_key(&1, |&(a, b)| b); assert!(match r { Ok(1..=4) => true, _ => false, }); ``` ```rust pub fn sort_unstable(&mut self) where T: Ord ``` Sorts the slice in ascending order **without** preserving the initial order of equal elements. This sort is unstable (i.e., may reorder equal elements), in-place (i.e., does not allocate), and *O*(*n* * log(*n*)) worst-case. If the implementation of [`Ord`](https://doc.rust-lang.org/1.99.1/core/cmp/trait.Ord.html) for `T` does not implement a [total order](https://en.wikipedia.org/wiki/Total_order), the function may panic; even if the function exits normally, the resulting order of elements in the slice is unspecified. See also the note on panicking below. For example `|a, b| (a - b).cmp(a)` is a comparison function that is neither transitive nor reflexive nor total, `a < b < c < a` with `a = 1, b = 2, c = 3`. For more information and examples see the [`Ord`](https://doc.rust-lang.org/1.99.1/core/cmp/trait.Ord.html) documentation. All original elements will remain in the slice and any possible modifications via interior mutability are observed in the input. Same is true if the implementation of [`Ord`](https://doc.rust-lang.org/1.99.1/core/cmp/trait.Ord.html) for `T` panics. Sorting types that only implement [`PartialOrd`](https://doc.rust-lang.org/1.99.1/core/cmp/trait.PartialOrd.html) such as [`f32`](https://doc.rust-lang.org/1.99.1/std/primitive.f32.html) and [`f64`](https://doc.rust-lang.org/1.99.1/std/primitive.f64.html) require additional precautions. For example, `f32::NAN != f32::NAN`, which doesn’t fulfill the reflexivity requirement of [`Ord`](https://doc.rust-lang.org/1.99.1/core/cmp/trait.Ord.html). By using an alternative comparison function with `slice::sort_unstable_by` such as [`f32::total_cmp`](https://doc.rust-lang.org/1.99.1/std/primitive.f32.html#method.total_cmp) or [`f64::total_cmp`](https://doc.rust-lang.org/1.99.1/std/primitive.f64.html#method.total_cmp) that defines a [total order](https://en.wikipedia.org/wiki/Total_order) users can sort slices containing floating-point values. Alternatively, if all values in the slice are guaranteed to be in a subset for which [`PartialOrd::partial_cmp`](https://doc.rust-lang.org/1.99.1/core/cmp/trait.PartialOrd.html#tymethod.partial_cmp) forms a [total order](https://en.wikipedia.org/wiki/Total_order), it’s possible to sort the slice with `sort_unstable_by(|a, b| a.partial_cmp(b).unwrap())`. **Current implementation** The current implementation is based on [ipnsort](https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort) by Lukas Bergdoll and Orson Peters, which combines the fast average case of quicksort with the fast worst case of heapsort, achieving linear time on fully sorted and reversed inputs. On inputs with k distinct elements, the expected time to sort the data is *O*(*n* * log(*k*)). It is typically faster than stable sorting, except in a few special cases, e.g., when the slice is partially sorted. **Panics** May panic if the implementation of [`Ord`](https://doc.rust-lang.org/1.99.1/core/cmp/trait.Ord.html) for `T` does not implement a [total order](https://en.wikipedia.org/wiki/Total_order), or if the [`Ord`](https://doc.rust-lang.org/1.99.1/core/cmp/trait.Ord.html) implementation panics. **Examples** ```rust let mut v = [4, -5, 1, -3, 2]; v.sort_unstable(); assert_eq!(v, [-5, -3, 1, 2, 4]); ``` ```rust pub fn sort_unstable_by(&mut self, compare: F) where F: FnMut(&T, &T) -> Ordering ``` Sorts the slice in ascending order with a comparison function, **without** preserving the initial order of equal elements. This sort is unstable (i.e., may reorder equal elements), in-place (i.e., does not allocate), and *O*(*n* * log(*n*)) worst-case. If the comparison function `compare` does not implement a [total order](https://en.wikipedia.org/wiki/Total_order), the function may panic; even if the function exits normally, the resulting order of elements in the slice is unspecified. See also the note on panicking below. For example `|a, b| (a - b).cmp(a)` is a comparison function that is neither transitive nor reflexive nor total, `a < b < c < a` with `a = 1, b = 2, c = 3`. For more information and examples see the [`Ord`](https://doc.rust-lang.org/1.99.1/core/cmp/trait.Ord.html) documentation. All original elements will remain in the slice and any possible modifications via interior mutability are observed in the input. Same is true if `compare` panics. **Current implementation** The current implementation is based on [ipnsort](https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort) by Lukas Bergdoll and Orson Peters, which combines the fast average case of quicksort with the fast worst case of heapsort, achieving linear time on fully sorted and reversed inputs. On inputs with k distinct elements, the expected time to sort the data is *O*(*n* * log(*k*)). It is typically faster than stable sorting, except in a few special cases, e.g., when the slice is partially sorted. **Panics** May panic if the `compare` does not implement a [total order](https://en.wikipedia.org/wiki/Total_order), or if the `compare` itself panics. **Examples** ```rust let mut v = [4, -5, 1, -3, 2]; v.sort_unstable_by(|a, b| a.cmp(b)); assert_eq!(v, [-5, -3, 1, 2, 4]); // reverse sorting v.sort_unstable_by(|a, b| b.cmp(a)); assert_eq!(v, [4, 2, 1, -3, -5]); ``` ```rust pub fn sort_unstable_by_key(&mut self, f: F) where F: FnMut(&T) -> K, K: Ord ``` Sorts the slice in ascending order with a key extraction function, **without** preserving the initial order of equal elements. This sort is unstable (i.e., may reorder equal elements), in-place (i.e., does not allocate), and *O*(*n* * log(*n*)) worst-case. If the implementation of [`Ord`](https://doc.rust-lang.org/1.99.1/core/cmp/trait.Ord.html) for `K` does not implement a [total order](https://en.wikipedia.org/wiki/Total_order), the function may panic; even if the function exits normally, the resulting order of elements in the slice is unspecified. See also the note on panicking below. For example `|a, b| (a - b).cmp(a)` is a comparison function that is neither transitive nor reflexive nor total, `a < b < c < a` with `a = 1, b = 2, c = 3`. For more information and examples see the [`Ord`](https://doc.rust-lang.org/1.99.1/core/cmp/trait.Ord.html) documentation. All original elements will remain in the slice and any possible modifications via interior mutability are observed in the input. Same is true if the implementation of [`Ord`](https://doc.rust-lang.org/1.99.1/core/cmp/trait.Ord.html) for `K` panics. **Current implementation** The current implementation is based on [ipnsort](https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort) by Lukas Bergdoll and Orson Peters, which combines the fast average case of quicksort with the fast worst case of heapsort, achieving linear time on fully sorted and reversed inputs. On inputs with k distinct elements, the expected time to sort the data is *O*(*n* * log(*k*)). It is typically faster than stable sorting, except in a few special cases, e.g., when the slice is partially sorted. **Panics** May panic if the implementation of [`Ord`](https://doc.rust-lang.org/1.99.1/core/cmp/trait.Ord.html) for `K` does not implement a [total order](https://en.wikipedia.org/wiki/Total_order), or if the [`Ord`](https://doc.rust-lang.org/1.99.1/core/cmp/trait.Ord.html) implementation panics. **Examples** ```rust let mut v = [4i32, -5, 1, -3, 2]; v.sort_unstable_by_key(|k| k.abs()); assert_eq!(v, [1, 2, -3, 4, -5]); ``` ```rust pub fn partial_sort_unstable(&mut self, range: R) where T: Ord, R: RangeBounds ``` 🔬This is a nightly-only experimental API. (`slice_partial_sort_unstable`) Partially sorts the slice in ascending order **without** preserving the initial order of equal elements. Upon completion, for the specified range `start..end`, it’s guaranteed that: 1. Every element in `self[..start]` is smaller than or equal to 2. Every element in `self[start..end]`, which is sorted, and smaller than or equal to 3. Every element in `self[end..]`. This partial sort is unstable, meaning it may reorder equal elements in the specified range. It may reorder elements outside the specified range as well, but the guarantees above still hold. This partial sort is in-place (i.e., does not allocate), and *O*(*n* + *k* * log(*k*)) worst-case, where *n* is the length of the slice and *k* is the length of the specified range. See the documentation of [`sort_unstable`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.sort_unstable) for implementation notes. **Panics** May panic if the implementation of [`Ord`](https://doc.rust-lang.org/1.99.1/core/cmp/trait.Ord.html) for `T` does not implement a total order, or if the [`Ord`](https://doc.rust-lang.org/1.99.1/core/cmp/trait.Ord.html) implementation panics, or if the specified range is out of bounds. **Examples** ```rust #![feature(slice_partial_sort_unstable)] let mut v = [4, -5, 1, -3, 2]; // empty range at the beginning, nothing changed v.partial_sort_unstable(0..0); assert_eq!(v, [4, -5, 1, -3, 2]); // empty range in the middle, partitioning the slice v.partial_sort_unstable(2..2); for i in 0..2 { assert!(v[i] <= v[2]); } for i in 3..v.len() { assert!(v[2] <= v[i]); } // single element range, same as select_nth_unstable v.partial_sort_unstable(2..3); for i in 0..2 { assert!(v[i] <= v[2]); } for i in 3..v.len() { assert!(v[2] <= v[i]); } // partial sort a subrange v.partial_sort_unstable(1..4); assert_eq!(&v[1..4], [-3, 1, 2]); // partial sort the whole range, same as sort_unstable v.partial_sort_unstable(..); assert_eq!(v, [-5, -3, 1, 2, 4]); ``` ```rust pub fn partial_sort_unstable_by(&mut self, range: R, compare: F) where F: FnMut(&T, &T) -> Ordering, R: RangeBounds ``` 🔬This is a nightly-only experimental API. (`slice_partial_sort_unstable`) Partially sorts the slice in ascending order with a comparison function, **without** preserving the initial order of equal elements. Upon completion, for the specified range `start..end`, it’s guaranteed that: 1. Every element in `self[..start]` is smaller than or equal to 2. Every element in `self[start..end]`, which is sorted, and smaller than or equal to 3. Every element in `self[end..]`. This partial sort is unstable, meaning it may reorder equal elements in the specified range. It may reorder elements outside the specified range as well, but the guarantees above still hold. This partial sort is in-place (i.e., does not allocate), and *O*(*n* + *k* * log(*k*)) worst-case, where *n* is the length of the slice and *k* is the length of the specified range. See the documentation of [`sort_unstable_by`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.sort_unstable_by) for implementation notes. **Panics** May panic if the `compare` does not implement a total order, or if the `compare` itself panics, or if the specified range is out of bounds. **Examples** ```rust #![feature(slice_partial_sort_unstable)] let mut v = [4, -5, 1, -3, 2]; // empty range at the beginning, nothing changed v.partial_sort_unstable_by(0..0, |a, b| b.cmp(a)); assert_eq!(v, [4, -5, 1, -3, 2]); // empty range in the middle, partitioning the slice v.partial_sort_unstable_by(2..2, |a, b| b.cmp(a)); for i in 0..2 { assert!(v[i] >= v[2]); } for i in 3..v.len() { assert!(v[2] >= v[i]); } // single element range, same as select_nth_unstable v.partial_sort_unstable_by(2..3, |a, b| b.cmp(a)); for i in 0..2 { assert!(v[i] >= v[2]); } for i in 3..v.len() { assert!(v[2] >= v[i]); } // partial sort a subrange v.partial_sort_unstable_by(1..4, |a, b| b.cmp(a)); assert_eq!(&v[1..4], [2, 1, -3]); // partial sort the whole range, same as sort_unstable v.partial_sort_unstable_by(.., |a, b| b.cmp(a)); assert_eq!(v, [4, 2, 1, -3, -5]); ``` ```rust pub fn partial_sort_unstable_by_key(&mut self, range: R, f: F) where F: FnMut(&T) -> K, K: Ord, R: RangeBounds ``` 🔬This is a nightly-only experimental API. (`slice_partial_sort_unstable`) Partially sorts the slice in ascending order with a key extraction function, **without** preserving the initial order of equal elements. Upon completion, for the specified range `start..end`, it’s guaranteed that: 1. Every element in `self[..start]` is smaller than or equal to 2. Every element in `self[start..end]`, which is sorted, and smaller than or equal to 3. Every element in `self[end..]`. This partial sort is unstable, meaning it may reorder equal elements in the specified range. It may reorder elements outside the specified range as well, but the guarantees above still hold. This partial sort is in-place (i.e., does not allocate), and *O*(*n* + *k* * log(*k*)) worst-case, where *n* is the length of the slice and *k* is the length of the specified range. See the documentation of [`sort_unstable_by_key`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.sort_unstable_by_key) for implementation notes. **Panics** May panic if the implementation of [`Ord`](https://doc.rust-lang.org/1.99.1/core/cmp/trait.Ord.html) for `K` does not implement a total order, or if the [`Ord`](https://doc.rust-lang.org/1.99.1/core/cmp/trait.Ord.html) implementation panics, or if the specified range is out of bounds. **Examples** ```rust #![feature(slice_partial_sort_unstable)] let mut v = [4i32, -5, 1, -3, 2]; // empty range at the beginning, nothing changed v.partial_sort_unstable_by_key(0..0, |k| k.abs()); assert_eq!(v, [4, -5, 1, -3, 2]); // empty range in the middle, partitioning the slice v.partial_sort_unstable_by_key(2..2, |k| k.abs()); for i in 0..2 { assert!(v[i].abs() <= v[2].abs()); } for i in 3..v.len() { assert!(v[2].abs() <= v[i].abs()); } // single element range, same as select_nth_unstable v.partial_sort_unstable_by_key(2..3, |k| k.abs()); for i in 0..2 { assert!(v[i].abs() <= v[2].abs()); } for i in 3..v.len() { assert!(v[2].abs() <= v[i].abs()); } // partial sort a subrange v.partial_sort_unstable_by_key(1..4, |k| k.abs()); assert_eq!(&v[1..4], [2, -3, 4]); // partial sort the whole range, same as sort_unstable v.partial_sort_unstable_by_key(.., |k| k.abs()); assert_eq!(v, [1, 2, -3, 4, -5]); ``` ```rust pub fn select_nth_unstable( &mut self, index: usize, ) -> (&mut [T], &mut T, &mut [T]) where T: Ord ``` Reorders the slice such that the element at `index` is at a sort-order position. All elements before `index` will be `<=` to this value, and all elements after will be `>=` to it. This reordering is unstable (i.e. any element that compares equal to the nth element may end up at that position), in-place (i.e. does not allocate), and runs in *O*(*n*) time. This function is also known as “kth element” in other libraries. Returns a triple that partitions the reordered slice: - The unsorted subslice before `index`, whose elements all satisfy `x <= self[index]`. - The element at `index`. - The unsorted subslice after `index`, whose elements all satisfy `x >= self[index]`. **Current implementation** The current algorithm is an introselect implementation based on [ipnsort](https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort) by Lukas Bergdoll and Orson Peters, which is also the basis for [`sort_unstable`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.sort_unstable). The fallback algorithm is Median of Medians using Tukey’s Ninther for pivot selection, which guarantees linear runtime for all inputs. **Panics** Panics when `index >= len()`, and so always panics on empty slices. May panic if the implementation of [`Ord`](https://doc.rust-lang.org/1.99.1/core/cmp/trait.Ord.html) for `T` does not implement a [total order](https://en.wikipedia.org/wiki/Total_order). **Examples** ```rust let mut v = [-5i32, 4, 2, -3, 1]; // Find the items `<=` to the median, the median itself, and the items `>=` to it. let (lesser, median, greater) = v.select_nth_unstable(2); assert!(lesser == [-3, -5] || lesser == [-5, -3]); assert_eq!(median, &mut 1); assert!(greater == [4, 2] || greater == [2, 4]); // We are only guaranteed the slice will be one of the following, based on the way we sort // about the specified index. assert!(v == [-3, -5, 1, 2, 4] || v == [-5, -3, 1, 2, 4] || v == [-3, -5, 1, 4, 2] || v == [-5, -3, 1, 4, 2]); ``` ```rust pub fn select_nth_unstable_by( &mut self, index: usize, compare: F, ) -> (&mut [T], &mut T, &mut [T]) where F: FnMut(&T, &T) -> Ordering ``` Reorders the slice with a comparator function such that the element at `index` is at a sort-order position. All elements before `index` will be `<=` to this value, and all elements after will be `>=` to it, according to the comparator function. This reordering is unstable (i.e. any element that compares equal to the nth element may end up at that position), in-place (i.e. does not allocate), and runs in *O*(*n*) time. This function is also known as “kth element” in other libraries. Returns a triple partitioning the reordered slice: - The unsorted subslice before `index`, whose elements all satisfy `compare(x, self[index]).is_le()`. - The element at `index`. - The unsorted subslice after `index`, whose elements all satisfy `compare(x, self[index]).is_ge()`. **Current implementation** The current algorithm is an introselect implementation based on [ipnsort](https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort) by Lukas Bergdoll and Orson Peters, which is also the basis for [`sort_unstable`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.sort_unstable). The fallback algorithm is Median of Medians using Tukey’s Ninther for pivot selection, which guarantees linear runtime for all inputs. **Panics** Panics when `index >= len()`, and so always panics on empty slices. May panic if `compare` does not implement a [total order](https://en.wikipedia.org/wiki/Total_order). **Examples** ```rust let mut v = [-5i32, 4, 2, -3, 1]; // Find the items `>=` to the median, the median itself, and the items `<=` to it, by using // a reversed comparator. let (before, median, after) = v.select_nth_unstable_by(2, |a, b| b.cmp(a)); assert!(before == [4, 2] || before == [2, 4]); assert_eq!(median, &mut 1); assert!(after == [-3, -5] || after == [-5, -3]); // We are only guaranteed the slice will be one of the following, based on the way we sort // about the specified index. assert!(v == [2, 4, 1, -5, -3] || v == [2, 4, 1, -3, -5] || v == [4, 2, 1, -5, -3] || v == [4, 2, 1, -3, -5]); ``` ```rust pub fn select_nth_unstable_by_key( &mut self, index: usize, f: F, ) -> (&mut [T], &mut T, &mut [T]) where F: FnMut(&T) -> K, K: Ord ``` Reorders the slice with a key extraction function such that the element at `index` is at a sort-order position. All elements before `index` will have keys `<=` to the key at `index`, and all elements after will have keys `>=` to it. This reordering is unstable (i.e. any element that compares equal to the nth element may end up at that position), in-place (i.e. does not allocate), and runs in *O*(*n*) time. This function is also known as “kth element” in other libraries. Returns a triple partitioning the reordered slice: - The unsorted subslice before `index`, whose elements all satisfy `f(x) <= f(self[index])`. - The element at `index`. - The unsorted subslice after `index`, whose elements all satisfy `f(x) >= f(self[index])`. **Current implementation** The current algorithm is an introselect implementation based on [ipnsort](https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort) by Lukas Bergdoll and Orson Peters, which is also the basis for [`sort_unstable`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.sort_unstable). The fallback algorithm is Median of Medians using Tukey’s Ninther for pivot selection, which guarantees linear runtime for all inputs. **Panics** Panics when `index >= len()`, meaning it always panics on empty slices. May panic if `K: Ord` does not implement a total order. **Examples** ```rust let mut v = [-5i32, 4, 1, -3, 2]; // Find the items `<=` to the absolute median, the absolute median itself, and the items // `>=` to it. let (lesser, median, greater) = v.select_nth_unstable_by_key(2, |a| a.abs()); assert!(lesser == [1, 2] || lesser == [2, 1]); assert_eq!(median, &mut -3); assert!(greater == [4, -5] || greater == [-5, 4]); // We are only guaranteed the slice will be one of the following, based on the way we sort // about the specified index. assert!(v == [1, 2, -3, 4, -5] || v == [1, 2, -3, -5, 4] || v == [2, 1, -3, 4, -5] || v == [2, 1, -3, -5, 4]); ``` ```rust pub fn partition_dedup(&mut self) -> (&mut [T], &mut [T]) where T: PartialEq ``` 🔬This is a nightly-only experimental API. (`slice_partition_dedup`) Moves all consecutive repeated elements to the end of the slice according to the [`PartialEq`](https://doc.rust-lang.org/1.99.1/core/cmp/trait.PartialEq.html) trait implementation. Returns two slices. The first contains no consecutive repeated elements. The second contains all the duplicates in no specified order. If the slice is sorted, the first returned slice contains no duplicates. **Examples** ```rust #![feature(slice_partition_dedup)] let mut slice = [1, 2, 2, 3, 3, 2, 1, 1]; let (dedup, duplicates) = slice.partition_dedup(); assert_eq!(dedup, [1, 2, 3, 2, 1]); assert_eq!(duplicates, [2, 3, 1]); ``` ```rust pub fn partition_dedup_by(&mut self, same_bucket: F) -> (&mut [T], &mut [T]) where F: FnMut(&mut T, &mut T) -> bool ``` 🔬This is a nightly-only experimental API. (`slice_partition_dedup`) Moves all but the first of consecutive elements to the end of the slice that are “equal” according to the given predicate function. Returns two slices. The first contains no consecutive repeated elements. The second contains all the duplicates in no specified order. The predicate `same_bucket(x, p)` is passed references to two elements from the slice and must determine if the elements compare equal. The element `p` occurs *before* `x` in the slice (`[.., p, .., x, ..]`), so `same_bucket(x, p)` is receiving them in reversed order. If the slice is sorted, the first returned slice contains no duplicates. For more complicated predicates however, the order (ascending vs. descending) can matter. Both references passed to `same_bucket` are mutable. This allows merged elements in the first slice by mutating `p` and returning `true`. **Examples** ```rust #![feature(slice_partition_dedup)] let mut slice = ["foo", "Foo", "BAZ", "Bar", "bar", "baz", "BAZ"]; let (dedup, duplicates) = slice.partition_dedup_by(|x, p| x.eq_ignore_ascii_case(p)); assert_eq!(dedup, ["foo", "BAZ", "Bar", "baz"]); assert_eq!(duplicates, ["bar", "Foo", "BAZ"]); ``` ```rust pub fn partition_dedup_by_key(&mut self, key: F) -> (&mut [T], &mut [T]) where F: FnMut(&mut T) -> K, K: PartialEq ``` 🔬This is a nightly-only experimental API. (`slice_partition_dedup`) Moves all but the first of consecutive elements to the end of the slice that resolve to the same key. Returns two slices. The first contains no consecutive repeated elements. The second contains all the duplicates in no specified order. If the slice is sorted, the first returned slice contains no duplicates. **Examples** ```rust #![feature(slice_partition_dedup)] let mut slice = [10, 20, 21, 30, 30, 20, 11, 13]; let (dedup, duplicates) = slice.partition_dedup_by_key(|i| *i / 10); assert_eq!(dedup, [10, 20, 30, 20, 11]); assert_eq!(duplicates, [21, 30, 13]); ``` ```rust pub fn rotate_left(&mut self, mid: usize) ``` Rotates the slice in-place such that the first `mid` elements of the slice move to the end while the last `self.len() - mid` elements move to the front. After calling `rotate_left`, the element previously at index `mid` will become the first element in the slice. **Panics** This function will panic if `mid` is greater than the length of the slice. Note that `mid == self.len()` does *not* panic and is a no-op rotation. **Complexity** Takes linear (in `self.len()`) time. **Examples** ```rust let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; a.rotate_left(2); assert_eq!(a, ['c', 'd', 'e', 'f', 'a', 'b']); ``` Rotating a subslice: ```rust let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; a[1..5].rotate_left(1); assert_eq!(a, ['a', 'c', 'd', 'e', 'b', 'f']); ``` ```rust pub fn rotate_right(&mut self, k: usize) ``` Rotates the slice in-place such that the first `self.len() - k` elements of the slice move to the end while the last `k` elements move to the front. After calling `rotate_right`, the element previously at index `self.len() - k` will become the first element in the slice. **Panics** This function will panic if `k` is greater than the length of the slice. Note that `k == self.len()` does *not* panic and is a no-op rotation. **Complexity** Takes linear (in `self.len()`) time. **Examples** ```rust let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; a.rotate_right(2); assert_eq!(a, ['e', 'f', 'a', 'b', 'c', 'd']); ``` Rotating a subslice: ```rust let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; a[1..5].rotate_right(1); assert_eq!(a, ['a', 'e', 'b', 'c', 'd', 'f']); ``` ```rust pub fn shift_left(&mut self, inserted: [T; N]) -> [T; N] ``` 🔬This is a nightly-only experimental API. (`slice_shift`) Moves the elements of this slice `N` places to the left, returning the ones that “fall off” the front, and putting `inserted` at the end. Equivalently, you can think of concatenating `self` and `inserted` into one long sequence, then returning the left-most `N` items and the rest into `self`: ```text self (before) inserted vvvvvvvvvvvvvvv vvv [1, 2, 3, 4, 5] [9] ↙ ↙ ↙ ↙ ↙ ↙ [1] [2, 3, 4, 5, 9] ^^^ ^^^^^^^^^^^^^^^ returned self (after) ``` See also [`Self::shift_right`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.shift_right) and compare [`Self::rotate_left`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.rotate_left). **Examples** ```rust #![feature(slice_shift)] // Same as the diagram above let mut a = [1, 2, 3, 4, 5]; let inserted = [9]; let returned = a.shift_left(inserted); assert_eq!(returned, [1]); assert_eq!(a, [2, 3, 4, 5, 9]); // You can shift multiple items at a time let mut a = *b"Hello world"; assert_eq!(a.shift_left(*b" peace"), *b"Hello "); assert_eq!(a, *b"world peace"); // The name comes from this operation's similarity to bitshifts let mut a: u8 = 0b10010110; a <<= 3; assert_eq!(a, 0b10110000_u8); let mut a: [_; 8] = [1, 0, 0, 1, 0, 1, 1, 0]; a.shift_left([0; 3]); assert_eq!(a, [1, 0, 1, 1, 0, 0, 0, 0]); // Remember you can sub-slice to affect less that the whole slice. // For example, this is similar to `.remove(1)` + `.insert(4, 'Z')` let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; assert_eq!(a[1..=4].shift_left(['Z']), ['b']); assert_eq!(a, ['a', 'c', 'd', 'e', 'Z', 'f']); // If the size matches it's equivalent to `mem::replace` let mut a = [1, 2, 3]; assert_eq!(a.shift_left([7, 8, 9]), [1, 2, 3]); assert_eq!(a, [7, 8, 9]); // Some of the "inserted" elements end up returned if the slice is too short let mut a = []; assert_eq!(a.shift_left([1, 2, 3]), [1, 2, 3]); let mut a = [9]; assert_eq!(a.shift_left([1, 2, 3]), [9, 1, 2]); assert_eq!(a, [3]); ``` ```rust pub fn shift_right(&mut self, inserted: [T; N]) -> [T; N] ``` 🔬This is a nightly-only experimental API. (`slice_shift`) Moves the elements of this slice `N` places to the right, returning the ones that “fall off” the back, and putting `inserted` at the beginning. Equivalently, you can think of concatenating `inserted` and `self` into one long sequence, then returning the right-most `N` items and the rest into `self`: ```text inserted self (before) vvv vvvvvvvvvvvvvvv [0] [5, 6, 7, 8, 9] ↘ ↘ ↘ ↘ ↘ ↘ [0, 5, 6, 7, 8] [9] ^^^^^^^^^^^^^^^ ^^^ self (after) returned ``` See also [`Self::shift_left`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.shift_left) and compare [`Self::rotate_right`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.rotate_right). **Examples** ```rust #![feature(slice_shift)] // Same as the diagram above let mut a = [5, 6, 7, 8, 9]; let inserted = [0]; let returned = a.shift_right(inserted); assert_eq!(returned, [9]); assert_eq!(a, [0, 5, 6, 7, 8]); // The name comes from this operation's similarity to bitshifts let mut a: u8 = 0b10010110; a >>= 3; assert_eq!(a, 0b00010010_u8); let mut a: [_; 8] = [1, 0, 0, 1, 0, 1, 1, 0]; a.shift_right([0; 3]); assert_eq!(a, [0, 0, 0, 1, 0, 0, 1, 0]); // Remember you can sub-slice to affect less that the whole slice. // For example, this is similar to `.remove(4)` + `.insert(1, 'Z')` let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; assert_eq!(a[1..=4].shift_right(['Z']), ['e']); assert_eq!(a, ['a', 'Z', 'b', 'c', 'd', 'f']); // If the size matches it's equivalent to `mem::replace` let mut a = [1, 2, 3]; assert_eq!(a.shift_right([7, 8, 9]), [1, 2, 3]); assert_eq!(a, [7, 8, 9]); // Some of the "inserted" elements end up returned if the slice is too short let mut a = []; assert_eq!(a.shift_right([1, 2, 3]), [1, 2, 3]); let mut a = [9]; assert_eq!(a.shift_right([1, 2, 3]), [2, 3, 9]); assert_eq!(a, [1]); ``` ```rust pub fn fill(&mut self, value: T) where T: Clone ``` Fills `self` with elements by cloning `value`. **Examples** ```rust let mut buf = vec![0; 10]; buf.fill(1); assert_eq!(buf, vec![1; 10]); ``` ```rust pub fn fill_with(&mut self, f: F) where F: FnMut() -> T ``` Fills `self` with elements returned by calling a closure repeatedly. This method uses a closure to create new values. If you’d rather [`Clone`](https://doc.rust-lang.org/1.99.1/core/clone/trait.Clone.html) a given value, use [`fill`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.fill). If you want to use the [`Default`](https://doc.rust-lang.org/1.99.1/core/default/trait.Default.html) trait to generate values, you can pass [`Default::default`](https://doc.rust-lang.org/1.99.1/core/default/trait.Default.html#tymethod.default) as the argument. **Examples** ```rust let mut buf = vec![1; 10]; buf.fill_with(Default::default); assert_eq!(buf, vec![0; 10]); ``` ```rust pub fn clone_from_slice(&mut self, src: &[T]) where T: Clone ``` Copies the elements from `src` into `self`. The length of `src` must be the same as `self`. **Panics** This function will panic if the two slices have different lengths. **Examples** Cloning two elements from a slice into another: ```rust let src = [1, 2, 3, 4]; let mut dst = [0, 0]; // Because the slices have to be the same length, // we slice the source slice from four elements // to two. It will panic if we don't do this. dst.clone_from_slice(&src[2..]); assert_eq!(src, [1, 2, 3, 4]); assert_eq!(dst, [3, 4]); ``` Rust enforces that there can only be one mutable reference with no immutable references to a particular piece of data in a particular scope. Because of this, attempting to use `clone_from_slice` on a single slice will result in a compile failure: ```rust let mut slice = [1, 2, 3, 4, 5]; slice[..2].clone_from_slice(&slice[3..]); // compile fail! ``` To work around this, we can use [`split_at_mut`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.split_at_mut) to create two distinct sub-slices from a slice: ```rust let mut slice = [1, 2, 3, 4, 5]; { let (left, right) = slice.split_at_mut(2); left.clone_from_slice(&right[1..]); } assert_eq!(slice, [4, 5, 3, 4, 5]); ``` ```rust pub fn copy_from_slice(&mut self, src: &[T]) where T: Copy ``` Copies all elements from `src` into `self`, using a memcpy. The length of `src` must be the same as `self`. If `T` does not implement `Copy`, use [`clone_from_slice`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.clone_from_slice). **Panics** This function will panic if the two slices have different lengths. **Examples** Copying two elements from a slice into another: ```rust let src = [1, 2, 3, 4]; let mut dst = [0, 0]; // Because the slices have to be the same length, // we slice the source slice from four elements // to two. It will panic if we don't do this. dst.copy_from_slice(&src[2..]); assert_eq!(src, [1, 2, 3, 4]); assert_eq!(dst, [3, 4]); ``` Rust enforces that there can only be one mutable reference with no immutable references to a particular piece of data in a particular scope. Because of this, attempting to use `copy_from_slice` on a single slice will result in a compile failure: ```rust let mut slice = [1, 2, 3, 4, 5]; slice[..2].copy_from_slice(&slice[3..]); // compile fail! ``` To work around this, we can use [`split_at_mut`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.split_at_mut) to create two distinct sub-slices from a slice: ```rust let mut slice = [1, 2, 3, 4, 5]; { let (left, right) = slice.split_at_mut(2); left.copy_from_slice(&right[1..]); } assert_eq!(slice, [4, 5, 3, 4, 5]); ``` ```rust pub fn copy_within(&mut self, src: R, dest: usize) where R: RangeBounds, T: Copy ``` Copies elements from one part of the slice to another part of itself, using a memmove. `src` is the range within `self` to copy from. `dest` is the starting index of the range within `self` to copy to, which will have the same length as `src`. The two ranges may overlap. The ends of the two ranges must be less than or equal to `self.len()`. **Panics** This function will panic if either range exceeds the end of the slice, or if the end of `src` is before the start. **Examples** Copying four bytes within a slice: ```rust let mut bytes = *b"Hello, World!"; bytes.copy_within(1..5, 8); assert_eq!(&bytes, b"Hello, Wello!"); ``` ```rust pub fn swap_with_slice(&mut self, other: &mut [T]) ``` Swaps all elements in `self` with those in `other`. The length of `other` must be the same as `self`. **Panics** This function will panic if the two slices have different lengths. **Example** Swapping two elements across slices: ```rust let mut slice1 = [0, 0]; let mut slice2 = [1, 2, 3, 4]; slice1.swap_with_slice(&mut slice2[2..]); assert_eq!(slice1, [3, 4]); assert_eq!(slice2, [1, 2, 0, 0]); ``` Rust enforces that there can only be one mutable reference to a particular piece of data in a particular scope. Because of this, attempting to use `swap_with_slice` on a single slice will result in a compile failure: ```rust let mut slice = [1, 2, 3, 4, 5]; slice[..2].swap_with_slice(&mut slice[3..]); // compile fail! ``` To work around this, we can use [`split_at_mut`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.split_at_mut) to create two distinct mutable sub-slices from a slice: ```rust let mut slice = [1, 2, 3, 4, 5]; { let (left, right) = slice.split_at_mut(2); left.swap_with_slice(&mut right[1..]); } assert_eq!(slice, [4, 5, 3, 1, 2]); ``` ```rust pub unsafe fn align_to(&self) -> (&[T], &[U], &[T]) ``` Transmutes the slice to a slice of another type, ensuring alignment of the types is maintained. This method splits the slice into three distinct slices: prefix, correctly aligned middle slice of a new type, and the suffix slice. The middle part will be as big as possible under the given alignment constraint and element size. This method has no purpose when either input element `T` or output element `U` are zero-sized and will return the original slice without splitting anything. **Safety** This method is essentially a `transmute` with respect to the elements in the returned middle slice, so all the usual caveats pertaining to `transmute::` also apply here. **Examples** Basic usage: ```rust unsafe { let bytes: [u8; 7] = [1, 2, 3, 4, 5, 6, 7]; let (prefix, shorts, suffix) = bytes.align_to::(); // less_efficient_algorithm_for_bytes(prefix); // more_efficient_algorithm_for_aligned_shorts(shorts); // less_efficient_algorithm_for_bytes(suffix); } ``` ```rust pub unsafe fn align_to_mut(&mut self) -> (&mut [T], &mut [U], &mut [T]) ``` Transmutes the mutable slice to a mutable slice of another type, ensuring alignment of the types is maintained. This method splits the slice into three distinct slices: prefix, correctly aligned middle slice of a new type, and the suffix slice. The middle part will be as big as possible under the given alignment constraint and element size. This method has no purpose when either input element `T` or output element `U` are zero-sized and will return the original slice without splitting anything. **Safety** This method is essentially a `transmute` with respect to the elements in the returned middle slice, so all the usual caveats pertaining to `transmute::` also apply here. **Examples** Basic usage: ```rust unsafe { let mut bytes: [u8; 7] = [1, 2, 3, 4, 5, 6, 7]; let (prefix, shorts, suffix) = bytes.align_to_mut::(); // less_efficient_algorithm_for_bytes(prefix); // more_efficient_algorithm_for_aligned_shorts(shorts); // less_efficient_algorithm_for_bytes(suffix); } ``` ```rust pub fn as_simd(&self) -> (&[T], &[Simd], &[T]) where Simd: AsRef<[T; LANES]>, T: SimdElement ``` 🔬This is a nightly-only experimental API. (`portable_simd`) Splits a slice into a prefix, a middle of aligned SIMD types, and a suffix. This is a safe wrapper around [`slice::align_to`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.align_to), so inherits the same guarantees as that method. **Panics** This will panic if the size of the SIMD type is different from `LANES` times that of the scalar. At the time of writing, the trait restrictions on `Simd` keeps that from ever happening, as only power-of-two numbers of lanes are supported. It’s possible that, in the future, those restrictions might be lifted in a way that would make it possible to see panics from this method for something like `LANES == 3`. **Examples** ```rust #![feature(portable_simd)] use core::simd::prelude::*; let short = &[1, 2, 3]; let (prefix, middle, suffix) = short.as_simd::<4>(); assert_eq!(middle, []); // Not enough elements for anything in the middle // They might be split in any possible way between prefix and suffix let it = prefix.iter().chain(suffix).copied(); assert_eq!(it.collect::>(), vec![1, 2, 3]); fn basic_simd_sum(x: &[f32]) -> f32 { use std::ops::Add; let (prefix, middle, suffix) = x.as_simd(); let sums = f32x4::from_array([ prefix.iter().copied().sum(), 0.0, 0.0, suffix.iter().copied().sum(), ]); let sums = middle.iter().copied().fold(sums, f32x4::add); sums.reduce_sum() } let numbers: Vec = (1..101).map(|x| x as _).collect(); assert_eq!(basic_simd_sum(&numbers[1..99]), 4949.0); ``` ```rust pub fn as_simd_mut( &mut self, ) -> (&mut [T], &mut [Simd], &mut [T]) where Simd: AsMut<[T; LANES]>, T: SimdElement ``` 🔬This is a nightly-only experimental API. (`portable_simd`) Splits a mutable slice into a mutable prefix, a middle of aligned SIMD types, and a mutable suffix. This is a safe wrapper around [`slice::align_to_mut`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.align_to_mut), so inherits the same guarantees as that method. This is the mutable version of [`slice::as_simd`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.as_simd); see that for examples. **Panics** This will panic if the size of the SIMD type is different from `LANES` times that of the scalar. At the time of writing, the trait restrictions on `Simd` keeps that from ever happening, as only power-of-two numbers of lanes are supported. It’s possible that, in the future, those restrictions might be lifted in a way that would make it possible to see panics from this method for something like `LANES == 3`. ```rust pub fn is_sorted(&self) -> bool where T: PartialOrd ``` Checks if the elements of this slice are sorted. That is, for each element `a` and its following element `b`, `a <= b` must hold. If the slice yields exactly zero or one element, `true` is returned. Note that if `Self::Item` is only `PartialOrd`, but not `Ord`, the above definition implies that this function returns `false` if any two consecutive items are not comparable. **Examples** ```rust let empty: [i32; 0] = []; assert!([1, 2, 2, 9].is_sorted()); assert!(![1, 3, 2, 4].is_sorted()); assert!([0].is_sorted()); assert!(empty.is_sorted()); assert!(![0.0, 1.0, f32::NAN].is_sorted()); ``` ```rust pub fn is_sorted_by<'a, F>(&'a self, compare: F) -> bool where F: FnMut(&'a T, &'a T) -> bool ``` Checks if the elements of this slice are sorted using the given comparator function. Instead of using `PartialOrd::partial_cmp`, this function uses the given `compare` function to determine whether two elements are to be considered in sorted order. **Examples** ```rust assert!([1, 2, 2, 9].is_sorted_by(|a, b| a <= b)); assert!(![1, 2, 2, 9].is_sorted_by(|a, b| a < b)); assert!([0].is_sorted_by(|a, b| true)); assert!([0].is_sorted_by(|a, b| false)); let empty: [i32; 0] = []; assert!(empty.is_sorted_by(|a, b| false)); assert!(empty.is_sorted_by(|a, b| true)); ``` ```rust pub fn is_sorted_by_key<'a, F, K>(&'a self, f: F) -> bool where F: FnMut(&'a T) -> K, K: PartialOrd ``` Checks if the elements of this slice are sorted using the given key extraction function. Instead of comparing the slice’s elements directly, this function compares the keys of the elements, as determined by `f`. Apart from that, it’s equivalent to [`is_sorted`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.is_sorted); see its documentation for more information. **Examples** ```rust assert!(["c", "bb", "aaa"].is_sorted_by_key(|s| s.len())); assert!(![-2i32, -1, 0, 3].is_sorted_by_key(|n| n.abs())); ``` ```rust pub fn partition_point

(&self, pred: P) -> usize where P: FnMut(&T) -> bool ``` Returns the index of the partition point according to the given predicate (the index of the first element of the second partition). The slice is assumed to be partitioned according to the given predicate. This means that all elements for which the predicate returns true are at the start of the slice and all elements for which the predicate returns false are at the end. For example, `[7, 15, 3, 5, 4, 12, 6]` is partitioned under the predicate `x % 2 != 0` (all odd numbers are at the start, all even at the end). If this slice is not partitioned, the returned result is unspecified and meaningless, as this method performs a kind of binary search. See also [`binary_search`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.binary_search), [`binary_search_by`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.binary_search_by), and [`binary_search_by_key`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.binary_search_by_key). **Examples** ```rust let v = [1, 2, 3, 3, 5, 6, 7]; let i = v.partition_point(|&x| x < 5); assert_eq!(i, 4); assert!(v[..i].iter().all(|&x| x < 5)); assert!(v[i..].iter().all(|&x| !(x < 5))); ``` If all elements of the slice match the predicate, including if the slice is empty, then the length of the slice will be returned: ```rust let a = [2, 4, 8]; assert_eq!(a.partition_point(|x| x < &100), a.len()); let a: [i32; 0] = []; assert_eq!(a.partition_point(|x| x < &100), 0); ``` If you want to insert an item to a sorted vector, while maintaining sort order: ```rust let mut s = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; let num = 42; let idx = s.partition_point(|&x| x <= num); s.insert(idx, num); assert_eq!(s, [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]); ``` ```rust pub fn split_off<'a, R>(self: &mut &'a [T], range: R) -> Option<&'a [T]> where R: OneSidedRange ``` Removes the subslice corresponding to the given range and returns a reference to it. Returns `None` and does not modify the slice if the given range is out of bounds. Note that this method only accepts one-sided ranges such as `2..` or `..6`, but not `2..6`. **Examples** Splitting off the first three elements of a slice: ```rust let mut slice: &[_] = &['a', 'b', 'c', 'd']; let mut first_three = slice.split_off(..3).unwrap(); assert_eq!(slice, &['d']); assert_eq!(first_three, &['a', 'b', 'c']); ``` Splitting off a slice starting with the third element: ```rust let mut slice: &[_] = &['a', 'b', 'c', 'd']; let mut tail = slice.split_off(2..).unwrap(); assert_eq!(slice, &['a', 'b']); assert_eq!(tail, &['c', 'd']); ``` Getting `None` when `range` is out of bounds: ```rust let mut slice: &[_] = &['a', 'b', 'c', 'd']; assert_eq!(None, slice.split_off(5..)); assert_eq!(None, slice.split_off(..5)); assert_eq!(None, slice.split_off(..=4)); let expected: &[char] = &['a', 'b', 'c', 'd']; assert_eq!(Some(expected), slice.split_off(..4)); ``` ```rust pub fn split_off_mut<'a, R>( self: &mut &'a mut [T], range: R, ) -> Option<&'a mut [T]> where R: OneSidedRange ``` Removes the subslice corresponding to the given range and returns a mutable reference to it. Returns `None` and does not modify the slice if the given range is out of bounds. Note that this method only accepts one-sided ranges such as `2..` or `..6`, but not `2..6`. **Examples** Splitting off the first three elements of a slice: ```rust let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd']; let mut first_three = slice.split_off_mut(..3).unwrap(); assert_eq!(slice, &mut ['d']); assert_eq!(first_three, &mut ['a', 'b', 'c']); ``` Splitting off a slice starting with the third element: ```rust let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd']; let mut tail = slice.split_off_mut(2..).unwrap(); assert_eq!(slice, &mut ['a', 'b']); assert_eq!(tail, &mut ['c', 'd']); ``` Getting `None` when `range` is out of bounds: ```rust let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd']; assert_eq!(None, slice.split_off_mut(5..)); assert_eq!(None, slice.split_off_mut(..5)); assert_eq!(None, slice.split_off_mut(..=4)); let expected: &mut [_] = &mut ['a', 'b', 'c', 'd']; assert_eq!(Some(expected), slice.split_off_mut(..4)); ``` ```rust pub fn split_off_first<'a>(self: &mut &'a [T]) -> Option<&'a T> ``` Removes the first element of the slice and returns a reference to it. Returns `None` if the slice is empty. **Examples** ```rust let mut slice: &[_] = &['a', 'b', 'c']; let first = slice.split_off_first().unwrap(); assert_eq!(slice, &['b', 'c']); assert_eq!(first, &'a'); ``` ```rust pub fn split_off_first_mut<'a>(self: &mut &'a mut [T]) -> Option<&'a mut T> ``` Removes the first element of the slice and returns a mutable reference to it. Returns `None` if the slice is empty. **Examples** ```rust let mut slice: &mut [_] = &mut ['a', 'b', 'c']; let first = slice.split_off_first_mut().unwrap(); *first = 'd'; assert_eq!(slice, &['b', 'c']); assert_eq!(first, &'d'); ``` ```rust pub fn split_off_last<'a>(self: &mut &'a [T]) -> Option<&'a T> ``` Removes the last element of the slice and returns a reference to it. Returns `None` if the slice is empty. **Examples** ```rust let mut slice: &[_] = &['a', 'b', 'c']; let last = slice.split_off_last().unwrap(); assert_eq!(slice, &['a', 'b']); assert_eq!(last, &'c'); ``` ```rust pub fn split_off_last_mut<'a>(self: &mut &'a mut [T]) -> Option<&'a mut T> ``` Removes the last element of the slice and returns a mutable reference to it. Returns `None` if the slice is empty. **Examples** ```rust let mut slice: &mut [_] = &mut ['a', 'b', 'c']; let last = slice.split_off_last_mut().unwrap(); *last = 'd'; assert_eq!(slice, &['a', 'b']); assert_eq!(last, &'d'); ``` ```rust pub unsafe fn get_disjoint_unchecked_mut( &mut self, indices: [I; N], ) -> [&mut >::Output; N] where I: GetDisjointMutIndex + SliceIndex<[T]> ``` Returns mutable references to many indices at once, without doing any checks. An index can be either a `usize`, a [`Range`](https://doc.rust-lang.org/1.99.1/core/ops/range/struct.Range.html) or a [`RangeInclusive`](https://doc.rust-lang.org/1.99.1/core/ops/range/struct.RangeInclusive.html). Note that this method takes an array, so all indices must be of the same type. If passed an array of `usize`s this method gives back an array of mutable references to single elements, while if passed an array of ranges it gives back an array of mutable references to slices. For a safe alternative see [`get_disjoint_mut`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.get_disjoint_mut). **Safety** Calling this method with overlapping or out-of-bounds indices is *[undefined behavior](https://doc.rust-lang.org/reference/behavior-considered-undefined.html)* even if the resulting references are not used. **Examples** ```rust let x = &mut [1, 2, 4]; unsafe { let [a, b] = x.get_disjoint_unchecked_mut([0, 2]); *a *= 10; *b *= 100; } assert_eq!(x, &[10, 2, 400]); unsafe { let [a, b] = x.get_disjoint_unchecked_mut([0..1, 1..3]); a[0] = 8; b[0] = 88; b[1] = 888; } assert_eq!(x, &[8, 88, 888]); unsafe { let [a, b] = x.get_disjoint_unchecked_mut([1..=2, 0..=0]); a[0] = 11; a[1] = 111; b[0] = 1; } assert_eq!(x, &[1, 11, 111]); ``` ```rust pub fn get_disjoint_mut( &mut self, indices: [I; N], ) -> Result<[&mut >::Output; N], GetDisjointMutError> where I: GetDisjointMutIndex + SliceIndex<[T]> ``` Returns mutable references to many indices at once. An index can be either a `usize`, a [`Range`](https://doc.rust-lang.org/1.99.1/core/ops/range/struct.Range.html) or a [`RangeInclusive`](https://doc.rust-lang.org/1.99.1/core/ops/range/struct.RangeInclusive.html). Note that this method takes an array, so all indices must be of the same type. If passed an array of `usize`s this method gives back an array of mutable references to single elements, while if passed an array of ranges it gives back an array of mutable references to slices. Returns an error if any index is out-of-bounds, or if there are overlapping indices. An empty range is not considered to overlap if it is located at the beginning or at the end of another range, but is considered to overlap if it is located in the middle. This method does a O(n^2) check to check that there are no overlapping indices, so be careful when passing many indices. **Examples** ```rust let v = &mut [1, 2, 3]; if let Ok([a, b]) = v.get_disjoint_mut([0, 2]) { *a = 413; *b = 612; } assert_eq!(v, &[413, 2, 612]); if let Ok([a, b]) = v.get_disjoint_mut([0..1, 1..3]) { a[0] = 8; b[0] = 88; b[1] = 888; } assert_eq!(v, &[8, 88, 888]); if let Ok([a, b]) = v.get_disjoint_mut([1..=2, 0..=0]) { a[0] = 11; a[1] = 111; b[0] = 1; } assert_eq!(v, &[1, 11, 111]); ``` ```rust pub fn element_offset(&self, element: &T) -> Option ``` Returns the index that an element reference points to. Returns `None` if `element` does not point to the start of an element within the slice. This method is useful for extending slice iterators like [`slice::split`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.split). Note that this uses pointer arithmetic and **does not compare elements**. To find the index of an element via comparison, use [`.iter().position()`](https://doc.rust-lang.org/1.99.1/core/iter/traits/iterator/trait.Iterator.html#method.position) instead. **Panics** Panics if `T` is zero-sized. **Examples** Basic usage: ```rust let nums: &[u32] = &[1, 7, 1, 1]; let num = &nums[2]; assert_eq!(num, &1); assert_eq!(nums.element_offset(num), Some(2)); ``` Returning `None` with an unaligned element: ```rust let arr: &[[u32; 2]] = &[[0, 1], [2, 3]]; let flat_arr: &[u32] = arr.as_flattened(); let ok_elm: &[u32; 2] = flat_arr[0..2].try_into().unwrap(); let weird_elm: &[u32; 2] = flat_arr[1..3].try_into().unwrap(); assert_eq!(ok_elm, &[0, 1]); assert_eq!(weird_elm, &[1, 2]); assert_eq!(arr.element_offset(ok_elm), Some(0)); // Points to element 0 assert_eq!(arr.element_offset(weird_elm), None); // Points between element 0 and 1 ``` ```rust pub fn subslice_range(&self, subslice: &[T]) -> Option> ``` Returns the range of indices that a subslice points to. Returns `None` if `subslice` does not point within the slice or if it is not aligned with the elements in the slice. This method **does not compare elements**. Instead, this method finds the location in the slice that `subslice` was obtained from. To find the index of a subslice via comparison, instead use [`.windows()`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.windows)[`.position()`](https://doc.rust-lang.org/1.99.1/core/iter/traits/iterator/trait.Iterator.html#method.position). This method is useful for extending slice iterators like [`slice::split`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.split). Note that this may return a false positive (either `Some(0..0)` or `Some(self.len()..self.len())`) if `subslice` has a length of zero and points to the beginning or end of another, separate, slice. **Panics** Panics if `T` is zero-sized. **Examples** Basic usage: ```rust use core::range::Range; let nums = &[0, 5, 10, 0, 0, 5]; let mut iter = nums .split(|t| *t == 0) .map(|n| nums.subslice_range(n).unwrap()); assert_eq!(iter.next(), Some(Range { start: 0, end: 0 })); assert_eq!(iter.next(), Some(Range { start: 1, end: 3 })); assert_eq!(iter.next(), Some(Range { start: 4, end: 4 })); assert_eq!(iter.next(), Some(Range { start: 5, end: 6 })); ``` ```rust pub fn as_slice(&self) -> &[T] ``` 🔬This is a nightly-only experimental API. (`str_as_str`) Returns the same slice `&[T]`. This method is redundant when used directly on `&[T]`, but it helps dereferencing other “container” types to slices, for example `Box<[T]>` or `Arc<[T]>`. ```rust pub fn as_mut_slice(&mut self) -> &mut [T] ``` 🔬This is a nightly-only experimental API. (`str_as_str`) Returns the same slice `&mut [T]`. This method is redundant when used directly on `&mut [T]`, but it helps dereferencing other “container” types to slices, for example `Box<[T]>` or `MutexGuard<[T]>`. ```rust pub fn utf8_chunks(&self) -> Utf8Chunks<'_> ``` Creates an iterator over the contiguous valid UTF-8 ranges of this slice, and the non-UTF-8 fragments in between. See the [`Utf8Chunk`](https://doc.rust-lang.org/1.99.1/core/str/lossy/struct.Utf8Chunk.html) type for documentation of the items yielded by this iterator. **Examples** This function formats arbitrary but mostly-UTF-8 bytes into Rust source code in the form of a C-string literal (`c"..."`). ```rust use std::fmt::Write as _; pub fn cstr_literal(bytes: &[u8]) -> String { let mut repr = String::new(); repr.push_str("c\""); for chunk in bytes.utf8_chunks() { for ch in chunk.valid().chars() { // Escapes \0, \t, \r, \n, \\, \', \", and uses \u{...} for non-printable characters. write!(repr, "{}", ch.escape_debug()).unwrap(); } for byte in chunk.invalid() { write!(repr, "\\x{:02X}", byte).unwrap(); } } repr.push('"'); repr } fn main() { let lit = cstr_literal(b"\xferris the \xf0\x9f\xa6\x80\x07"); let expected = stringify!(c"\xFErris the 🦀\u{7}"); assert_eq!(lit, expected); } ``` ```rust pub fn sort(&mut self) where T: Ord ``` Sorts the slice in ascending order, preserving initial order of equal elements. This sort is stable (i.e., does not reorder equal elements) and *O*(*n* * log(*n*)) worst-case. If the implementation of [`Ord`](https://doc.rust-lang.org/1.99.1/core/cmp/trait.Ord.html) for `T` does not implement a [total order](https://en.wikipedia.org/wiki/Total_order), the function may panic; even if the function exits normally, the resulting order of elements in the slice is unspecified. See also the note on panicking below. When applicable, unstable sorting is preferred because it is generally faster than stable sorting and it doesn’t allocate auxiliary memory. See [`sort_unstable`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.sort_unstable). The exception are partially sorted slices, which may be better served with `slice::sort`. Sorting types that only implement [`PartialOrd`](https://doc.rust-lang.org/1.99.1/core/cmp/trait.PartialOrd.html) such as [`f32`](https://doc.rust-lang.org/1.99.1/std/primitive.f32.html) and [`f64`](https://doc.rust-lang.org/1.99.1/std/primitive.f64.html) require additional precautions. For example, `f32::NAN != f32::NAN`, which doesn’t fulfill the reflexivity requirement of [`Ord`](https://doc.rust-lang.org/1.99.1/core/cmp/trait.Ord.html). By using an alternative comparison function with `slice::sort_by` such as [`f32::total_cmp`](https://doc.rust-lang.org/1.99.1/std/primitive.f32.html#method.total_cmp) or [`f64::total_cmp`](https://doc.rust-lang.org/1.99.1/std/primitive.f64.html#method.total_cmp) that defines a [total order](https://en.wikipedia.org/wiki/Total_order) users can sort slices containing floating-point values. Alternatively, if all values in the slice are guaranteed to be in a subset for which [`PartialOrd::partial_cmp`](https://doc.rust-lang.org/1.99.1/core/cmp/trait.PartialOrd.html#tymethod.partial_cmp) forms a [total order](https://en.wikipedia.org/wiki/Total_order), it’s possible to sort the slice with `sort_by(|a, b| a.partial_cmp(b).unwrap())`. **Current implementation** The current implementation is based on [driftsort](https://github.com/Voultapher/driftsort) by Orson Peters and Lukas Bergdoll, which combines the fast average case of quicksort with the fast worst case and partial run detection of mergesort, achieving linear time on fully sorted and reversed inputs. On inputs with k distinct elements, the expected time to sort the data is *O*(*n* * log(*k*)). The auxiliary memory allocation behavior depends on the input length. Short slices are handled without allocation, medium sized slices allocate `self.len()` and beyond that it clamps at `self.len() / 2`. **Panics** May panic if the implementation of [`Ord`](https://doc.rust-lang.org/1.99.1/core/cmp/trait.Ord.html) for `T` does not implement a [total order](https://en.wikipedia.org/wiki/Total_order), or if the [`Ord`](https://doc.rust-lang.org/1.99.1/core/cmp/trait.Ord.html) implementation itself panics. All safe functions on slices preserve the invariant that even if the function panics, all original elements will remain in the slice and any possible modifications via interior mutability are observed in the input. This ensures that recovery code (for instance inside of a `Drop` or following a `catch_unwind`) will still have access to all the original elements. For instance, if the slice belongs to a `Vec`, the `Vec::drop` method will be able to dispose of all contained elements. **Examples** ```rust let mut v = [4, -5, 1, -3, 2]; v.sort(); assert_eq!(v, [-5, -3, 1, 2, 4]); ``` ```rust pub fn sort_by(&mut self, compare: F) where F: FnMut(&T, &T) -> Ordering ``` Sorts the slice in ascending order with a comparison function, preserving initial order of equal elements. This sort is stable (i.e., does not reorder equal elements) and *O*(*n* * log(*n*)) worst-case. If the comparison function `compare` does not implement a [total order](https://en.wikipedia.org/wiki/Total_order), the function may panic; even if the function exits normally, the resulting order of elements in the slice is unspecified. See also the note on panicking below. For example `|a, b| (a - b).cmp(a)` is a comparison function that is neither transitive nor reflexive nor total, `a < b < c < a` with `a = 1, b = 2, c = 3`. For more information and examples see the [`Ord`](https://doc.rust-lang.org/1.99.1/core/cmp/trait.Ord.html) documentation. **Current implementation** The current implementation is based on [driftsort](https://github.com/Voultapher/driftsort) by Orson Peters and Lukas Bergdoll, which combines the fast average case of quicksort with the fast worst case and partial run detection of mergesort, achieving linear time on fully sorted and reversed inputs. On inputs with k distinct elements, the expected time to sort the data is *O*(*n* * log(*k*)). The auxiliary memory allocation behavior depends on the input length. Short slices are handled without allocation, medium sized slices allocate `self.len()` and beyond that it clamps at `self.len() / 2`. **Panics** May panic if `compare` does not implement a [total order](https://en.wikipedia.org/wiki/Total_order), or if `compare` itself panics. All safe functions on slices preserve the invariant that even if the function panics, all original elements will remain in the slice and any possible modifications via interior mutability are observed in the input. This ensures that recovery code (for instance inside of a `Drop` or following a `catch_unwind`) will still have access to all the original elements. For instance, if the slice belongs to a `Vec`, the `Vec::drop` method will be able to dispose of all contained elements. **Examples** ```rust let mut v = [4, -5, 1, -3, 2]; v.sort_by(|a, b| a.cmp(b)); assert_eq!(v, [-5, -3, 1, 2, 4]); // reverse sorting v.sort_by(|a, b| b.cmp(a)); assert_eq!(v, [4, 2, 1, -3, -5]); ``` ```rust pub fn sort_by_key(&mut self, f: F) where F: FnMut(&T) -> K, K: Ord ``` Sorts the slice in ascending order with a key extraction function, preserving initial order of equal elements. This sort is stable (i.e., does not reorder equal elements) and *O*(*m* * *n* * log(*n*)) worst-case, where the key function is *O*(*m*). If the implementation of [`Ord`](https://doc.rust-lang.org/1.99.1/core/cmp/trait.Ord.html) for `K` does not implement a [total order](https://en.wikipedia.org/wiki/Total_order), the function may panic; even if the function exits normally, the resulting order of elements in the slice is unspecified. See also the note on panicking below. **Current implementation** The current implementation is based on [driftsort](https://github.com/Voultapher/driftsort) by Orson Peters and Lukas Bergdoll, which combines the fast average case of quicksort with the fast worst case and partial run detection of mergesort, achieving linear time on fully sorted and reversed inputs. On inputs with k distinct elements, the expected time to sort the data is *O*(*n* * log(*k*)). The auxiliary memory allocation behavior depends on the input length. Short slices are handled without allocation, medium sized slices allocate `self.len()` and beyond that it clamps at `self.len() / 2`. **Panics** May panic if the implementation of [`Ord`](https://doc.rust-lang.org/1.99.1/core/cmp/trait.Ord.html) for `K` does not implement a [total order](https://en.wikipedia.org/wiki/Total_order), or if the [`Ord`](https://doc.rust-lang.org/1.99.1/core/cmp/trait.Ord.html) implementation or the key-function `f` panics. All safe functions on slices preserve the invariant that even if the function panics, all original elements will remain in the slice and any possible modifications via interior mutability are observed in the input. This ensures that recovery code (for instance inside of a `Drop` or following a `catch_unwind`) will still have access to all the original elements. For instance, if the slice belongs to a `Vec`, the `Vec::drop` method will be able to dispose of all contained elements. **Examples** ```rust let mut v = [4i32, -5, 1, -3, 2]; v.sort_by_key(|k| k.abs()); assert_eq!(v, [1, 2, -3, 4, -5]); ``` ```rust pub fn sort_by_cached_key(&mut self, f: F) where F: FnMut(&T) -> K, K: Ord ``` Sorts the slice in ascending order with a key extraction function, preserving initial order of equal elements. This sort is stable (i.e., does not reorder equal elements) and *O*(*m* * *n* + *n* * log(*n*)) worst-case, where the key function is *O*(*m*). During sorting, the key function is called at most once per element, by using temporary storage to remember the results of key evaluation. The order of calls to the key function is unspecified and may change in future versions of the standard library. If the implementation of [`Ord`](https://doc.rust-lang.org/1.99.1/core/cmp/trait.Ord.html) for `K` does not implement a [total order](https://en.wikipedia.org/wiki/Total_order), the function may panic; even if the function exits normally, the resulting order of elements in the slice is unspecified. See also the note on panicking below. For simple key functions (e.g., functions that are property accesses or basic operations), [`sort_by_key`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.sort_by_key) is likely to be faster. **Current implementation** The current implementation is based on [instruction-parallel-network sort](https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort) by Lukas Bergdoll, which combines the fast average case of randomized quicksort with the fast worst case of heapsort, while achieving linear time on fully sorted and reversed inputs. And *O*(*k* * log(*n*)) where *k* is the number of distinct elements in the input. It leverages superscalar out-of-order execution capabilities commonly found in CPUs, to efficiently perform the operation. In the worst case, the algorithm allocates temporary storage in a `Vec<(K, usize)>` the length of the slice. **Panics** May panic if the implementation of [`Ord`](https://doc.rust-lang.org/1.99.1/core/cmp/trait.Ord.html) for `K` does not implement a [total order](https://en.wikipedia.org/wiki/Total_order), or if the [`Ord`](https://doc.rust-lang.org/1.99.1/core/cmp/trait.Ord.html) implementation panics. All safe functions on slices preserve the invariant that even if the function panics, all original elements will remain in the slice and any possible modifications via interior mutability are observed in the input. This ensures that recovery code (for instance inside of a `Drop` or following a `catch_unwind`) will still have access to all the original elements. For instance, if the slice belongs to a `Vec`, the `Vec::drop` method will be able to dispose of all contained elements. **Examples** ```rust let mut v = [4i32, -5, 1, -3, 2, 10]; // Strings are sorted by lexicographical order. v.sort_by_cached_key(|k| k.to_string()); assert_eq!(v, [-3, -5, 1, 10, 2, 4]); ``` ```rust pub fn to_vec(&self) -> Vec where T: Clone ``` Copies `self` into a new `Vec`. **Examples** ```rust let s = [10, 40, 30]; let x = s.to_vec(); // Here, `s` and `x` can be modified independently. ``` ```rust pub fn to_vec_in(&self, alloc: A) -> Vec where A: Allocator, T: Clone ``` 🔬This is a nightly-only experimental API. (`allocator_api`) Copies `self` into a new `Vec` with an allocator. **Examples** ```rust #![feature(allocator_api)] use std::alloc::System; let s = [10, 40, 30]; let x = s.to_vec_in(System); // Here, `s` and `x` can be modified independently. ``` ```rust pub fn repeat(&self, n: usize) -> Vec where T: Copy ``` Creates a vector by copying a slice `n` times. **Panics** This function will panic if the capacity would overflow. **Examples** ```rust assert_eq!([1, 2].repeat(3), vec![1, 2, 1, 2, 1, 2]); ``` A panic upon overflow: ```rust // this will panic at runtime b"0123456789abcdef".repeat(usize::MAX); ``` ```rust pub fn concat(&self) -> <[T] as Concat>::Output where [T]: Concat, Item: ?Sized ``` Flattens a slice of `T` into a single value `Self::Output`. **Examples** ```rust assert_eq!(["hello", "world"].concat(), "helloworld"); assert_eq!([[1, 2], [3, 4]].concat(), [1, 2, 3, 4]); ``` ```rust pub fn join( &self, sep: Separator, ) -> <[T] as Join>::Output where [T]: Join ``` Flattens a slice of `T` into a single value `Self::Output`, placing a given separator between each. **Examples** ```rust assert_eq!(["hello", "world"].join(" "), "hello world"); assert_eq!([[1, 2], [3, 4]].join(&0), [1, 2, 0, 3, 4]); assert_eq!([[1, 2], [3, 4]].join(&[0, 0][..]), [1, 2, 0, 0, 3, 4]); ``` ```rust pub fn connect( &self, sep: Separator, ) -> <[T] as Join>::Output where [T]: Join ``` 👎Deprecated since 1.3.0: renamed to join Flattens a slice of `T` into a single value `Self::Output`, placing a given separator between each. **Examples** ```rust assert_eq!(["hello", "world"].connect(" "), "hello world"); assert_eq!([[1, 2], [3, 4]].connect(&0), [1, 2, 0, 3, 4]); ``` ```rust pub fn to_ascii_uppercase(&self) -> Vec ``` Returns a vector containing a copy of this slice where each byte is mapped to its ASCII upper case equivalent. ASCII letters ‘a’ to ‘z’ are mapped to ‘A’ to ‘Z’, but non-ASCII letters are unchanged. To uppercase the value in-place, use [`make_ascii_uppercase`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.make_ascii_uppercase). ```rust pub fn to_ascii_lowercase(&self) -> Vec ``` Returns a vector containing a copy of this slice where each byte is mapped to its ASCII lower case equivalent. ASCII letters ‘A’ to ‘Z’ are mapped to ‘a’ to ‘z’, but non-ASCII letters are unchanged. To lowercase the value in-place, use [`make_ascii_lowercase`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.make_ascii_lowercase). #### Trait Implementations - `impl Debug for AlignedBuf` - `impl Default for AlignedBuf` - `impl Deref for AlignedBuf` - `impl DerefMut for AlignedBuf` - `impl Drop for AlignedBuf` - `impl IoBuf for AlignedBuf` - `impl IoBufMut for AlignedBuf` - `impl Send for AlignedBuf` - `impl Sync for AlignedBuf` #### Auto Trait Implementations - `impl Freeze for AlignedBuf` - `impl RefUnwindSafe for AlignedBuf` - `impl Unpin for AlignedBuf` - `impl UnsafeUnpin for AlignedBuf` - `impl UnwindSafe for AlignedBuf` ### struct `nuclei::io::BufReader` https://nuclei.rs/api/nuclei/io/struct.BufReader.html ```rust pub struct BufReader { /* private fields */ } ``` A reader with a buffer in front: small reads take from the buffer, which is filled by large reads of the reader. Writes, if the reader is also a writer, go straight through. #### Implementations `impl BufReader` ```rust pub fn new(inner: R) -> Self ``` A reader with a buffer of 8 KiB in front of `inner`. ```rust pub fn with_capacity(capacity: usize, inner: R) -> Self ``` A reader with a buffer of `capacity` bytes in front of `inner`. ```rust pub fn get_ref(&self) -> &R ``` The reader inside. ```rust pub fn get_mut(&mut self) -> &mut R ``` The reader inside, to change (reading it directly skips the bytes buffered). ```rust pub fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut R> where R: Unpin ``` The reader inside, pinned. ```rust pub fn into_inner(self) -> R ``` The reader inside, taken back; the bytes buffered are lost. ```rust pub fn buffer(&self) -> &[u8] ``` The bytes buffered and not read yet. #### Trait Implementations - `impl AsyncBufRead for BufReader` - `impl AsyncRead for BufReader` - `impl AsyncSeek for BufReader` - `impl AsyncWrite for BufReader` - `impl Debug for BufReader` #### Auto Trait Implementations - `impl Freeze for BufReader where R: Freeze` - `impl RefUnwindSafe for BufReader where R: RefUnwindSafe` - `impl Send for BufReader where R: Send` - `impl Sync for BufReader where R: Sync` - `impl Unpin for BufReader where R: Unpin` - `impl UnsafeUnpin for BufReader where R: UnsafeUnpin` - `impl UnwindSafe for BufReader where R: UnwindSafe` ### struct `nuclei::io::BufStream` https://nuclei.rs/api/nuclei/io/struct.BufStream.html ```rust pub struct BufStream { /* private fields */ } ``` A stream with a read buffer and a write buffer in front: a [`BufReader`](https://nuclei.rs/api/nuclei/io/struct.BufReader.html) around a [`BufWriter`](https://nuclei.rs/api/nuclei/io/struct.BufWriter.html). #### Implementations `impl BufStream` ```rust pub fn new(stream: S) -> Self ``` Buffers of 8 KiB each way in front of `stream`. ```rust pub fn with_capacity(read: usize, write: usize, stream: S) -> Self ``` A read buffer of `read` bytes and a write buffer of `write` bytes in front of `stream`. ```rust pub fn get_ref(&self) -> &S ``` The stream inside. ```rust pub fn get_mut(&mut self) -> &mut S ``` The stream inside, to change. ```rust pub fn into_inner(self) -> S ``` The stream inside, taken back; the bytes buffered either way are lost. #### Trait Implementations - `impl AsyncBufRead for BufStream` - `impl AsyncRead for BufStream` - `impl AsyncWrite for BufStream` - `impl Debug for BufStream` #### Auto Trait Implementations - `impl Freeze for BufStream where S: Freeze` - `impl RefUnwindSafe for BufStream where S: RefUnwindSafe` - `impl Send for BufStream where S: Send` - `impl Sync for BufStream where S: Sync` - `impl Unpin for BufStream where S: Unpin` - `impl UnsafeUnpin for BufStream where S: UnsafeUnpin` - `impl UnwindSafe for BufStream where S: UnwindSafe` ### struct `nuclei::io::BufWriter` https://nuclei.rs/api/nuclei/io/struct.BufWriter.html ```rust pub struct BufWriter { /* private fields */ } ``` A writer with a buffer in front: small writes gather in the buffer, which goes to the writer when full, on a flush, or on a close. Reads, if the writer is also a reader, go straight through. Dropping it loses what is still buffered: flush or close it first. #### Implementations `impl BufWriter` ```rust pub fn new(inner: W) -> Self ``` A writer with a buffer of 8 KiB in front of `inner`. ```rust pub fn with_capacity(capacity: usize, inner: W) -> Self ``` A writer with a buffer of `capacity` bytes in front of `inner`. ```rust pub fn get_ref(&self) -> &W ``` The writer inside. ```rust pub fn get_mut(&mut self) -> &mut W ``` The writer inside, to change (writing it directly puts the bytes ahead of what is buffered). ```rust pub fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut W> where W: Unpin ``` The writer inside, pinned. ```rust pub fn into_inner(self) -> W ``` The writer inside, taken back; the bytes buffered are lost. ```rust pub fn buffer(&self) -> &[u8] ``` The bytes buffered and not written to the writer yet. #### Trait Implementations - `impl AsyncBufRead for BufWriter` - `impl AsyncRead for BufWriter` - `impl AsyncSeek for BufWriter` - `impl AsyncWrite for BufWriter` - `impl Debug for BufWriter` #### Auto Trait Implementations - `impl Freeze for BufWriter where W: Freeze` - `impl RefUnwindSafe for BufWriter where W: RefUnwindSafe` - `impl Send for BufWriter where W: Send` - `impl Sync for BufWriter where W: Sync` - `impl Unpin for BufWriter where W: Unpin` - `impl UnsafeUnpin for BufWriter where W: UnsafeUnpin` - `impl UnwindSafe for BufWriter where W: UnwindSafe` ### struct `nuclei::io::Chain` https://nuclei.rs/api/nuclei/io/struct.Chain.html ```rust pub struct Chain { /* private fields */ } ``` A reader that reads one to its end, then another; made by [`chain`](https://nuclei.rs/api/nuclei/io/trait.AsyncReadExt.html#method.chain). #### Implementations `impl Chain` ```rust pub fn get_ref(&self) -> (&A, &B) ``` The two readers. ```rust pub fn get_mut(&mut self) -> (&mut A, &mut B) ``` The two readers, to change. ```rust pub fn into_inner(self) -> (A, B) ``` The two readers, taken back. #### Trait Implementations - `impl AsyncRead for Chain` - `impl Debug for Chain` #### Auto Trait Implementations - `impl Freeze for Chain where A: Freeze, B: Freeze` - `impl RefUnwindSafe for Chain where A: RefUnwindSafe, B: RefUnwindSafe` - `impl Send for Chain where A: Send, B: Send` - `impl Sync for Chain where A: Sync, B: Sync` - `impl Unpin for Chain where A: Unpin, B: Unpin` - `impl UnsafeUnpin for Chain where A: UnsafeUnpin, B: UnsafeUnpin` - `impl UnwindSafe for Chain where A: UnwindSafe, B: UnwindSafe` ### struct `nuclei::io::DuplexStream` https://nuclei.rs/api/nuclei/io/struct.DuplexStream.html ```rust pub struct DuplexStream { /* private fields */ } ``` One end of a [`duplex`](https://nuclei.rs/api/nuclei/io/fn.duplex.html) pair: what it writes the other reads, and what the other writes it reads. Dropping it ends the other’s reads (after what is left) and fails the other’s writes. #### Trait Implementations - `impl AsyncRead for DuplexStream` - `impl AsyncWrite for DuplexStream` - `impl Debug for DuplexStream` - `impl Drop for DuplexStream` #### Auto Trait Implementations - `impl !RefUnwindSafe for DuplexStream` - `impl !UnwindSafe for DuplexStream` - `impl Freeze for DuplexStream` - `impl Send for DuplexStream` - `impl Sync for DuplexStream` - `impl Unpin for DuplexStream` - `impl UnsafeUnpin for DuplexStream` ### struct `nuclei::io::Empty` https://nuclei.rs/api/nuclei/io/struct.Empty.html ```rust pub struct Empty { /* private fields */ } ``` A reader at its end at once, and a writer that takes every byte and keeps none. Made by [`empty`](https://nuclei.rs/api/nuclei/io/fn.empty.html). #### Trait Implementations - `impl AsyncBufRead for Empty` - `impl AsyncRead for Empty` - `impl AsyncWrite for Empty` - `impl Clone for Empty` - `impl Copy for Empty` - `impl Debug for Empty` - `impl Default for Empty` #### Auto Trait Implementations - `impl Freeze for Empty` - `impl RefUnwindSafe for Empty` - `impl Send for Empty` - `impl Sync for Empty` - `impl Unpin for Empty` - `impl UnsafeUnpin for Empty` - `impl UnwindSafe for Empty` ### struct `nuclei::io::FillBuf` https://nuclei.rs/api/nuclei/io/struct.FillBuf.html ```rust pub struct FillBuf<'a, R: ?Sized> { /* private fields */ } ``` The future of [`fill_buf`](https://nuclei.rs/api/nuclei/io/trait.AsyncBufReadExt.html#method.fill_buf). #### Trait Implementations - `impl<'a, R: Debug + ?Sized> Debug for FillBuf<'a, R>` - `impl<'a, R: AsyncBufRead + Unpin + ?Sized> Future for FillBuf<'a, R>` #### Auto Trait Implementations - `impl<'a, R> !UnwindSafe for FillBuf<'a, R>` - `impl<'a, R> Freeze for FillBuf<'a, R> where R: ?Sized` - `impl<'a, R> RefUnwindSafe for FillBuf<'a, R> where R: RefUnwindSafe + ?Sized` - `impl<'a, R> Send for FillBuf<'a, R> where R: Send + ?Sized` - `impl<'a, R> Sync for FillBuf<'a, R> where R: Sync + ?Sized` - `impl<'a, R> Unpin for FillBuf<'a, R> where R: ?Sized` - `impl<'a, R> UnsafeUnpin for FillBuf<'a, R> where R: ?Sized` ### struct `nuclei::io::Flush` https://nuclei.rs/api/nuclei/io/struct.Flush.html ```rust pub struct Flush<'a, W: ?Sized> { /* private fields */ } ``` The future of [`flush`](https://nuclei.rs/api/nuclei/io/trait.AsyncWriteExt.html#method.flush). #### Trait Implementations - `impl<'a, W: Debug + ?Sized> Debug for Flush<'a, W>` - `impl Future for Flush<'_, W>` #### Auto Trait Implementations - `impl<'a, W> !UnwindSafe for Flush<'a, W>` - `impl<'a, W> Freeze for Flush<'a, W> where W: ?Sized` - `impl<'a, W> RefUnwindSafe for Flush<'a, W> where W: RefUnwindSafe + ?Sized` - `impl<'a, W> Send for Flush<'a, W> where W: Send + ?Sized` - `impl<'a, W> Sync for Flush<'a, W> where W: Sync + ?Sized` - `impl<'a, W> Unpin for Flush<'a, W> where W: ?Sized` - `impl<'a, W> UnsafeUnpin for Flush<'a, W> where W: ?Sized` ### struct `nuclei::io::Handle` https://nuclei.rs/api/nuclei/io/struct.Handle.html Also exported as `nuclei::Handle`. ```rust pub struct Handle { /* private fields */ } ``` An IO object (a socket, a pipe, a file) whose operations run on nuclei’s shards. `Send` and `Sync` exactly when the object is. **std’s calls through `Deref`** `Deref` hands the object out for its own methods (socket options, addresses), and the handle’s methods of the same name take their place where it has them (`connect`, `send`, `linger`, …). A few of std’s calls reached through it go around the handle, so around the bytes it read ahead and the ones it wrote behind, or block its shard: - `shutdown` shuts the halves at once, ahead of the bytes still behind, which then never reach the peer; [`shut`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.shut) waits for them first. - `set_nonblocking(false)` makes the driver’s own calls on the object block the shard’s thread, and every task of the shard with them. - `take_error` takes the error the socket holds, which the handle’s connect in progress or its next operation would have answered. - `Read` and `Write` on a shared reference to the object (`&TcpStream`, `&UnixStream`) read past the bytes read ahead and write ahead of the bytes written behind, and answer `WouldBlock` where the handle’s own reads and writes wait. Called on the handle with std’s traits in scope (`stream.read(&mut buf)`), they reach the object through `DerefMut`, after the wait of [`get_mut`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.get_mut). ```rust use std::net::TcpListener; use nuclei::Handle; let listener = Handle::new(TcpListener::bind("127.0.0.1:0").unwrap()).unwrap(); assert!(listener.local_addr().unwrap().port() > 0); ``` #### Implementations `impl Handle` ```rust pub async fn copy_range_to( &self, to: &Handle, from_offset: u64, to_offset: u64, len: u64, ) -> Result ``` Copies up to `len` bytes from this file at `from_offset` to `to` at `to_offset` and answers how many were copied: fewer only where this file ends, and zero at its end. Neither file’s cursor is used or moved. On Linux the bytes move in the kernel (`copy_file_range(2)`), in jobs of the blocking pool that each take a chunk of at most 16 MiB, so no job holds a pool thread for a whole copy. Where the kernel cannot copy between the two files, or the system has no such call (macOS, Windows, the other unix), the bytes go through a buffer of the runtime’s pool, one buffer a job. The copy waits for the writes accepted before it on both files. For `to` it is a write: a read at its cursor made after the copy sees the bytes, and a future dropped while a chunk is out leaves that chunk to `to`, which every later call of `to` waits for; the chunks after it are not made. A failure after some bytes were copied is not reported: the count is, and the next call meets the failure again. A file that is not a regular file (a pipe, a terminal) gets the system’s answer to one call. **Errors** `InvalidInput` when the end of either range is past the largest offset a file can have, or when both handles name one file and the ranges overlap; otherwise the system’s own error, among them that of a handle that cannot be read or written. `impl Handle` ```rust pub async fn read_many_at( &self, reads: Vec<(B, u64)>, ) -> Vec<(Result, B)> where B: IoBufMut ``` Reads at each offset of `reads` into the spare capacity of its buffer, after the bytes it holds, and gives every buffer back in the order of `reads` with its read’s result, as [`read_at_owned`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.read_at_owned) answers one: the bytes that came, zero at the end of the file or for a buffer with no spare capacity. The reads are made at once, in any order: on io_uring together, in the shard ring’s one submission, at most 64 out at a time; elsewhere as jobs of the blocking pool, as many at a time. The reads see every write accepted at the cursor before the call, and every positional write that returned before it. Each read is one call of the system’s positional read into its buffer itself, never copied. If the future is dropped, the reads still out are left to end by themselves, and their buffers go with them. **Errors** Each read’s own, as `read_at_owned`’s. On a stream (a pipe, a terminal) the file has no offset to read at, and every read answers the system’s error for that. `impl Handle` ```rust pub async fn read_at(&self, buf: &mut [u8], offset: u64) -> Result ``` Reads at `offset` into `buf` and answers how many bytes came, zero at the end of the file, as std’s `FileExt::read_at` does (on Windows `seek_read`, after which the system’s own position of the file is past the bytes read, as std documents; the handle’s cursor never moves). The handle’s cursor and the reads and writes at it are left as they are, and any number of positional calls may run at once on one handle. The read sees every write accepted at the cursor before it, and every positional write that returned before it. The bytes come through a buffer of the runtime’s pool, at most 64 KiB a call (a short read, as `read_at` may answer). On a file opened for direct IO the call reads exactly `buf.len()` bytes at `offset`, into memory placed in its page as `buf` is, so the kernel refuses (with `EINVAL`) exactly what it would refuse of `buf` itself. [`read_at_owned`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.read_at_owned) reads into the caller’s own buffer with no copy. **Errors** As the system’s positional read: on a stream (a pipe, a terminal) the file has no offset to read at. ```rust pub async fn write_at(&self, buf: &[u8], offset: u64) -> Result ``` Writes `buf` at `offset` and answers how many bytes landed, as std’s `FileExt::write_at` does (on Windows `seek_write`, after which the system’s own position of the file is past the bytes written; the handle’s cursor never moves). On Linux a file opened to append takes the bytes at its end whatever the offset, as `pwrite(2)` does there. The write lands after every write accepted at the cursor before it, and before any write the handle accepts after it returned; positional writes running at once land in any order, as `pwrite` from two threads does. If the future is dropped while the write is out, it still lands, and every later call of the handle waits for it. The bytes go through a buffer of the runtime’s pool, at most 64 KiB a call (a short write, as `write_at` may answer). On a file opened for direct IO the call writes exactly `buf` at `offset`, from memory placed in its page as `buf` is, so the kernel refuses (with `EINVAL`) exactly what it would refuse of `buf` itself. [`write_at_owned`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.write_at_owned) writes from the caller’s own buffer with no copy. **Errors** As the system’s positional write. ```rust pub async fn read_exact_at(&self, buf: &mut [u8], offset: u64) -> Result<()> ``` Reads exactly `buf.len()` bytes at `offset`, as std’s `FileExt::read_exact_at` does, with [`read_at`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.read_at). **Errors** `UnexpectedEof` when the file ends first (the bytes read so far are in `buf`), or the first error of a read. ```rust pub async fn write_all_at(&self, buf: &[u8], offset: u64) -> Result<()> ``` Writes all of `buf` at `offset`, as std’s `FileExt::write_all_at` does, with [`write_at`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.write_at). **Errors** `WriteZero` when a write takes nothing, or the first error of a write. ```rust pub async fn read_at_owned(&self, buf: B, offset: u64) -> (Result, B) where B: IoBufMut ``` Reads at `offset` into the spare capacity of `buf`, after the bytes it holds, in one call of the system’s positional read, and gives `buf` back with how many bytes came: zero at the end of the file, or when `buf` has no spare capacity. The bytes are read into `buf` itself, never copied; on a file opened for direct IO the kernel’s alignment rules apply to `buf`’s own memory, which an [`AlignedBuf`](https://nuclei.rs/api/nuclei/io/struct.AlignedBuf.html) aligns. `buf` is any [`IoBufMut`](https://nuclei.rs/api/nuclei/io/trait.IoBufMut.html). Otherwise as [`read_at`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.read_at). ```rust pub async fn write_at_owned(&self, buf: B, offset: u64) -> (Result, B) where B: IoBuf ``` Writes all of `buf` at `offset` and gives it back with its length once the bytes landed. They are written from `buf` itself, never copied; on a file opened for direct IO the kernel’s alignment rules apply to `buf`’s own memory, which an [`AlignedBuf`](https://nuclei.rs/api/nuclei/io/struct.AlignedBuf.html) aligns. If the future is dropped while the write is out, it still lands, `buf` going with it. `buf` is any [`IoBuf`](https://nuclei.rs/api/nuclei/io/trait.IoBuf.html). Otherwise as [`write_at`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.write_at). `impl Handle` ```rust pub async fn create(path: impl AsRef) -> Result> ``` Opens the file at `path` for writing, creating it or cutting it down to nothing. ```rust pub async fn create_new(path: impl AsRef) -> Result> ``` Creates the file at `path` and opens it for reading and writing, failing if it exists. ```rust pub fn options() -> OpenOptions ``` The options to open a file with. ```rust pub async fn sync_all(&self) -> Result<()> ``` Writes the file’s data and metadata through to the device, as std’s `File::sync_all` does, once every write accepted before the call (at the cursor, or positional and returned) landed. On io_uring the sync is an operation of the shard’s ring (`IORING_OP_FSYNC`); elsewhere a job of the blocking pool. **Errors** A write that failed (reported here as by a flush), or the sync’s own failure. Once a sync of the handle failed, every later one fails with that error: the system reports a failure to write data back once, so a later sync that succeeded would not mean the data reached the device. Open the file again to start over. ```rust pub async fn sync_data(&self) -> Result<()> ``` Writes the file’s data through to the device, and the metadata a read needs, as std’s `File::sync_data` does (`IORING_FSYNC_DATASYNC` on io_uring); otherwise as [`sync_all`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.sync_all). **Errors** As [`sync_all`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.sync_all). ```rust pub async fn sync_range(&self, offset: u64, len: u64) -> Result<()> ``` Writes back the dirty data of the `len` bytes of the file from `offset` and waits for it (`len` of zero: to the end of the file), as Linux’s `sync_file_range` does, once every write accepted before the call landed. On io_uring this is an operation of the shard’s ring (`IORING_OP_SYNC_FILE_RANGE`, for a range its length field holds, else a job of the blocking pool). This is not a durability guarantee: it writes no metadata and flushes no cache of the device, so a crash may still lose the data. Use [`sync_data`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.sync_data) for that. On the systems that have no such call (macOS, Windows, other unix) it does what `sync_data` does for the whole file, which is stronger and covers the range. **Errors** As [`sync_all`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.sync_all): a write that failed, or the call’s own failure, which every later sync of the handle then repeats (the system reports a write-back error to one call only). ```rust pub async fn allocate( &self, offset: u64, len: u64, mode: Allocate, ) -> Result<()> ``` Changes the space the `len` bytes of the file from `offset` use, as `mode` says: reserves it, keeps the length, frees it, or zeroes it. The call is a write of the range: it lands after every write accepted at the cursor before it and every positional write that returned before it, a read at the cursor made after it sees what it did, and a future dropped while the call is out leaves it to the file, which every later call of the handle waits for. On io_uring it is an operation of the shard’s ring (`fallocate(2)`); elsewhere a job of the blocking pool (`fcntl` on macOS, `DeviceIoControl` and `SetFileInformationByHandle` on Windows). A system that cannot do `mode` answers `Unsupported` (macOS cannot zero a range in place), and a file system may refuse a mode as the system says. **Errors** `InvalidInput` when the end of the range is past the largest offset a file can have; otherwise the system’s own answer, among them that of an empty range, a handle that cannot be written, and a stream. ```rust pub async fn set_len(&self, len: u64) -> Result<()> ``` Sets the file’s length: cut down, or grown with zeros. The cursor stays where it is. Bytes of the file read ahead before the cut are never handed out after it. ```rust pub async fn metadata(&self) -> Result ``` The file’s metadata. ```rust pub async fn set_permissions(&self, perm: Permissions) -> Result<()> ``` Sets the file’s permissions. ```rust pub async fn set_times(&self, times: FileTimes) -> Result<()> ``` Sets the file’s access and modification times. ```rust pub async fn set_modified(&self, time: SystemTime) -> Result<()> ``` Sets the file’s modification time. ```rust pub async fn try_clone(&self) -> Result> ``` A second handle to the same open file, with a cursor of its own starting where the file’s offset is (writes in flight landed first). `impl Handle` ```rust pub async fn lock_file(&self, shared: bool) -> Result<()> ``` Locks the whole file, shared for any number of holders if `shared`, else exclusively for one, as std’s `File::lock_shared` and `File::lock` do, waiting for the lock on the blocking pool so the worker is free meanwhile. The lock is advisory, and it is released by [`unlock_file`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.unlock_file) or when the file is closed. If the future is dropped while it waits, the lock is never left held with nobody to release it: a job that had not started is cancelled, and one that got the lock gives it back. std’s own `File::lock`, reached through `Deref`, blocks the worker thread that makes it. **Errors** The system’s own, as std’s. ```rust pub async fn try_lock_file(&self, shared: bool) -> Result<(), TryLockError> ``` Locks the whole file if it is free now, shared if `shared`, else exclusively, as std’s `File::try_lock_shared` and `File::try_lock` do. The call does not wait, so it is made on the calling thread. **Errors** `WouldBlock` when another holder has the lock, else the system’s own error, as std’s. ```rust pub async fn unlock_file(&self) -> Result<()> ``` Releases the lock this file holds, as std’s `File::unlock` does, once every write accepted before the call landed (as a flush waits for them), so a holder that wrote under the lock lets go only after its bytes are in the file. **Errors** A write that failed (reported here as by a flush), or the system’s own error. The lock is released even when a write failed. `impl Handle` ```rust pub async fn open(p: impl AsRef) -> Result> ``` Opens the file at `p` for reading: on the calling thread when it is a regular file on a local file system and the kernel’s caches answer at once (Linux), on the blocking pool otherwise. **Errors** As [`File::open`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.open). ```rust pub async fn read_owned(&self, buf: B) -> (Result, B) where B: IoBufMut ``` Reads at the cursor into the spare capacity of `buf`, after the bytes it holds, and gives `buf` back with how many bytes came: zero at the end of the file, or when `buf` has no spare capacity. The bytes are read into `buf` itself, never copied, once the writes before the read landed. If the future is dropped before it completes, the cursor stays where it was. `buf` is any [`IoBufMut`](https://nuclei.rs/api/nuclei/io/trait.IoBufMut.html): a `Vec`, an [`AlignedBuf`](https://nuclei.rs/api/nuclei/io/struct.AlignedBuf.html) for a file opened for direct IO, or a type of the caller’s. ```rust pub async fn write_owned(&self, buf: B) -> (Result, B) where B: IoBuf ``` Writes all of `buf` at the cursor (at the end, for a file opened to append), after the writes before it, and gives it back with its length once the bytes reached the file. They are written from `buf` itself, never copied. If the future is dropped before it completes, the write is withdrawn while it still waits for the writes before it, and lands whole, in its place, once it started. `buf` is any [`IoBuf`](https://nuclei.rs/api/nuclei/io/trait.IoBuf.html), as for [`read_owned`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.read_owned). ```rust pub async fn read_vectored_owned(&self, bufs: V) -> (Result, V) where V: IoVecBufMut ``` Reads at the cursor into the spare capacity of `bufs`, after the bytes each holds, filling each buffer’s room before the next one’s, as [`read_owned`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.read_owned) reads into one, and gives `bufs` back with how many bytes came: zero at the end of the file, or when no buffer has spare capacity. One call of the kernel takes every room (`preadv`, or `IORING_OP_READV` on the ring); on Windows, which has no vectored read of a buffered file, one read a buffer, in order, until one comes short. ```rust pub async fn write_vectored_owned(&self, bufs: V) -> (Result, V) where V: IoVecBuf ``` Writes all of the bytes of `bufs`, each buffer’s in order, at the cursor as one write (as [`write_owned`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.write_owned) writes one buffer), and gives `bufs` back with how many bytes that was. No other write of the handle comes between two of them. One call of the kernel takes every buffer left (`pwritev`, `writev` for a file opened to append, or `IORING_OP_WRITEV` on the ring; on Windows, which has no vectored write of a buffered file, one write a buffer, in order), from the buffers themselves, never copied; on a file opened for direct IO each buffer’s memory and length meet the kernel’s alignment rules on their own. `impl Handle` ```rust pub fn new(io: T) -> Result> ``` Takes `io` over: what kind of object it is (a socket, a file, a pipe) decides how its IO runs. On unix it is made non-blocking. **Errors** When the object cannot be inspected or set up. `impl Handle` ```rust pub fn get_ref(&self) -> &T ``` The IO object. ```rust pub fn get_mut(&mut self) -> &mut T ``` The IO object, to change. Bytes written behind reach the kernel first (this waits for them), then the handle’s IO stops, and every call still out on its descriptor ends; its next operation takes the object as it is then (another descriptor discards what the old one left). ```rust pub fn into_inner(self) -> T ``` The IO object, back from the handle, once the bytes written behind reached the kernel and every call still out on its descriptor ended (this waits for them). Bytes the handle read ahead and had not handed out are dropped with it. `impl Handle` ```rust pub async fn shut(&self, how: Shutdown) -> Result<()> ``` Shuts down the reading half of the stream, its writing half, or both, as std’s `shutdown` does, once the bytes written behind reached the kernel. `Write` and `Both` wait until the kernel took every byte the handle accepted, so the peer reads all of them before the end of the stream, then ask the kernel; a peer that never reads holds them up, as it would hold up std’s blocking writes. `Read` leaves the writes alone. After `Read` or `Both`, reads answer as std’s do: Linux hands out what came before the shutdown, then the end; macOS and Windows end at once, so there the handle drops what it read ahead. It is not named `shutdown`, so that `stream.shutdown(how)` still calls std’s own, reached through `Deref`, which shuts the halves at once: the bytes still behind then never reach the peer, and it reads the end before them. **Errors** The error that stopped the bytes written behind, and what `shutdown(2)` answers: a half shut already on macOS (`NotConnected`), as std’s. `impl Handle` ```rust pub async fn shut(&self, how: Shutdown) -> Result<()> ``` Shuts down the reading half of the stream, its writing half, or both, as std’s `shutdown` does, once the bytes written behind reached the kernel. `Write` and `Both` wait until the kernel took every byte the handle accepted, so the peer reads all of them before the end of the stream, then ask the kernel; a peer that never reads holds them up, as it would hold up std’s blocking writes. `Read` leaves the writes alone. After `Read` or `Both`, reads answer as std’s do: Linux hands out what came before the shutdown, then the end; macOS and Windows end at once, so there the handle drops what it read ahead. It is not named `shutdown`, so that `stream.shutdown(how)` still calls std’s own, reached through `Deref`, which shuts the halves at once: the bytes still behind then never reach the peer, and it reads the end before them. **Errors** The error that stopped the bytes written behind, and what `shutdown(2)` answers: a half shut already on macOS (`NotConnected`), as std’s. `impl Handle` ```rust pub fn abort(self) -> Result<()> ``` Closes the stream now and resets the connection: `SO_LINGER` goes to zero, the bytes written behind and the buffers lent to writes still out are dropped, nothing lingers, and the close sends the peer a reset, so its reads fail with `ConnectionReset` rather than end as if every byte came. The kernel drops what its own queue holds too. A plain drop instead delivers the bytes behind, for at most the runtime’s [`write_behind_linger`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.write_behind_linger), and ends the stream cleanly; one whose time runs out resets the connection the same way. **Errors** When `SO_LINGER` cannot be set: the stream then closes as a drop closes it. `impl Handle` ```rust pub async fn send_file(&self, file: &File, offset: u64, len: u64) -> Result ``` Sends up to `len` bytes of `file`, from `offset`, to the stream, and returns how many it sent: fewer than `len` when the file ends first. Where the system has `sendfile(2)` (Linux, Android, macOS, FreeBSD) or `TransmitFile` (Windows, through the completion port) the bytes go from the page cache to the socket in the kernel and never enter user space; elsewhere (and on a Windows provider without `TransmitFile`) they are read at `offset` and written, which works the same and copies. The file’s own cursor does not move. Bytes written to the stream before the call go out first; do not write to the stream while the call runs, or its bytes may land between the call’s. If the future is dropped before it completes, the stream has got a prefix of the range, in order and whole, and a chunk of at most the runtime’s [`send_file_chunk`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.send_file_chunk) (one MiB by default) may still be on its way. **Errors** An error the stream or the file met (also the error of an earlier write behind), `InvalidInput` for a range past what an offset can name, and `file` not being a regular file. The bytes sent before an error are not counted. `impl Handle` ```rust pub async fn send_file(&self, file: &File, offset: u64, len: u64) -> Result ``` Sends up to `len` bytes of `file`, from `offset`, to the stream, and returns how many it sent: fewer than `len` when the file ends first. Where the system has `sendfile(2)` (Linux, Android, macOS, FreeBSD) or `TransmitFile` (Windows, through the completion port) the bytes go from the page cache to the socket in the kernel and never enter user space; elsewhere (and on a Windows provider without `TransmitFile`) they are read at `offset` and written, which works the same and copies. The file’s own cursor does not move. Bytes written to the stream before the call go out first; do not write to the stream while the call runs, or its bytes may land between the call’s. If the future is dropped before it completes, the stream has got a prefix of the range, in order and whole, and a chunk of at most the runtime’s [`send_file_chunk`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.send_file_chunk) (one MiB by default) may still be on its way. **Errors** An error the stream or the file met (also the error of an earlier write behind), `InvalidInput` for a range past what an offset can name, and `file` not being a regular file. The bytes sent before an error are not counted. `impl Handle` ```rust pub async fn read_owned(&self, buf: B) -> (Result, B) where B: IoBufMut ``` Reads into the spare capacity of `buf`, after the bytes it holds, and gives `buf` back with how many bytes came: zero at the end of the stream, or when `buf` has no spare capacity. The driver reads into `buf` itself, so the bytes are never copied. If the future is dropped before it completes, bytes the driver read into `buf` stay with the handle for its next read, so none is lost. `buf` is any [`IoBufMut`](https://nuclei.rs/api/nuclei/io/trait.IoBufMut.html). ```rust pub async fn read_vectored_owned(&self, bufs: V) -> (Result, V) where V: IoVecBufMut ``` Reads into the spare capacity of `bufs`, after the bytes each holds, filling each buffer’s room before the next one’s, and gives `bufs` back with how many bytes came: zero at the end of the stream, or when no buffer has spare capacity. One read of the kernel takes every room at once (`readv`, a `recvmsg` of several buffers, a `WSARecv` of several `WSABUF`s), as [`read_owned`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.read_owned) lends one buffer: the bytes land in the buffers themselves, never copied. Bytes another read left behind are copied in instead, in the same order. ```rust pub async fn readable(&self) -> Result<()> ``` Waits until a read would end at once. **Errors** When the stream cannot be watched. ```rust pub fn poll_read_ready(&self, cx: &mut Context<'_>) -> Poll> ``` Polls until a read would end at once. **Errors** When the stream cannot be watched. ```rust pub fn try_read(&self, buf: &mut [u8]) -> Result ``` Reads what came ahead into `buf` without waiting; zero at the end of the stream. **Errors** `WouldBlock` when nothing came yet (the driver goes on reading, so a later call finds what comes), and as `read(2)`. ```rust pub fn try_read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> Result ``` Reads what came ahead into `bufs` without waiting, as [`try_read`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.try_read). **Errors** As [`try_read`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.try_read). `impl Handle` ```rust pub async fn write_owned(&self, buf: B) -> (Result, B) where B: IoBuf ``` Writes all of `buf` and gives it back with its length. The driver writes from `buf` itself, so the bytes are never copied, and the write ends once the kernel took the last of them. If the future is dropped before it completes, the stream gets `buf` whole or not at all: a write none of which went out is withdrawn, and one that started is finished by the driver. On Windows a TCP write is always finished: there a cancelled send may have handed bytes to the stack while it says it took none. `buf` is any [`IoBuf`](https://nuclei.rs/api/nuclei/io/trait.IoBuf.html). ```rust pub async fn write_vectored_owned(&self, bufs: V) -> (Result, V) where V: IoVecBuf ``` Writes all of the bytes of `bufs`, each buffer’s in order, as one write, and gives `bufs` back with how many bytes that was. No other write of the stream comes between two of them. Each call of the kernel takes every buffer left at once (`writev`, a `sendmsg` of several buffers, a `WSASend` of several `WSABUF`s), from the buffers themselves, never copied; a call the kernel takes part of goes on from the first byte it did not take. If the future is dropped, as with [`write_owned`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.write_owned): the stream gets all of the bytes or none of them. ```rust pub async fn writable(&self) -> Result<()> ``` Waits until a write would be taken at once. **Errors** When the stream cannot be watched. ```rust pub fn poll_write_ready(&self, cx: &mut Context<'_>) -> Poll> ``` Polls until a write would be taken at once. **Errors** When the stream cannot be watched. ```rust pub fn try_write(&self, buf: &[u8]) -> Result ``` Hands `buf` to the write-behind without waiting; returns how many bytes it took. **Errors** `WouldBlock` when the write-behind has no room, and the error that stopped earlier bytes. ```rust pub fn try_write_vectored(&self, bufs: &[IoSlice<'_>]) -> Result ``` Hands the bytes of `bufs`, in order, to the write-behind without waiting, as [`try_write`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.try_write). **Errors** As [`try_write`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.try_write). `impl Handle` ```rust pub fn split(&self) -> (ReadHalf<'_, TcpStream>, WriteHalf<'_, TcpStream>) ``` The stream’s two halves, borrowed: to read on one task and write on another. Nothing is allocated. ```rust pub fn into_split(self) -> (OwnedReadHalf, OwnedWriteHalf) ``` The stream’s two halves, owning it together; see [`OwnedReadHalf::reunite`](https://nuclei.rs/api/nuclei/net/struct.OwnedReadHalf.html#method.reunite). ```rust pub async fn ready(&self, interest: Interest) -> Result ``` Waits until some of `interest` is ready, and says what is. **Errors** When the stream cannot be watched. `impl Handle` ```rust pub async fn write_zero_copy(&self, buf: B) -> (Result, Released) where B: IoBuf ``` Writes all of `buf` as [`write_owned`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.write_owned) does, with the kernel’s zero-copy send where it has one, and returns the write’s result with a [`Released`](https://nuclei.rs/api/nuclei/net/struct.Released.html) that gives `buf` back once the kernel let go of it. The write ends once the kernel took the last byte, as `write_owned`’s does, but the kernel keeps reading `buf` until the peer acknowledged every byte; only then does the `Released` resolve to it. So a peer that writes before it reads cannot hold the write up, and writes pipeline: the next one may start while earlier buffers are still out. A write of less than the runtime’s [`zero_copy_threshold`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.zero_copy_threshold) (1 MiB by default), where copying costs less, and every write on epoll, kqueue, I/O completion ports or an io_uring kernel without zero-copy sends (or without memory it may lock for them), is copied by the kernel as `write_owned`’s is, and its `Released` is ready at once. So is a write served by a ring only its own thread may reap: a thread’s own shard (a stream polled by `block_on` outside the runtime’s workers), or the workers of a runtime built with [`handoff_after(None)`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.handoff_after). Their rings could not be handed to another thread, which a buffer still out when the thread stops would need. If the future is dropped before it completes, the stream gets `buf` whole or not at all, as with `write_owned`. Either way `buf` is dropped only once the kernel let go of it. `buf` is any [`IoBuf`](https://nuclei.rs/api/nuclei/io/trait.IoBuf.html). `impl Handle` ```rust pub async fn read_owned(&self, buf: B) -> (Result, B) where B: IoBufMut ``` Reads into the spare capacity of `buf`, after the bytes it holds, and gives `buf` back with how many bytes came: zero at the end of the stream, or when `buf` has no spare capacity. The driver reads into `buf` itself, so the bytes are never copied. If the future is dropped before it completes, bytes the driver read into `buf` stay with the handle for its next read, so none is lost. `buf` is any [`IoBufMut`](https://nuclei.rs/api/nuclei/io/trait.IoBufMut.html). ```rust pub async fn read_vectored_owned(&self, bufs: V) -> (Result, V) where V: IoVecBufMut ``` Reads into the spare capacity of `bufs`, after the bytes each holds, filling each buffer’s room before the next one’s, and gives `bufs` back with how many bytes came: zero at the end of the stream, or when no buffer has spare capacity. One read of the kernel takes every room at once (`readv`, a `recvmsg` of several buffers, a `WSARecv` of several `WSABUF`s), as [`read_owned`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.read_owned) lends one buffer: the bytes land in the buffers themselves, never copied. Bytes another read left behind are copied in instead, in the same order. ```rust pub async fn readable(&self) -> Result<()> ``` Waits until a read would end at once. **Errors** When the stream cannot be watched. ```rust pub fn poll_read_ready(&self, cx: &mut Context<'_>) -> Poll> ``` Polls until a read would end at once. **Errors** When the stream cannot be watched. ```rust pub fn try_read(&self, buf: &mut [u8]) -> Result ``` Reads what came ahead into `buf` without waiting; zero at the end of the stream. **Errors** `WouldBlock` when nothing came yet (the driver goes on reading, so a later call finds what comes), and as `read(2)`. ```rust pub fn try_read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> Result ``` Reads what came ahead into `bufs` without waiting, as [`try_read`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.try_read). **Errors** As [`try_read`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.try_read). `impl Handle` ```rust pub async fn write_owned(&self, buf: B) -> (Result, B) where B: IoBuf ``` Writes all of `buf` and gives it back with its length. The driver writes from `buf` itself, so the bytes are never copied, and the write ends once the kernel took the last of them. If the future is dropped before it completes, the stream gets `buf` whole or not at all: a write none of which went out is withdrawn, and one that started is finished by the driver. On Windows a TCP write is always finished: there a cancelled send may have handed bytes to the stack while it says it took none. `buf` is any [`IoBuf`](https://nuclei.rs/api/nuclei/io/trait.IoBuf.html). ```rust pub async fn write_vectored_owned(&self, bufs: V) -> (Result, V) where V: IoVecBuf ``` Writes all of the bytes of `bufs`, each buffer’s in order, as one write, and gives `bufs` back with how many bytes that was. No other write of the stream comes between two of them. Each call of the kernel takes every buffer left at once (`writev`, a `sendmsg` of several buffers, a `WSASend` of several `WSABUF`s), from the buffers themselves, never copied; a call the kernel takes part of goes on from the first byte it did not take. If the future is dropped, as with [`write_owned`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.write_owned): the stream gets all of the bytes or none of them. ```rust pub async fn writable(&self) -> Result<()> ``` Waits until a write would be taken at once. **Errors** When the stream cannot be watched. ```rust pub fn poll_write_ready(&self, cx: &mut Context<'_>) -> Poll> ``` Polls until a write would be taken at once. **Errors** When the stream cannot be watched. ```rust pub fn try_write(&self, buf: &[u8]) -> Result ``` Hands `buf` to the write-behind without waiting; returns how many bytes it took. **Errors** `WouldBlock` when the write-behind has no room, and the error that stopped earlier bytes. ```rust pub fn try_write_vectored(&self, bufs: &[IoSlice<'_>]) -> Result ``` Hands the bytes of `bufs`, in order, to the write-behind without waiting, as [`try_write`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.try_write). **Errors** As [`try_write`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.try_write). `impl Handle` ```rust pub fn split(&self) -> (ReadHalf<'_, UnixStream>, WriteHalf<'_, UnixStream>) ``` The stream’s two halves, borrowed: to read on one task and write on another. Nothing is allocated. ```rust pub fn into_split( self, ) -> (OwnedReadHalf, OwnedWriteHalf) ``` The stream’s two halves, owning it together; see [`OwnedReadHalf::reunite`](https://nuclei.rs/api/nuclei/net/struct.OwnedReadHalf.html#method.reunite). ```rust pub async fn ready(&self, interest: Interest) -> Result ``` Waits until some of `interest` is ready, and says what is. **Errors** When the stream cannot be watched. `impl Handle` ```rust pub async fn read_owned(&self, buf: B) -> (Result, B) where B: IoBufMut ``` Reads into the spare capacity of `buf`, after the bytes it holds, and gives `buf` back with how many bytes came: zero at the end of the stream, or when `buf` has no spare capacity. The driver reads into `buf` itself, so the bytes are never copied. If the future is dropped before it completes, bytes the driver read into `buf` stay with the handle for its next read, so none is lost. `buf` is any [`IoBufMut`](https://nuclei.rs/api/nuclei/io/trait.IoBufMut.html). ```rust pub async fn read_vectored_owned(&self, bufs: V) -> (Result, V) where V: IoVecBufMut ``` Reads into the spare capacity of `bufs`, after the bytes each holds, filling each buffer’s room before the next one’s, and gives `bufs` back with how many bytes came: zero at the end of the stream, or when no buffer has spare capacity. One read of the kernel takes every room at once (`readv`, a `recvmsg` of several buffers, a `WSARecv` of several `WSABUF`s), as [`read_owned`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.read_owned) lends one buffer: the bytes land in the buffers themselves, never copied. Bytes another read left behind are copied in instead, in the same order. ```rust pub async fn readable(&self) -> Result<()> ``` Waits until a read would end at once. **Errors** When the stream cannot be watched. ```rust pub fn poll_read_ready(&self, cx: &mut Context<'_>) -> Poll> ``` Polls until a read would end at once. **Errors** When the stream cannot be watched. ```rust pub fn try_read(&self, buf: &mut [u8]) -> Result ``` Reads what came ahead into `buf` without waiting; zero at the end of the stream. **Errors** `WouldBlock` when nothing came yet (the driver goes on reading, so a later call finds what comes), and as `read(2)`. ```rust pub fn try_read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> Result ``` Reads what came ahead into `bufs` without waiting, as [`try_read`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.try_read). **Errors** As [`try_read`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.try_read). `impl Handle` ```rust pub async fn write_owned(&self, buf: B) -> (Result, B) where B: IoBuf ``` Writes all of `buf` and gives it back with its length. The driver writes from `buf` itself, so the bytes are never copied, and the write ends once the kernel took the last of them. If the future is dropped before it completes, the stream gets `buf` whole or not at all: a write none of which went out is withdrawn, and one that started is finished by the driver. On Windows a TCP write is always finished: there a cancelled send may have handed bytes to the stack while it says it took none. `buf` is any [`IoBuf`](https://nuclei.rs/api/nuclei/io/trait.IoBuf.html). ```rust pub async fn write_vectored_owned(&self, bufs: V) -> (Result, V) where V: IoVecBuf ``` Writes all of the bytes of `bufs`, each buffer’s in order, as one write, and gives `bufs` back with how many bytes that was. No other write of the stream comes between two of them. Each call of the kernel takes every buffer left at once (`writev`, a `sendmsg` of several buffers, a `WSASend` of several `WSABUF`s), from the buffers themselves, never copied; a call the kernel takes part of goes on from the first byte it did not take. If the future is dropped, as with [`write_owned`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.write_owned): the stream gets all of the bytes or none of them. ```rust pub async fn writable(&self) -> Result<()> ``` Waits until a write would be taken at once. **Errors** When the stream cannot be watched. ```rust pub fn poll_write_ready(&self, cx: &mut Context<'_>) -> Poll> ``` Polls until a write would be taken at once. **Errors** When the stream cannot be watched. ```rust pub fn try_write(&self, buf: &[u8]) -> Result ``` Hands `buf` to the write-behind without waiting; returns how many bytes it took. **Errors** `WouldBlock` when the write-behind has no room, and the error that stopped earlier bytes. ```rust pub fn try_write_vectored(&self, bufs: &[IoSlice<'_>]) -> Result ``` Hands the bytes of `bufs`, in order, to the write-behind without waiting, as [`try_write`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.try_write). **Errors** As [`try_write`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.try_write). `impl Handle` ```rust pub async fn bind(addr: A) -> Result> ``` A listener bound to the first of the addresses `addr` names that it can bind. **Errors** The last address’s error when none could be bound, or the lookup’s. ```rust pub async fn accept(&self) -> Result<(Handle, SocketAddr)> ``` The next connection, with its peer’s address. On macOS an accept that finds the process out of descriptors closes the connection it took off the backlog, as the system’s own does; the next ones fail with the same error and take none until a descriptor is free. **Errors** As `accept(2)`: a connection reset before it was taken, or the process out of descriptors. ```rust pub fn poll_accept( &self, cx: &mut Context<'_>, ) -> Poll, SocketAddr)>> ``` Polls for the next connection, with its peer’s address: `Pending` with `cx`’s waker kept until one comes. **Errors** As [`accept`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.accept). ```rust pub fn incoming( &self, ) -> impl Stream>> + Send + Unpin + '_ ``` The connections as they come, without their addresses; the stream never ends, and an error is one of its items. ```rust pub async fn accept_multi(&self) -> Result ``` The connections as they come, from a stream that owns its own copy of the listener, so it may outlive this handle. A connection reset before it was taken is skipped, and so is the process having no descriptor left to accept into: the stream waits, with a growing pause, until there is one, and the connections wait in the listener’s backlog (on macOS but for the one the first accept to find none took, which the system closes, as [`accept`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.accept) says). Any other error ends the stream, and [`TcpStreamGenerator::take_error`](https://nuclei.rs/api/nuclei/net/struct.TcpStreamGenerator.html#method.take_error) says what it was. On io_uring the stream keeps one accept armed for every connection that comes, so it takes connections ahead of its polls; those it took and never yielded close when it drops, as a listener’s own backlog does when the last copy of the listener closes. **Errors** When the listener’s descriptor cannot be copied. `impl Handle` ```rust pub async fn connect( sock_addrs: A, ) -> Result> ``` A stream connected to the first of `sock_addrs` that takes the connection. **Errors** The last address’s error when none took it, or the lookup’s. ```rust pub async fn send(&self, buf: &[u8]) -> Result ``` Sends bytes; returns how many were taken (into the write-behind, as for [`AsyncWrite`](https://nuclei.rs/api/nuclei/io/trait.AsyncWrite.html)). **Errors** As `send(2)`, or the error that stopped earlier bytes. ```rust pub async fn recv(&self, buf: &mut [u8]) -> Result ``` Receives bytes; zero at the end of the stream. **Errors** As `recv(2)`. ```rust pub async fn peek(&self, buf: &mut [u8]) -> Result ``` Looks at the bytes the next receive returns, without taking them. **Errors** As `recv(2)` with `MSG_PEEK`. ```rust pub fn poll_peek( &self, cx: &mut Context<'_>, buf: &mut ReadBuf<'_>, ) -> Poll> ``` Polls for the bytes the next receive returns, into the unfilled part of `buf`, without taking them; `buf` advances by what came. **Errors** As `recv(2)` with `MSG_PEEK`. ```rust pub fn linger(&self) -> Result> ``` `SO_LINGER`: how long a close waits for unsent data, `None` if it does not wait. ```rust pub fn set_linger(&self, linger: Option) -> Result<()> ``` Sets `SO_LINGER`: with `Some(time)` a close waits up to `time` (whole seconds) for unsent data; with `None` it returns at once and the system sends what is left. ```rust pub fn set_zero_linger(&self) -> Result<()> ``` Sets `SO_LINGER` to zero: the close drops unsent data and resets the connection. `impl Handle` ```rust pub fn set_keepalive_timing(&self, keepalive: TcpKeepalive) -> Result<()> ``` Turns keepalive probes on (`SO_KEEPALIVE`), timed as `keepalive` says (`TCP_KEEPIDLE`, `TCP_KEEPINTVL`, `TCP_KEEPCNT`; macOS calls the first `TCP_KEEPALIVE`). **Errors** `Unsupported` where the system has no such options, `InvalidInput` for a value past what it takes, and what `setsockopt(2)` answers (a zero time or count). ```rust pub fn keepalive_timing(&self) -> Result ``` The keepalive’s timing: the system’s values where none was set. **Errors** `Unsupported` where the system has no such options. ```rust pub fn set_user_timeout(&self, timeout: Option) -> Result<()> ``` Sets `TCP_USER_TIMEOUT` (Linux): how long sent bytes may go unacknowledged before the connection is dropped, in whole milliseconds; `None` or zero leaves it to the system. **Errors** `Unsupported` off Linux, `InvalidInput` for a time past what the system takes. ```rust pub fn user_timeout(&self) -> Result> ``` `TCP_USER_TIMEOUT` (Linux), `None` where the system’s own applies. **Errors** `Unsupported` off Linux. `impl Handle` ```rust pub fn set_quickack(&self, quickack: bool) -> Result<()> ``` Sets `TCP_QUICKACK` (Linux): with `true` the stream acknowledges at once rather than waiting to send it with data. The kernel turns it off again as it sees fit, so it is set again where it matters. **Errors** `Unsupported` off Linux. ```rust pub fn quickack(&self) -> Result ``` `TCP_QUICKACK` (Linux): whether the stream acknowledges at once now. **Errors** `Unsupported` off Linux. `impl Handle` ```rust pub async fn bind(addr: A) -> Result> ``` A socket bound to the first of the addresses `addr` names that it can bind. **Errors** The last address’s error when none could be bound, or the lookup’s. ```rust pub async fn connect( sock_addrs: A, ) -> Result> ``` A socket on an ephemeral local port, connected to the first of `sock_addrs` it can connect to: `send` and `recv` then talk to that peer only. This makes a socket: it is called as `UdpSocket::connect(addr)`. Called on a socket, `socket.connect(addr)` is std’s own `UdpSocket::connect`, reached through `Deref`, which connects that socket in place and looks a name up with a blocking call, on the calling thread (a shard’s, with every task of it). Connect a socket in place with a numeric address, or look the name up first with [`lookup_host`](https://nuclei.rs/api/nuclei/net/fn.lookup_host.html). **Errors** The last address’s error when none worked, or the lookup’s. ```rust pub async fn send(&self, buf: &[u8]) -> Result ``` Sends a datagram to the connected peer. **Errors** As `send(2)` of this datagram. On Windows the completion port sends it after the call returns, so a failure the stack finds only then (its size is checked first) is the next send’s error. ```rust pub async fn recv(&self, buf: &mut [u8]) -> Result ``` Receives a datagram from the connected peer; what does not fit `buf` is cut. **Errors** As `recv(2)`. ```rust pub async fn send_owned(&self, buf: B) -> (Result, B) where B: IoBuf ``` Sends all of `buf` as one datagram to the connected peer and gives it back with its length. The driver sends from `buf` itself, so the bytes are never copied. If the future is dropped before it completes, the datagram is sent whole or not at all: one the driver has not handed to the kernel is withdrawn, and one already handed over goes out. `buf` is any [`IoBuf`](https://nuclei.rs/api/nuclei/io/trait.IoBuf.html). ```rust pub async fn send_to_owned(&self, buf: B, addr: A) -> (Result, B) where A: ToSocketAddrs, B: IoBuf ``` Sends all of `buf` as one datagram to the first address `addr` names and gives it back with its length, as [`send_owned`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.send_owned) sends to the connected peer. ```rust pub async fn recv_owned(&self, buf: B) -> (Result, B) where B: IoBufMut ``` Receives a datagram from the connected peer into the spare capacity of `buf`, after the bytes it holds, and gives `buf` back with the datagram’s length. The driver receives into `buf` itself, so the bytes are never copied; what does not fit is cut. If the future is dropped before it completes, a datagram the driver received into `buf` stays with the socket for its next receive, so none is lost. `buf` is any [`IoBufMut`](https://nuclei.rs/api/nuclei/io/trait.IoBufMut.html). ```rust pub async fn recv_from_owned( &self, buf: B, ) -> (Result<(usize, SocketAddr)>, B) where B: IoBufMut ``` Receives a datagram with its sender’s address into the spare capacity of `buf`, as [`recv_owned`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.recv_owned). ```rust pub async fn peek(&self, buf: &mut [u8]) -> Result ``` Looks at the next datagram without taking it. **Errors** As `recv(2)` with `MSG_PEEK`. ```rust pub async fn send_to( &self, buf: &[u8], addr: A, ) -> Result ``` Sends a datagram to the first address `addr` names. **Errors** As `sendto(2)` of this datagram (on Windows, as for [`send`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.send)), or the lookup’s. ```rust pub async fn recv_from(&self, buf: &mut [u8]) -> Result<(usize, SocketAddr)> ``` Receives a datagram with its sender’s address. **Errors** As `recvfrom(2)`. ```rust pub async fn peek_from(&self, buf: &mut [u8]) -> Result<(usize, SocketAddr)> ``` Looks at the next datagram and its sender without taking it. **Errors** As `recvfrom(2)` with `MSG_PEEK`. ```rust pub fn poll_recv_from( &self, cx: &mut Context<'_>, buf: &mut ReadBuf<'_>, ) -> Poll> ``` Polls for a datagram and its sender, received into the unfilled part of `buf`, which advances by its length; what does not fit is cut. `Pending` with `cx`’s waker kept until one comes. **Errors** As `recvfrom(2)`. ```rust pub fn poll_send_to( &self, cx: &mut Context<'_>, buf: &[u8], target: SocketAddr, ) -> Poll> ``` Polls to send a datagram to `target`, `Pending` with `cx`’s waker kept while one is still queued. **Errors** As `sendto(2)` of this datagram (on Windows, as for [`send`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.send)). ```rust pub async fn readable(&self) -> Result<()> ``` Waits until a receive would end at once: a datagram came, or an error (which the receive reports). **Errors** When the socket cannot be watched. ```rust pub async fn writable(&self) -> Result<()> ``` Waits until a send would be taken at once. **Errors** When the socket cannot be watched. ```rust pub async fn ready(&self, interest: Interest) -> Result ``` Waits until some of `interest` is ready, and says what is. **Errors** When the socket cannot be watched. ```rust pub fn poll_recv_ready(&self, cx: &mut Context<'_>) -> Poll> ``` Polls until a receive would end at once. **Errors** When the socket cannot be watched. ```rust pub fn poll_send_ready(&self, cx: &mut Context<'_>) -> Poll> ``` Polls until a send would be taken at once. **Errors** When the socket cannot be watched. ```rust pub fn try_send(&self, buf: &[u8]) -> Result ``` Sends a datagram to the connected peer without waiting. **Errors** `WouldBlock` when a datagram is still queued, and as `send(2)`. ```rust pub fn try_recv(&self, buf: &mut [u8]) -> Result ``` Receives a datagram from the connected peer without waiting; what does not fit `buf` is cut. **Errors** `WouldBlock` when none came yet, and as `recv(2)`. ```rust pub fn try_peek(&self, buf: &mut [u8]) -> Result ``` Looks at the next datagram without taking it or waiting. **Errors** `WouldBlock` when none came yet, and as `recv(2)` with `MSG_PEEK`. ```rust pub fn try_send_to(&self, buf: &[u8], target: SocketAddr) -> Result ``` Sends a datagram to `target` without waiting. **Errors** `WouldBlock` when a datagram is still queued, and as `sendto(2)`. ```rust pub fn try_recv_from(&self, buf: &mut [u8]) -> Result<(usize, SocketAddr)> ``` Receives a datagram and its sender’s address without waiting. **Errors** `WouldBlock` when none came yet, and as `recvfrom(2)`. ```rust pub fn try_peek_from(&self, buf: &mut [u8]) -> Result<(usize, SocketAddr)> ``` Looks at the next datagram and its sender without taking it or waiting. **Errors** `WouldBlock` when none came yet, and as `recvfrom(2)` with `MSG_PEEK`. ```rust pub async fn peek_sender(&self) -> Result ``` The sender of the next datagram, which stays to be received. **Errors** As `recvfrom(2)` with `MSG_PEEK`. ```rust pub fn poll_peek_sender(&self, cx: &mut Context<'_>) -> Poll> ``` Polls for the sender of the next datagram, which stays to be received. At most one byte of it is copied, and dropped. **Errors** As `recvfrom(2)` with `MSG_PEEK`. ```rust pub async fn recv_buf(&self, buf: &mut ReadBuf<'_>) -> Result ``` Receives a datagram from the connected peer into the unfilled part of `buf`, which advances by its length; what does not fit is cut. **Errors** As `recv(2)`. ```rust pub async fn recv_buf_from( &self, buf: &mut ReadBuf<'_>, ) -> Result<(usize, SocketAddr)> ``` Receives a datagram and its sender’s address into the unfilled part of `buf`, which advances by its length; what does not fit is cut. **Errors** As `recvfrom(2)`. `impl Handle` ```rust pub fn bind>(path: P) -> Result> ``` A listener bound to `path`. **Errors** As [`UnixListener::bind`](https://doc.rust-lang.org/1.99.1/std/os/unix/net/listener/struct.UnixListener.html#method.bind). ```rust pub fn bind_addr(addr: &UnixSocketAddr) -> Result> ``` A listener bound to `addr`: a path, or on Linux a name in the abstract namespace. **Errors** As [`UnixListener::bind_addr`](https://doc.rust-lang.org/1.99.1/std/os/unix/net/listener/struct.UnixListener.html#method.bind_addr). ```rust pub async fn accept(&self) -> Result<(Handle, UnixSocketAddr)> ``` The next connection, with its peer’s address. On macOS an accept that finds the process out of descriptors closes the connection it took, and the next ones take none until a descriptor is free, as a TCP listener’s do. **Errors** As `accept(2)`. ```rust pub fn incoming( &self, ) -> impl Stream>> + Send + Unpin + '_ ``` The connections as they come, without their addresses; the stream never ends, and an error is one of its items. `impl Handle` ```rust pub async fn connect>(path: P) -> Result> ``` A stream connected to the listener at `path`. **Errors** As `connect(2)`. ```rust pub async fn connect_addr(addr: &UnixSocketAddr) -> Result> ``` A stream connected to the listener at `addr`: a path, or on Linux a name in the abstract namespace. **Errors** As `connect(2)`; an unnamed address names no listener. ```rust pub fn peer_cred(&self) -> Result ``` The credentials of the process at the other end, as the connection was made. **Errors** When the system cannot tell them. ```rust pub fn pair() -> Result<(Handle, Handle)> ``` Two streams connected to each other. **Errors** As `socketpair(2)`. ```rust pub async fn send(&self, buf: &[u8]) -> Result ``` Sends bytes; returns how many were taken. **Errors** As `send(2)`, or the error that stopped earlier bytes. ```rust pub async fn recv(&self, buf: &mut [u8]) -> Result ``` Receives bytes; zero at the end of the stream. **Errors** As `recv(2)`. ```rust pub async fn peek(&self, buf: &mut [u8]) -> Result ``` Looks at the bytes the next receive returns, without taking them. **Errors** As `recv(2)` with `MSG_PEEK`. `impl Handle` ```rust pub fn bind>(path: P) -> Result> ``` A socket bound to `path`. **Errors** As [`UnixDatagram::bind`](https://doc.rust-lang.org/1.99.1/std/os/unix/net/datagram/struct.UnixDatagram.html#method.bind). ```rust pub fn bind_addr(addr: &UnixSocketAddr) -> Result> ``` A socket bound to `addr`: a path, or on Linux a name in the abstract namespace. **Errors** As [`UnixDatagram::bind_addr`](https://doc.rust-lang.org/1.99.1/std/os/unix/net/datagram/struct.UnixDatagram.html#method.bind_addr). ```rust pub fn unbound() -> Result> ``` A socket bound to no address: it sends with `send_to`, or to the peer its `connect` names. **Errors** When the system has no socket to give. ```rust pub fn pair() -> Result<(Handle, Handle)> ``` Two sockets connected to each other. **Errors** As `socketpair(2)`. ```rust pub async fn send(&self, buf: &[u8]) -> Result ``` Sends a datagram to the connected peer. **Errors** As `send(2)` of this datagram. ```rust pub async fn recv(&self, buf: &mut [u8]) -> Result ``` Receives a datagram from the connected peer; what does not fit `buf` is cut. **Errors** As `recv(2)`. ```rust pub async fn send_owned(&self, buf: B) -> (Result, B) where B: IoBuf ``` Sends all of `buf` as one datagram to the connected peer and gives it back with its length. The driver sends from `buf` itself, so the bytes are never copied. If the future is dropped before it completes, the datagram is sent whole or not at all: one the driver has not handed to the kernel is withdrawn, and one already handed over goes out. `buf` is any [`IoBuf`](https://nuclei.rs/api/nuclei/io/trait.IoBuf.html). ```rust pub async fn send_to_owned(&self, buf: B, path: P) -> (Result, B) where P: AsRef, B: IoBuf ``` Sends all of `buf` as one datagram to the socket at `path` and gives it back with its length, as [`send_owned`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.send_owned) sends to the connected peer. ```rust pub async fn recv_owned(&self, buf: B) -> (Result, B) where B: IoBufMut ``` Receives a datagram from the connected peer into the spare capacity of `buf`, after the bytes it holds, and gives `buf` back with the datagram’s length. The driver receives into `buf` itself, so the bytes are never copied; what does not fit is cut. If the future is dropped before it completes, a datagram the driver received into `buf` stays with the socket for its next receive, so none is lost. `buf` is any [`IoBufMut`](https://nuclei.rs/api/nuclei/io/trait.IoBufMut.html). ```rust pub async fn recv_from_owned( &self, buf: B, ) -> (Result<(usize, UnixSocketAddr)>, B) where B: IoBufMut ``` Receives a datagram with its sender’s address into the spare capacity of `buf`, as [`recv_owned`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.recv_owned). ```rust pub async fn peek(&self, buf: &mut [u8]) -> Result ``` Looks at the next datagram without taking it. **Errors** As `recv(2)` with `MSG_PEEK`. ```rust pub async fn send_to>( &self, buf: &[u8], path: P, ) -> Result ``` Sends a datagram to the socket at `path`. **Errors** As `sendto(2)` of this datagram. ```rust pub async fn recv_from(&self, buf: &mut [u8]) -> Result<(usize, UnixSocketAddr)> ``` Receives a datagram with its sender’s address. **Errors** As `recvfrom(2)`. ```rust pub async fn peek_from(&self, buf: &mut [u8]) -> Result<(usize, UnixSocketAddr)> ``` Looks at the next datagram and its sender without taking it. **Errors** As `recvfrom(2)` with `MSG_PEEK`. ```rust pub async fn readable(&self) -> Result<()> ``` Waits until a receive would end at once: a datagram came, or an error (which the receive reports). **Errors** When the socket cannot be watched. ```rust pub async fn writable(&self) -> Result<()> ``` Waits until a send would be taken at once. **Errors** When the socket cannot be watched. ```rust pub async fn ready(&self, interest: Interest) -> Result ``` Waits until some of `interest` is ready, and says what is. **Errors** When the socket cannot be watched. ```rust pub fn poll_recv_ready(&self, cx: &mut Context<'_>) -> Poll> ``` Polls until a receive would end at once. **Errors** When the socket cannot be watched. ```rust pub fn poll_send_ready(&self, cx: &mut Context<'_>) -> Poll> ``` Polls until a send would be taken at once. **Errors** When the socket cannot be watched. ```rust pub fn try_send(&self, buf: &[u8]) -> Result ``` Sends a datagram to the connected peer without waiting. **Errors** `WouldBlock` when a datagram is still queued, and as `send(2)`. ```rust pub fn try_send_to>(&self, buf: &[u8], path: P) -> Result ``` Sends a datagram to the socket at `path` without waiting. **Errors** `WouldBlock` when a datagram is still queued, and as `sendto(2)`. ```rust pub fn try_recv(&self, buf: &mut [u8]) -> Result ``` Receives a datagram from the connected peer without waiting; what does not fit `buf` is cut. **Errors** `WouldBlock` when none came yet, and as `recv(2)`. ```rust pub fn try_recv_from(&self, buf: &mut [u8]) -> Result<(usize, UnixSocketAddr)> ``` Receives a datagram and its sender’s address without waiting. **Errors** `WouldBlock` when none came yet, and as `recvfrom(2)`. `impl Handle` ```rust pub fn try_io( &self, interest: Interest, f: impl FnOnce() -> Result, ) -> Result ``` Runs `f`, a call of the caller’s own on the socket (through [`get_ref`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.get_ref) or its descriptor), if the socket may be ready for `interest`, and clears that readiness if `f` answers `WouldBlock`. The side then takes its caller’s calls only, until the handle’s own next read or write on it. Nothing is reordered: bytes the handle wrote behind go out first, and data it read ahead must be read before. **Errors** `WouldBlock` when none of `interest` may be ready (or bytes written behind are still going out), `ResourceBusy` when the handle holds data it read ahead, and what `f` answers. ```rust pub async fn async_io( &self, interest: Interest, f: impl FnMut() -> Result, ) -> Result ``` Runs `f`, a call of the caller’s own on the socket, each time it may be ready for `interest`, until `f` answers other than `WouldBlock`, clearing the readiness each time it does; as [`try_io`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.try_io), bytes written behind go out first. **Errors** `ResourceBusy` when the handle holds data it read ahead, and what `f` answers. `impl Handle` ```rust pub fn try_io( &self, interest: Interest, f: impl FnOnce() -> Result, ) -> Result ``` Runs `f`, a call of the caller’s own on the socket (through [`get_ref`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.get_ref) or its descriptor), if the socket may be ready for `interest`, and clears that readiness if `f` answers `WouldBlock`. The side then takes its caller’s calls only, until the handle’s own next read or write on it. Nothing is reordered: bytes the handle wrote behind go out first, and data it read ahead must be read before. **Errors** `WouldBlock` when none of `interest` may be ready (or bytes written behind are still going out), `ResourceBusy` when the handle holds data it read ahead, and what `f` answers. ```rust pub async fn async_io( &self, interest: Interest, f: impl FnMut() -> Result, ) -> Result ``` Runs `f`, a call of the caller’s own on the socket, each time it may be ready for `interest`, until `f` answers other than `WouldBlock`, clearing the readiness each time it does; as [`try_io`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.try_io), bytes written behind go out first. **Errors** `ResourceBusy` when the handle holds data it read ahead, and what `f` answers. `impl Handle` ```rust pub fn try_io( &self, interest: Interest, f: impl FnOnce() -> Result, ) -> Result ``` Runs `f`, a call of the caller’s own on the socket (through [`get_ref`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.get_ref) or its descriptor), if the socket may be ready for `interest`, and clears that readiness if `f` answers `WouldBlock`. The side then takes its caller’s calls only, until the handle’s own next read or write on it. Nothing is reordered: bytes the handle wrote behind go out first, and data it read ahead must be read before. **Errors** `WouldBlock` when none of `interest` may be ready (or bytes written behind are still going out), `ResourceBusy` when the handle holds data it read ahead, and what `f` answers. ```rust pub async fn async_io( &self, interest: Interest, f: impl FnMut() -> Result, ) -> Result ``` Runs `f`, a call of the caller’s own on the socket, each time it may be ready for `interest`, until `f` answers other than `WouldBlock`, clearing the readiness each time it does; as [`try_io`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.try_io), bytes written behind go out first. **Errors** `ResourceBusy` when the handle holds data it read ahead, and what `f` answers. `impl Handle` ```rust pub fn try_io( &self, interest: Interest, f: impl FnOnce() -> Result, ) -> Result ``` Runs `f`, a call of the caller’s own on the socket (through [`get_ref`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.get_ref) or its descriptor), if the socket may be ready for `interest`, and clears that readiness if `f` answers `WouldBlock`. The side then takes its caller’s calls only, until the handle’s own next read or write on it. Nothing is reordered: bytes the handle wrote behind go out first, and data it read ahead must be read before. **Errors** `WouldBlock` when none of `interest` may be ready (or bytes written behind are still going out), `ResourceBusy` when the handle holds data it read ahead, and what `f` answers. ```rust pub async fn async_io( &self, interest: Interest, f: impl FnMut() -> Result, ) -> Result ``` Runs `f`, a call of the caller’s own on the socket, each time it may be ready for `interest`, until `f` answers other than `WouldBlock`, clearing the readiness each time it does; as [`try_io`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.try_io), bytes written behind go out first. **Errors** `ResourceBusy` when the handle holds data it read ahead, and what `f` answers. #### Trait Implementations - `impl AsFd for Handle` - `impl AsRawFd for Handle` - `impl AsRef> for ReadHalf<'_, S>` - `impl AsRef> for WriteHalf<'_, S>` - `impl AsRef> for OwnedReadHalf` - `impl AsRef> for OwnedWriteHalf` - `impl AsyncBufRead for Handle` - `impl AsyncRead for Handle` - `impl AsyncRead for &Handle` - `impl AsyncRead for &Handle` - `impl AsyncRead for Handle` - `impl AsyncRead for &Handle` - `impl AsyncRead for Handle` - `impl AsyncRead for &Handle` - `impl AsyncRead for Handle` - `impl AsyncSeek for Handle` - `impl AsyncWrite for Handle` - `impl AsyncWrite for &Handle` - `impl AsyncWrite for &Handle` - `impl AsyncWrite for Handle` - `impl AsyncWrite for &Handle` - `impl AsyncWrite for Handle` - `impl AsyncWrite for &Handle` - `impl AsyncWrite for Handle` - `impl Debug for Handle` - `impl Deref for Handle` - `impl DerefMut for Handle` - `impl Drop for Handle` - `impl IntoRawFd for Handle` #### Auto Trait Implementations - `impl !Freeze for Handle` - `impl !RefUnwindSafe for Handle` - `impl !UnwindSafe for Handle` - `impl Send for Handle where T: Send` - `impl Sync for Handle where T: Sync` - `impl Unpin for Handle where T: Unpin` - `impl UnsafeUnpin for Handle where T: UnsafeUnpin` ### struct `nuclei::io::Interest` https://nuclei.rs/api/nuclei/io/struct.Interest.html ```rust pub struct Interest(/* private fields */); ``` What a readiness call waits for: reading, writing, or either. #### Implementations `impl Interest` ```rust pub const READABLE: Interest ``` A read would end at once. ```rust pub const WRITABLE: Interest ``` A write would be taken at once. ```rust pub fn is_readable(self) -> bool ``` Whether it asks for reading. ```rust pub fn is_writable(self) -> bool ``` Whether it asks for writing. #### Trait Implementations - `impl BitOr for Interest` - `impl Clone for Interest` - `impl Copy for Interest` - `impl Debug for Interest` - `impl Eq for Interest` - `impl PartialEq for Interest` - `impl StructuralPartialEq for Interest` #### Auto Trait Implementations - `impl Freeze for Interest` - `impl RefUnwindSafe for Interest` - `impl Send for Interest` - `impl Sync for Interest` - `impl Unpin for Interest` - `impl UnsafeUnpin for Interest` - `impl UnwindSafe for Interest` ### struct `nuclei::io::Lines` https://nuclei.rs/api/nuclei/io/struct.Lines.html ```rust pub struct Lines { /* private fields */ } ``` The lines of a buffered reader; made by [`lines`](https://nuclei.rs/api/nuclei/io/trait.AsyncBufReadExt.html#method.lines). #### Implementations `impl Lines` ```rust pub async fn next_line(&mut self) -> Result> ``` The next line without its `\n` or `\r\n`, `None` at the end. ```rust pub fn poll_next_line( &mut self, cx: &mut Context<'_>, ) -> Poll>> ``` Polls for the next line. ```rust pub fn into_inner(self) -> R ``` The reader, taken back. #### Trait Implementations - `impl Debug for Lines` #### Auto Trait Implementations - `impl Freeze for Lines where R: Freeze` - `impl RefUnwindSafe for Lines where R: RefUnwindSafe` - `impl Send for Lines where R: Send` - `impl Sync for Lines where R: Sync` - `impl Unpin for Lines where R: Unpin` - `impl UnsafeUnpin for Lines where R: UnsafeUnpin` - `impl UnwindSafe for Lines where R: UnwindSafe` ### struct `nuclei::io::Read` https://nuclei.rs/api/nuclei/io/struct.Read.html ```rust pub struct Read<'a, R: ?Sized> { /* private fields */ } ``` The future of [`read`](https://nuclei.rs/api/nuclei/io/trait.AsyncReadExt.html#method.read). #### Trait Implementations - `impl<'a, R: Debug + ?Sized> Debug for Read<'a, R>` - `impl Future for Read<'_, R>` #### Auto Trait Implementations - `impl<'a, R> !UnwindSafe for Read<'a, R>` - `impl<'a, R> Freeze for Read<'a, R> where R: ?Sized` - `impl<'a, R> RefUnwindSafe for Read<'a, R> where R: RefUnwindSafe + ?Sized` - `impl<'a, R> Send for Read<'a, R> where R: Send + ?Sized` - `impl<'a, R> Sync for Read<'a, R> where R: Sync + ?Sized` - `impl<'a, R> Unpin for Read<'a, R> where R: ?Sized` - `impl<'a, R> UnsafeUnpin for Read<'a, R> where R: ?Sized` ### struct `nuclei::io::ReadBuf` https://nuclei.rs/api/nuclei/io/struct.ReadBuf.html ```rust pub struct ReadBuf<'a> { /* private fields */ } ``` A buffer being filled by reads: its first `filled` bytes hold data, its first `initialized` bytes are initialized (`filled <= initialized`), and the rest may be uninitialized memory that a read may write into. #### Implementations `impl<'a> ReadBuf<'a>` ```rust pub fn new(buf: &'a mut [u8]) -> Self ``` A buffer over `buf`, all of it initialized, none of it filled. ```rust pub fn uninit(buf: &'a mut [MaybeUninit]) -> Self ``` A buffer over `buf`, none of it initialized or filled. ```rust pub fn capacity(&self) -> usize ``` The buffer’s whole length. ```rust pub fn filled(&self) -> &[u8] ``` The bytes filled so far. ```rust pub fn filled_mut(&mut self) -> &mut [u8] ``` The bytes filled so far, to change. ```rust pub fn initialized(&self) -> &[u8] ``` The bytes known to be initialized, filled or not. ```rust pub fn initialized_mut(&mut self) -> &mut [u8] ``` The bytes known to be initialized, to change. ```rust pub fn take(&mut self, n: usize) -> ReadBuf<'_> ``` A buffer over at most `n` bytes of the unfilled part, sharing what is known to be initialized there. ```rust pub fn initialize_unfilled(&mut self) -> &mut [u8] ``` Initializes the whole unfilled part (zeroing what was not initialized) and answers it, for a read to write into. ```rust pub fn initialize_unfilled_to(&mut self, n: usize) -> &mut [u8] ``` Initializes the first `n` bytes of the unfilled part and answers them. **Panics** When `n` is more than [`remaining`](https://nuclei.rs/api/nuclei/io/struct.ReadBuf.html#method.remaining). ```rust pub fn remaining(&self) -> usize ``` The room left after the filled part. ```rust pub fn clear(&mut self) ``` Empties the filled part; what was initialized stays initialized. ```rust pub fn advance(&mut self, n: usize) ``` Counts `n` more bytes as filled. **Panics** When that passes the initialized part. ```rust pub fn set_filled(&mut self, n: usize) ``` Sets how many bytes are filled. **Panics** When `n` passes the initialized part. ```rust pub unsafe fn assume_init(&mut self, n: usize) ``` Counts the first `n` bytes of the unfilled part as initialized. **Safety** The caller has initialized those bytes. ```rust pub fn put_slice(&mut self, bytes: &[u8]) ``` Appends `bytes` to the filled part. **Panics** When they do not fit in [`remaining`](https://nuclei.rs/api/nuclei/io/struct.ReadBuf.html#method.remaining). ```rust pub unsafe fn unfilled_mut(&mut self) -> &mut [MaybeUninit] ``` The unfilled part, as memory that may be uninitialized. **Safety** The caller must not write uninitialized bytes into it: the part known to be initialized must stay initialized. #### Trait Implementations - `impl Debug for ReadBuf<'_>` #### Auto Trait Implementations - `impl<'a> !UnwindSafe for ReadBuf<'a>` - `impl<'a> Freeze for ReadBuf<'a>` - `impl<'a> RefUnwindSafe for ReadBuf<'a>` - `impl<'a> Send for ReadBuf<'a>` - `impl<'a> Sync for ReadBuf<'a>` - `impl<'a> Unpin for ReadBuf<'a>` - `impl<'a> UnsafeUnpin for ReadBuf<'a>` ### struct `nuclei::io::ReadBufFuture` https://nuclei.rs/api/nuclei/io/struct.ReadBufFuture.html ```rust pub struct ReadBufFuture<'a, 'b, R: ?Sized> { /* private fields */ } ``` The future of [`read_buf`](https://nuclei.rs/api/nuclei/io/trait.AsyncReadExt.html#method.read_buf). #### Trait Implementations - `impl<'a, 'b, R: Debug + ?Sized> Debug for ReadBufFuture<'a, 'b, R>` - `impl Future for ReadBufFuture<'_, '_, R>` #### Auto Trait Implementations - `impl<'a, 'b, R> !UnwindSafe for ReadBufFuture<'a, 'b, R>` - `impl<'a, 'b, R> Freeze for ReadBufFuture<'a, 'b, R> where R: ?Sized` - `impl<'a, 'b, R> RefUnwindSafe for ReadBufFuture<'a, 'b, R> where R: RefUnwindSafe + ?Sized` - `impl<'a, 'b, R> Send for ReadBufFuture<'a, 'b, R> where R: Send + ?Sized` - `impl<'a, 'b, R> Sync for ReadBufFuture<'a, 'b, R> where R: Sync + ?Sized` - `impl<'a, 'b, R> Unpin for ReadBufFuture<'a, 'b, R> where R: ?Sized` - `impl<'a, 'b, R> UnsafeUnpin for ReadBufFuture<'a, 'b, R> where R: ?Sized` ### struct `nuclei::io::ReadExact` https://nuclei.rs/api/nuclei/io/struct.ReadExact.html ```rust pub struct ReadExact<'a, R: ?Sized> { /* private fields */ } ``` The future of [`read_exact`](https://nuclei.rs/api/nuclei/io/trait.AsyncReadExt.html#method.read_exact). #### Trait Implementations - `impl<'a, R: Debug + ?Sized> Debug for ReadExact<'a, R>` - `impl Future for ReadExact<'_, R>` #### Auto Trait Implementations - `impl<'a, R> !UnwindSafe for ReadExact<'a, R>` - `impl<'a, R> Freeze for ReadExact<'a, R> where R: ?Sized` - `impl<'a, R> RefUnwindSafe for ReadExact<'a, R> where R: RefUnwindSafe + ?Sized` - `impl<'a, R> Send for ReadExact<'a, R> where R: Send + ?Sized` - `impl<'a, R> Sync for ReadExact<'a, R> where R: Sync + ?Sized` - `impl<'a, R> Unpin for ReadExact<'a, R> where R: ?Sized` - `impl<'a, R> UnsafeUnpin for ReadExact<'a, R> where R: ?Sized` ### struct `nuclei::io::ReadHalf` https://nuclei.rs/api/nuclei/io/struct.ReadHalf.html ```rust pub struct ReadHalf { /* private fields */ } ``` The read half of a stream [`split`](https://nuclei.rs/api/nuclei/io/fn.split.html) in two. #### Implementations `impl ReadHalf` ```rust pub fn is_pair_of(&self, other: &WriteHalf) -> bool ``` Whether `other` is this half’s write half. ```rust pub fn unsplit(self, write: WriteHalf) -> T where T: Unpin ``` The stream, back from its two halves. **Panics** When `write` is not this half’s write half. #### Trait Implementations - `impl AsyncRead for ReadHalf` - `impl Debug for ReadHalf` #### Auto Trait Implementations - `impl !RefUnwindSafe for ReadHalf` - `impl !UnwindSafe for ReadHalf` - `impl Freeze for ReadHalf` - `impl Send for ReadHalf where T: Send` - `impl Sync for ReadHalf where T: Send` - `impl Unpin for ReadHalf` - `impl UnsafeUnpin for ReadHalf` ### struct `nuclei::io::ReadLine` https://nuclei.rs/api/nuclei/io/struct.ReadLine.html ```rust pub struct ReadLine<'a, R: ?Sized> { /* private fields */ } ``` The future of [`read_line`](https://nuclei.rs/api/nuclei/io/trait.AsyncBufReadExt.html#method.read_line). #### Trait Implementations - `impl<'a, R: Debug + ?Sized> Debug for ReadLine<'a, R>` - `impl Future for ReadLine<'_, R>` #### Auto Trait Implementations - `impl<'a, R> !UnwindSafe for ReadLine<'a, R>` - `impl<'a, R> Freeze for ReadLine<'a, R> where R: ?Sized` - `impl<'a, R> RefUnwindSafe for ReadLine<'a, R> where R: RefUnwindSafe + ?Sized` - `impl<'a, R> Send for ReadLine<'a, R> where R: Send + ?Sized` - `impl<'a, R> Sync for ReadLine<'a, R> where R: Sync + ?Sized` - `impl<'a, R> Unpin for ReadLine<'a, R> where R: ?Sized` - `impl<'a, R> UnsafeUnpin for ReadLine<'a, R> where R: ?Sized` ### struct `nuclei::io::ReadNumber` https://nuclei.rs/api/nuclei/io/struct.ReadNumber.html ```rust pub struct ReadNumber<'a, R: ?Sized, T, const N: usize> { /* private fields */ } ``` The future of a typed read ([`read_u32`](https://nuclei.rs/api/nuclei/io/trait.AsyncReadExt.html#method.read_u32) and the like). #### Trait Implementations - `impl Debug for ReadNumber<'_, R, T, N>` - `impl Future for ReadNumber<'_, R, T, N>` #### Auto Trait Implementations - `impl<'a, R, T, const N: usize> !UnwindSafe for ReadNumber<'a, R, T, N>` - `impl<'a, R, T, const N: usize> Freeze for ReadNumber<'a, R, T, N> where R: ?Sized` - `impl<'a, R, T, const N: usize> RefUnwindSafe for ReadNumber<'a, R, T, N> where R: RefUnwindSafe + ?Sized` - `impl<'a, R, T, const N: usize> Send for ReadNumber<'a, R, T, N> where R: Send + ?Sized` - `impl<'a, R, T, const N: usize> Sync for ReadNumber<'a, R, T, N> where R: Sync + ?Sized` - `impl<'a, R, T, const N: usize> Unpin for ReadNumber<'a, R, T, N> where R: ?Sized` - `impl<'a, R, T, const N: usize> UnsafeUnpin for ReadNumber<'a, R, T, N> where R: ?Sized` ### struct `nuclei::io::ReadToEnd` https://nuclei.rs/api/nuclei/io/struct.ReadToEnd.html ```rust pub struct ReadToEnd<'a, R: ?Sized> { /* private fields */ } ``` The future of [`read_to_end`](https://nuclei.rs/api/nuclei/io/trait.AsyncReadExt.html#method.read_to_end). #### Trait Implementations - `impl<'a, R: Debug + ?Sized> Debug for ReadToEnd<'a, R>` - `impl Future for ReadToEnd<'_, R>` #### Auto Trait Implementations - `impl<'a, R> !UnwindSafe for ReadToEnd<'a, R>` - `impl<'a, R> Freeze for ReadToEnd<'a, R> where R: ?Sized` - `impl<'a, R> RefUnwindSafe for ReadToEnd<'a, R> where R: RefUnwindSafe + ?Sized` - `impl<'a, R> Send for ReadToEnd<'a, R> where R: Send + ?Sized` - `impl<'a, R> Sync for ReadToEnd<'a, R> where R: Sync + ?Sized` - `impl<'a, R> Unpin for ReadToEnd<'a, R> where R: ?Sized` - `impl<'a, R> UnsafeUnpin for ReadToEnd<'a, R> where R: ?Sized` ### struct `nuclei::io::ReadToString` https://nuclei.rs/api/nuclei/io/struct.ReadToString.html ```rust pub struct ReadToString<'a, R: ?Sized> { /* private fields */ } ``` The future of [`read_to_string`](https://nuclei.rs/api/nuclei/io/trait.AsyncReadExt.html#method.read_to_string). #### Trait Implementations - `impl<'a, R: Debug + ?Sized> Debug for ReadToString<'a, R>` - `impl Future for ReadToString<'_, R>` #### Auto Trait Implementations - `impl<'a, R> !UnwindSafe for ReadToString<'a, R>` - `impl<'a, R> Freeze for ReadToString<'a, R> where R: ?Sized` - `impl<'a, R> RefUnwindSafe for ReadToString<'a, R> where R: RefUnwindSafe + ?Sized` - `impl<'a, R> Send for ReadToString<'a, R> where R: Send + ?Sized` - `impl<'a, R> Sync for ReadToString<'a, R> where R: Sync + ?Sized` - `impl<'a, R> Unpin for ReadToString<'a, R> where R: ?Sized` - `impl<'a, R> UnsafeUnpin for ReadToString<'a, R> where R: ?Sized` ### struct `nuclei::io::ReadUntil` https://nuclei.rs/api/nuclei/io/struct.ReadUntil.html ```rust pub struct ReadUntil<'a, R: ?Sized> { /* private fields */ } ``` The future of [`read_until`](https://nuclei.rs/api/nuclei/io/trait.AsyncBufReadExt.html#method.read_until). #### Trait Implementations - `impl<'a, R: Debug + ?Sized> Debug for ReadUntil<'a, R>` - `impl Future for ReadUntil<'_, R>` #### Auto Trait Implementations - `impl<'a, R> !UnwindSafe for ReadUntil<'a, R>` - `impl<'a, R> Freeze for ReadUntil<'a, R> where R: ?Sized` - `impl<'a, R> RefUnwindSafe for ReadUntil<'a, R> where R: RefUnwindSafe + ?Sized` - `impl<'a, R> Send for ReadUntil<'a, R> where R: Send + ?Sized` - `impl<'a, R> Sync for ReadUntil<'a, R> where R: Sync + ?Sized` - `impl<'a, R> Unpin for ReadUntil<'a, R> where R: ?Sized` - `impl<'a, R> UnsafeUnpin for ReadUntil<'a, R> where R: ?Sized` ### struct `nuclei::io::Ready` https://nuclei.rs/api/nuclei/io/struct.Ready.html ```rust pub struct Ready(/* private fields */); ``` What a readiness call found. #### Implementations `impl Ready` ```rust pub const EMPTY: Ready ``` Nothing is ready. ```rust pub const READABLE: Ready ``` A read would end at once. ```rust pub const WRITABLE: Ready ``` A write would be taken at once. ```rust pub const READ_CLOSED: Ready ``` The stream ended: reads answer zero from now on. ```rust pub const WRITE_CLOSED: Ready ``` Writing failed: writes answer the error from now on. ```rust pub fn is_empty(self) -> bool ``` ```rust pub fn is_readable(self) -> bool ``` ```rust pub fn is_writable(self) -> bool ``` ```rust pub fn is_read_closed(self) -> bool ``` ```rust pub fn is_write_closed(self) -> bool ``` #### Trait Implementations - `impl BitOr for Ready` - `impl Clone for Ready` - `impl Copy for Ready` - `impl Debug for Ready` - `impl Default for Ready` - `impl Eq for Ready` - `impl PartialEq for Ready` - `impl StructuralPartialEq for Ready` #### Auto Trait Implementations - `impl Freeze for Ready` - `impl RefUnwindSafe for Ready` - `impl Send for Ready` - `impl Sync for Ready` - `impl Unpin for Ready` - `impl UnsafeUnpin for Ready` - `impl UnwindSafe for Ready` ### struct `nuclei::io::Repeat` https://nuclei.rs/api/nuclei/io/struct.Repeat.html ```rust pub struct Repeat { /* private fields */ } ``` A reader that gives one byte over and over, without end. Made by [`repeat`](https://nuclei.rs/api/nuclei/io/fn.repeat.html). #### Trait Implementations - `impl AsyncRead for Repeat` - `impl Clone for Repeat` - `impl Copy for Repeat` - `impl Debug for Repeat` #### Auto Trait Implementations - `impl Freeze for Repeat` - `impl RefUnwindSafe for Repeat` - `impl Send for Repeat` - `impl Sync for Repeat` - `impl Unpin for Repeat` - `impl UnsafeUnpin for Repeat` - `impl UnwindSafe for Repeat` ### struct `nuclei::io::Seek` https://nuclei.rs/api/nuclei/io/struct.Seek.html ```rust pub struct Seek<'a, S: ?Sized> { /* private fields */ } ``` The future of [`seek`](https://nuclei.rs/api/nuclei/io/trait.AsyncSeekExt.html#method.seek) and the seeks built on it. #### Trait Implementations - `impl<'a, S: Debug + ?Sized> Debug for Seek<'a, S>` - `impl Future for Seek<'_, S>` #### Auto Trait Implementations - `impl<'a, S> !UnwindSafe for Seek<'a, S>` - `impl<'a, S> Freeze for Seek<'a, S> where S: ?Sized` - `impl<'a, S> RefUnwindSafe for Seek<'a, S> where S: RefUnwindSafe + ?Sized` - `impl<'a, S> Send for Seek<'a, S> where S: Send + ?Sized` - `impl<'a, S> Sync for Seek<'a, S> where S: Sync + ?Sized` - `impl<'a, S> Unpin for Seek<'a, S> where S: ?Sized` - `impl<'a, S> UnsafeUnpin for Seek<'a, S> where S: ?Sized` ### struct `nuclei::io::Shutdown` https://nuclei.rs/api/nuclei/io/struct.Shutdown.html ```rust pub struct Shutdown<'a, W: ?Sized> { /* private fields */ } ``` The future of [`shutdown`](https://nuclei.rs/api/nuclei/io/trait.AsyncWriteExt.html#method.shutdown). #### Trait Implementations - `impl<'a, W: Debug + ?Sized> Debug for Shutdown<'a, W>` - `impl Future for Shutdown<'_, W>` #### Auto Trait Implementations - `impl<'a, W> !UnwindSafe for Shutdown<'a, W>` - `impl<'a, W> Freeze for Shutdown<'a, W> where W: ?Sized` - `impl<'a, W> RefUnwindSafe for Shutdown<'a, W> where W: RefUnwindSafe + ?Sized` - `impl<'a, W> Send for Shutdown<'a, W> where W: Send + ?Sized` - `impl<'a, W> Sync for Shutdown<'a, W> where W: Sync + ?Sized` - `impl<'a, W> Unpin for Shutdown<'a, W> where W: ?Sized` - `impl<'a, W> UnsafeUnpin for Shutdown<'a, W> where W: ?Sized` ### struct `nuclei::io::SimplexReader` https://nuclei.rs/api/nuclei/io/struct.SimplexReader.html ```rust pub struct SimplexReader { /* private fields */ } ``` The reading end of a [`simplex`](https://nuclei.rs/api/nuclei/io/fn.simplex.html) pipe. Dropping it fails the writer’s next write. #### Trait Implementations - `impl AsyncRead for SimplexReader` - `impl Debug for SimplexReader` - `impl Drop for SimplexReader` #### Auto Trait Implementations - `impl !RefUnwindSafe for SimplexReader` - `impl !UnwindSafe for SimplexReader` - `impl Freeze for SimplexReader` - `impl Send for SimplexReader` - `impl Sync for SimplexReader` - `impl Unpin for SimplexReader` - `impl UnsafeUnpin for SimplexReader` ### struct `nuclei::io::SimplexWriter` https://nuclei.rs/api/nuclei/io/struct.SimplexWriter.html ```rust pub struct SimplexWriter { /* private fields */ } ``` The writing end of a [`simplex`](https://nuclei.rs/api/nuclei/io/fn.simplex.html) pipe. Dropping it (or closing it) ends the reader’s reads after what is left. #### Trait Implementations - `impl AsyncWrite for SimplexWriter` - `impl Debug for SimplexWriter` - `impl Drop for SimplexWriter` #### Auto Trait Implementations - `impl !RefUnwindSafe for SimplexWriter` - `impl !UnwindSafe for SimplexWriter` - `impl Freeze for SimplexWriter` - `impl Send for SimplexWriter` - `impl Sync for SimplexWriter` - `impl Unpin for SimplexWriter` - `impl UnsafeUnpin for SimplexWriter` ### struct `nuclei::io::Sink` https://nuclei.rs/api/nuclei/io/struct.Sink.html ```rust pub struct Sink { /* private fields */ } ``` A writer that takes every byte and keeps none. Made by [`sink`](https://nuclei.rs/api/nuclei/io/fn.sink.html). #### Trait Implementations - `impl AsyncWrite for Sink` - `impl Clone for Sink` - `impl Copy for Sink` - `impl Debug for Sink` - `impl Default for Sink` #### Auto Trait Implementations - `impl Freeze for Sink` - `impl RefUnwindSafe for Sink` - `impl Send for Sink` - `impl Sync for Sink` - `impl Unpin for Sink` - `impl UnsafeUnpin for Sink` - `impl UnwindSafe for Sink` ### struct `nuclei::io::Split` https://nuclei.rs/api/nuclei/io/struct.Split.html ```rust pub struct Split { /* private fields */ } ``` The segments of a buffered reader between a byte; made by [`split`](https://nuclei.rs/api/nuclei/io/trait.AsyncBufReadExt.html#method.split). #### Implementations `impl Split` ```rust pub async fn next_segment(&mut self) -> Result>> ``` The next segment without its delimiter, `None` at the end. ```rust pub fn poll_next_segment( &mut self, cx: &mut Context<'_>, ) -> Poll>>> ``` Polls for the next segment. ```rust pub fn into_inner(self) -> R ``` The reader, taken back. #### Trait Implementations - `impl Debug for Split` #### Auto Trait Implementations - `impl Freeze for Split where R: Freeze` - `impl RefUnwindSafe for Split where R: RefUnwindSafe` - `impl Send for Split where R: Send` - `impl Sync for Split where R: Sync` - `impl Unpin for Split where R: Unpin` - `impl UnsafeUnpin for Split where R: UnsafeUnpin` - `impl UnwindSafe for Split where R: UnwindSafe` ### struct `nuclei::io::Stderr` https://nuclei.rs/api/nuclei/io/struct.Stderr.html ```rust pub struct Stderr { /* private fields */ } ``` The process’s standard error: writes run on the blocking pool, one at a time. #### Trait Implementations - `impl AsyncWrite for Stderr` - `impl Debug for Stderr` #### Auto Trait Implementations - `impl Freeze for Stderr` - `impl RefUnwindSafe for Stderr` - `impl Send for Stderr` - `impl Sync for Stderr` - `impl Unpin for Stderr` - `impl UnsafeUnpin for Stderr` - `impl UnwindSafe for Stderr` ### struct `nuclei::io::Stdin` https://nuclei.rs/api/nuclei/io/struct.Stdin.html ```rust pub struct Stdin { /* private fields */ } ``` The process’s standard input: reads run on the blocking pool. #### Trait Implementations - `impl AsyncRead for Stdin` - `impl Debug for Stdin` #### Auto Trait Implementations - `impl Freeze for Stdin` - `impl RefUnwindSafe for Stdin` - `impl Send for Stdin` - `impl Sync for Stdin` - `impl Unpin for Stdin` - `impl UnsafeUnpin for Stdin` - `impl UnwindSafe for Stdin` ### struct `nuclei::io::Stdout` https://nuclei.rs/api/nuclei/io/struct.Stdout.html ```rust pub struct Stdout { /* private fields */ } ``` The process’s standard output: writes run on the blocking pool, one at a time; flush before the process exits to see the last one done. #### Trait Implementations - `impl AsyncWrite for Stdout` - `impl Debug for Stdout` #### Auto Trait Implementations - `impl Freeze for Stdout` - `impl RefUnwindSafe for Stdout` - `impl Send for Stdout` - `impl Sync for Stdout` - `impl Unpin for Stdout` - `impl UnsafeUnpin for Stdout` - `impl UnwindSafe for Stdout` ### struct `nuclei::io::Take` https://nuclei.rs/api/nuclei/io/struct.Take.html ```rust pub struct Take { /* private fields */ } ``` A reader that ends after a number of bytes of another; made by [`take`](https://nuclei.rs/api/nuclei/io/trait.AsyncReadExt.html#method.take). #### Implementations `impl Take` ```rust pub fn limit(&self) -> u64 ``` The bytes left before it ends. ```rust pub fn set_limit(&mut self, limit: u64) ``` Sets the bytes left before it ends. ```rust pub fn get_ref(&self) -> &R ``` The reader it reads from. ```rust pub fn get_mut(&mut self) -> &mut R ``` The reader it reads from, to change. ```rust pub fn into_inner(self) -> R ``` The reader it reads from, taken back. #### Trait Implementations - `impl AsyncRead for Take` - `impl Debug for Take` #### Auto Trait Implementations - `impl Freeze for Take where R: Freeze` - `impl RefUnwindSafe for Take where R: RefUnwindSafe` - `impl Send for Take where R: Send` - `impl Sync for Take where R: Sync` - `impl Unpin for Take where R: Unpin` - `impl UnsafeUnpin for Take where R: UnsafeUnpin` - `impl UnwindSafe for Take where R: UnwindSafe` ### struct `nuclei::io::Write` https://nuclei.rs/api/nuclei/io/struct.Write.html ```rust pub struct Write<'a, W: ?Sized> { /* private fields */ } ``` The future of [`write`](https://nuclei.rs/api/nuclei/io/trait.AsyncWriteExt.html#method.write). #### Trait Implementations - `impl<'a, W: Debug + ?Sized> Debug for Write<'a, W>` - `impl Future for Write<'_, W>` #### Auto Trait Implementations - `impl<'a, W> !UnwindSafe for Write<'a, W>` - `impl<'a, W> Freeze for Write<'a, W> where W: ?Sized` - `impl<'a, W> RefUnwindSafe for Write<'a, W> where W: RefUnwindSafe + ?Sized` - `impl<'a, W> Send for Write<'a, W> where W: Send + ?Sized` - `impl<'a, W> Sync for Write<'a, W> where W: Sync + ?Sized` - `impl<'a, W> Unpin for Write<'a, W> where W: ?Sized` - `impl<'a, W> UnsafeUnpin for Write<'a, W> where W: ?Sized` ### struct `nuclei::io::WriteAll` https://nuclei.rs/api/nuclei/io/struct.WriteAll.html ```rust pub struct WriteAll<'a, W: ?Sized> { /* private fields */ } ``` The future of [`write_all`](https://nuclei.rs/api/nuclei/io/trait.AsyncWriteExt.html#method.write_all). #### Trait Implementations - `impl<'a, W: Debug + ?Sized> Debug for WriteAll<'a, W>` - `impl Future for WriteAll<'_, W>` #### Auto Trait Implementations - `impl<'a, W> !UnwindSafe for WriteAll<'a, W>` - `impl<'a, W> Freeze for WriteAll<'a, W> where W: ?Sized` - `impl<'a, W> RefUnwindSafe for WriteAll<'a, W> where W: RefUnwindSafe + ?Sized` - `impl<'a, W> Send for WriteAll<'a, W> where W: Send + ?Sized` - `impl<'a, W> Sync for WriteAll<'a, W> where W: Sync + ?Sized` - `impl<'a, W> Unpin for WriteAll<'a, W> where W: ?Sized` - `impl<'a, W> UnsafeUnpin for WriteAll<'a, W> where W: ?Sized` ### struct `nuclei::io::WriteHalf` https://nuclei.rs/api/nuclei/io/struct.WriteHalf.html ```rust pub struct WriteHalf { /* private fields */ } ``` The write half of a stream [`split`](https://nuclei.rs/api/nuclei/io/fn.split.html) in two. #### Implementations `impl WriteHalf` ```rust pub fn is_pair_of(&self, other: &ReadHalf) -> bool ``` Whether `other` is this half’s read half. #### Trait Implementations - `impl AsyncWrite for WriteHalf` - `impl Debug for WriteHalf` #### Auto Trait Implementations - `impl !RefUnwindSafe for WriteHalf` - `impl !UnwindSafe for WriteHalf` - `impl Freeze for WriteHalf` - `impl Send for WriteHalf where T: Send` - `impl Sync for WriteHalf where T: Send` - `impl Unpin for WriteHalf` - `impl UnsafeUnpin for WriteHalf` ### struct `nuclei::io::WriteNumber` https://nuclei.rs/api/nuclei/io/struct.WriteNumber.html ```rust pub struct WriteNumber<'a, W: ?Sized, const N: usize> { /* private fields */ } ``` The future of a typed write ([`write_u32`](https://nuclei.rs/api/nuclei/io/trait.AsyncWriteExt.html#method.write_u32) and the like). #### Trait Implementations - `impl<'a, W: Debug + ?Sized, const N: usize> Debug for WriteNumber<'a, W, N>` - `impl Future for WriteNumber<'_, W, N>` #### Auto Trait Implementations - `impl<'a, W, const N: usize> !UnwindSafe for WriteNumber<'a, W, N>` - `impl<'a, W, const N: usize> Freeze for WriteNumber<'a, W, N> where W: ?Sized` - `impl<'a, W, const N: usize> RefUnwindSafe for WriteNumber<'a, W, N> where W: RefUnwindSafe + ?Sized` - `impl<'a, W, const N: usize> Send for WriteNumber<'a, W, N> where W: Send + ?Sized` - `impl<'a, W, const N: usize> Sync for WriteNumber<'a, W, N> where W: Sync + ?Sized` - `impl<'a, W, const N: usize> Unpin for WriteNumber<'a, W, N> where W: ?Sized` - `impl<'a, W, const N: usize> UnsafeUnpin for WriteNumber<'a, W, N> where W: ?Sized` ### struct `nuclei::io::WriteVectored` https://nuclei.rs/api/nuclei/io/struct.WriteVectored.html ```rust pub struct WriteVectored<'a, 'b, W: ?Sized> { /* private fields */ } ``` The future of [`write_vectored`](https://nuclei.rs/api/nuclei/io/trait.AsyncWriteExt.html#method.write_vectored). #### Trait Implementations - `impl<'a, 'b, W: Debug + ?Sized> Debug for WriteVectored<'a, 'b, W>` - `impl Future for WriteVectored<'_, '_, W>` #### Auto Trait Implementations - `impl<'a, 'b, W> !UnwindSafe for WriteVectored<'a, 'b, W>` - `impl<'a, 'b, W> Freeze for WriteVectored<'a, 'b, W> where W: ?Sized` - `impl<'a, 'b, W> RefUnwindSafe for WriteVectored<'a, 'b, W> where W: RefUnwindSafe + ?Sized` - `impl<'a, 'b, W> Send for WriteVectored<'a, 'b, W> where W: Send + ?Sized` - `impl<'a, 'b, W> Sync for WriteVectored<'a, 'b, W> where W: Sync + ?Sized` - `impl<'a, 'b, W> Unpin for WriteVectored<'a, 'b, W> where W: ?Sized` - `impl<'a, 'b, W> UnsafeUnpin for WriteVectored<'a, 'b, W> where W: ?Sized` ### trait `nuclei::io::AsyncBufRead` https://nuclei.rs/api/nuclei/io/trait.AsyncBufRead.html ```rust pub trait AsyncBufRead: AsyncRead { // Required methods fn poll_fill_buf( self: Pin<&mut Self>, cx: &mut Context<'_>, ) -> Poll>; fn consume(self: Pin<&mut Self>, amt: usize); } ``` Read bytes asynchronously. This trait is analogous to the `std::io::BufRead` trait, but integrates with the asynchronous task system. In particular, the `poll_fill_buf` method, unlike `BufRead::fill_buf`, will automatically queue the current task for wakeup and return if data is not yet available, rather than blocking the calling thread. #### Required Methods ```rust fn poll_fill_buf( self: Pin<&mut Self>, cx: &mut Context<'_>, ) -> Poll> ``` Attempt to return the contents of the internal buffer, filling it with more data from the inner reader if it is empty. On success, returns `Poll::Ready(Ok(buf))`. If no data is available for reading, the method returns `Poll::Pending` and arranges for the current task (via `cx.waker().wake_by_ref()`) to receive a notification when the object becomes readable or is closed. This function is a lower-level call. It needs to be paired with the [`consume`](https://nuclei.rs/api/nuclei/io/trait.AsyncBufRead.html#tymethod.consume) method to function properly. When calling this method, none of the contents will be “read” in the sense that later calling [`poll_read`](https://nuclei.rs/api/nuclei/io/trait.AsyncRead.html#tymethod.poll_read) may return the same contents. As such, [`consume`](https://nuclei.rs/api/nuclei/io/trait.AsyncBufRead.html#tymethod.consume) must be called with the number of bytes that are consumed from this buffer to ensure that the bytes are never returned twice. An empty buffer returned indicates that the stream has reached EOF. **Implementation** This function may not return errors of kind `WouldBlock` or `Interrupted`. Implementations must convert `WouldBlock` into `Poll::Pending` and either internally retry or convert `Interrupted` into another error kind. ```rust fn consume(self: Pin<&mut Self>, amt: usize) ``` Tells this buffer that `amt` bytes have been consumed from the buffer, so they should no longer be returned in calls to [`poll_read`](https://nuclei.rs/api/nuclei/io/trait.AsyncRead.html#tymethod.poll_read). This function is a lower-level call. It needs to be paired with the [`poll_fill_buf`](https://nuclei.rs/api/nuclei/io/trait.AsyncBufRead.html#tymethod.poll_fill_buf) method to function properly. This function does not perform any I/O, it simply informs this object that some amount of its buffer, returned from [`poll_fill_buf`](https://nuclei.rs/api/nuclei/io/trait.AsyncBufRead.html#tymethod.poll_fill_buf), has been consumed and should no longer be returned. As such, this function may do odd things if [`poll_fill_buf`](https://nuclei.rs/api/nuclei/io/trait.AsyncBufRead.html#tymethod.poll_fill_buf) isn’t called before calling it. The `amt` must be `<=` the number of bytes in the buffer returned by [`poll_fill_buf`](https://nuclei.rs/api/nuclei/io/trait.AsyncBufRead.html#tymethod.poll_fill_buf). #### Dyn Compatibility This trait **is** [dyn compatible](https://doc.rust-lang.org/1.99.1/reference/items/traits.html#dyn-compatibility). *In older versions of Rust, dyn compatibility was called "object safety".* #### Implementations on Foreign Types `impl AsyncBufRead for &[u8]` ```rust fn poll_fill_buf( self: Pin<&mut &[u8]>, _: &mut Context<'_>, ) -> Poll> ``` ```rust fn consume(self: Pin<&mut &[u8]>, amt: usize) ``` `impl

AsyncBufRead for Pin

where P: DerefMut + Unpin,

::Target: AsyncBufRead` ```rust fn poll_fill_buf( self: Pin<&mut Pin

>, cx: &mut Context<'_>, ) -> Poll> ``` ```rust fn consume(self: Pin<&mut Pin

>, amt: usize) ``` `impl AsyncBufRead for &mut T where T: AsyncBufRead + Unpin + ?Sized` ```rust fn poll_fill_buf( self: Pin<&mut &mut T>, cx: &mut Context<'_>, ) -> Poll> ``` ```rust fn consume(self: Pin<&mut &mut T>, amt: usize) ``` `impl AsyncBufRead for Box where T: AsyncBufRead + Unpin + ?Sized` ```rust fn poll_fill_buf( self: Pin<&mut Box>, cx: &mut Context<'_>, ) -> Poll> ``` ```rust fn consume(self: Pin<&mut Box>, amt: usize) ``` #### Implementors - `impl AsyncBufRead for Empty` - `impl AsyncBufRead for Handle` - `impl AsyncBufRead for BufReader` - `impl AsyncBufRead for BufStream` - `impl AsyncBufRead for BufWriter` ### trait `nuclei::io::AsyncBufReadExt` https://nuclei.rs/api/nuclei/io/trait.AsyncBufReadExt.html ```rust pub trait AsyncBufReadExt: AsyncBufRead { // Provided methods fn read_until<'a>( &'a mut self, byte: u8, buf: &'a mut Vec, ) -> ReadUntil<'a, Self> where Self: Unpin { ... } fn read_line<'a>(&'a mut self, buf: &'a mut String) -> ReadLine<'a, Self> where Self: Unpin { ... } fn lines(self) -> Lines where Self: Sized { ... } fn split(self, byte: u8) -> Split where Self: Sized { ... } fn fill_buf(&mut self) -> FillBuf<'_, Self> where Self: Unpin { ... } fn consume(&mut self, amount: usize) where Self: Unpin { ... } } ``` Reads on any [`AsyncBufRead`](https://nuclei.rs/api/nuclei/io/trait.AsyncBufRead.html): up to a delimiter, a line, the lines or the segments one by one. #### Provided Methods ```rust fn read_until<'a>( &'a mut self, byte: u8, buf: &'a mut Vec, ) -> ReadUntil<'a, Self> where Self: Unpin ``` Reads up to and including `byte` (or to the end), appending to `buf`; answers how many bytes it appended (0 at the end). ```rust fn read_line<'a>(&'a mut self, buf: &'a mut String) -> ReadLine<'a, Self> where Self: Unpin ``` Reads up to and including a newline (or to the end), appending to `buf` if what it read is UTF-8 (an [`InvalidData`](https://doc.rust-lang.org/1.99.1/core/io/error/enum.ErrorKind.html#variant.InvalidData) error and `buf` as it was otherwise); answers how many bytes it appended (0 at the end). ```rust fn lines(self) -> Lines where Self: Sized ``` The lines, without their `\n` or `\r\n`, one by one through [`Lines::next_line`](https://nuclei.rs/api/nuclei/io/struct.Lines.html#method.next_line). ```rust fn split(self, byte: u8) -> Split where Self: Sized ``` The segments between `byte`s, without it, one by one through [`Split::next_segment`](https://nuclei.rs/api/nuclei/io/struct.Split.html#method.next_segment). ```rust fn fill_buf(&mut self) -> FillBuf<'_, Self> where Self: Unpin ``` The reader’s buffer, filled if it was empty (empty at the end). ```rust fn consume(&mut self, amount: usize) where Self: Unpin ``` Marks `amount` bytes of the buffer read. #### Dyn Compatibility This trait is **not** [dyn compatible](https://doc.rust-lang.org/1.99.1/reference/items/traits.html#dyn-compatibility). *In older versions of Rust, dyn compatibility was called "object safety".* #### Implementors - `impl AsyncBufReadExt for R` ### trait `nuclei::io::AsyncRead` https://nuclei.rs/api/nuclei/io/trait.AsyncRead.html ```rust pub trait AsyncRead { // Required method fn poll_read( self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8], ) -> Poll>; // Provided method fn poll_read_vectored( self: Pin<&mut Self>, cx: &mut Context<'_>, bufs: &mut [IoSliceMut<'_>], ) -> Poll> { ... } } ``` Read bytes asynchronously. This trait is analogous to the `std::io::Read` trait, but integrates with the asynchronous task system. In particular, the `poll_read` method, unlike `Read::read`, will automatically queue the current task for wakeup and return if data is not yet available, rather than blocking the calling thread. #### Required Methods ```rust fn poll_read( self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8], ) -> Poll> ``` Attempt to read from the `AsyncRead` into `buf`. On success, returns `Poll::Ready(Ok(num_bytes_read))`. If no data is available for reading, the method returns `Poll::Pending` and arranges for the current task (via `cx.waker().wake_by_ref()`) to receive a notification when the object becomes readable or is closed. **Implementation** This function may not return errors of kind `WouldBlock` or `Interrupted`. Implementations must convert `WouldBlock` into `Poll::Pending` and either internally retry or convert `Interrupted` into another error kind. #### Provided Methods ```rust fn poll_read_vectored( self: Pin<&mut Self>, cx: &mut Context<'_>, bufs: &mut [IoSliceMut<'_>], ) -> Poll> ``` Attempt to read from the `AsyncRead` into `bufs` using vectored IO operations. This method is similar to `poll_read`, but allows data to be read into multiple buffers using a single operation. On success, returns `Poll::Ready(Ok(num_bytes_read))`. If no data is available for reading, the method returns `Poll::Pending` and arranges for the current task (via `cx.waker().wake_by_ref()`) to receive a notification when the object becomes readable or is closed. By default, this method delegates to using `poll_read` on the first nonempty buffer in `bufs`, or an empty one if none exists. Objects which support vectored IO should override this method. **Implementation** This function may not return errors of kind `WouldBlock` or `Interrupted`. Implementations must convert `WouldBlock` into `Poll::Pending` and either internally retry or convert `Interrupted` into another error kind. #### Dyn Compatibility This trait **is** [dyn compatible](https://doc.rust-lang.org/1.99.1/reference/items/traits.html#dyn-compatibility). *In older versions of Rust, dyn compatibility was called "object safety".* #### Implementations on Foreign Types `impl AsyncRead for &[u8]` ```rust fn poll_read( self: Pin<&mut &[u8]>, _: &mut Context<'_>, buf: &mut [u8], ) -> Poll> ``` ```rust fn poll_read_vectored( self: Pin<&mut &[u8]>, _: &mut Context<'_>, bufs: &mut [IoSliceMut<'_>], ) -> Poll> ``` `impl

AsyncRead for Pin

where P: DerefMut + Unpin,

::Target: AsyncRead` ```rust fn poll_read( self: Pin<&mut Pin

>, cx: &mut Context<'_>, buf: &mut [u8], ) -> Poll> ``` ```rust fn poll_read_vectored( self: Pin<&mut Pin

>, cx: &mut Context<'_>, bufs: &mut [IoSliceMut<'_>], ) -> Poll> ``` `impl AsyncRead for &mut T where T: AsyncRead + Unpin + ?Sized` ```rust fn poll_read( self: Pin<&mut &mut T>, cx: &mut Context<'_>, buf: &mut [u8], ) -> Poll> ``` ```rust fn poll_read_vectored( self: Pin<&mut &mut T>, cx: &mut Context<'_>, bufs: &mut [IoSliceMut<'_>], ) -> Poll> ``` `impl AsyncRead for Box where T: AsyncRead + Unpin + ?Sized` ```rust fn poll_read( self: Pin<&mut Box>, cx: &mut Context<'_>, buf: &mut [u8], ) -> Poll> ``` ```rust fn poll_read_vectored( self: Pin<&mut Box>, cx: &mut Context<'_>, bufs: &mut [IoSliceMut<'_>], ) -> Poll> ``` #### Implementors - `impl AsyncRead for &Handle` - `impl AsyncRead for &Handle` - `impl AsyncRead for &Handle` - `impl AsyncRead for &Handle` - `impl AsyncRead for ChildStderr` - `impl AsyncRead for ChildStdout` - `impl AsyncRead for DuplexStream` - `impl AsyncRead for Empty` - `impl AsyncRead for Handle` - `impl AsyncRead for Handle` - `impl AsyncRead for Handle` - `impl AsyncRead for Handle` - `impl AsyncRead for Repeat` - `impl AsyncRead for SimplexReader` - `impl AsyncRead for Stdin` - `impl<'a, S> AsyncRead for nuclei::net::ReadHalf<'a, S> where for<'x> &'x Handle: AsyncRead` - `impl AsyncRead for Chain` - `impl AsyncRead for BufReader` - `impl AsyncRead for Take` - `impl AsyncRead for BufStream` - `impl AsyncRead for OwnedReadHalf where for<'x> &'x Handle: AsyncRead` - `impl AsyncRead for nuclei::io::ReadHalf` - `impl AsyncRead for BufWriter` ### trait `nuclei::io::AsyncReadExt` https://nuclei.rs/api/nuclei/io/trait.AsyncReadExt.html ```rust pub trait AsyncReadExt: AsyncRead { // Provided methods fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Read<'a, Self> where Self: Unpin { ... } fn read_buf<'a, 'b>( &'a mut self, buf: &'a mut ReadBuf<'b>, ) -> ReadBufFuture<'a, 'b, Self> where Self: Unpin { ... } fn read_exact<'a>(&'a mut self, buf: &'a mut [u8]) -> ReadExact<'a, Self> where Self: Unpin { ... } fn read_to_end<'a>( &'a mut self, buf: &'a mut Vec, ) -> ReadToEnd<'a, Self> where Self: Unpin { ... } fn read_to_string<'a>( &'a mut self, buf: &'a mut String, ) -> ReadToString<'a, Self> where Self: Unpin { ... } fn take(self, limit: u64) -> Take where Self: Sized { ... } fn chain(self, next: R) -> Chain where Self: Sized { ... } fn read_u8(&mut self) -> ReadNumber<'_, Self, u8, 1> where Self: Unpin { ... } fn read_i8(&mut self) -> ReadNumber<'_, Self, i8, 1> where Self: Unpin { ... } fn read_u16(&mut self) -> ReadNumber<'_, Self, u16, 2> where Self: Unpin { ... } fn read_u16_le(&mut self) -> ReadNumber<'_, Self, u16, 2> where Self: Unpin { ... } fn read_i16(&mut self) -> ReadNumber<'_, Self, i16, 2> where Self: Unpin { ... } fn read_i16_le(&mut self) -> ReadNumber<'_, Self, i16, 2> where Self: Unpin { ... } fn read_u32(&mut self) -> ReadNumber<'_, Self, u32, 4> where Self: Unpin { ... } fn read_u32_le(&mut self) -> ReadNumber<'_, Self, u32, 4> where Self: Unpin { ... } fn read_i32(&mut self) -> ReadNumber<'_, Self, i32, 4> where Self: Unpin { ... } fn read_i32_le(&mut self) -> ReadNumber<'_, Self, i32, 4> where Self: Unpin { ... } fn read_u64(&mut self) -> ReadNumber<'_, Self, u64, 8> where Self: Unpin { ... } fn read_u64_le(&mut self) -> ReadNumber<'_, Self, u64, 8> where Self: Unpin { ... } fn read_i64(&mut self) -> ReadNumber<'_, Self, i64, 8> where Self: Unpin { ... } fn read_i64_le(&mut self) -> ReadNumber<'_, Self, i64, 8> where Self: Unpin { ... } fn read_u128(&mut self) -> ReadNumber<'_, Self, u128, 16> where Self: Unpin { ... } fn read_u128_le(&mut self) -> ReadNumber<'_, Self, u128, 16> where Self: Unpin { ... } fn read_i128(&mut self) -> ReadNumber<'_, Self, i128, 16> where Self: Unpin { ... } fn read_i128_le(&mut self) -> ReadNumber<'_, Self, i128, 16> where Self: Unpin { ... } fn read_f32(&mut self) -> ReadNumber<'_, Self, f32, 4> where Self: Unpin { ... } fn read_f32_le(&mut self) -> ReadNumber<'_, Self, f32, 4> where Self: Unpin { ... } fn read_f64(&mut self) -> ReadNumber<'_, Self, f64, 8> where Self: Unpin { ... } fn read_f64_le(&mut self) -> ReadNumber<'_, Self, f64, 8> where Self: Unpin { ... } } ``` Reads on any [`AsyncRead`](https://nuclei.rs/api/nuclei/io/trait.AsyncRead.html): into a slice, a [`ReadBuf`](https://nuclei.rs/api/nuclei/io/struct.ReadBuf.html), to the end, as typed numbers in big or little endian. #### Provided Methods ```rust fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Read<'a, Self> where Self: Unpin ``` Reads some bytes into `buf`, answering how many (0 at the end). ```rust fn read_buf<'a, 'b>( &'a mut self, buf: &'a mut ReadBuf<'b>, ) -> ReadBufFuture<'a, 'b, Self> where Self: Unpin ``` Reads some bytes into the unfilled part of `buf` and counts them filled, answering how many (0 at the end, or when `buf` is full). ```rust fn read_exact<'a>(&'a mut self, buf: &'a mut [u8]) -> ReadExact<'a, Self> where Self: Unpin ``` Fills `buf` exactly, answering its length; an end of the stream first is an [`UnexpectedEof`](https://doc.rust-lang.org/1.99.1/core/io/error/enum.ErrorKind.html#variant.UnexpectedEof) error. ```rust fn read_to_end<'a>(&'a mut self, buf: &'a mut Vec) -> ReadToEnd<'a, Self> where Self: Unpin ``` Reads to the end of the stream, appending to `buf`; answers how many bytes it appended. ```rust fn read_to_string<'a>( &'a mut self, buf: &'a mut String, ) -> ReadToString<'a, Self> where Self: Unpin ``` Reads to the end of the stream, appending to `buf` if what it read is UTF-8 (an [`InvalidData`](https://doc.rust-lang.org/1.99.1/core/io/error/enum.ErrorKind.html#variant.InvalidData) error and `buf` as it was otherwise); answers how many bytes it appended. ```rust fn take(self, limit: u64) -> Take where Self: Sized ``` A reader that ends after `limit` bytes of this one. ```rust fn chain(self, next: R) -> Chain where Self: Sized ``` A reader that reads this one to its end, then `next`. ```rust fn read_u8(&mut self) -> ReadNumber<'_, Self, u8, 1> where Self: Unpin ``` Reads an unsigned byte (1 bytes, exactly). ```rust fn read_i8(&mut self) -> ReadNumber<'_, Self, i8, 1> where Self: Unpin ``` Reads a signed byte (1 bytes, exactly). ```rust fn read_u16(&mut self) -> ReadNumber<'_, Self, u16, 2> where Self: Unpin ``` Reads a big-endian `u16` (2 bytes, exactly). ```rust fn read_u16_le(&mut self) -> ReadNumber<'_, Self, u16, 2> where Self: Unpin ``` Reads a little-endian `u16` (2 bytes, exactly). ```rust fn read_i16(&mut self) -> ReadNumber<'_, Self, i16, 2> where Self: Unpin ``` Reads a big-endian `i16` (2 bytes, exactly). ```rust fn read_i16_le(&mut self) -> ReadNumber<'_, Self, i16, 2> where Self: Unpin ``` Reads a little-endian `i16` (2 bytes, exactly). ```rust fn read_u32(&mut self) -> ReadNumber<'_, Self, u32, 4> where Self: Unpin ``` Reads a big-endian `u32` (4 bytes, exactly). ```rust fn read_u32_le(&mut self) -> ReadNumber<'_, Self, u32, 4> where Self: Unpin ``` Reads a little-endian `u32` (4 bytes, exactly). ```rust fn read_i32(&mut self) -> ReadNumber<'_, Self, i32, 4> where Self: Unpin ``` Reads a big-endian `i32` (4 bytes, exactly). ```rust fn read_i32_le(&mut self) -> ReadNumber<'_, Self, i32, 4> where Self: Unpin ``` Reads a little-endian `i32` (4 bytes, exactly). ```rust fn read_u64(&mut self) -> ReadNumber<'_, Self, u64, 8> where Self: Unpin ``` Reads a big-endian `u64` (8 bytes, exactly). ```rust fn read_u64_le(&mut self) -> ReadNumber<'_, Self, u64, 8> where Self: Unpin ``` Reads a little-endian `u64` (8 bytes, exactly). ```rust fn read_i64(&mut self) -> ReadNumber<'_, Self, i64, 8> where Self: Unpin ``` Reads a big-endian `i64` (8 bytes, exactly). ```rust fn read_i64_le(&mut self) -> ReadNumber<'_, Self, i64, 8> where Self: Unpin ``` Reads a little-endian `i64` (8 bytes, exactly). ```rust fn read_u128(&mut self) -> ReadNumber<'_, Self, u128, 16> where Self: Unpin ``` Reads a big-endian `u128` (16 bytes, exactly). ```rust fn read_u128_le(&mut self) -> ReadNumber<'_, Self, u128, 16> where Self: Unpin ``` Reads a little-endian `u128` (16 bytes, exactly). ```rust fn read_i128(&mut self) -> ReadNumber<'_, Self, i128, 16> where Self: Unpin ``` Reads a big-endian `i128` (16 bytes, exactly). ```rust fn read_i128_le(&mut self) -> ReadNumber<'_, Self, i128, 16> where Self: Unpin ``` Reads a little-endian `i128` (16 bytes, exactly). ```rust fn read_f32(&mut self) -> ReadNumber<'_, Self, f32, 4> where Self: Unpin ``` Reads a big-endian `f32` (4 bytes, exactly). ```rust fn read_f32_le(&mut self) -> ReadNumber<'_, Self, f32, 4> where Self: Unpin ``` Reads a little-endian `f32` (4 bytes, exactly). ```rust fn read_f64(&mut self) -> ReadNumber<'_, Self, f64, 8> where Self: Unpin ``` Reads a big-endian `f64` (8 bytes, exactly). ```rust fn read_f64_le(&mut self) -> ReadNumber<'_, Self, f64, 8> where Self: Unpin ``` Reads a little-endian `f64` (8 bytes, exactly). #### Dyn Compatibility This trait is **not** [dyn compatible](https://doc.rust-lang.org/1.99.1/reference/items/traits.html#dyn-compatibility). *In older versions of Rust, dyn compatibility was called "object safety".* #### Implementors - `impl AsyncReadExt for R` ### trait `nuclei::io::AsyncSeek` https://nuclei.rs/api/nuclei/io/trait.AsyncSeek.html ```rust pub trait AsyncSeek { // Required method fn poll_seek( self: Pin<&mut Self>, cx: &mut Context<'_>, pos: SeekFrom, ) -> Poll>; } ``` Seek bytes asynchronously. This trait is analogous to the `std::io::Seek` trait, but integrates with the asynchronous task system. In particular, the `poll_seek` method, unlike `Seek::seek`, will automatically queue the current task for wakeup and return if data is not yet available, rather than blocking the calling thread. #### Required Methods ```rust fn poll_seek( self: Pin<&mut Self>, cx: &mut Context<'_>, pos: SeekFrom, ) -> Poll> ``` Attempt to seek to an offset, in bytes, in a stream. A seek beyond the end of a stream is allowed, but behavior is defined by the implementation. If the seek operation completed successfully, this method returns the new position from the start of the stream. That position can be used later with [`SeekFrom::Start`](https://doc.rust-lang.org/1.99.1/core/io/seek/enum.SeekFrom.html#variant.Start). **Errors** Seeking to a negative offset is considered an error. **Implementation** This function may not return errors of kind `WouldBlock` or `Interrupted`. Implementations must convert `WouldBlock` into `Poll::Pending` and either internally retry or convert `Interrupted` into another error kind. #### Dyn Compatibility This trait **is** [dyn compatible](https://doc.rust-lang.org/1.99.1/reference/items/traits.html#dyn-compatibility). *In older versions of Rust, dyn compatibility was called "object safety".* #### Implementations on Foreign Types `impl

AsyncSeek for Pin

where P: DerefMut + Unpin,

::Target: AsyncSeek` ```rust fn poll_seek( self: Pin<&mut Pin

>, cx: &mut Context<'_>, pos: SeekFrom, ) -> Poll> ``` `impl AsyncSeek for &mut T where T: AsyncSeek + Unpin + ?Sized` ```rust fn poll_seek( self: Pin<&mut &mut T>, cx: &mut Context<'_>, pos: SeekFrom, ) -> Poll> ``` `impl AsyncSeek for Box where T: AsyncSeek + Unpin + ?Sized` ```rust fn poll_seek( self: Pin<&mut Box>, cx: &mut Context<'_>, pos: SeekFrom, ) -> Poll> ``` #### Implementors - `impl AsyncSeek for Handle` - `impl AsyncSeek for BufReader` - `impl AsyncSeek for BufWriter` ### trait `nuclei::io::AsyncSeekExt` https://nuclei.rs/api/nuclei/io/trait.AsyncSeekExt.html ```rust pub trait AsyncSeekExt: AsyncSeek { // Provided methods fn seek(&mut self, pos: SeekFrom) -> Seek<'_, Self> where Self: Unpin { ... } fn rewind(&mut self) -> Seek<'_, Self> where Self: Unpin { ... } fn stream_position(&mut self) -> Seek<'_, Self> where Self: Unpin { ... } } ``` Seeks on any [`AsyncSeek`](https://nuclei.rs/api/nuclei/io/trait.AsyncSeek.html). #### Provided Methods ```rust fn seek(&mut self, pos: SeekFrom) -> Seek<'_, Self> where Self: Unpin ``` Moves the stream’s position, answering the new one from the start. ```rust fn rewind(&mut self) -> Seek<'_, Self> where Self: Unpin ``` Moves the stream’s position to the start. ```rust fn stream_position(&mut self) -> Seek<'_, Self> where Self: Unpin ``` The stream’s position from the start. #### Dyn Compatibility This trait is **not** [dyn compatible](https://doc.rust-lang.org/1.99.1/reference/items/traits.html#dyn-compatibility). *In older versions of Rust, dyn compatibility was called "object safety".* #### Implementors - `impl AsyncSeekExt for S` ### trait `nuclei::io::AsyncWrite` https://nuclei.rs/api/nuclei/io/trait.AsyncWrite.html ```rust pub trait AsyncWrite { // Required methods fn poll_write( self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8], ) -> Poll>; fn poll_flush( self: Pin<&mut Self>, cx: &mut Context<'_>, ) -> Poll>; fn poll_close( self: Pin<&mut Self>, cx: &mut Context<'_>, ) -> Poll>; // Provided method fn poll_write_vectored( self: Pin<&mut Self>, cx: &mut Context<'_>, bufs: &[IoSlice<'_>], ) -> Poll> { ... } } ``` Write bytes asynchronously. This trait is analogous to the `std::io::Write` trait, but integrates with the asynchronous task system. In particular, the `poll_write` method, unlike `Write::write`, will automatically queue the current task for wakeup and return if the writer cannot take more data, rather than blocking the calling thread. #### Required Methods ```rust fn poll_write( self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8], ) -> Poll> ``` Attempt to write bytes from `buf` into the object. On success, returns `Poll::Ready(Ok(num_bytes_written))`. If the object is not ready for writing, the method returns `Poll::Pending` and arranges for the current task (via `cx.waker().wake_by_ref()`) to receive a notification when the object becomes writable or is closed. **Implementation** This function may not return errors of kind `WouldBlock` or `Interrupted`. Implementations must convert `WouldBlock` into `Poll::Pending` and either internally retry or convert `Interrupted` into another error kind. `poll_write` must try to make progress by flushing the underlying object if that is the only way the underlying object can become writable again. ```rust fn poll_flush( self: Pin<&mut Self>, cx: &mut Context<'_>, ) -> Poll> ``` Attempt to flush the object, ensuring that any buffered data reach their destination. On success, returns `Poll::Ready(Ok(()))`. If flushing cannot immediately complete, this method returns `Poll::Pending` and arranges for the current task (via `cx.waker().wake_by_ref()`) to receive a notification when the object can make progress towards flushing. **Implementation** This function may not return errors of kind `WouldBlock` or `Interrupted`. Implementations must convert `WouldBlock` into `Poll::Pending` and either internally retry or convert `Interrupted` into another error kind. It only makes sense to do anything here if you actually buffer data. ```rust fn poll_close( self: Pin<&mut Self>, cx: &mut Context<'_>, ) -> Poll> ``` Attempt to close the object. On success, returns `Poll::Ready(Ok(()))`. If closing cannot immediately complete, this function returns `Poll::Pending` and arranges for the current task (via `cx.waker().wake_by_ref()`) to receive a notification when the object can make progress towards closing. **Implementation** This function may not return errors of kind `WouldBlock` or `Interrupted`. Implementations must convert `WouldBlock` into `Poll::Pending` and either internally retry or convert `Interrupted` into another error kind. #### Provided Methods ```rust fn poll_write_vectored( self: Pin<&mut Self>, cx: &mut Context<'_>, bufs: &[IoSlice<'_>], ) -> Poll> ``` Attempt to write bytes from `bufs` into the object using vectored IO operations. This method is similar to `poll_write`, but allows data from multiple buffers to be written using a single operation. On success, returns `Poll::Ready(Ok(num_bytes_written))`. If the object is not ready for writing, the method returns `Poll::Pending` and arranges for the current task (via `cx.waker().wake_by_ref()`) to receive a notification when the object becomes writable or is closed. By default, this method delegates to using `poll_write` on the first nonempty buffer in `bufs`, or an empty one if none exists. Objects which support vectored IO should override this method. **Implementation** This function may not return errors of kind `WouldBlock` or `Interrupted`. Implementations must convert `WouldBlock` into `Poll::Pending` and either internally retry or convert `Interrupted` into another error kind. #### Dyn Compatibility This trait **is** [dyn compatible](https://doc.rust-lang.org/1.99.1/reference/items/traits.html#dyn-compatibility). *In older versions of Rust, dyn compatibility was called "object safety".* #### Implementations on Foreign Types `impl AsyncWrite for Vec` ```rust fn poll_write( self: Pin<&mut Vec>, _: &mut Context<'_>, buf: &[u8], ) -> Poll> ``` ```rust fn poll_write_vectored( self: Pin<&mut Vec>, _: &mut Context<'_>, bufs: &[IoSlice<'_>], ) -> Poll> ``` ```rust fn poll_flush( self: Pin<&mut Vec>, _: &mut Context<'_>, ) -> Poll> ``` ```rust fn poll_close( self: Pin<&mut Vec>, cx: &mut Context<'_>, ) -> Poll> ``` `impl

AsyncWrite for Pin

where P: DerefMut + Unpin,

::Target: AsyncWrite` ```rust fn poll_write( self: Pin<&mut Pin

>, cx: &mut Context<'_>, buf: &[u8], ) -> Poll> ``` ```rust fn poll_write_vectored( self: Pin<&mut Pin

>, cx: &mut Context<'_>, bufs: &[IoSlice<'_>], ) -> Poll> ``` ```rust fn poll_flush( self: Pin<&mut Pin

>, cx: &mut Context<'_>, ) -> Poll> ``` ```rust fn poll_close( self: Pin<&mut Pin

>, cx: &mut Context<'_>, ) -> Poll> ``` `impl AsyncWrite for &mut T where T: AsyncWrite + Unpin + ?Sized` ```rust fn poll_write( self: Pin<&mut &mut T>, cx: &mut Context<'_>, buf: &[u8], ) -> Poll> ``` ```rust fn poll_write_vectored( self: Pin<&mut &mut T>, cx: &mut Context<'_>, bufs: &[IoSlice<'_>], ) -> Poll> ``` ```rust fn poll_flush( self: Pin<&mut &mut T>, cx: &mut Context<'_>, ) -> Poll> ``` ```rust fn poll_close( self: Pin<&mut &mut T>, cx: &mut Context<'_>, ) -> Poll> ``` `impl AsyncWrite for Box where T: AsyncWrite + Unpin + ?Sized` ```rust fn poll_write( self: Pin<&mut Box>, cx: &mut Context<'_>, buf: &[u8], ) -> Poll> ``` ```rust fn poll_write_vectored( self: Pin<&mut Box>, cx: &mut Context<'_>, bufs: &[IoSlice<'_>], ) -> Poll> ``` ```rust fn poll_flush( self: Pin<&mut Box>, cx: &mut Context<'_>, ) -> Poll> ``` ```rust fn poll_close( self: Pin<&mut Box>, cx: &mut Context<'_>, ) -> Poll> ``` #### Implementors - `impl AsyncWrite for &Handle` - `impl AsyncWrite for &Handle` - `impl AsyncWrite for &Handle` - `impl AsyncWrite for &Handle` - `impl AsyncWrite for ChildStdin` - `impl AsyncWrite for DuplexStream` - `impl AsyncWrite for Empty` - `impl AsyncWrite for Handle` - `impl AsyncWrite for Handle` - `impl AsyncWrite for Handle` - `impl AsyncWrite for Handle` - `impl AsyncWrite for SimplexWriter` - `impl AsyncWrite for Sink` - `impl AsyncWrite for Stderr` - `impl AsyncWrite for Stdout` - `impl<'a, S> AsyncWrite for nuclei::net::WriteHalf<'a, S> where for<'x> &'x Handle: AsyncWrite` - `impl AsyncWrite for BufReader` - `impl AsyncWrite for BufStream` - `impl AsyncWrite for OwnedWriteHalf where for<'x> &'x Handle: AsyncWrite` - `impl AsyncWrite for nuclei::io::WriteHalf` - `impl AsyncWrite for BufWriter` ### trait `nuclei::io::AsyncWriteExt` https://nuclei.rs/api/nuclei/io/trait.AsyncWriteExt.html ```rust pub trait AsyncWriteExt: AsyncWrite { // Provided methods fn write<'a>(&'a mut self, buf: &'a [u8]) -> Write<'a, Self> where Self: Unpin { ... } fn write_vectored<'a, 'b>( &'a mut self, bufs: &'a [IoSlice<'b>], ) -> WriteVectored<'a, 'b, Self> where Self: Unpin { ... } fn write_all<'a>(&'a mut self, buf: &'a [u8]) -> WriteAll<'a, Self> where Self: Unpin { ... } fn flush(&mut self) -> Flush<'_, Self> where Self: Unpin { ... } fn shutdown(&mut self) -> Shutdown<'_, Self> where Self: Unpin { ... } fn write_u8(&mut self, n: u8) -> WriteNumber<'_, Self, { _ }> where Self: Unpin { ... } fn write_i8(&mut self, n: i8) -> WriteNumber<'_, Self, { _ }> where Self: Unpin { ... } fn write_u16(&mut self, n: u16) -> WriteNumber<'_, Self, { _ }> where Self: Unpin { ... } fn write_u16_le(&mut self, n: u16) -> WriteNumber<'_, Self, { _ }> where Self: Unpin { ... } fn write_i16(&mut self, n: i16) -> WriteNumber<'_, Self, { _ }> where Self: Unpin { ... } fn write_i16_le(&mut self, n: i16) -> WriteNumber<'_, Self, { _ }> where Self: Unpin { ... } fn write_u32(&mut self, n: u32) -> WriteNumber<'_, Self, { _ }> where Self: Unpin { ... } fn write_u32_le(&mut self, n: u32) -> WriteNumber<'_, Self, { _ }> where Self: Unpin { ... } fn write_i32(&mut self, n: i32) -> WriteNumber<'_, Self, { _ }> where Self: Unpin { ... } fn write_i32_le(&mut self, n: i32) -> WriteNumber<'_, Self, { _ }> where Self: Unpin { ... } fn write_u64(&mut self, n: u64) -> WriteNumber<'_, Self, { _ }> where Self: Unpin { ... } fn write_u64_le(&mut self, n: u64) -> WriteNumber<'_, Self, { _ }> where Self: Unpin { ... } fn write_i64(&mut self, n: i64) -> WriteNumber<'_, Self, { _ }> where Self: Unpin { ... } fn write_i64_le(&mut self, n: i64) -> WriteNumber<'_, Self, { _ }> where Self: Unpin { ... } fn write_u128(&mut self, n: u128) -> WriteNumber<'_, Self, { _ }> where Self: Unpin { ... } fn write_u128_le(&mut self, n: u128) -> WriteNumber<'_, Self, { _ }> where Self: Unpin { ... } fn write_i128(&mut self, n: i128) -> WriteNumber<'_, Self, { _ }> where Self: Unpin { ... } fn write_i128_le(&mut self, n: i128) -> WriteNumber<'_, Self, { _ }> where Self: Unpin { ... } fn write_f32(&mut self, n: f32) -> WriteNumber<'_, Self, { _ }> where Self: Unpin { ... } fn write_f32_le(&mut self, n: f32) -> WriteNumber<'_, Self, { _ }> where Self: Unpin { ... } fn write_f64(&mut self, n: f64) -> WriteNumber<'_, Self, { _ }> where Self: Unpin { ... } fn write_f64_le(&mut self, n: f64) -> WriteNumber<'_, Self, { _ }> where Self: Unpin { ... } } ``` Writes on any [`AsyncWrite`](https://nuclei.rs/api/nuclei/io/trait.AsyncWrite.html): a slice, all of a slice, typed numbers in big or little endian; and its flush and shutdown. #### Provided Methods ```rust fn write<'a>(&'a mut self, buf: &'a [u8]) -> Write<'a, Self> where Self: Unpin ``` Writes some of `buf`, answering how many bytes. ```rust fn write_vectored<'a, 'b>( &'a mut self, bufs: &'a [IoSlice<'b>], ) -> WriteVectored<'a, 'b, Self> where Self: Unpin ``` Writes some of the slices `bufs`, in order, answering how many bytes. ```rust fn write_all<'a>(&'a mut self, buf: &'a [u8]) -> WriteAll<'a, Self> where Self: Unpin ``` Writes all of `buf`; a writer that takes no more bytes is a [`WriteZero`](https://doc.rust-lang.org/1.99.1/core/io/error/enum.ErrorKind.html#variant.WriteZero) error. ```rust fn flush(&mut self) -> Flush<'_, Self> where Self: Unpin ``` Writes out what the writer holds back, down to its destination. ```rust fn shutdown(&mut self) -> Shutdown<'_, Self> where Self: Unpin ``` Flushes and closes the writing side (`poll_close`): a socket sends its end of stream, a pipe’s reader sees its end. ```rust fn write_u8(&mut self, n: u8) -> WriteNumber<'_, Self, { _ }> where Self: Unpin ``` Writes an unsigned byte, all of its bytes. ```rust fn write_i8(&mut self, n: i8) -> WriteNumber<'_, Self, { _ }> where Self: Unpin ``` Writes a signed byte, all of its bytes. ```rust fn write_u16(&mut self, n: u16) -> WriteNumber<'_, Self, { _ }> where Self: Unpin ``` Writes a big-endian `u16`, all of its bytes. ```rust fn write_u16_le(&mut self, n: u16) -> WriteNumber<'_, Self, { _ }> where Self: Unpin ``` Writes a little-endian `u16`, all of its bytes. ```rust fn write_i16(&mut self, n: i16) -> WriteNumber<'_, Self, { _ }> where Self: Unpin ``` Writes a big-endian `i16`, all of its bytes. ```rust fn write_i16_le(&mut self, n: i16) -> WriteNumber<'_, Self, { _ }> where Self: Unpin ``` Writes a little-endian `i16`, all of its bytes. ```rust fn write_u32(&mut self, n: u32) -> WriteNumber<'_, Self, { _ }> where Self: Unpin ``` Writes a big-endian `u32`, all of its bytes. ```rust fn write_u32_le(&mut self, n: u32) -> WriteNumber<'_, Self, { _ }> where Self: Unpin ``` Writes a little-endian `u32`, all of its bytes. ```rust fn write_i32(&mut self, n: i32) -> WriteNumber<'_, Self, { _ }> where Self: Unpin ``` Writes a big-endian `i32`, all of its bytes. ```rust fn write_i32_le(&mut self, n: i32) -> WriteNumber<'_, Self, { _ }> where Self: Unpin ``` Writes a little-endian `i32`, all of its bytes. ```rust fn write_u64(&mut self, n: u64) -> WriteNumber<'_, Self, { _ }> where Self: Unpin ``` Writes a big-endian `u64`, all of its bytes. ```rust fn write_u64_le(&mut self, n: u64) -> WriteNumber<'_, Self, { _ }> where Self: Unpin ``` Writes a little-endian `u64`, all of its bytes. ```rust fn write_i64(&mut self, n: i64) -> WriteNumber<'_, Self, { _ }> where Self: Unpin ``` Writes a big-endian `i64`, all of its bytes. ```rust fn write_i64_le(&mut self, n: i64) -> WriteNumber<'_, Self, { _ }> where Self: Unpin ``` Writes a little-endian `i64`, all of its bytes. ```rust fn write_u128(&mut self, n: u128) -> WriteNumber<'_, Self, { _ }> where Self: Unpin ``` Writes a big-endian `u128`, all of its bytes. ```rust fn write_u128_le(&mut self, n: u128) -> WriteNumber<'_, Self, { _ }> where Self: Unpin ``` Writes a little-endian `u128`, all of its bytes. ```rust fn write_i128(&mut self, n: i128) -> WriteNumber<'_, Self, { _ }> where Self: Unpin ``` Writes a big-endian `i128`, all of its bytes. ```rust fn write_i128_le(&mut self, n: i128) -> WriteNumber<'_, Self, { _ }> where Self: Unpin ``` Writes a little-endian `i128`, all of its bytes. ```rust fn write_f32(&mut self, n: f32) -> WriteNumber<'_, Self, { _ }> where Self: Unpin ``` Writes a big-endian `f32`, all of its bytes. ```rust fn write_f32_le(&mut self, n: f32) -> WriteNumber<'_, Self, { _ }> where Self: Unpin ``` Writes a little-endian `f32`, all of its bytes. ```rust fn write_f64(&mut self, n: f64) -> WriteNumber<'_, Self, { _ }> where Self: Unpin ``` Writes a big-endian `f64`, all of its bytes. ```rust fn write_f64_le(&mut self, n: f64) -> WriteNumber<'_, Self, { _ }> where Self: Unpin ``` Writes a little-endian `f64`, all of its bytes. #### Dyn Compatibility This trait is **not** [dyn compatible](https://doc.rust-lang.org/1.99.1/reference/items/traits.html#dyn-compatibility). *In older versions of Rust, dyn compatibility was called "object safety".* #### Implementors - `impl AsyncWriteExt for W` ### trait `nuclei::io::IoBuf` https://nuclei.rs/api/nuclei/io/trait.IoBuf.html ```rust pub unsafe trait IoBuf: Default + Send + Sync + 'static { // Required methods fn stable_ptr(&self) -> *const u8; fn bytes_init(&self) -> usize; fn bytes_total(&self) -> usize; } ``` A buffer an owned write takes: memory at an address that does not move while the runtime holds the buffer, whose first [`bytes_init`](https://nuclei.rs/api/nuclei/io/trait.IoBuf.html#tymethod.bytes_init) bytes are written. Implemented for `Vec` and [`AlignedBuf`](https://nuclei.rs/api/nuclei/io/struct.AlignedBuf.html); a caller’s own type (a shared byte buffer, memory of a registered region) may implement it too. It is `Send` and `Sync`, since the runtime may hand it to another thread and several zero-copy sends read it at once, and its [`Default`](https://doc.rust-lang.org/1.99.1/core/default/trait.Default.html) is the empty buffer a call gives back when the caller’s own cannot come back. **Safety** [`stable_ptr`](https://nuclei.rs/api/nuclei/io/trait.IoBuf.html#tymethod.stable_ptr) is never null and points at [`bytes_total`](https://nuclei.rs/api/nuclei/io/trait.IoBuf.html#tymethod.bytes_total) bytes of memory, the first [`bytes_init`](https://nuclei.rs/api/nuclei/io/trait.IoBuf.html#tymethod.bytes_init) of them initialized, which stay valid and in place while the value is not used through `&mut` or dropped, even when the value itself moves: the kernel may read them after the value moved into the runtime. `bytes_init() <= bytes_total()`. #### Required Methods ```rust fn stable_ptr(&self) -> *const u8 ``` The address of the buffer’s first byte. ```rust fn bytes_init(&self) -> usize ``` How many bytes from the start hold data: what a write sends. ```rust fn bytes_total(&self) -> usize ``` How many bytes the buffer’s memory holds in all. #### Dyn Compatibility This trait is **not** [dyn compatible](https://doc.rust-lang.org/1.99.1/reference/items/traits.html#dyn-compatibility). *In older versions of Rust, dyn compatibility was called "object safety".* #### Implementations on Foreign Types `impl IoBuf for Vec` ```rust fn stable_ptr(&self) -> *const u8 ``` ```rust fn bytes_init(&self) -> usize ``` ```rust fn bytes_total(&self) -> usize ``` #### Implementors - `impl IoBuf for AlignedBuf` ### trait `nuclei::io::IoBufMut` https://nuclei.rs/api/nuclei/io/trait.IoBufMut.html ```rust pub unsafe trait IoBufMut: IoBuf { // Required methods fn stable_mut_ptr(&mut self) -> *mut u8; unsafe fn set_init(&mut self, pos: usize); } ``` A buffer an owned read fills: an [`IoBuf`](https://nuclei.rs/api/nuclei/io/trait.IoBuf.html) whose memory past the bytes it holds may be written, and told how many hold data after a read. **Safety** As [`IoBuf`](https://nuclei.rs/api/nuclei/io/trait.IoBuf.html); and [`stable_mut_ptr`](https://nuclei.rs/api/nuclei/io/trait.IoBufMut.html#tymethod.stable_mut_ptr) points at the same memory, writable for all [`bytes_total`](https://nuclei.rs/api/nuclei/io/trait.IoBuf.html#tymethod.bytes_total) bytes. #### Required Methods ```rust fn stable_mut_ptr(&mut self) -> *mut u8 ``` The address of the buffer’s first byte, for writing. ```rust unsafe fn set_init(&mut self, pos: usize) ``` Sets how many bytes from the start hold data to `pos` (the runtime calls it with a smaller count too, never below what the caller handed in). **Safety** `pos <= bytes_total()`, and the first `pos` bytes are initialized. #### Dyn Compatibility This trait is **not** [dyn compatible](https://doc.rust-lang.org/1.99.1/reference/items/traits.html#dyn-compatibility). *In older versions of Rust, dyn compatibility was called "object safety".* #### Implementations on Foreign Types `impl IoBufMut for Vec` ```rust fn stable_mut_ptr(&mut self) -> *mut u8 ``` ```rust unsafe fn set_init(&mut self, pos: usize) ``` #### Implementors - `impl IoBufMut for AlignedBuf` ### trait `nuclei::io::IoObject` https://nuclei.rs/api/nuclei/io/trait.IoObject.html Also exported as `nuclei::IoObject`. ```rust pub trait IoObject: Sealed { } ``` An IO object a [`Handle`](https://nuclei.rs/api/nuclei/io/struct.Handle.html) takes over: on unix anything with a file descriptor; on Windows std’s `TcpStream`, `TcpListener`, `UdpSocket` and `File`. #### Dyn Compatibility This trait **is** [dyn compatible](https://doc.rust-lang.org/1.99.1/reference/items/traits.html#dyn-compatibility). *In older versions of Rust, dyn compatibility was called "object safety".* #### Implementors - `impl IoObject for T` ### trait `nuclei::io::IoVecBuf` https://nuclei.rs/api/nuclei/io/trait.IoVecBuf.html ```rust pub trait IoVecBuf: Written + Send + 'static { } ``` The buffers of an owned vectored write: each one’s bytes, in order, go out as one write. Implemented for `Vec` and `[B; N]` of any [`IoBuf`](https://nuclei.rs/api/nuclei/io/trait.IoBuf.html), `Vec>` among them. #### Dyn Compatibility This trait is **not** [dyn compatible](https://doc.rust-lang.org/1.99.1/reference/items/traits.html#dyn-compatibility). *In older versions of Rust, dyn compatibility was called "object safety".* #### Implementations on Foreign Types `impl IoVecBuf for [B; N] where B: IoBuf` `impl IoVecBuf for Vec where B: IoBuf` #### Implementors ### trait `nuclei::io::IoVecBufMut` https://nuclei.rs/api/nuclei/io/trait.IoVecBufMut.html ```rust pub trait IoVecBufMut: Filled + Send + 'static { } ``` The buffers of an owned vectored read: the bytes read fill each one’s spare capacity in order. Implemented for `Vec` and `[B; N]` of any [`IoBufMut`](https://nuclei.rs/api/nuclei/io/trait.IoBufMut.html). #### Dyn Compatibility This trait is **not** [dyn compatible](https://doc.rust-lang.org/1.99.1/reference/items/traits.html#dyn-compatibility). *In older versions of Rust, dyn compatibility was called "object safety".* #### Implementations on Foreign Types `impl IoVecBufMut for [B; N] where B: IoBufMut` `impl IoVecBufMut for Vec where B: IoBufMut` #### Implementors ### fn `nuclei::io::copy` https://nuclei.rs/api/nuclei/io/fn.copy.html ```rust pub async fn copy(reader: &mut R, writer: &mut W) -> Resultwhere R: AsyncRead + Unpin + ?Sized, W: AsyncWrite + Unpin + ?Sized, ``` Copies everything `reader` gives into `writer`, then flushes it; answers the bytes copied. ```rust let mut reader: &[u8] = b"hello"; let mut writer = Vec::new(); let copied = nuclei::io::copy(&mut reader, &mut writer).await.unwrap(); assert_eq!(copied, 5); assert_eq!(writer, b"hello"); ``` ### fn `nuclei::io::copy_bidirectional` https://nuclei.rs/api/nuclei/io/fn.copy_bidirectional.html ```rust pub async fn copy_bidirectional( a: &mut A, b: &mut B, ) -> Result<(u64, u64)>where A: AsyncRead + AsyncWrite + Unpin + ?Sized, B: AsyncRead + AsyncWrite + Unpin + ?Sized, ``` Copies `a` into `b` and `b` into `a` at once, in the calling task, each direction through a buffer of 8 KiB; a direction whose reader ends closes its writer. Answers the bytes copied each way, `(a to b, b to a)`, once both ended; the first error ends both. ### fn `nuclei::io::copy_bidirectional_with_sizes` https://nuclei.rs/api/nuclei/io/fn.copy_bidirectional_with_sizes.html ```rust pub async fn copy_bidirectional_with_sizes( a: &mut A, b: &mut B, a_to_b: usize, b_to_a: usize, ) -> Result<(u64, u64)>where A: AsyncRead + AsyncWrite + Unpin + ?Sized, B: AsyncRead + AsyncWrite + Unpin + ?Sized, ``` [`copy_bidirectional`](https://nuclei.rs/api/nuclei/io/fn.copy_bidirectional.html) with a buffer of `a_to_b` bytes for one direction and of `b_to_a` bytes for the other. ### fn `nuclei::io::copy_buf` https://nuclei.rs/api/nuclei/io/fn.copy_buf.html ```rust pub async fn copy_buf(reader: &mut R, writer: &mut W) -> Resultwhere R: AsyncBufRead + Unpin + ?Sized, W: AsyncWrite + Unpin + ?Sized, ``` Copies everything a buffered `reader` gives into `writer` from the reader’s own buffer, then flushes it; answers the bytes copied. ### fn `nuclei::io::duplex` https://nuclei.rs/api/nuclei/io/fn.duplex.html ```rust pub fn duplex(max_buf_size: usize) -> (DuplexStream, DuplexStream) ``` Two connected in-memory streams, each direction a pipe of `max_buf_size` bytes: a write waits while its pipe is full. ```rust use nuclei::io::{AsyncReadExt, AsyncWriteExt}; let (mut client, mut server) = nuclei::io::duplex(64); client.write_all(b"ping").await.unwrap(); let mut buf = [0u8; 4]; server.read_exact(&mut buf).await.unwrap(); assert_eq!(&buf, b"ping"); ``` ### fn `nuclei::io::empty` https://nuclei.rs/api/nuclei/io/fn.empty.html ```rust pub fn empty() -> Empty ``` A reader at its end at once, and a writer that takes every byte and keeps none. ### fn `nuclei::io::repeat` https://nuclei.rs/api/nuclei/io/fn.repeat.html ```rust pub fn repeat(byte: u8) -> Repeat ``` A reader that gives `byte` over and over, without end. ### fn `nuclei::io::simplex` https://nuclei.rs/api/nuclei/io/fn.simplex.html ```rust pub fn simplex(max_buf_size: usize) -> (SimplexReader, SimplexWriter) ``` One in-memory pipe of `max_buf_size` bytes: what the writer writes, the reader reads. ### fn `nuclei::io::sink` https://nuclei.rs/api/nuclei/io/fn.sink.html ```rust pub fn sink() -> Sink ``` A writer that takes every byte and keeps none. ### fn `nuclei::io::split` https://nuclei.rs/api/nuclei/io/fn.split.html ```rust pub fn split( stream: T, ) -> (ReadHalf, WriteHalf) ``` Splits `stream` into a read half and a write half; [`ReadHalf::unsplit`](https://nuclei.rs/api/nuclei/io/struct.ReadHalf.html#method.unsplit) puts them back together. ### fn `nuclei::io::stderr` https://nuclei.rs/api/nuclei/io/fn.stderr.html ```rust pub fn stderr() -> Stderr ``` The process’s standard error, as an async stream (see [`Stderr`](https://nuclei.rs/api/nuclei/io/struct.Stderr.html)). ### fn `nuclei::io::stdin` https://nuclei.rs/api/nuclei/io/fn.stdin.html ```rust pub fn stdin() -> Stdin ``` The process’s standard input, as an async stream (see [`Stdin`](https://nuclei.rs/api/nuclei/io/struct.Stdin.html)). ### fn `nuclei::io::stdout` https://nuclei.rs/api/nuclei/io/fn.stdout.html ```rust pub fn stdout() -> Stdout ``` The process’s standard output, as an async stream (see [`Stdout`](https://nuclei.rs/api/nuclei/io/struct.Stdout.html)). ## Module `nuclei::io::unix` https://nuclei.rs/api/nuclei/io/unix/index.html Unix’s own: [`AsyncFd`](https://nuclei.rs/api/nuclei/io/unix/struct.AsyncFd.html), a caller’s descriptor driven by readiness, and its guards. ### Structs - [AsyncFd](https://nuclei.rs/api/nuclei/io/unix/struct.AsyncFd.html): A caller’s own descriptor, driven by readiness. - [AsyncFdReadyGuard](https://nuclei.rs/api/nuclei/io/unix/struct.AsyncFdReadyGuard.html): What a readiness wait of an [`AsyncFd`](https://nuclei.rs/api/nuclei/io/unix/struct.AsyncFd.html) found: the readiness, and the edge counts it is of, to clear with. - [AsyncFdReadyMutGuard](https://nuclei.rs/api/nuclei/io/unix/struct.AsyncFdReadyMutGuard.html): As [`AsyncFdReadyGuard`](https://nuclei.rs/api/nuclei/io/unix/struct.AsyncFdReadyGuard.html), with the descriptor borrowed mutably. - [TryIoError](https://nuclei.rs/api/nuclei/io/unix/struct.TryIoError.html): The call of a guard’s `try_io` would block: the guard’s readiness was cleared. ### struct `nuclei::io::unix::AsyncFd` https://nuclei.rs/api/nuclei/io/unix/struct.AsyncFd.html ```rust pub struct AsyncFd { /* private fields */ } ``` A caller’s own descriptor, driven by readiness. #### Implementations `impl AsyncFd` ```rust pub fn new(inner: T) -> Result ``` Drives `inner` by readiness for reading and writing both. **Errors** Never today: the descriptor registers with the shard that first waits on it, and a poller that refuses it (a regular file, on epoll) says so at that wait. ```rust pub fn with_interest(inner: T, interest: Interest) -> Result ``` Drives `inner` by readiness for what `interest` names. **Errors** As [`new`](https://nuclei.rs/api/nuclei/io/unix/struct.AsyncFd.html#method.new). ```rust pub fn get_ref(&self) -> &T ``` The descriptor. ```rust pub fn get_mut(&mut self) -> &mut T ``` The descriptor, to change. ```rust pub fn into_inner(self) -> T ``` The descriptor back, no longer watched. ```rust pub fn poll_read_ready<'a>( &'a self, cx: &mut Context<'_>, ) -> Poll>> ``` Polls until the descriptor may be readable. **Errors** When the descriptor cannot be watched. ```rust pub fn poll_write_ready<'a>( &'a self, cx: &mut Context<'_>, ) -> Poll>> ``` Polls until the descriptor may be writable. **Errors** When the descriptor cannot be watched. ```rust pub async fn readable(&self) -> Result> ``` Waits until the descriptor may be readable. **Errors** When the descriptor cannot be watched. ```rust pub async fn writable(&self) -> Result> ``` Waits until the descriptor may be writable. **Errors** When the descriptor cannot be watched. ```rust pub async fn ready( &self, interest: Interest, ) -> Result> ``` Waits until some of `interest` may be ready. **Errors** When the descriptor cannot be watched, and `InvalidInput` when it is not watched for any of `interest`. ```rust pub async fn readable_mut(&mut self) -> Result> ``` As [`readable`](https://nuclei.rs/api/nuclei/io/unix/struct.AsyncFd.html#method.readable), with the descriptor borrowed mutably. **Errors** When the descriptor cannot be watched. ```rust pub async fn writable_mut(&mut self) -> Result> ``` As [`writable`](https://nuclei.rs/api/nuclei/io/unix/struct.AsyncFd.html#method.writable), with the descriptor borrowed mutably. **Errors** When the descriptor cannot be watched. ```rust pub async fn ready_mut( &mut self, interest: Interest, ) -> Result> ``` As [`ready`](https://nuclei.rs/api/nuclei/io/unix/struct.AsyncFd.html#method.ready), with the descriptor borrowed mutably. **Errors** When the descriptor cannot be watched. ```rust pub async fn async_io( &self, interest: Interest, f: impl FnMut(&T) -> Result, ) -> Result ``` Runs `f` on the descriptor each time some of `interest` may be ready, until it answers other than `WouldBlock`, clearing the readiness each time it does. **Errors** What `f` answers, when the descriptor cannot be watched, and `InvalidInput` when it is not watched for any of `interest`. ```rust pub fn try_io( &self, interest: Interest, f: impl FnOnce(&T) -> Result, ) -> Result ``` Runs `f` on the descriptor now if some of `interest` may be ready, clearing that readiness if it answers `WouldBlock`. **Errors** `WouldBlock` when none of `interest` may be ready, `InvalidInput` when the descriptor is not watched for any of it, and what `f` answers. #### Trait Implementations - `impl Debug for AsyncFd` #### Auto Trait Implementations - `impl !Freeze for AsyncFd` - `impl !RefUnwindSafe for AsyncFd` - `impl !UnwindSafe for AsyncFd` - `impl Send for AsyncFd where T: Send` - `impl Sync for AsyncFd where T: Sync` - `impl Unpin for AsyncFd where T: Unpin` - `impl UnsafeUnpin for AsyncFd where T: UnsafeUnpin` ### struct `nuclei::io::unix::AsyncFdReadyGuard` https://nuclei.rs/api/nuclei/io/unix/struct.AsyncFdReadyGuard.html ```rust pub struct AsyncFdReadyGuard<'a, T: AsFd> { /* private fields */ } ``` What a readiness wait of an [`AsyncFd`](https://nuclei.rs/api/nuclei/io/unix/struct.AsyncFd.html) found: the readiness, and the edge counts it is of, to clear with. #### Implementations `impl AsyncFdReadyGuard<'_, T>` ```rust pub fn ready(&self) -> Ready ``` What may be ready. ```rust pub fn clear_ready(&mut self) ``` The descriptor would block: the next wait lasts until the driver says it may be ready again. ```rust pub fn clear_ready_matching(&mut self, ready: Ready) ``` Clears what of `ready` this guard holds. ```rust pub fn retain_ready(&mut self) ``` Keeps the readiness: the next wait may answer at once. ```rust pub fn get_inner(&self) -> &T ``` The descriptor. `impl<'a, T: AsFd> AsyncFdReadyGuard<'a, T>` ```rust pub fn try_io( &mut self, f: impl FnOnce(&'a AsyncFd) -> Result, ) -> Result, TryIoError> ``` Runs `f`; if it answers `WouldBlock`, the readiness is cleared and `Err(TryIoError)` comes back, else `Ok` with what it answered. **Errors** [`TryIoError`](https://nuclei.rs/api/nuclei/io/unix/struct.TryIoError.html) when `f` would block. ```rust pub fn get_ref(&self) -> &'a AsyncFd ``` The descriptor’s `AsyncFd`. #### Trait Implementations - `impl Debug for AsyncFdReadyGuard<'_, T>` #### Auto Trait Implementations - `impl<'a, T> !RefUnwindSafe for AsyncFdReadyGuard<'a, T>` - `impl<'a, T> !UnwindSafe for AsyncFdReadyGuard<'a, T>` - `impl<'a, T> Freeze for AsyncFdReadyGuard<'a, T>` - `impl<'a, T> Send for AsyncFdReadyGuard<'a, T> where T: Sync` - `impl<'a, T> Sync for AsyncFdReadyGuard<'a, T> where T: Sync` - `impl<'a, T> Unpin for AsyncFdReadyGuard<'a, T>` - `impl<'a, T> UnsafeUnpin for AsyncFdReadyGuard<'a, T>` ### struct `nuclei::io::unix::AsyncFdReadyMutGuard` https://nuclei.rs/api/nuclei/io/unix/struct.AsyncFdReadyMutGuard.html ```rust pub struct AsyncFdReadyMutGuard<'a, T: AsFd> { /* private fields */ } ``` As [`AsyncFdReadyGuard`](https://nuclei.rs/api/nuclei/io/unix/struct.AsyncFdReadyGuard.html), with the descriptor borrowed mutably. #### Implementations `impl AsyncFdReadyMutGuard<'_, T>` ```rust pub fn ready(&self) -> Ready ``` What may be ready. ```rust pub fn clear_ready(&mut self) ``` The descriptor would block: the next wait lasts until the driver says it may be ready again. ```rust pub fn clear_ready_matching(&mut self, ready: Ready) ``` Clears what of `ready` this guard holds. ```rust pub fn retain_ready(&mut self) ``` Keeps the readiness: the next wait may answer at once. ```rust pub fn get_inner(&self) -> &T ``` The descriptor. `impl AsyncFdReadyMutGuard<'_, T>` ```rust pub fn try_io( &mut self, f: impl FnOnce(&mut AsyncFd) -> Result, ) -> Result, TryIoError> ``` Runs `f`; if it answers `WouldBlock`, the readiness is cleared and `Err(TryIoError)` comes back, else `Ok` with what it answered. **Errors** [`TryIoError`](https://nuclei.rs/api/nuclei/io/unix/struct.TryIoError.html) when `f` would block. ```rust pub fn get_ref(&self) -> &AsyncFd ``` The descriptor’s `AsyncFd`. ```rust pub fn get_mut(&mut self) -> &mut AsyncFd ``` The descriptor’s `AsyncFd`, mutably. ```rust pub fn get_inner_mut(&mut self) -> &mut T ``` The descriptor, mutably. #### Trait Implementations - `impl Debug for AsyncFdReadyMutGuard<'_, T>` #### Auto Trait Implementations - `impl<'a, T> !RefUnwindSafe for AsyncFdReadyMutGuard<'a, T>` - `impl<'a, T> !UnwindSafe for AsyncFdReadyMutGuard<'a, T>` - `impl<'a, T> Freeze for AsyncFdReadyMutGuard<'a, T>` - `impl<'a, T> Send for AsyncFdReadyMutGuard<'a, T> where T: Send` - `impl<'a, T> Sync for AsyncFdReadyMutGuard<'a, T> where T: Sync` - `impl<'a, T> Unpin for AsyncFdReadyMutGuard<'a, T>` - `impl<'a, T> UnsafeUnpin for AsyncFdReadyMutGuard<'a, T>` ### struct `nuclei::io::unix::TryIoError` https://nuclei.rs/api/nuclei/io/unix/struct.TryIoError.html ```rust pub struct TryIoError(/* private fields */); ``` The call of a guard’s `try_io` would block: the guard’s readiness was cleared. #### Trait Implementations - `impl Debug for TryIoError` - `impl Display for TryIoError` - `impl Error for TryIoError` #### Auto Trait Implementations - `impl Freeze for TryIoError` - `impl RefUnwindSafe for TryIoError` - `impl Send for TryIoError` - `impl Sync for TryIoError` - `impl Unpin for TryIoError` - `impl UnsafeUnpin for TryIoError` - `impl UnwindSafe for TryIoError` ## Module `nuclei::net` https://nuclei.rs/api/nuclei/net/index.html Sockets: TCP, UDP and Unix domain, as [`Handle`](https://nuclei.rs/api/nuclei/io/struct.Handle.html)s. Each type keeps std’s own socket inside; the handle adds the async operations (`accept`, `connect`, `send`, `recv`, `peek`, `send_to`, `recv_from`, `peek_from`) and, for the streams, `AsyncRead` and `AsyncWrite` on the handle and on a shared reference to it, so two tasks can read and write one stream at once. A stream’s `read_owned` and `write_owned` take the caller’s buffer (any [`IoBuf`](https://nuclei.rs/api/nuclei/io/trait.IoBuf.html) or [`IoBufMut`](https://nuclei.rs/api/nuclei/io/trait.IoBufMut.html)) and give it back, so the driver reads into it and writes from it with no copy, and `read_vectored_owned` and `write_vectored_owned` do the same with several buffers in one call; a TCP stream’s `write_zero_copy` asks the kernel not to copy it either, and gives it back through a [`Released`](https://nuclei.rs/api/nuclei/net/struct.Released.html) once the kernel let go of it. `send_file` sends a range of a file to a stream. A stream ends with [`shut`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.shut), std’s shutdown made once the bytes written behind reached the kernel, or for TCP with [`abort`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.abort), which resets the connection now. [`TcpSocket`](https://nuclei.rs/api/nuclei/net/struct.TcpSocket.html) and [`UdpSocketBuilder`](https://nuclei.rs/api/nuclei/net/struct.UdpSocketBuilder.html) set a socket up before it listens, connects or binds, and [`TcpKeepalive`](https://nuclei.rs/api/nuclei/net/struct.TcpKeepalive.html) times a TCP connection’s keepalive probes. An address is anything [`ToSocketAddrs`](https://nuclei.rs/api/nuclei/net/trait.ToSocketAddrs.html) takes: numbers are used at once; a name (`"localhost:80"`) is looked up on the blocking pool, so no shard waits on the resolver. [`lookup_host`](https://nuclei.rs/api/nuclei/net/fn.lookup_host.html) looks one up alone. ```rust use nuclei::net::{TcpListener, TcpStream}; let listener = TcpListener::bind("127.0.0.1:0").await?; let addr = listener.get_ref().local_addr()?; let client = TcpStream::connect(addr).await?; let (server, _) = listener.accept().await?; client.send(b"hi").await?; let mut buf = [0u8; 2]; assert_eq!(server.recv(&mut buf).await?, 2); ``` ### Modules - [unix](https://nuclei.rs/api/nuclei/net/unix/index.html): Unix domain sockets: listeners, streams and datagrams, and [`UCred`](https://nuclei.rs/api/nuclei/net/unix/struct.UCred.html), the credentials of a stream’s peer; and Unix pipes ([`pipe`](https://nuclei.rs/api/nuclei/net/unix/pipe/index.html)). ### Structs - [DeviceName](https://nuclei.rs/api/nuclei/net/struct.DeviceName.html): A network interface’s name, as `bind_device` takes it: up to 16 bytes, held in place. - [OwnedReadHalf](https://nuclei.rs/api/nuclei/net/struct.OwnedReadHalf.html): The read half of a stream, owning it with the write half. - [OwnedWriteHalf](https://nuclei.rs/api/nuclei/net/struct.OwnedWriteHalf.html): The write half of a stream, owning it with the read half. - [ReadHalf](https://nuclei.rs/api/nuclei/net/struct.ReadHalf.html): The read half of a stream, borrowed from it. - [Released](https://nuclei.rs/api/nuclei/net/struct.Released.html): The buffer of a [`TcpStream::write_zero_copy`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.write_zero_copy), as a future that resolves to it once the kernel let go of every byte. For a send the kernel did not copy, that is once the peer acknowledged the bytes, which may be long after the write ended. - [ReuniteError](https://nuclei.rs/api/nuclei/net/struct.ReuniteError.html): Two halves of different streams, given back by [`OwnedReadHalf::reunite`](https://nuclei.rs/api/nuclei/net/struct.OwnedReadHalf.html#method.reunite). - [TcpKeepalive](https://nuclei.rs/api/nuclei/net/struct.TcpKeepalive.html): When an idle connection’s keepalive probes start, how far apart they go, and how many unanswered ones drop the connection. A field left `None` keeps the system’s value. - [TcpSocket](https://nuclei.rs/api/nuclei/net/struct.TcpSocket.html): A TCP socket to set up before it connects or listens. - [TcpStreamGenerator](https://nuclei.rs/api/nuclei/net/struct.TcpStreamGenerator.html): The connections of a listener, as [`Handle::accept_multi`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.accept_multi) makes them. - [UdpSocketBuilder](https://nuclei.rs/api/nuclei/net/struct.UdpSocketBuilder.html): A UDP socket to set up before it binds: what only a socket not bound yet takes (`SO_REUSEPORT` among sockets that share a port, `IPV6_V6ONLY`, a device), and the rest before the first datagram. - [UnixSocket](https://nuclei.rs/api/nuclei/net/struct.UnixSocket.html): A Unix domain socket, of streams or of datagrams, to bind before it connects, listens or sends. - [WriteHalf](https://nuclei.rs/api/nuclei/net/struct.WriteHalf.html): The write half of a stream, borrowed from it. ### Traits - [ToSocketAddrs](https://nuclei.rs/api/nuclei/net/trait.ToSocketAddrs.html): What an operation that takes an address accepts: a `SocketAddr`, an `(IpAddr, u16)` pair, a slice or array of addresses, or a string, `"host:port"` or `("host", port)`. Numbers are used as they are; a name is looked up on the blocking pool (`getaddrinfo`), never on the calling thread. ### Functions - [lookup_host](https://nuclei.rs/api/nuclei/net/fn.lookup_host.html): Every address `host` names: numbers at once, a name looked up on the blocking pool. The iterator owns what it walks, so a slice given here is copied into it; the operations that take an address walk it in place. ### Type Aliases - [TcpListener](https://nuclei.rs/api/nuclei/net/type.TcpListener.html): A TCP listener: std’s, with an async `accept`. - [TcpStream](https://nuclei.rs/api/nuclei/net/type.TcpStream.html): A TCP stream: std’s, with async reads and writes. A few of std’s calls reached through `Deref` go around the handle (`shutdown` among them): see [`Handle`](https://nuclei.rs/api/nuclei/io/struct.Handle.html). - [UdpSocket](https://nuclei.rs/api/nuclei/net/type.UdpSocket.html): A UDP socket: std’s, with async sends and receives. Its [`connect`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.connect) makes a socket; `socket.connect(addr)` on one is std’s own (see there). - [UnixDatagram](https://nuclei.rs/api/nuclei/net/type.UnixDatagram.html): A Unix datagram socket: std’s, with async sends and receives. - [UnixListener](https://nuclei.rs/api/nuclei/net/type.UnixListener.html): A Unix stream listener: std’s, with an async `accept`. - [UnixStream](https://nuclei.rs/api/nuclei/net/type.UnixStream.html): A Unix stream: std’s, with async reads and writes. A few of std’s calls reached through `Deref` go around the handle (`shutdown` among them): see [`Handle`](https://nuclei.rs/api/nuclei/io/struct.Handle.html). ### struct `nuclei::net::DeviceName` https://nuclei.rs/api/nuclei/net/struct.DeviceName.html ```rust pub struct DeviceName { /* private fields */ } ``` A network interface’s name, as `bind_device` takes it: up to 16 bytes, held in place. #### Methods from Deref ```rust pub fn is_ascii(&self) -> bool ``` Checks if all bytes in this slice are within the ASCII range. An empty slice returns `true`. ```rust pub fn as_ascii(&self) -> Option<&[AsciiChar]> ``` 🔬This is a nightly-only experimental API. (`ascii_char`) If this slice [`is_ascii`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.is_ascii), returns it as a slice of [ASCII characters](https://doc.rust-lang.org/1.99.1/core/ascii/ascii_char/enum.AsciiChar.html), otherwise returns `None`. ```rust pub unsafe fn as_ascii_unchecked(&self) -> &[AsciiChar] ``` 🔬This is a nightly-only experimental API. (`ascii_char`) Converts this slice of bytes into a slice of ASCII characters, without checking whether they’re valid. **Safety** Every byte in the slice must be in `0..=127`, or else this is UB. ```rust pub fn eq_ignore_ascii_case(&self, other: &[u8]) -> bool ``` Checks that two slices are an ASCII case-insensitive match. Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`, but without allocating and copying temporaries. ```rust pub fn escape_ascii(&self) -> EscapeAscii<'_> ``` Returns an iterator that produces an escaped version of this slice, treating it as an ASCII string. **Examples** ```rust let s = b"0\t\r\n'\"\\\x9d"; let escaped = s.escape_ascii().to_string(); assert_eq!(escaped, "0\\t\\r\\n\\'\\\"\\\\\\x9d"); ``` ```rust pub fn trim_ascii_start(&self) -> &[u8] ``` Returns a byte slice with leading ASCII whitespace bytes removed. ‘Whitespace’ refers to the definition used by [`u8::is_ascii_whitespace`](https://doc.rust-lang.org/1.99.1/std/primitive.u8.html#method.is_ascii_whitespace). Importantly, this definition excludes the `\0x0B` byte even though it has the Unicode [`White_Space`](https://www.unicode.org/reports/tr44/#White_Space) property and is removed by [`str::trim_start`](https://doc.rust-lang.org/1.99.1/std/primitive.str.html#method.trim_start). **Examples** ```rust assert_eq!(b" \t hello world\n".trim_ascii_start(), b"hello world\n"); assert_eq!(b" ".trim_ascii_start(), b""); assert_eq!(b"".trim_ascii_start(), b""); ``` ```rust pub fn trim_ascii_end(&self) -> &[u8] ``` Returns a byte slice with trailing ASCII whitespace bytes removed. ‘Whitespace’ refers to the definition used by [`u8::is_ascii_whitespace`](https://doc.rust-lang.org/1.99.1/std/primitive.u8.html#method.is_ascii_whitespace). Importantly, this definition excludes the `\0x0B` byte even though it has the Unicode [`White_Space`](https://www.unicode.org/reports/tr44/#White_Space) property and is removed by [`str::trim_end`](https://doc.rust-lang.org/1.99.1/std/primitive.str.html#method.trim_end). **Examples** ```rust assert_eq!(b"\r hello world\n ".trim_ascii_end(), b"\r hello world"); assert_eq!(b" ".trim_ascii_end(), b""); assert_eq!(b"".trim_ascii_end(), b""); ``` ```rust pub fn trim_ascii(&self) -> &[u8] ``` Returns a byte slice with leading and trailing ASCII whitespace bytes removed. ‘Whitespace’ refers to the definition used by [`u8::is_ascii_whitespace`](https://doc.rust-lang.org/1.99.1/std/primitive.u8.html#method.is_ascii_whitespace). Importantly, this definition excludes the `\0x0B` byte even though it has the Unicode [`White_Space`](https://www.unicode.org/reports/tr44/#White_Space) property and is removed by [`str::trim`](https://doc.rust-lang.org/1.99.1/std/primitive.str.html#method.trim). **Examples** ```rust assert_eq!(b"\r hello world\n ".trim_ascii(), b"hello world"); assert_eq!(b" ".trim_ascii(), b""); assert_eq!(b"".trim_ascii(), b""); ``` ```rust pub fn len(&self) -> usize ``` Returns the number of elements in the slice. **Examples** ```rust let a = [1, 2, 3]; assert_eq!(a.len(), 3); ``` ```rust pub fn is_empty(&self) -> bool ``` Returns `true` if the slice has a length of 0. **Examples** ```rust let a = [1, 2, 3]; assert!(!a.is_empty()); let b: &[i32] = &[]; assert!(b.is_empty()); ``` ```rust pub fn first(&self) -> Option<&T> ``` Returns the first element of the slice, or `None` if it is empty. **Examples** ```rust let v = [10, 40, 30]; assert_eq!(Some(&10), v.first()); let w: &[i32] = &[]; assert_eq!(None, w.first()); ``` ```rust pub fn split_first(&self) -> Option<(&T, &[T])> ``` Returns the first and all the rest of the elements of the slice, or `None` if it is empty. **Examples** ```rust let x = &[0, 1, 2]; if let Some((first, elements)) = x.split_first() { assert_eq!(first, &0); assert_eq!(elements, &[1, 2]); } ``` ```rust pub fn split_last(&self) -> Option<(&T, &[T])> ``` Returns the last and all the rest of the elements of the slice, or `None` if it is empty. **Examples** ```rust let x = &[0, 1, 2]; if let Some((last, elements)) = x.split_last() { assert_eq!(last, &2); assert_eq!(elements, &[0, 1]); } ``` ```rust pub fn last(&self) -> Option<&T> ``` Returns the last element of the slice, or `None` if it is empty. **Examples** ```rust let v = [10, 40, 30]; assert_eq!(Some(&30), v.last()); let w: &[i32] = &[]; assert_eq!(None, w.last()); ``` ```rust pub fn first_chunk(&self) -> Option<&[T; N]> ``` Returns an array reference to the first `N` items in the slice. If the slice is not at least `N` in length, this will return `None`. **Examples** ```rust let u = [10, 40, 30]; assert_eq!(Some(&[10, 40]), u.first_chunk::<2>()); let v: &[i32] = &[10]; assert_eq!(None, v.first_chunk::<2>()); let w: &[i32] = &[]; assert_eq!(Some(&[]), w.first_chunk::<0>()); ``` ```rust pub fn split_first_chunk(&self) -> Option<(&[T; N], &[T])> ``` Returns an array reference to the first `N` items in the slice and the remaining slice. If the slice is not at least `N` in length, this will return `None`. **Examples** ```rust let x = &[0, 1, 2]; if let Some((first, elements)) = x.split_first_chunk::<2>() { assert_eq!(first, &[0, 1]); assert_eq!(elements, &[2]); } assert_eq!(None, x.split_first_chunk::<4>()); ``` ```rust pub fn split_last_chunk(&self) -> Option<(&[T], &[T; N])> ``` Returns an array reference to the last `N` items in the slice and the remaining slice. If the slice is not at least `N` in length, this will return `None`. **Examples** ```rust let x = &[0, 1, 2]; if let Some((elements, last)) = x.split_last_chunk::<2>() { assert_eq!(elements, &[0]); assert_eq!(last, &[1, 2]); } assert_eq!(None, x.split_last_chunk::<4>()); ``` ```rust pub fn last_chunk(&self) -> Option<&[T; N]> ``` Returns an array reference to the last `N` items in the slice. If the slice is not at least `N` in length, this will return `None`. **Examples** ```rust let u = [10, 40, 30]; assert_eq!(Some(&[40, 30]), u.last_chunk::<2>()); let v: &[i32] = &[10]; assert_eq!(None, v.last_chunk::<2>()); let w: &[i32] = &[]; assert_eq!(Some(&[]), w.last_chunk::<0>()); ``` ```rust pub fn get(&self, index: I) -> Option<&>::Output> where I: SliceIndex<[T]> ``` Returns a reference to an element or subslice depending on the type of index. - If given a position, returns a reference to the element at that position or `None` if out of bounds. - If given a range, returns the subslice corresponding to that range, or `None` if out of bounds. **Examples** ```rust let v = [10, 40, 30]; assert_eq!(Some(&40), v.get(1)); assert_eq!(Some(&[10, 40][..]), v.get(0..2)); assert_eq!(None, v.get(3)); assert_eq!(None, v.get(0..4)); ``` ```rust pub unsafe fn get_unchecked( &self, index: I, ) -> &>::Output where I: SliceIndex<[T]> ``` Returns a reference to an element or subslice, without doing bounds checking. For a safe alternative see [`get`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.get). **Safety** Calling this method with an out-of-bounds index is *[undefined behavior](https://doc.rust-lang.org/reference/behavior-considered-undefined.html)* even if the resulting reference is not used. You can think of this like `.get(index).unwrap_unchecked()`. It’s UB to call `.get_unchecked(len)`, even if you immediately convert to a pointer. And it’s UB to call `.get_unchecked(..len + 1)`, `.get_unchecked(..=len)`, or similar. **Examples** ```rust let x = &[1, 2, 4]; unsafe { assert_eq!(x.get_unchecked(1), &2); } ``` ```rust pub fn as_ptr(&self) -> *const T ``` Returns a raw pointer to the slice’s buffer. The caller must ensure that the slice outlives the pointer this function returns, or else it will end up dangling. The caller must also ensure that the memory the pointer (non-transitively) points to is never written to (except inside an `UnsafeCell`) using this pointer or any pointer derived from it. If you need to mutate the contents of the slice, use [`as_mut_ptr`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.as_mut_ptr). Modifying the container referenced by this slice may cause its buffer to be reallocated, which would also make any pointers to it invalid. **Examples** ```rust let x = &[1, 2, 4]; let x_ptr = x.as_ptr(); unsafe { for i in 0..x.len() { assert_eq!(x.get_unchecked(i), &*x_ptr.add(i)); } } ``` ```rust pub fn as_ptr_range(&self) -> Range<*const T> ``` Returns the two raw pointers spanning the slice. The returned range is half-open, which means that the end pointer points *one past* the last element of the slice. This way, an empty slice is represented by two equal pointers, and the difference between the two pointers represents the size of the slice. See [`as_ptr`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.as_ptr) for warnings on using these pointers. The end pointer requires extra caution, as it does not point to a valid element in the slice. This function is useful for interacting with foreign interfaces which use two pointers to refer to a range of elements in memory, as is common in C++. It can also be useful to check if a pointer to an element refers to an element of this slice: ```rust let a = [1, 2, 3]; let x = &a[1] as *const _; let y = &5 as *const _; assert!(a.as_ptr_range().contains(&x)); assert!(!a.as_ptr_range().contains(&y)); ``` ```rust pub fn as_array(&self) -> Option<&[T; N]> ``` Gets a reference to the underlying array. If `N` is not exactly equal to the length of `self`, then this method returns `None`. ```rust pub fn iter(&self) -> Iter<'_, T> ``` Returns an iterator over the slice. The iterator yields all items from start to end. **Examples** ```rust let x = &[1, 2, 4]; let mut iterator = x.iter(); assert_eq!(iterator.next(), Some(&1)); assert_eq!(iterator.next(), Some(&2)); assert_eq!(iterator.next(), Some(&4)); assert_eq!(iterator.next(), None); ``` ```rust pub fn windows(&self, size: usize) -> Windows<'_, T> ``` Returns an iterator over all contiguous windows of length `size`. The windows overlap. If the slice is shorter than `size`, the iterator returns no values. **Panics** Panics if `size` is zero. **Examples** ```rust let slice = ['l', 'o', 'r', 'e', 'm']; let mut iter = slice.windows(3); assert_eq!(iter.next().unwrap(), &['l', 'o', 'r']); assert_eq!(iter.next().unwrap(), &['o', 'r', 'e']); assert_eq!(iter.next().unwrap(), &['r', 'e', 'm']); assert!(iter.next().is_none()); ``` If the slice is shorter than `size`: ```rust let slice = ['f', 'o', 'o']; let mut iter = slice.windows(4); assert!(iter.next().is_none()); ``` Because the [Iterator](https://doc.rust-lang.org/1.99.1/core/iter/traits/iterator/trait.Iterator.html) trait cannot represent the required lifetimes, there is no `windows_mut` analog to `windows`; `[0,1,2].windows_mut(2).collect()` would violate [the rules of references](https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html#the-rules-of-references) (though a [LendingIterator](https://blog.rust-lang.org/2022/10/28/gats-stabilization.html) analog is possible). You can sometimes use [`Cell::as_slice_of_cells`](https://doc.rust-lang.org/1.99.1/core/cell/struct.Cell.html#method.as_slice_of_cells) in conjunction with `windows` instead: ```rust use std::cell::Cell; let mut array = ['R', 'u', 's', 't', ' ', '2', '0', '1', '5']; let slice = &mut array[..]; let slice_of_cells: &[Cell] = Cell::from_mut(slice).as_slice_of_cells(); for w in slice_of_cells.windows(3) { Cell::swap(&w[0], &w[2]); } assert_eq!(array, ['s', 't', ' ', '2', '0', '1', '5', 'u', 'R']); ``` ```rust pub fn chunks(&self, chunk_size: usize) -> Chunks<'_, T> ``` Returns an iterator over `chunk_size` elements of the slice at a time, starting at the beginning of the slice. The chunks are slices and do not overlap. If `chunk_size` does not divide the length of the slice, then the last chunk will not have length `chunk_size`. See [`chunks_exact`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.chunks_exact) for a variant of this iterator that returns chunks of always exactly `chunk_size` elements, and [`rchunks`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.rchunks) for the same iterator but starting at the end of the slice. If your `chunk_size` is a constant, consider using [`as_chunks`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.as_chunks) instead, which will give references to arrays of exactly that length, rather than slices. **Panics** Panics if `chunk_size` is zero. **Examples** ```rust let slice = ['l', 'o', 'r', 'e', 'm']; let mut iter = slice.chunks(2); assert_eq!(iter.next().unwrap(), &['l', 'o']); assert_eq!(iter.next().unwrap(), &['r', 'e']); assert_eq!(iter.next().unwrap(), &['m']); assert!(iter.next().is_none()); ``` ```rust pub fn chunks_exact(&self, chunk_size: usize) -> ChunksExact<'_, T> ``` Returns an iterator over `chunk_size` elements of the slice at a time, starting at the beginning of the slice. The chunks are slices and do not overlap. If `chunk_size` does not divide the length of the slice, then the last up to `chunk_size-1` elements will be omitted and can be retrieved from the `remainder` function of the iterator. Due to each chunk having exactly `chunk_size` elements, the compiler can often optimize the resulting code better than in the case of [`chunks`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.chunks). See [`chunks`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.chunks) for a variant of this iterator that also returns the remainder as a smaller chunk, and [`rchunks_exact`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.rchunks_exact) for the same iterator but starting at the end of the slice. If your `chunk_size` is a constant, consider using [`as_chunks`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.as_chunks) instead, which will give references to arrays of exactly that length, rather than slices. **Panics** Panics if `chunk_size` is zero. **Examples** ```rust let slice = ['l', 'o', 'r', 'e', 'm']; let mut iter = slice.chunks_exact(2); assert_eq!(iter.next().unwrap(), &['l', 'o']); assert_eq!(iter.next().unwrap(), &['r', 'e']); assert!(iter.next().is_none()); assert_eq!(iter.remainder(), &['m']); ``` ```rust pub unsafe fn as_chunks_unchecked(&self) -> &[[T; N]] ``` Splits the slice into a slice of `N`-element arrays, assuming that there’s no remainder. This is the inverse operation to [`as_flattened`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.as_flattened). As this is `unsafe`, consider whether you could use [`as_chunks`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.as_chunks) or [`as_rchunks`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.as_rchunks) instead, perhaps via something like `if let (chunks, []) = slice.as_chunks()` or `let (chunks, []) = slice.as_chunks() else { unreachable!() };`. **Safety** This may only be called when - The slice splits exactly into `N`-element chunks (aka `self.len() % N == 0`). - `N != 0`. **Examples** ```rust let slice: &[char] = &['l', 'o', 'r', 'e', 'm', '!']; let chunks: &[[char; 1]] = // SAFETY: 1-element chunks never have remainder unsafe { slice.as_chunks_unchecked() }; assert_eq!(chunks, &[['l'], ['o'], ['r'], ['e'], ['m'], ['!']]); let chunks: &[[char; 3]] = // SAFETY: The slice length (6) is a multiple of 3 unsafe { slice.as_chunks_unchecked() }; assert_eq!(chunks, &[['l', 'o', 'r'], ['e', 'm', '!']]); // These would be unsound: // let chunks: &[[_; 5]] = slice.as_chunks_unchecked() // The slice length is not a multiple of 5 // let chunks: &[[_; 0]] = slice.as_chunks_unchecked() // Zero-length chunks are never allowed ``` ```rust pub fn as_chunks(&self) -> (&[[T; N]], &[T]) ``` Splits the slice into a slice of `N`-element arrays, starting at the beginning of the slice, and a remainder slice with length strictly less than `N`. The remainder is meaningful in the division sense. Given `let (chunks, remainder) = slice.as_chunks()`, then: - `chunks.len()` equals `slice.len() / N`, - `remainder.len()` equals `slice.len() % N`, and - `slice.len()` equals `chunks.len() * N + remainder.len()`. You can flatten the chunks back into a slice-of-`T` with [`as_flattened`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.as_flattened). **Panics** Panics if `N` is zero. Note that this check is against a const generic parameter, not a runtime value, and thus a particular monomorphization will either always panic or it will never panic. **Examples** ```rust let slice = ['l', 'o', 'r', 'e', 'm']; let (chunks, remainder) = slice.as_chunks(); assert_eq!(chunks, &[['l', 'o'], ['r', 'e']]); assert_eq!(remainder, &['m']); ``` If you expect the slice to be an exact multiple, you can combine `let`-`else` with an empty slice pattern: ```rust let slice = ['R', 'u', 's', 't']; let (chunks, []) = slice.as_chunks::<2>() else { panic!("slice didn't have even length") }; assert_eq!(chunks, &[['R', 'u'], ['s', 't']]); ``` ```rust pub fn as_rchunks(&self) -> (&[T], &[[T; N]]) ``` Splits the slice into a slice of `N`-element arrays, starting at the end of the slice, and a remainder slice with length strictly less than `N`. The remainder is meaningful in the division sense. Given `let (remainder, chunks) = slice.as_rchunks()`, then: - `remainder.len()` equals `slice.len() % N`, - `chunks.len()` equals `slice.len() / N`, and - `slice.len()` equals `chunks.len() * N + remainder.len()`. You can flatten the chunks back into a slice-of-`T` with [`as_flattened`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.as_flattened). **Panics** Panics if `N` is zero. Note that this check is against a const generic parameter, not a runtime value, and thus a particular monomorphization will either always panic or it will never panic. **Examples** ```rust let slice = ['l', 'o', 'r', 'e', 'm']; let (remainder, chunks) = slice.as_rchunks(); assert_eq!(remainder, &['l']); assert_eq!(chunks, &[['o', 'r'], ['e', 'm']]); ``` ```rust pub fn array_windows(&self) -> ArrayWindows<'_, T, N> ``` Returns an iterator over overlapping windows of `N` elements of a slice, starting at the beginning of the slice. This is the const generic equivalent of [`windows`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.windows). If `N` is greater than the size of the slice, it will return no windows. **Panics** Panics if `N` is zero. Note that this check is against a const generic parameter, not a runtime value, and thus a particular monomorphization will either always panic or it will never panic. **Examples** ```rust let slice = [0, 1, 2, 3]; let mut iter = slice.array_windows(); assert_eq!(iter.next().unwrap(), &[0, 1]); assert_eq!(iter.next().unwrap(), &[1, 2]); assert_eq!(iter.next().unwrap(), &[2, 3]); assert!(iter.next().is_none()); ``` ```rust pub fn rchunks(&self, chunk_size: usize) -> RChunks<'_, T> ``` Returns an iterator over `chunk_size` elements of the slice at a time, starting at the end of the slice. The chunks are slices and do not overlap. If `chunk_size` does not divide the length of the slice, then the last chunk will not have length `chunk_size`. See [`rchunks_exact`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.rchunks_exact) for a variant of this iterator that returns chunks of always exactly `chunk_size` elements, and [`chunks`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.chunks) for the same iterator but starting at the beginning of the slice. If your `chunk_size` is a constant, consider using [`as_rchunks`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.as_rchunks) instead, which will give references to arrays of exactly that length, rather than slices. **Panics** Panics if `chunk_size` is zero. **Examples** ```rust let slice = ['l', 'o', 'r', 'e', 'm']; let mut iter = slice.rchunks(2); assert_eq!(iter.next().unwrap(), &['e', 'm']); assert_eq!(iter.next().unwrap(), &['o', 'r']); assert_eq!(iter.next().unwrap(), &['l']); assert!(iter.next().is_none()); ``` ```rust pub fn rchunks_exact(&self, chunk_size: usize) -> RChunksExact<'_, T> ``` Returns an iterator over `chunk_size` elements of the slice at a time, starting at the end of the slice. The chunks are slices and do not overlap. If `chunk_size` does not divide the length of the slice, then the last up to `chunk_size-1` elements will be omitted and can be retrieved from the `remainder` function of the iterator. Due to each chunk having exactly `chunk_size` elements, the compiler can often optimize the resulting code better than in the case of [`rchunks`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.rchunks). See [`rchunks`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.rchunks) for a variant of this iterator that also returns the remainder as a smaller chunk, and [`chunks_exact`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.chunks_exact) for the same iterator but starting at the beginning of the slice. If your `chunk_size` is a constant, consider using [`as_rchunks`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.as_rchunks) instead, which will give references to arrays of exactly that length, rather than slices. **Panics** Panics if `chunk_size` is zero. **Examples** ```rust let slice = ['l', 'o', 'r', 'e', 'm']; let mut iter = slice.rchunks_exact(2); assert_eq!(iter.next().unwrap(), &['e', 'm']); assert_eq!(iter.next().unwrap(), &['o', 'r']); assert!(iter.next().is_none()); assert_eq!(iter.remainder(), &['l']); ``` ```rust pub fn chunk_by(&self, pred: F) -> ChunkBy<'_, T, F> where F: FnMut(&T, &T) -> bool ``` Returns an iterator over the slice producing non-overlapping runs of elements using the predicate to separate them. The predicate is called for every pair of consecutive elements, meaning that it is called on `slice[0]` and `slice[1]`, followed by `slice[1]` and `slice[2]`, and so on. **Examples** ```rust let slice = &[1, 1, 1, 3, 3, 2, 2, 2]; let mut iter = slice.chunk_by(|a, b| a == b); assert_eq!(iter.next(), Some(&[1, 1, 1][..])); assert_eq!(iter.next(), Some(&[3, 3][..])); assert_eq!(iter.next(), Some(&[2, 2, 2][..])); assert_eq!(iter.next(), None); ``` This method can be used to extract the sorted subslices: ```rust let slice = &[1, 1, 2, 3, 2, 3, 2, 3, 4]; let mut iter = slice.chunk_by(|a, b| a <= b); assert_eq!(iter.next(), Some(&[1, 1, 2, 3][..])); assert_eq!(iter.next(), Some(&[2, 3][..])); assert_eq!(iter.next(), Some(&[2, 3, 4][..])); assert_eq!(iter.next(), None); ``` ```rust pub fn split_at(&self, mid: usize) -> (&[T], &[T]) ``` Divides one slice into two at an index. The first will contain all indices from `[0, mid)` (excluding the index `mid` itself) and the second will contain all indices from `[mid, len)` (excluding the index `len` itself). **Panics** Panics if `mid > len`. For a non-panicking alternative see [`split_at_checked`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.split_at_checked). **Examples** ```rust let v = ['a', 'b', 'c']; { let (left, right) = v.split_at(0); assert_eq!(left, []); assert_eq!(right, ['a', 'b', 'c']); } { let (left, right) = v.split_at(2); assert_eq!(left, ['a', 'b']); assert_eq!(right, ['c']); } { let (left, right) = v.split_at(3); assert_eq!(left, ['a', 'b', 'c']); assert_eq!(right, []); } ``` ```rust pub unsafe fn split_at_unchecked(&self, mid: usize) -> (&[T], &[T]) ``` Divides one slice into two at an index, without doing bounds checking. The first will contain all indices from `[0, mid)` (excluding the index `mid` itself) and the second will contain all indices from `[mid, len)` (excluding the index `len` itself). For a safe alternative see [`split_at`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.split_at). **Safety** Calling this method with an out-of-bounds index is *[undefined behavior](https://doc.rust-lang.org/reference/behavior-considered-undefined.html)* even if the resulting reference is not used. The caller has to ensure that `0 <= mid <= self.len()`. **Examples** ```rust let v = ['a', 'b', 'c']; unsafe { let (left, right) = v.split_at_unchecked(0); assert_eq!(left, []); assert_eq!(right, ['a', 'b', 'c']); } unsafe { let (left, right) = v.split_at_unchecked(2); assert_eq!(left, ['a', 'b']); assert_eq!(right, ['c']); } unsafe { let (left, right) = v.split_at_unchecked(3); assert_eq!(left, ['a', 'b', 'c']); assert_eq!(right, []); } ``` ```rust pub fn split_at_checked(&self, mid: usize) -> Option<(&[T], &[T])> ``` Divides one slice into two at an index, returning `None` if the slice is too short. If `mid ≤ len` returns a pair of slices where the first will contain all indices from `[0, mid)` (excluding the index `mid` itself) and the second will contain all indices from `[mid, len)` (excluding the index `len` itself). Otherwise, if `mid > len`, returns `None`. **Examples** ```rust let v = [1, -2, 3, -4, 5, -6]; { let (left, right) = v.split_at_checked(0).unwrap(); assert_eq!(left, []); assert_eq!(right, [1, -2, 3, -4, 5, -6]); } { let (left, right) = v.split_at_checked(2).unwrap(); assert_eq!(left, [1, -2]); assert_eq!(right, [3, -4, 5, -6]); } { let (left, right) = v.split_at_checked(6).unwrap(); assert_eq!(left, [1, -2, 3, -4, 5, -6]); assert_eq!(right, []); } assert_eq!(None, v.split_at_checked(7)); ``` ```rust pub fn split(&self, pred: F) -> Split<'_, T, F> where F: FnMut(&T) -> bool ``` Returns an iterator over subslices separated by elements that match `pred`. The matched element is not contained in the subslices. **Examples** ```rust let slice = [10, 40, 33, 20]; let mut iter = slice.split(|num| num % 3 == 0); assert_eq!(iter.next().unwrap(), &[10, 40]); assert_eq!(iter.next().unwrap(), &[20]); assert!(iter.next().is_none()); ``` If the first element is matched, an empty slice will be the first item returned by the iterator. Similarly, if the last element in the slice is matched, an empty slice will be the last item returned by the iterator: ```rust let slice = [10, 40, 33]; let mut iter = slice.split(|num| num % 3 == 0); assert_eq!(iter.next().unwrap(), &[10, 40]); assert_eq!(iter.next().unwrap(), &[]); assert!(iter.next().is_none()); ``` If two matched elements are directly adjacent, an empty slice will be present between them: ```rust let slice = [10, 6, 33, 20]; let mut iter = slice.split(|num| num % 3 == 0); assert_eq!(iter.next().unwrap(), &[10]); assert_eq!(iter.next().unwrap(), &[]); assert_eq!(iter.next().unwrap(), &[20]); assert!(iter.next().is_none()); ``` ```rust pub fn split_inclusive(&self, pred: F) -> SplitInclusive<'_, T, F> where F: FnMut(&T) -> bool ``` Returns an iterator over subslices separated by elements that match `pred`. The matched element is contained in the end of the previous subslice as a terminator. **Examples** ```rust let slice = [10, 40, 33, 20]; let mut iter = slice.split_inclusive(|num| num % 3 == 0); assert_eq!(iter.next().unwrap(), &[10, 40, 33]); assert_eq!(iter.next().unwrap(), &[20]); assert!(iter.next().is_none()); ``` If the last element of the slice is matched, that element will be considered the terminator of the preceding slice. That slice will be the last item returned by the iterator. ```rust let slice = [3, 10, 40, 33]; let mut iter = slice.split_inclusive(|num| num % 3 == 0); assert_eq!(iter.next().unwrap(), &[3]); assert_eq!(iter.next().unwrap(), &[10, 40, 33]); assert!(iter.next().is_none()); ``` ```rust pub fn rsplit(&self, pred: F) -> RSplit<'_, T, F> where F: FnMut(&T) -> bool ``` Returns an iterator over subslices separated by elements that match `pred`, starting at the end of the slice and working backwards. The matched element is not contained in the subslices. **Examples** ```rust let slice = [11, 22, 33, 0, 44, 55]; let mut iter = slice.rsplit(|num| *num == 0); assert_eq!(iter.next().unwrap(), &[44, 55]); assert_eq!(iter.next().unwrap(), &[11, 22, 33]); assert_eq!(iter.next(), None); ``` As with `split()`, if the first or last element is matched, an empty slice will be the first (or last) item returned by the iterator. ```rust let v = &[0, 1, 1, 2, 3, 5, 8]; let mut it = v.rsplit(|n| *n % 2 == 0); assert_eq!(it.next().unwrap(), &[]); assert_eq!(it.next().unwrap(), &[3, 5]); assert_eq!(it.next().unwrap(), &[1, 1]); assert_eq!(it.next().unwrap(), &[]); assert_eq!(it.next(), None); ``` ```rust pub fn splitn(&self, n: usize, pred: F) -> SplitN<'_, T, F> where F: FnMut(&T) -> bool ``` Returns an iterator over subslices separated by elements that match `pred`, limited to returning at most `n` items. The matched element is not contained in the subslices. The last element returned, if any, will contain the remainder of the slice. **Examples** Print the slice split once by numbers divisible by 3 (i.e., `[10, 40]`, `[20, 60, 50]`): ```rust let v = [10, 40, 30, 20, 60, 50]; for group in v.splitn(2, |num| *num % 3 == 0) { println!("{group:?}"); } ``` ```rust pub fn rsplitn(&self, n: usize, pred: F) -> RSplitN<'_, T, F> where F: FnMut(&T) -> bool ``` Returns an iterator over subslices separated by elements that match `pred` limited to returning at most `n` items. This starts at the end of the slice and works backwards. The matched element is not contained in the subslices. The last element returned, if any, will contain the remainder of the slice. **Examples** Print the slice split once, starting from the end, by numbers divisible by 3 (i.e., `[50]`, `[10, 40, 30, 20]`): ```rust let v = [10, 40, 30, 20, 60, 50]; for group in v.rsplitn(2, |num| *num % 3 == 0) { println!("{group:?}"); } ``` ```rust pub fn split_once(&self, pred: F) -> Option<(&[T], &[T])> where F: FnMut(&T) -> bool ``` 🔬This is a nightly-only experimental API. (`slice_split_once`) Splits the slice on the first element that matches the specified predicate. If any matching elements are present in the slice, returns the prefix before the match and suffix after. The matching element itself is not included. If no elements match, returns `None`. **Examples** ```rust #![feature(slice_split_once)] let s = [1, 2, 3, 2, 4]; assert_eq!(s.split_once(|&x| x == 2), Some(( &[1][..], &[3, 2, 4][..] ))); assert_eq!(s.split_once(|&x| x == 0), None); ``` ```rust pub fn rsplit_once(&self, pred: F) -> Option<(&[T], &[T])> where F: FnMut(&T) -> bool ``` 🔬This is a nightly-only experimental API. (`slice_split_once`) Splits the slice on the last element that matches the specified predicate. If any matching elements are present in the slice, returns the prefix before the match and suffix after. The matching element itself is not included. If no elements match, returns `None`. **Examples** ```rust #![feature(slice_split_once)] let s = [1, 2, 3, 2, 4]; assert_eq!(s.rsplit_once(|&x| x == 2), Some(( &[1, 2, 3][..], &[4][..] ))); assert_eq!(s.rsplit_once(|&x| x == 0), None); ``` ```rust pub fn contains(&self, x: &T) -> bool where T: PartialEq ``` Returns `true` if the slice contains an element with the given value. This operation is *O*(*n*). Note that if you have a sorted slice, [`binary_search`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.binary_search) may be faster. **Examples** ```rust let v = [10, 40, 30]; assert!(v.contains(&30)); assert!(!v.contains(&50)); ``` If you do not have a `&T`, but some other value that you can compare with one (for example, `String` implements `PartialEq`), you can use `iter().any`: ```rust let v = [String::from("hello"), String::from("world")]; // slice of `String` assert!(v.iter().any(|e| e == "hello")); // search with `&str` assert!(!v.iter().any(|e| e == "hi")); ``` ```rust pub fn starts_with(&self, needle: &[T]) -> bool where T: PartialEq ``` Returns `true` if `needle` is a prefix of the slice or equal to the slice. **Examples** ```rust let v = [10, 40, 30]; assert!(v.starts_with(&[10])); assert!(v.starts_with(&[10, 40])); assert!(v.starts_with(&v)); assert!(!v.starts_with(&[50])); assert!(!v.starts_with(&[10, 50])); ``` Always returns `true` if `needle` is an empty slice: ```rust let v = &[10, 40, 30]; assert!(v.starts_with(&[])); let v: &[u8] = &[]; assert!(v.starts_with(&[])); ``` ```rust pub fn ends_with(&self, needle: &[T]) -> bool where T: PartialEq ``` Returns `true` if `needle` is a suffix of the slice or equal to the slice. **Examples** ```rust let v = [10, 40, 30]; assert!(v.ends_with(&[30])); assert!(v.ends_with(&[40, 30])); assert!(v.ends_with(&v)); assert!(!v.ends_with(&[50])); assert!(!v.ends_with(&[50, 30])); ``` Always returns `true` if `needle` is an empty slice: ```rust let v = &[10, 40, 30]; assert!(v.ends_with(&[])); let v: &[u8] = &[]; assert!(v.ends_with(&[])); ``` ```rust pub fn strip_prefix

(&self, prefix: &P) -> Option<&[T]> where P: SlicePattern + ?Sized, T: PartialEq ``` Returns a subslice with the prefix removed. If the slice starts with `prefix`, returns the subslice after the prefix, wrapped in `Some`. If `prefix` is empty, simply returns the original slice. If `prefix` is equal to the original slice, returns an empty slice. If the slice does not start with `prefix`, returns `None`. **Examples** ```rust let v = &[10, 40, 30]; assert_eq!(v.strip_prefix(&[10]), Some(&[40, 30][..])); assert_eq!(v.strip_prefix(&[10, 40]), Some(&[30][..])); assert_eq!(v.strip_prefix(&[10, 40, 30]), Some(&[][..])); assert_eq!(v.strip_prefix(&[50]), None); assert_eq!(v.strip_prefix(&[10, 50]), None); let prefix : &str = "he"; assert_eq!(b"hello".strip_prefix(prefix.as_bytes()), Some(b"llo".as_ref())); ``` ```rust pub fn strip_suffix

(&self, suffix: &P) -> Option<&[T]> where P: SlicePattern + ?Sized, T: PartialEq ``` Returns a subslice with the suffix removed. If the slice ends with `suffix`, returns the subslice before the suffix, wrapped in `Some`. If `suffix` is empty, simply returns the original slice. If `suffix` is equal to the original slice, returns an empty slice. If the slice does not end with `suffix`, returns `None`. **Examples** ```rust let v = &[10, 40, 30]; assert_eq!(v.strip_suffix(&[30]), Some(&[10, 40][..])); assert_eq!(v.strip_suffix(&[40, 30]), Some(&[10][..])); assert_eq!(v.strip_suffix(&[10, 40, 30]), Some(&[][..])); assert_eq!(v.strip_suffix(&[50]), None); assert_eq!(v.strip_suffix(&[50, 30]), None); ``` ```rust pub fn strip_circumfix(&self, prefix: &P, suffix: &S) -> Option<&[T]> where T: PartialEq, S: SlicePattern + ?Sized, P: SlicePattern + ?Sized ``` Returns a subslice with the prefix and suffix removed. If the slice starts with `prefix`, ends with `suffix`, and the prefix and suffix don’t overlap, returns the subslice after the prefix and before the suffix, wrapped in `Some`. If the slice does not start with `prefix`, does not end with `suffix`, or the prefix and suffix overlap in the slice, returns `None`. **Examples** ```rust let v = &[10, 50, 40, 30]; assert_eq!(v.strip_circumfix(&[10], &[30]), Some(&[50, 40][..])); assert_eq!(v.strip_circumfix(&[10], &[40, 30]), Some(&[50][..])); assert_eq!(v.strip_circumfix(&[10, 50], &[40, 30]), Some(&[][..])); assert_eq!(v.strip_circumfix(&[50], &[30]), None); assert_eq!(v.strip_circumfix(&[10], &[40]), None); assert_eq!(v.strip_circumfix(&[], &[40, 30]), Some(&[10, 50][..])); assert_eq!(v.strip_circumfix(&[10, 50], &[]), Some(&[40, 30][..])); assert_eq!(v.strip_circumfix(&[10, 50, 40], &[50, 40, 30]), None); ``` ```rust pub fn trim_prefix

(&self, prefix: &P) -> &[T] where P: SlicePattern + ?Sized, T: PartialEq ``` 🔬This is a nightly-only experimental API. (`trim_prefix_suffix`) Returns a subslice with the optional prefix removed. If the slice starts with `prefix`, returns the subslice after the prefix. If `prefix` is empty or the slice does not start with `prefix`, simply returns the original slice. If `prefix` is equal to the original slice, returns an empty slice. **Examples** ```rust #![feature(trim_prefix_suffix)] let v = &[10, 40, 30]; // Prefix present - removes it assert_eq!(v.trim_prefix(&[10]), &[40, 30][..]); assert_eq!(v.trim_prefix(&[10, 40]), &[30][..]); assert_eq!(v.trim_prefix(&[10, 40, 30]), &[][..]); // Prefix absent - returns original slice assert_eq!(v.trim_prefix(&[50]), &[10, 40, 30][..]); assert_eq!(v.trim_prefix(&[10, 50]), &[10, 40, 30][..]); let prefix : &str = "he"; assert_eq!(b"hello".trim_prefix(prefix.as_bytes()), b"llo".as_ref()); ``` ```rust pub fn trim_suffix

(&self, suffix: &P) -> &[T] where P: SlicePattern + ?Sized, T: PartialEq ``` 🔬This is a nightly-only experimental API. (`trim_prefix_suffix`) Returns a subslice with the optional suffix removed. If the slice ends with `suffix`, returns the subslice before the suffix. If `suffix` is empty or the slice does not end with `suffix`, simply returns the original slice. If `suffix` is equal to the original slice, returns an empty slice. **Examples** ```rust #![feature(trim_prefix_suffix)] let v = &[10, 40, 30]; // Suffix present - removes it assert_eq!(v.trim_suffix(&[30]), &[10, 40][..]); assert_eq!(v.trim_suffix(&[40, 30]), &[10][..]); assert_eq!(v.trim_suffix(&[10, 40, 30]), &[][..]); // Suffix absent - returns original slice assert_eq!(v.trim_suffix(&[50]), &[10, 40, 30][..]); assert_eq!(v.trim_suffix(&[50, 30]), &[10, 40, 30][..]); ``` ```rust pub fn binary_search(&self, x: &T) -> Result where T: Ord ``` Binary searches this slice for a given element. If the slice is not sorted, the returned result is unspecified and meaningless. If the value is found then [`Result::Ok`](https://doc.rust-lang.org/1.99.1/core/result/enum.Result.html#variant.Ok) is returned, containing the index of the matching element. If there are multiple matches, then any one of the matches could be returned. The index is chosen deterministically, but is subject to change in future versions of Rust. If the value is not found then [`Result::Err`](https://doc.rust-lang.org/1.99.1/core/result/enum.Result.html#variant.Err) is returned, containing the index where a matching element could be inserted while maintaining sorted order. See also [`binary_search_by`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.binary_search_by), [`binary_search_by_key`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.binary_search_by_key), and [`partition_point`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.partition_point). **Examples** Looks up a series of four elements. The first is found, with a uniquely determined position; the second and third are not found; the fourth could match any position in `[1, 4]`. ```rust let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; assert_eq!(s.binary_search(&13), Ok(9)); assert_eq!(s.binary_search(&4), Err(7)); assert_eq!(s.binary_search(&100), Err(13)); let r = s.binary_search(&1); assert!(match r { Ok(1..=4) => true, _ => false, }); ``` If you want to find that whole *range* of matching items, rather than an arbitrary matching one, that can be done using [`partition_point`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.partition_point): ```rust let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; let low = s.partition_point(|x| x < &1); assert_eq!(low, 1); let high = s.partition_point(|x| x <= &1); assert_eq!(high, 5); let r = s.binary_search(&1); assert!((low..high).contains(&r.unwrap())); assert!(s[..low].iter().all(|&x| x < 1)); assert!(s[low..high].iter().all(|&x| x == 1)); assert!(s[high..].iter().all(|&x| x > 1)); // For something not found, the "range" of equal items is empty assert_eq!(s.partition_point(|x| x < &11), 9); assert_eq!(s.partition_point(|x| x <= &11), 9); assert_eq!(s.binary_search(&11), Err(9)); ``` If you want to insert an item to a sorted vector, while maintaining sort order, consider using [`partition_point`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.partition_point): ```rust let mut s = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; let num = 42; let idx = s.partition_point(|&x| x <= num); // If `num` is unique, `s.partition_point(|&x| x < num)` (with `<`) is equivalent to // `s.binary_search(&num).unwrap_or_else(|x| x)`, but using `<=` will allow `insert` // to shift less elements. s.insert(idx, num); assert_eq!(s, [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]); ``` ```rust pub fn binary_search_by<'a, F>(&'a self, f: F) -> Result where F: FnMut(&'a T) -> Ordering ``` Binary searches this slice with a comparator function. The comparator function should return an order code that indicates whether its argument is `Less`, `Equal` or `Greater` the desired target. If the slice is not sorted or if the comparator function does not implement an order consistent with the sort order of the underlying slice, the returned result is unspecified and meaningless. If the value is found then [`Result::Ok`](https://doc.rust-lang.org/1.99.1/core/result/enum.Result.html#variant.Ok) is returned, containing the index of the matching element. If there are multiple matches, then any one of the matches could be returned. The index is chosen deterministically, but is subject to change in future versions of Rust. If the value is not found then [`Result::Err`](https://doc.rust-lang.org/1.99.1/core/result/enum.Result.html#variant.Err) is returned, containing the index where a matching element could be inserted while maintaining sorted order. See also [`binary_search`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.binary_search), [`binary_search_by_key`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.binary_search_by_key), and [`partition_point`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.partition_point). **Examples** Looks up a series of four elements. The first is found, with a uniquely determined position; the second and third are not found; the fourth could match any position in `[1, 4]`. ```rust let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; let seek = 13; assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Ok(9)); let seek = 4; assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Err(7)); let seek = 100; assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Err(13)); let seek = 1; let r = s.binary_search_by(|probe| probe.cmp(&seek)); assert!(match r { Ok(1..=4) => true, _ => false, }); ``` ```rust pub fn binary_search_by_key<'a, B, F>( &'a self, b: &B, f: F, ) -> Result where F: FnMut(&'a T) -> B, B: Ord ``` Binary searches this slice with a key extraction function. Assumes that the slice is sorted by the key, for instance with [`sort_by_key`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.sort_by_key) using the same key extraction function. If the slice is not sorted by the key, the returned result is unspecified and meaningless. If the value is found then [`Result::Ok`](https://doc.rust-lang.org/1.99.1/core/result/enum.Result.html#variant.Ok) is returned, containing the index of the matching element. If there are multiple matches, then any one of the matches could be returned. The index is chosen deterministically, but is subject to change in future versions of Rust. If the value is not found then [`Result::Err`](https://doc.rust-lang.org/1.99.1/core/result/enum.Result.html#variant.Err) is returned, containing the index where a matching element could be inserted while maintaining sorted order. See also [`binary_search`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.binary_search), [`binary_search_by`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.binary_search_by), and [`partition_point`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.partition_point). **Examples** Looks up a series of four elements in a slice of pairs sorted by their second elements. The first is found, with a uniquely determined position; the second and third are not found; the fourth could match any position in `[1, 4]`. ```rust let s = [(0, 0), (2, 1), (4, 1), (5, 1), (3, 1), (1, 2), (2, 3), (4, 5), (5, 8), (3, 13), (1, 21), (2, 34), (4, 55)]; assert_eq!(s.binary_search_by_key(&13, |&(a, b)| b), Ok(9)); assert_eq!(s.binary_search_by_key(&4, |&(a, b)| b), Err(7)); assert_eq!(s.binary_search_by_key(&100, |&(a, b)| b), Err(13)); let r = s.binary_search_by_key(&1, |&(a, b)| b); assert!(match r { Ok(1..=4) => true, _ => false, }); ``` ```rust pub unsafe fn align_to(&self) -> (&[T], &[U], &[T]) ``` Transmutes the slice to a slice of another type, ensuring alignment of the types is maintained. This method splits the slice into three distinct slices: prefix, correctly aligned middle slice of a new type, and the suffix slice. The middle part will be as big as possible under the given alignment constraint and element size. This method has no purpose when either input element `T` or output element `U` are zero-sized and will return the original slice without splitting anything. **Safety** This method is essentially a `transmute` with respect to the elements in the returned middle slice, so all the usual caveats pertaining to `transmute::` also apply here. **Examples** Basic usage: ```rust unsafe { let bytes: [u8; 7] = [1, 2, 3, 4, 5, 6, 7]; let (prefix, shorts, suffix) = bytes.align_to::(); // less_efficient_algorithm_for_bytes(prefix); // more_efficient_algorithm_for_aligned_shorts(shorts); // less_efficient_algorithm_for_bytes(suffix); } ``` ```rust pub fn as_simd(&self) -> (&[T], &[Simd], &[T]) where Simd: AsRef<[T; LANES]>, T: SimdElement ``` 🔬This is a nightly-only experimental API. (`portable_simd`) Splits a slice into a prefix, a middle of aligned SIMD types, and a suffix. This is a safe wrapper around [`slice::align_to`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.align_to), so inherits the same guarantees as that method. **Panics** This will panic if the size of the SIMD type is different from `LANES` times that of the scalar. At the time of writing, the trait restrictions on `Simd` keeps that from ever happening, as only power-of-two numbers of lanes are supported. It’s possible that, in the future, those restrictions might be lifted in a way that would make it possible to see panics from this method for something like `LANES == 3`. **Examples** ```rust #![feature(portable_simd)] use core::simd::prelude::*; let short = &[1, 2, 3]; let (prefix, middle, suffix) = short.as_simd::<4>(); assert_eq!(middle, []); // Not enough elements for anything in the middle // They might be split in any possible way between prefix and suffix let it = prefix.iter().chain(suffix).copied(); assert_eq!(it.collect::>(), vec![1, 2, 3]); fn basic_simd_sum(x: &[f32]) -> f32 { use std::ops::Add; let (prefix, middle, suffix) = x.as_simd(); let sums = f32x4::from_array([ prefix.iter().copied().sum(), 0.0, 0.0, suffix.iter().copied().sum(), ]); let sums = middle.iter().copied().fold(sums, f32x4::add); sums.reduce_sum() } let numbers: Vec = (1..101).map(|x| x as _).collect(); assert_eq!(basic_simd_sum(&numbers[1..99]), 4949.0); ``` ```rust pub fn is_sorted(&self) -> bool where T: PartialOrd ``` Checks if the elements of this slice are sorted. That is, for each element `a` and its following element `b`, `a <= b` must hold. If the slice yields exactly zero or one element, `true` is returned. Note that if `Self::Item` is only `PartialOrd`, but not `Ord`, the above definition implies that this function returns `false` if any two consecutive items are not comparable. **Examples** ```rust let empty: [i32; 0] = []; assert!([1, 2, 2, 9].is_sorted()); assert!(![1, 3, 2, 4].is_sorted()); assert!([0].is_sorted()); assert!(empty.is_sorted()); assert!(![0.0, 1.0, f32::NAN].is_sorted()); ``` ```rust pub fn is_sorted_by<'a, F>(&'a self, compare: F) -> bool where F: FnMut(&'a T, &'a T) -> bool ``` Checks if the elements of this slice are sorted using the given comparator function. Instead of using `PartialOrd::partial_cmp`, this function uses the given `compare` function to determine whether two elements are to be considered in sorted order. **Examples** ```rust assert!([1, 2, 2, 9].is_sorted_by(|a, b| a <= b)); assert!(![1, 2, 2, 9].is_sorted_by(|a, b| a < b)); assert!([0].is_sorted_by(|a, b| true)); assert!([0].is_sorted_by(|a, b| false)); let empty: [i32; 0] = []; assert!(empty.is_sorted_by(|a, b| false)); assert!(empty.is_sorted_by(|a, b| true)); ``` ```rust pub fn is_sorted_by_key<'a, F, K>(&'a self, f: F) -> bool where F: FnMut(&'a T) -> K, K: PartialOrd ``` Checks if the elements of this slice are sorted using the given key extraction function. Instead of comparing the slice’s elements directly, this function compares the keys of the elements, as determined by `f`. Apart from that, it’s equivalent to [`is_sorted`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.is_sorted); see its documentation for more information. **Examples** ```rust assert!(["c", "bb", "aaa"].is_sorted_by_key(|s| s.len())); assert!(![-2i32, -1, 0, 3].is_sorted_by_key(|n| n.abs())); ``` ```rust pub fn partition_point

(&self, pred: P) -> usize where P: FnMut(&T) -> bool ``` Returns the index of the partition point according to the given predicate (the index of the first element of the second partition). The slice is assumed to be partitioned according to the given predicate. This means that all elements for which the predicate returns true are at the start of the slice and all elements for which the predicate returns false are at the end. For example, `[7, 15, 3, 5, 4, 12, 6]` is partitioned under the predicate `x % 2 != 0` (all odd numbers are at the start, all even at the end). If this slice is not partitioned, the returned result is unspecified and meaningless, as this method performs a kind of binary search. See also [`binary_search`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.binary_search), [`binary_search_by`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.binary_search_by), and [`binary_search_by_key`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.binary_search_by_key). **Examples** ```rust let v = [1, 2, 3, 3, 5, 6, 7]; let i = v.partition_point(|&x| x < 5); assert_eq!(i, 4); assert!(v[..i].iter().all(|&x| x < 5)); assert!(v[i..].iter().all(|&x| !(x < 5))); ``` If all elements of the slice match the predicate, including if the slice is empty, then the length of the slice will be returned: ```rust let a = [2, 4, 8]; assert_eq!(a.partition_point(|x| x < &100), a.len()); let a: [i32; 0] = []; assert_eq!(a.partition_point(|x| x < &100), 0); ``` If you want to insert an item to a sorted vector, while maintaining sort order: ```rust let mut s = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; let num = 42; let idx = s.partition_point(|&x| x <= num); s.insert(idx, num); assert_eq!(s, [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]); ``` ```rust pub fn element_offset(&self, element: &T) -> Option ``` Returns the index that an element reference points to. Returns `None` if `element` does not point to the start of an element within the slice. This method is useful for extending slice iterators like [`slice::split`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.split). Note that this uses pointer arithmetic and **does not compare elements**. To find the index of an element via comparison, use [`.iter().position()`](https://doc.rust-lang.org/1.99.1/core/iter/traits/iterator/trait.Iterator.html#method.position) instead. **Panics** Panics if `T` is zero-sized. **Examples** Basic usage: ```rust let nums: &[u32] = &[1, 7, 1, 1]; let num = &nums[2]; assert_eq!(num, &1); assert_eq!(nums.element_offset(num), Some(2)); ``` Returning `None` with an unaligned element: ```rust let arr: &[[u32; 2]] = &[[0, 1], [2, 3]]; let flat_arr: &[u32] = arr.as_flattened(); let ok_elm: &[u32; 2] = flat_arr[0..2].try_into().unwrap(); let weird_elm: &[u32; 2] = flat_arr[1..3].try_into().unwrap(); assert_eq!(ok_elm, &[0, 1]); assert_eq!(weird_elm, &[1, 2]); assert_eq!(arr.element_offset(ok_elm), Some(0)); // Points to element 0 assert_eq!(arr.element_offset(weird_elm), None); // Points between element 0 and 1 ``` ```rust pub fn subslice_range(&self, subslice: &[T]) -> Option> ``` Returns the range of indices that a subslice points to. Returns `None` if `subslice` does not point within the slice or if it is not aligned with the elements in the slice. This method **does not compare elements**. Instead, this method finds the location in the slice that `subslice` was obtained from. To find the index of a subslice via comparison, instead use [`.windows()`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.windows)[`.position()`](https://doc.rust-lang.org/1.99.1/core/iter/traits/iterator/trait.Iterator.html#method.position). This method is useful for extending slice iterators like [`slice::split`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.split). Note that this may return a false positive (either `Some(0..0)` or `Some(self.len()..self.len())`) if `subslice` has a length of zero and points to the beginning or end of another, separate, slice. **Panics** Panics if `T` is zero-sized. **Examples** Basic usage: ```rust use core::range::Range; let nums = &[0, 5, 10, 0, 0, 5]; let mut iter = nums .split(|t| *t == 0) .map(|n| nums.subslice_range(n).unwrap()); assert_eq!(iter.next(), Some(Range { start: 0, end: 0 })); assert_eq!(iter.next(), Some(Range { start: 1, end: 3 })); assert_eq!(iter.next(), Some(Range { start: 4, end: 4 })); assert_eq!(iter.next(), Some(Range { start: 5, end: 6 })); ``` ```rust pub fn as_slice(&self) -> &[T] ``` 🔬This is a nightly-only experimental API. (`str_as_str`) Returns the same slice `&[T]`. This method is redundant when used directly on `&[T]`, but it helps dereferencing other “container” types to slices, for example `Box<[T]>` or `Arc<[T]>`. ```rust pub fn utf8_chunks(&self) -> Utf8Chunks<'_> ``` Creates an iterator over the contiguous valid UTF-8 ranges of this slice, and the non-UTF-8 fragments in between. See the [`Utf8Chunk`](https://doc.rust-lang.org/1.99.1/core/str/lossy/struct.Utf8Chunk.html) type for documentation of the items yielded by this iterator. **Examples** This function formats arbitrary but mostly-UTF-8 bytes into Rust source code in the form of a C-string literal (`c"..."`). ```rust use std::fmt::Write as _; pub fn cstr_literal(bytes: &[u8]) -> String { let mut repr = String::new(); repr.push_str("c\""); for chunk in bytes.utf8_chunks() { for ch in chunk.valid().chars() { // Escapes \0, \t, \r, \n, \\, \', \", and uses \u{...} for non-printable characters. write!(repr, "{}", ch.escape_debug()).unwrap(); } for byte in chunk.invalid() { write!(repr, "\\x{:02X}", byte).unwrap(); } } repr.push('"'); repr } fn main() { let lit = cstr_literal(b"\xferris the \xf0\x9f\xa6\x80\x07"); let expected = stringify!(c"\xFErris the 🦀\u{7}"); assert_eq!(lit, expected); } ``` ```rust pub fn to_vec(&self) -> Vec where T: Clone ``` Copies `self` into a new `Vec`. **Examples** ```rust let s = [10, 40, 30]; let x = s.to_vec(); // Here, `s` and `x` can be modified independently. ``` ```rust pub fn to_vec_in(&self, alloc: A) -> Vec where A: Allocator, T: Clone ``` 🔬This is a nightly-only experimental API. (`allocator_api`) Copies `self` into a new `Vec` with an allocator. **Examples** ```rust #![feature(allocator_api)] use std::alloc::System; let s = [10, 40, 30]; let x = s.to_vec_in(System); // Here, `s` and `x` can be modified independently. ``` ```rust pub fn repeat(&self, n: usize) -> Vec where T: Copy ``` Creates a vector by copying a slice `n` times. **Panics** This function will panic if the capacity would overflow. **Examples** ```rust assert_eq!([1, 2].repeat(3), vec![1, 2, 1, 2, 1, 2]); ``` A panic upon overflow: ```rust // this will panic at runtime b"0123456789abcdef".repeat(usize::MAX); ``` ```rust pub fn concat(&self) -> <[T] as Concat>::Output where [T]: Concat, Item: ?Sized ``` Flattens a slice of `T` into a single value `Self::Output`. **Examples** ```rust assert_eq!(["hello", "world"].concat(), "helloworld"); assert_eq!([[1, 2], [3, 4]].concat(), [1, 2, 3, 4]); ``` ```rust pub fn join( &self, sep: Separator, ) -> <[T] as Join>::Output where [T]: Join ``` Flattens a slice of `T` into a single value `Self::Output`, placing a given separator between each. **Examples** ```rust assert_eq!(["hello", "world"].join(" "), "hello world"); assert_eq!([[1, 2], [3, 4]].join(&0), [1, 2, 0, 3, 4]); assert_eq!([[1, 2], [3, 4]].join(&[0, 0][..]), [1, 2, 0, 0, 3, 4]); ``` ```rust pub fn connect( &self, sep: Separator, ) -> <[T] as Join>::Output where [T]: Join ``` 👎Deprecated since 1.3.0: renamed to join Flattens a slice of `T` into a single value `Self::Output`, placing a given separator between each. **Examples** ```rust assert_eq!(["hello", "world"].connect(" "), "hello world"); assert_eq!([[1, 2], [3, 4]].connect(&0), [1, 2, 0, 3, 4]); ``` ```rust pub fn to_ascii_uppercase(&self) -> Vec ``` Returns a vector containing a copy of this slice where each byte is mapped to its ASCII upper case equivalent. ASCII letters ‘a’ to ‘z’ are mapped to ‘A’ to ‘Z’, but non-ASCII letters are unchanged. To uppercase the value in-place, use [`make_ascii_uppercase`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.make_ascii_uppercase). ```rust pub fn to_ascii_lowercase(&self) -> Vec ``` Returns a vector containing a copy of this slice where each byte is mapped to its ASCII lower case equivalent. ASCII letters ‘A’ to ‘Z’ are mapped to ‘a’ to ‘z’, but non-ASCII letters are unchanged. To lowercase the value in-place, use [`make_ascii_lowercase`](https://doc.rust-lang.org/1.99.1/std/primitive.slice.html#method.make_ascii_lowercase). #### Trait Implementations - `impl Clone for DeviceName` - `impl Copy for DeviceName` - `impl Debug for DeviceName` - `impl Deref for DeviceName` - `impl Eq for DeviceName` - `impl PartialEq for DeviceName` - `impl StructuralPartialEq for DeviceName` #### Auto Trait Implementations - `impl Freeze for DeviceName` - `impl RefUnwindSafe for DeviceName` - `impl Send for DeviceName` - `impl Sync for DeviceName` - `impl Unpin for DeviceName` - `impl UnsafeUnpin for DeviceName` - `impl UnwindSafe for DeviceName` ### struct `nuclei::net::OwnedReadHalf` https://nuclei.rs/api/nuclei/net/struct.OwnedReadHalf.html ```rust pub struct OwnedReadHalf(/* private fields */); ``` The read half of a stream, owning it with the write half. #### Implementations `impl OwnedReadHalf` ```rust pub fn reunite( self, other: OwnedWriteHalf, ) -> Result, ReuniteError> ``` The stream again, from its two halves. **Errors** When `other` is a half of another stream; both are given back. #### Trait Implementations - `impl AsRef> for OwnedReadHalf` - `impl AsyncRead for OwnedReadHalf where for<'x> &'x Handle: AsyncRead` - `impl Debug for OwnedReadHalf` #### Auto Trait Implementations - `impl !RefUnwindSafe for OwnedReadHalf` - `impl !UnwindSafe for OwnedReadHalf` - `impl Freeze for OwnedReadHalf` - `impl Send for OwnedReadHalf where S: Sync + Send` - `impl Sync for OwnedReadHalf where S: Sync + Send` - `impl Unpin for OwnedReadHalf` - `impl UnsafeUnpin for OwnedReadHalf` ### struct `nuclei::net::OwnedWriteHalf` https://nuclei.rs/api/nuclei/net/struct.OwnedWriteHalf.html ```rust pub struct OwnedWriteHalf(/* private fields */); ``` The write half of a stream, owning it with the read half. #### Implementations `impl OwnedWriteHalf` ```rust pub fn reunite( self, other: OwnedReadHalf, ) -> Result, ReuniteError> ``` The stream again, from its two halves. **Errors** When `other` is a half of another stream; both are given back. #### Trait Implementations - `impl AsRef> for OwnedWriteHalf` - `impl AsyncWrite for OwnedWriteHalf where for<'x> &'x Handle: AsyncWrite` - `impl Debug for OwnedWriteHalf` #### Auto Trait Implementations - `impl !RefUnwindSafe for OwnedWriteHalf` - `impl !UnwindSafe for OwnedWriteHalf` - `impl Freeze for OwnedWriteHalf` - `impl Send for OwnedWriteHalf where S: Sync + Send` - `impl Sync for OwnedWriteHalf where S: Sync + Send` - `impl Unpin for OwnedWriteHalf` - `impl UnsafeUnpin for OwnedWriteHalf` ### struct `nuclei::net::ReadHalf` https://nuclei.rs/api/nuclei/net/struct.ReadHalf.html ```rust pub struct ReadHalf<'a, S>(/* private fields */); ``` The read half of a stream, borrowed from it. #### Trait Implementations - `impl AsRef> for ReadHalf<'_, S>` - `impl<'a, S> AsyncRead for ReadHalf<'a, S> where for<'x> &'x Handle: AsyncRead` - `impl<'a, S: Debug> Debug for ReadHalf<'a, S>` #### Auto Trait Implementations - `impl<'a, S> !RefUnwindSafe for ReadHalf<'a, S>` - `impl<'a, S> !UnwindSafe for ReadHalf<'a, S>` - `impl<'a, S> Freeze for ReadHalf<'a, S>` - `impl<'a, S> Send for ReadHalf<'a, S> where S: Sync` - `impl<'a, S> Sync for ReadHalf<'a, S> where S: Sync` - `impl<'a, S> Unpin for ReadHalf<'a, S>` - `impl<'a, S> UnsafeUnpin for ReadHalf<'a, S>` ### struct `nuclei::net::Released` https://nuclei.rs/api/nuclei/net/struct.Released.html ```rust pub struct Released> { /* private fields */ } ``` The buffer of a [`TcpStream::write_zero_copy`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.write_zero_copy), as a future that resolves to it once the kernel let go of every byte. For a send the kernel did not copy, that is once the peer acknowledged the bytes, which may be long after the write ended. It may be polled from any thread, or dropped: the buffer is then dropped once the kernel let go of it, never before. A write the kernel copied gives one that is ready at once. The buffer comes back even after the runtime that sent it shut down: a keeper on the blocking pool takes over the completions of its worker’s ring then, and lets go of the ring once the kernel let go of every buffer. #### Trait Implementations - `impl Debug for Released` - `impl Future for Released where B: IoBuf` #### Auto Trait Implementations - `impl> !RefUnwindSafe for Released` - `impl> !UnwindSafe for Released` - `impl Freeze for Released` - `impl Send for Released` - `impl Sync for Released` - `impl Unpin for Released` - `impl UnsafeUnpin for Released` ### struct `nuclei::net::ReuniteError` https://nuclei.rs/api/nuclei/net/struct.ReuniteError.html ```rust pub struct ReuniteError(pub OwnedReadHalf, pub OwnedWriteHalf); ``` Two halves of different streams, given back by [`OwnedReadHalf::reunite`](https://nuclei.rs/api/nuclei/net/struct.OwnedReadHalf.html#method.reunite). #### Tuple Fields `0: OwnedReadHalf` `1: OwnedWriteHalf` #### Trait Implementations - `impl Debug for ReuniteError` - `impl Display for ReuniteError` - `impl Error for ReuniteError` #### Auto Trait Implementations - `impl !RefUnwindSafe for ReuniteError` - `impl !UnwindSafe for ReuniteError` - `impl Freeze for ReuniteError` - `impl Send for ReuniteError where S: Sync + Send` - `impl Sync for ReuniteError where S: Sync + Send` - `impl Unpin for ReuniteError` - `impl UnsafeUnpin for ReuniteError` ### struct `nuclei::net::TcpKeepalive` https://nuclei.rs/api/nuclei/net/struct.TcpKeepalive.html ```rust pub struct TcpKeepalive { pub time: Option, pub interval: Option, pub retries: Option, } ``` When an idle connection’s keepalive probes start, how far apart they go, and how many unanswered ones drop the connection. A field left `None` keeps the system’s value. Times are whole seconds, as the system takes them: a part of one counts as one more. ```rust use std::time::Duration; use nuclei::net::{TcpKeepalive, TcpSocket}; let socket = TcpSocket::new_v4()?; socket.set_keepalive_timing(TcpKeepalive { time: Some(Duration::from_secs(60)), interval: Some(Duration::from_secs(10)), retries: Some(5), })?; assert!(socket.keepalive()?); ``` #### Fields `time: Option` How long the connection is idle before the first probe. `interval: Option` How long after an unanswered probe the next one goes. `retries: Option` How many unanswered probes drop the connection. #### Trait Implementations - `impl Clone for TcpKeepalive` - `impl Copy for TcpKeepalive` - `impl Debug for TcpKeepalive` - `impl Default for TcpKeepalive` - `impl Eq for TcpKeepalive` - `impl PartialEq for TcpKeepalive` - `impl StructuralPartialEq for TcpKeepalive` #### Auto Trait Implementations - `impl Freeze for TcpKeepalive` - `impl RefUnwindSafe for TcpKeepalive` - `impl Send for TcpKeepalive` - `impl Sync for TcpKeepalive` - `impl Unpin for TcpKeepalive` - `impl UnsafeUnpin for TcpKeepalive` - `impl UnwindSafe for TcpKeepalive` ### struct `nuclei::net::TcpSocket` https://nuclei.rs/api/nuclei/net/struct.TcpSocket.html ```rust pub struct TcpSocket { /* private fields */ } ``` A TCP socket to set up before it connects or listens. ```rust use nuclei::net::TcpSocket; let socket = TcpSocket::new_v4()?; socket.set_reuseaddr(true)?; socket.bind("127.0.0.1:0".parse().unwrap())?; let addr = socket.local_addr()?; let listener = socket.listen(128)?; let client = TcpSocket::new_v4()?; client.set_nodelay(true)?; let stream = client.connect(addr).await?; let (_peer, _) = listener.accept().await?; assert!(stream.nodelay()?); ``` #### Implementations `impl TcpSocket` ```rust pub fn set_reuseaddr(&self, reuseaddr: bool) -> Result<()> ``` Sets `SO_REUSEADDR`: the socket may bind an address still held by a connection that is closing. ```rust pub fn reuseaddr(&self) -> Result ``` Whether `SO_REUSEADDR` is set. ```rust pub fn set_reuseport(&self, reuseport: bool) -> Result<()> ``` Sets `SO_REUSEPORT`: several sockets may bind the same address and port, and the system shares what comes among them. ```rust pub fn reuseport(&self) -> Result ``` Whether `SO_REUSEPORT` is set. ```rust pub fn set_send_buffer_size(&self, size: u32) -> Result<()> ``` Sets the size of the system’s send buffer (`SO_SNDBUF`); the system may round it (Linux doubles it). ```rust pub fn send_buffer_size(&self) -> Result ``` The size of the system’s send buffer (`SO_SNDBUF`). ```rust pub fn set_recv_buffer_size(&self, size: u32) -> Result<()> ``` Sets the size of the system’s receive buffer (`SO_RCVBUF`); the system may round it (Linux doubles it). ```rust pub fn recv_buffer_size(&self) -> Result ``` The size of the system’s receive buffer (`SO_RCVBUF`). ```rust pub fn set_tos(&self, tos: u32) -> Result<()> ``` Sets the type of service of the socket’s IPv4 packets (`IP_TOS`). ```rust pub fn tos(&self) -> Result ``` The type of service of the socket’s IPv4 packets (`IP_TOS`). ```rust pub fn set_tclass_v6(&self, tclass: u32) -> Result<()> ``` Sets the traffic class of the socket’s IPv6 packets (`IPV6_TCLASS`). ```rust pub fn tclass_v6(&self) -> Result ``` The traffic class of the socket’s IPv6 packets (`IPV6_TCLASS`). ```rust pub fn set_only_v6(&self, only_v6: bool) -> Result<()> ``` Sets `IPV6_V6ONLY` on an IPv6 socket: with `true` it takes IPv6 alone, else IPv4 too, through addresses mapped into IPv6. **Errors** As `setsockopt(2)`: an IPv4 socket has no such option, and a bound one may no longer change it. ```rust pub fn only_v6(&self) -> Result ``` Whether `IPV6_V6ONLY` is set. **Errors** As `getsockopt(2)`: an IPv4 socket has no such option. ```rust pub fn bind_device(&self, interface: Option<&[u8]>) -> Result<()> ``` Binds the socket to the network interface named `interface` (`SO_BINDTODEVICE`), or, with `None`, to none. ```rust pub fn device(&self) -> Result> ``` The network interface the socket is bound to, if any (`SO_BINDTODEVICE`). `impl TcpSocket` ```rust pub fn new_v4() -> Result ``` A new IPv4 TCP socket. **Errors** When the system has no socket to give. ```rust pub fn new_v6() -> Result ``` A new IPv6 TCP socket. **Errors** When the system has no socket to give. ```rust pub fn set_keepalive(&self, keepalive: bool) -> Result<()> ``` Sets `SO_KEEPALIVE`: the system probes an idle connection. ```rust pub fn keepalive(&self) -> Result ``` Whether `SO_KEEPALIVE` is set. ```rust pub fn set_linger(&self, linger: Option) -> Result<()> ``` Sets `SO_LINGER`: with `Some(time)` a close waits up to `time` (whole seconds) for unsent data; with `None` it returns at once and the system sends what is left. ```rust pub fn set_zero_linger(&self) -> Result<()> ``` Sets `SO_LINGER` to zero: a close drops unsent data and resets the connection. ```rust pub fn linger(&self) -> Result> ``` `SO_LINGER`: how long a close waits for unsent data, `None` if it does not wait. ```rust pub fn set_nodelay(&self, nodelay: bool) -> Result<()> ``` Sets `TCP_NODELAY`: small writes go out at once, not gathered. ```rust pub fn nodelay(&self) -> Result ``` Whether `TCP_NODELAY` is set. ```rust pub fn local_addr(&self) -> Result ``` The address the socket is bound to. ```rust pub fn take_error(&self) -> Result> ``` The socket’s pending error (`SO_ERROR`), taken. ```rust pub fn bind(&self, addr: SocketAddr) -> Result<()> ``` Binds the socket to `addr`. **Errors** As `bind(2)`: the address is in use, or not this host’s. ```rust pub async fn connect(self, addr: SocketAddr) -> Result ``` Connects the socket to `addr`, as a stream. **Errors** As `connect(2)`: refused, unreachable, or timed out. ```rust pub fn listen(self, backlog: u32) -> Result ``` Makes the socket a listener, with room for `backlog` connections not accepted yet. **Errors** As `listen(2)`; a socket not bound gets an address of the system’s choosing on unix, and an error on Windows. ```rust pub fn from_std_stream(stream: TcpStream) -> TcpSocket ``` Takes std’s stream over as a socket to set up, connected or not. `impl TcpSocket` ```rust pub fn set_keepalive_timing(&self, keepalive: TcpKeepalive) -> Result<()> ``` Turns keepalive probes on (`SO_KEEPALIVE`), timed as `keepalive` says (`TCP_KEEPIDLE`, `TCP_KEEPINTVL`, `TCP_KEEPCNT`; macOS calls the first `TCP_KEEPALIVE`). **Errors** `Unsupported` where the system has no such options, `InvalidInput` for a value past what it takes, and what `setsockopt(2)` answers (a zero time or count). ```rust pub fn keepalive_timing(&self) -> Result ``` The keepalive’s timing: the system’s values where none was set. **Errors** `Unsupported` where the system has no such options. ```rust pub fn set_user_timeout(&self, timeout: Option) -> Result<()> ``` Sets `TCP_USER_TIMEOUT` (Linux): how long sent bytes may go unacknowledged before the connection is dropped, in whole milliseconds; `None` or zero leaves it to the system. **Errors** `Unsupported` off Linux, `InvalidInput` for a time past what the system takes. ```rust pub fn user_timeout(&self) -> Result> ``` `TCP_USER_TIMEOUT` (Linux), `None` where the system’s own applies. **Errors** `Unsupported` off Linux. `impl TcpSocket` ```rust pub fn set_incoming_cpu(&self, cpu: u32) -> Result<()> ``` Sets `SO_INCOMING_CPU` (Linux): the CPU whose connections this listener takes among listeners sharing a port with `SO_REUSEPORT`, so each core accepts the connections its own queues received. **Errors** `Unsupported` off Linux, `InvalidInput` for a CPU past what the system takes. ```rust pub fn incoming_cpu(&self) -> Result> ``` `SO_INCOMING_CPU` (Linux): the CPU set, or the last to handle the socket’s packets; `None` before either. **Errors** `Unsupported` off Linux. ```rust pub fn set_fastopen(&self, queue: u32) -> Result<()> ``` Sets `TCP_FASTOPEN` on a socket that will listen: connections may bring data with their handshake. Linux keeps up to `queue` such handshakes waiting; macOS, FreeBSD and Windows take it as on (above zero) or off. **Errors** `Unsupported` where the system has no fast open, `InvalidInput` for a queue past what it takes, and what `setsockopt(2)` answers where the system turned fast open off. ```rust pub fn fastopen(&self) -> Result ``` `TCP_FASTOPEN`: the queue’s length on Linux, and 1 or 0 where the system takes it as on or off. **Errors** `Unsupported` where the system has no fast open. ```rust pub fn set_defer_accept(&self, wait: Option) -> Result<()> ``` Sets `TCP_DEFER_ACCEPT` (Linux) on a socket that will listen: a connection is handed to `accept` only once its first data came, or `wait` passed (whole seconds, which the kernel rounds up to its retransmission steps); `None` hands each over at once. **Errors** `Unsupported` off Linux, `InvalidInput` for a time past what the system takes. ```rust pub fn defer_accept(&self) -> Result> ``` `TCP_DEFER_ACCEPT` (Linux): how long a connection with no data waits, as the kernel rounded it; `None` if connections are handed over at once. **Errors** `Unsupported` off Linux. #### Trait Implementations - `impl AsFd for TcpSocket` - `impl AsRawFd for TcpSocket` - `impl Debug for TcpSocket` - `impl FromRawFd for TcpSocket` - `impl IntoRawFd for TcpSocket` #### Auto Trait Implementations - `impl Freeze for TcpSocket` - `impl RefUnwindSafe for TcpSocket` - `impl Send for TcpSocket` - `impl Sync for TcpSocket` - `impl Unpin for TcpSocket` - `impl UnsafeUnpin for TcpSocket` - `impl UnwindSafe for TcpSocket` ### struct `nuclei::net::TcpStreamGenerator` https://nuclei.rs/api/nuclei/net/struct.TcpStreamGenerator.html Also exported as `nuclei::TcpStreamGenerator`. ```rust pub struct TcpStreamGenerator { /* private fields */ } ``` The connections of a listener, as [`Handle::accept_multi`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.accept_multi) makes them. #### Implementations `impl TcpStreamGenerator` ```rust pub fn take_error(&mut self) -> Option ``` Why the stream ended, once it has. #### Trait Implementations - `impl Debug for TcpStreamGenerator` - `impl Stream for TcpStreamGenerator` #### Auto Trait Implementations - `impl !Freeze for TcpStreamGenerator` - `impl !RefUnwindSafe for TcpStreamGenerator` - `impl !UnwindSafe for TcpStreamGenerator` - `impl Send for TcpStreamGenerator` - `impl Sync for TcpStreamGenerator` - `impl Unpin for TcpStreamGenerator` - `impl UnsafeUnpin for TcpStreamGenerator` ### struct `nuclei::net::UdpSocketBuilder` https://nuclei.rs/api/nuclei/net/struct.UdpSocketBuilder.html ```rust pub struct UdpSocketBuilder { /* private fields */ } ``` A UDP socket to set up before it binds: what only a socket not bound yet takes (`SO_REUSEPORT` among sockets that share a port, `IPV6_V6ONLY`, a device), and the rest before the first datagram. ```rust use nuclei::net::UdpSocketBuilder; let builder = UdpSocketBuilder::new_v4()?; builder.set_reuseaddr(true)?; builder.set_recv_buffer_size(256 * 1024)?; let socket = builder.bind("127.0.0.1:0".parse().unwrap())?; let addr = socket.local_addr()?; socket.send_to(b"hi", addr).await?; let mut buf = [0u8; 2]; assert_eq!(socket.recv_from(&mut buf).await?, (2, addr)); ``` #### Implementations `impl UdpSocketBuilder` ```rust pub fn set_reuseaddr(&self, reuseaddr: bool) -> Result<()> ``` Sets `SO_REUSEADDR`: the socket may bind an address still held by a connection that is closing. ```rust pub fn reuseaddr(&self) -> Result ``` Whether `SO_REUSEADDR` is set. ```rust pub fn set_reuseport(&self, reuseport: bool) -> Result<()> ``` Sets `SO_REUSEPORT`: several sockets may bind the same address and port, and the system shares what comes among them. ```rust pub fn reuseport(&self) -> Result ``` Whether `SO_REUSEPORT` is set. ```rust pub fn set_send_buffer_size(&self, size: u32) -> Result<()> ``` Sets the size of the system’s send buffer (`SO_SNDBUF`); the system may round it (Linux doubles it). ```rust pub fn send_buffer_size(&self) -> Result ``` The size of the system’s send buffer (`SO_SNDBUF`). ```rust pub fn set_recv_buffer_size(&self, size: u32) -> Result<()> ``` Sets the size of the system’s receive buffer (`SO_RCVBUF`); the system may round it (Linux doubles it). ```rust pub fn recv_buffer_size(&self) -> Result ``` The size of the system’s receive buffer (`SO_RCVBUF`). ```rust pub fn set_tos(&self, tos: u32) -> Result<()> ``` Sets the type of service of the socket’s IPv4 packets (`IP_TOS`). ```rust pub fn tos(&self) -> Result ``` The type of service of the socket’s IPv4 packets (`IP_TOS`). ```rust pub fn set_tclass_v6(&self, tclass: u32) -> Result<()> ``` Sets the traffic class of the socket’s IPv6 packets (`IPV6_TCLASS`). ```rust pub fn tclass_v6(&self) -> Result ``` The traffic class of the socket’s IPv6 packets (`IPV6_TCLASS`). ```rust pub fn set_only_v6(&self, only_v6: bool) -> Result<()> ``` Sets `IPV6_V6ONLY` on an IPv6 socket: with `true` it takes IPv6 alone, else IPv4 too, through addresses mapped into IPv6. **Errors** As `setsockopt(2)`: an IPv4 socket has no such option, and a bound one may no longer change it. ```rust pub fn only_v6(&self) -> Result ``` Whether `IPV6_V6ONLY` is set. **Errors** As `getsockopt(2)`: an IPv4 socket has no such option. ```rust pub fn bind_device(&self, interface: Option<&[u8]>) -> Result<()> ``` Binds the socket to the network interface named `interface` (`SO_BINDTODEVICE`), or, with `None`, to none. ```rust pub fn device(&self) -> Result> ``` The network interface the socket is bound to, if any (`SO_BINDTODEVICE`). `impl UdpSocketBuilder` ```rust pub fn new_v4() -> Result ``` A new IPv4 UDP socket. **Errors** When the system has no socket to give. ```rust pub fn new_v6() -> Result ``` A new IPv6 UDP socket. **Errors** When the system has no socket to give. ```rust pub fn local_addr(&self) -> Result ``` The address the socket is bound to; before it binds, the unspecified one on unix, and an error (`InvalidInput`) on Windows, as std’s `local_addr` answers there. ```rust pub fn take_error(&self) -> Result> ``` The socket’s pending error (`SO_ERROR`), taken. ```rust pub fn bind(self, addr: SocketAddr) -> Result ``` Binds the socket to `addr`, and makes it a [`UdpSocket`](https://nuclei.rs/api/nuclei/net/type.UdpSocket.html). **Errors** As `bind(2)`: the address is in use (shared only by sockets that all set `SO_REUSEPORT`, or on Windows `SO_REUSEADDR`), or not this host’s. #### Trait Implementations - `impl AsFd for UdpSocketBuilder` - `impl AsRawFd for UdpSocketBuilder` - `impl Debug for UdpSocketBuilder` #### Auto Trait Implementations - `impl Freeze for UdpSocketBuilder` - `impl RefUnwindSafe for UdpSocketBuilder` - `impl Send for UdpSocketBuilder` - `impl Sync for UdpSocketBuilder` - `impl Unpin for UdpSocketBuilder` - `impl UnsafeUnpin for UdpSocketBuilder` - `impl UnwindSafe for UdpSocketBuilder` ### struct `nuclei::net::UnixSocket` https://nuclei.rs/api/nuclei/net/struct.UnixSocket.html ```rust pub struct UnixSocket { /* private fields */ } ``` A Unix domain socket, of streams or of datagrams, to bind before it connects, listens or sends. ```rust use nuclei::net::UnixSocket; let dir = std::env::temp_dir().join(format!("nuclei-doc-unix-socket-{}", std::process::id())); let _ = std::fs::remove_file(&dir); let listener = UnixSocket::new_stream()?; listener.bind(&dir)?; let listener = listener.listen(16)?; let client = UnixSocket::new_stream()?.connect(&dir).await?; let (_server, _) = listener.accept().await?; client.send(b"hi").await?; std::fs::remove_file(&dir)?; ``` #### Implementations `impl UnixSocket` ```rust pub fn new_stream() -> Result ``` A new socket of streams. **Errors** When the system has no socket to give. ```rust pub fn new_datagram() -> Result ``` A new socket of datagrams. **Errors** When the system has no socket to give. ```rust pub fn bind(&self, path: impl AsRef) -> Result<()> ``` Binds the socket to `path`, which must not exist yet. **Errors** As `bind(2)`: the path exists, or is too long. ```rust pub fn listen(self, backlog: u32) -> Result ``` Makes a socket of streams a listener, with room for `backlog` connections not accepted yet. **Errors** On a socket of datagrams, and as `listen(2)`. ```rust pub async fn connect(self, path: impl AsRef) -> Result ``` Connects a socket of streams to the listener at `path`. **Errors** On a socket of datagrams, and as `connect(2)`. ```rust pub fn datagram(self) -> Result ``` Makes a socket of datagrams a datagram socket, bound or not. **Errors** On a socket of streams. #### Trait Implementations - `impl AsFd for UnixSocket` - `impl AsRawFd for UnixSocket` - `impl Debug for UnixSocket` - `impl FromRawFd for UnixSocket` - `impl IntoRawFd for UnixSocket` #### Auto Trait Implementations - `impl Freeze for UnixSocket` - `impl RefUnwindSafe for UnixSocket` - `impl Send for UnixSocket` - `impl Sync for UnixSocket` - `impl Unpin for UnixSocket` - `impl UnsafeUnpin for UnixSocket` - `impl UnwindSafe for UnixSocket` ### struct `nuclei::net::WriteHalf` https://nuclei.rs/api/nuclei/net/struct.WriteHalf.html ```rust pub struct WriteHalf<'a, S>(/* private fields */); ``` The write half of a stream, borrowed from it. #### Trait Implementations - `impl AsRef> for WriteHalf<'_, S>` - `impl<'a, S> AsyncWrite for WriteHalf<'a, S> where for<'x> &'x Handle: AsyncWrite` - `impl<'a, S: Debug> Debug for WriteHalf<'a, S>` #### Auto Trait Implementations - `impl<'a, S> !RefUnwindSafe for WriteHalf<'a, S>` - `impl<'a, S> !UnwindSafe for WriteHalf<'a, S>` - `impl<'a, S> Freeze for WriteHalf<'a, S>` - `impl<'a, S> Send for WriteHalf<'a, S> where S: Sync` - `impl<'a, S> Sync for WriteHalf<'a, S> where S: Sync` - `impl<'a, S> Unpin for WriteHalf<'a, S>` - `impl<'a, S> UnsafeUnpin for WriteHalf<'a, S>` ### trait `nuclei::net::ToSocketAddrs` https://nuclei.rs/api/nuclei/net/trait.ToSocketAddrs.html ```rust pub trait ToSocketAddrs: Sealed { } ``` What an operation that takes an address accepts: a `SocketAddr`, an `(IpAddr, u16)` pair, a slice or array of addresses, or a string, `"host:port"` or `("host", port)`. Numbers are used as they are; a name is looked up on the blocking pool (`getaddrinfo`), never on the calling thread. The trait is sealed: its implementations are the ones listed here. #### Dyn Compatibility This trait **is** [dyn compatible](https://doc.rust-lang.org/1.99.1/reference/items/traits.html#dyn-compatibility). *In older versions of Rust, dyn compatibility was called "object safety".* #### Implementations on Foreign Types `impl ToSocketAddrs for (&str, u16)` `impl ToSocketAddrs for (IpAddr, u16)` `impl ToSocketAddrs for (Ipv4Addr, u16)` `impl ToSocketAddrs for (Ipv6Addr, u16)` `impl ToSocketAddrs for (String, u16)` `impl ToSocketAddrs for SocketAddr` `impl ToSocketAddrs for SocketAddrV4` `impl ToSocketAddrs for SocketAddrV6` `impl ToSocketAddrs for String` `impl ToSocketAddrs for [SocketAddr]` `impl ToSocketAddrs for str` `impl ToSocketAddrs for &T` `impl ToSocketAddrs for [SocketAddr; N]` #### Implementors ### fn `nuclei::net::lookup_host` https://nuclei.rs/api/nuclei/net/fn.lookup_host.html ```rust pub async fn lookup_host( host: T, ) -> Result + Send + 'static> ``` Every address `host` names: numbers at once, a name looked up on the blocking pool. The iterator owns what it walks, so a slice given here is copied into it; the operations that take an address walk it in place. ```rust let addrs: Vec<_> = nuclei::net::lookup_host("127.0.0.1:80").await?.collect(); assert_eq!(addrs, ["127.0.0.1:80".parse().unwrap()]); ``` **Errors** When the name cannot be looked up. ### type `nuclei::net::TcpListener` https://nuclei.rs/api/nuclei/net/type.TcpListener.html ```rust pub type TcpListener = Handle; ``` A TCP listener: std’s, with an async `accept`. #### Aliased Type ```rust pub struct TcpListener { /* private fields */ } ``` ### type `nuclei::net::TcpStream` https://nuclei.rs/api/nuclei/net/type.TcpStream.html ```rust pub type TcpStream = Handle; ``` A TCP stream: std’s, with async reads and writes. A few of std’s calls reached through `Deref` go around the handle (`shutdown` among them): see [`Handle`](https://nuclei.rs/api/nuclei/io/struct.Handle.html). #### Aliased Type ```rust pub struct TcpStream { /* private fields */ } ``` ### type `nuclei::net::UdpSocket` https://nuclei.rs/api/nuclei/net/type.UdpSocket.html ```rust pub type UdpSocket = Handle; ``` A UDP socket: std’s, with async sends and receives. Its [`connect`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.connect) makes a socket; `socket.connect(addr)` on one is std’s own (see there). #### Aliased Type ```rust pub struct UdpSocket { /* private fields */ } ``` ### type `nuclei::net::UnixDatagram` https://nuclei.rs/api/nuclei/net/type.UnixDatagram.html ```rust pub type UnixDatagram = Handle; ``` A Unix datagram socket: std’s, with async sends and receives. #### Aliased Type ```rust pub struct UnixDatagram { /* private fields */ } ``` ### type `nuclei::net::UnixListener` https://nuclei.rs/api/nuclei/net/type.UnixListener.html ```rust pub type UnixListener = Handle; ``` A Unix stream listener: std’s, with an async `accept`. #### Aliased Type ```rust pub struct UnixListener { /* private fields */ } ``` ### type `nuclei::net::UnixStream` https://nuclei.rs/api/nuclei/net/type.UnixStream.html ```rust pub type UnixStream = Handle; ``` A Unix stream: std’s, with async reads and writes. A few of std’s calls reached through `Deref` go around the handle (`shutdown` among them): see [`Handle`](https://nuclei.rs/api/nuclei/io/struct.Handle.html). #### Aliased Type ```rust pub struct UnixStream { /* private fields */ } ``` ## Module `nuclei::net::unix` https://nuclei.rs/api/nuclei/net/unix/index.html Unix domain sockets: listeners, streams and datagrams, and [`UCred`](https://nuclei.rs/api/nuclei/net/unix/struct.UCred.html), the credentials of a stream’s peer; and Unix pipes ([`pipe`](https://nuclei.rs/api/nuclei/net/unix/pipe/index.html)). ### Modules - [pipe](https://nuclei.rs/api/nuclei/net/unix/pipe/index.html): Unix pipes: an anonymous pair ([`pipe`](https://nuclei.rs/api/nuclei/net/unix/pipe/fn.pipe.html)) and FIFOs opened by path ([`OpenOptions`](https://nuclei.rs/api/nuclei/net/unix/pipe/struct.OpenOptions.html)), as a [`Sender`](https://nuclei.rs/api/nuclei/net/unix/pipe/type.Sender.html) (the write end) and a [`Receiver`](https://nuclei.rs/api/nuclei/net/unix/pipe/type.Receiver.html) (the read end). Each is a [`Handle`](https://nuclei.rs/api/nuclei/io/struct.Handle.html) of std’s pipe end, read or written by the driver as any byte stream, with the calls of its one direction. ### Structs - [UCred](https://nuclei.rs/api/nuclei/net/unix/struct.UCred.html): The credentials of a Unix stream’s peer: its user and group, and its process where the system tells it (Linux, Android, macOS, iOS). ### struct `nuclei::net::unix::UCred` https://nuclei.rs/api/nuclei/net/unix/struct.UCred.html ```rust pub struct UCred { /* private fields */ } ``` The credentials of a Unix stream’s peer: its user and group, and its process where the system tells it (Linux, Android, macOS, iOS). #### Implementations `impl UCred` ```rust pub fn uid(&self) -> u32 ``` The peer’s user id. ```rust pub fn gid(&self) -> u32 ``` The peer’s group id. ```rust pub fn pid(&self) -> Option ``` The peer’s process id, where the system tells it. #### Trait Implementations - `impl Clone for UCred` - `impl Copy for UCred` - `impl Debug for UCred` - `impl Eq for UCred` - `impl Hash for UCred` - `impl PartialEq for UCred` - `impl StructuralPartialEq for UCred` #### Auto Trait Implementations - `impl Freeze for UCred` - `impl RefUnwindSafe for UCred` - `impl Send for UCred` - `impl Sync for UCred` - `impl Unpin for UCred` - `impl UnsafeUnpin for UCred` - `impl UnwindSafe for UCred` ## Module `nuclei::net::unix::pipe` https://nuclei.rs/api/nuclei/net/unix/pipe/index.html Unix pipes: an anonymous pair ([`pipe`](https://nuclei.rs/api/nuclei/net/unix/pipe/fn.pipe.html)) and FIFOs opened by path ([`OpenOptions`](https://nuclei.rs/api/nuclei/net/unix/pipe/struct.OpenOptions.html)), as a [`Sender`](https://nuclei.rs/api/nuclei/net/unix/pipe/type.Sender.html) (the write end) and a [`Receiver`](https://nuclei.rs/api/nuclei/net/unix/pipe/type.Receiver.html) (the read end). Each is a [`Handle`](https://nuclei.rs/api/nuclei/io/struct.Handle.html) of std’s pipe end, read or written by the driver as any byte stream, with the calls of its one direction. ```rust use nuclei::io::{AsyncReadExt, AsyncWriteExt}; use nuclei::net::unix::pipe; let (mut tx, mut rx) = pipe::pipe()?; tx.write_all(b"through").await?; tx.flush().await?; let mut buf = [0u8; 7]; rx.read_exact(&mut buf).await?; assert_eq!(&buf, b"through"); ``` ### Structs - [OpenOptions](https://nuclei.rs/api/nuclei/net/unix/pipe/struct.OpenOptions.html): How a FIFO is opened by path. ### Functions - [pipe](https://nuclei.rs/api/nuclei/net/unix/pipe/fn.pipe.html): A new anonymous pipe: what is written to the sender is read from the receiver. ### Type Aliases - [Receiver](https://nuclei.rs/api/nuclei/net/unix/pipe/type.Receiver.html): A pipe’s read end. - [Sender](https://nuclei.rs/api/nuclei/net/unix/pipe/type.Sender.html): A pipe’s write end. ### struct `nuclei::net::unix::pipe::OpenOptions` https://nuclei.rs/api/nuclei/net/unix/pipe/struct.OpenOptions.html ```rust pub struct OpenOptions { /* private fields */ } ``` How a FIFO is opened by path. #### Implementations `impl OpenOptions` ```rust pub fn new() -> OpenOptions ``` Options with each set to its default. ```rust pub fn read_write(&mut self, value: bool) -> &mut Self ``` Opens the FIFO for reading and writing both (Linux): a receiver sees no end while it holds the write side itself, and a sender opens with no reader there yet. Default false. ```rust pub fn unchecked(&mut self, value: bool) -> &mut Self ``` Opens the path without checking it is a FIFO. Default false. ```rust pub fn open_receiver>(&self, path: P) -> Result ``` Opens the FIFO at `path` as a receiver. **Errors** When the path cannot be opened, or (unless unchecked) is not a FIFO. ```rust pub fn open_sender>(&self, path: P) -> Result ``` Opens the FIFO at `path` as a sender. **Errors** When the path cannot be opened (`ENXIO` when nothing reads it yet, unless opened for reading and writing), or (unless unchecked) is not a FIFO. #### Trait Implementations - `impl Clone for OpenOptions` - `impl Debug for OpenOptions` - `impl Default for OpenOptions` #### Auto Trait Implementations - `impl Freeze for OpenOptions` - `impl RefUnwindSafe for OpenOptions` - `impl Send for OpenOptions` - `impl Sync for OpenOptions` - `impl Unpin for OpenOptions` - `impl UnsafeUnpin for OpenOptions` - `impl UnwindSafe for OpenOptions` ### fn `nuclei::net::unix::pipe::pipe` https://nuclei.rs/api/nuclei/net/unix/pipe/fn.pipe.html ```rust pub fn pipe() -> Result<(Sender, Receiver)> ``` A new anonymous pipe: what is written to the sender is read from the receiver. **Errors** When the process has no descriptors left. ### type `nuclei::net::unix::pipe::Receiver` https://nuclei.rs/api/nuclei/net/unix/pipe/type.Receiver.html ```rust pub type Receiver = Handle; ``` A pipe’s read end. #### Aliased Type ```rust pub struct Receiver { /* private fields */ } ``` ### type `nuclei::net::unix::pipe::Sender` https://nuclei.rs/api/nuclei/net/unix/pipe/type.Sender.html ```rust pub type Sender = Handle; ``` A pipe’s write end. #### Aliased Type ```rust pub struct Sender { /* private fields */ } ``` ## Module `nuclei::process` https://nuclei.rs/api/nuclei/process/index.html Child processes: spawn one, wait for its exit and talk to it through async pipes. Child processes: a [`Command`](https://nuclei.rs/api/nuclei/process/struct.Command.html) spawns one, and its [`Child`](https://nuclei.rs/api/nuclei/process/struct.Child.html) waits for the exit without holding a thread and talks to it through async pipes. A child’s exit is reported by a shard’s driver, which reaps the child (see `exit`); a wait never blocks a thread. A child whose `Child` goes before it exits is still reaped (on unix), by the shard that watches it, so it leaves no zombie behind while a runtime runs. ### Structs - [Child](https://nuclei.rs/api/nuclei/process/struct.Child.html): A spawned child process. - [ChildStderr](https://nuclei.rs/api/nuclei/process/struct.ChildStderr.html): The child’s stderr. - [ChildStdin](https://nuclei.rs/api/nuclei/process/struct.ChildStdin.html): The child’s stdin: write to it, and drop it (or [`close`](https://nuclei.rs/api/nuclei/io/trait.AsyncWrite.html#tymethod.poll_close)) to end it. - [ChildStdout](https://nuclei.rs/api/nuclei/process/struct.ChildStdout.html): The child’s stdout. - [Command](https://nuclei.rs/api/nuclei/process/struct.Command.html): A process to spawn, as [`std::process::Command`](https://doc.rust-lang.org/1.99.1/std/process/struct.Command.html) describes it. - [ExitStatus](https://nuclei.rs/api/nuclei/process/struct.ExitStatus.html): Describes the result of a process after it has terminated. - [Output](https://nuclei.rs/api/nuclei/process/struct.Output.html): The output of a finished process. - [Stdio](https://nuclei.rs/api/nuclei/process/struct.Stdio.html): Describes what to do with a standard I/O stream for a child process when passed to the [`stdin`](https://doc.rust-lang.org/1.99.1/std/process/struct.Command.html#method.stdin), [`stdout`](https://doc.rust-lang.org/1.99.1/std/process/struct.Command.html#method.stdout), and [`stderr`](https://doc.rust-lang.org/1.99.1/std/process/struct.Command.html#method.stderr) methods of [`Command`](https://doc.rust-lang.org/1.99.1/std/process/struct.Command.html). ### struct `nuclei::process::Child` https://nuclei.rs/api/nuclei/process/struct.Child.html ```rust pub struct Child { pub stdin: Option, pub stdout: Option, pub stderr: Option, /* private fields */ } ``` A spawned child process. #### Fields `stdin: Option` The child’s stdin, if piped. `stdout: Option` The child’s stdout, if piped. `stderr: Option` The child’s stderr, if piped. #### Implementations `impl Child` ```rust pub fn id(&self) -> u32 ``` The child’s process id. ```rust pub async fn wait(&mut self) -> Result ``` Waits for the child’s exit. Its stdin, if piped, is closed first, so a child that reads it to its end can exit. **Errors** When the exit cannot be watched, or the child was reaped by something else (`ECHILD`: `SIGCHLD` ignored, or a `waitpid` of the program’s own). ```rust pub fn try_wait(&mut self) -> Result> ``` The child’s status if it exited, else `None`, without waiting. **Errors** When the child’s state cannot be read. ```rust pub fn start_kill(&mut self) -> Result<()> ``` Starts ending the child, without waiting for it to go: `SIGKILL` on unix, `TerminateProcess` on Windows. A child that exited already is left alone. **Errors** When the signal or the call fails. ```rust pub async fn kill(&mut self) -> Result<()> ``` Ends the child, as [`start_kill`](https://nuclei.rs/api/nuclei/process/struct.Child.html#method.start_kill) does, and waits for its exit. ```rust use nuclei::process::Command; let mut child = Command::new("sleep").arg("60").spawn()?; child.kill().await?; assert!(child.try_wait()?.is_some()); ``` **Errors** As for [`start_kill`](https://nuclei.rs/api/nuclei/process/struct.Child.html#method.start_kill) and [`wait`](https://nuclei.rs/api/nuclei/process/struct.Child.html#method.wait). ```rust pub async fn wait_with_output(self) -> Result ``` Waits for the child’s exit, collecting its stdout and stderr (those piped) until then. Its stdin, if piped, is closed first. **Errors** As for [`wait`](https://nuclei.rs/api/nuclei/process/struct.Child.html#method.wait), and when a pipe cannot be read. #### Trait Implementations - `impl Debug for Child` - `impl Drop for Child` #### Auto Trait Implementations - `impl !Freeze for Child` - `impl !RefUnwindSafe for Child` - `impl !UnwindSafe for Child` - `impl Send for Child` - `impl Sync for Child` - `impl Unpin for Child` - `impl UnsafeUnpin for Child` ### struct `nuclei::process::ChildStderr` https://nuclei.rs/api/nuclei/process/struct.ChildStderr.html ```rust pub struct ChildStderr(/* private fields */); ``` The child’s stderr. #### Trait Implementations - `impl AsyncRead for ChildStderr` - `impl Debug for ChildStderr` #### Auto Trait Implementations - `impl !Freeze for ChildStderr` - `impl !RefUnwindSafe for ChildStderr` - `impl !UnwindSafe for ChildStderr` - `impl Send for ChildStderr` - `impl Sync for ChildStderr` - `impl Unpin for ChildStderr` - `impl UnsafeUnpin for ChildStderr` ### struct `nuclei::process::ChildStdin` https://nuclei.rs/api/nuclei/process/struct.ChildStdin.html ```rust pub struct ChildStdin(/* private fields */); ``` The child’s stdin: write to it, and drop it (or [`close`](https://nuclei.rs/api/nuclei/io/trait.AsyncWrite.html#tymethod.poll_close)) to end it. #### Trait Implementations - `impl AsyncWrite for ChildStdin` - `impl Debug for ChildStdin` #### Auto Trait Implementations - `impl !Freeze for ChildStdin` - `impl !RefUnwindSafe for ChildStdin` - `impl !UnwindSafe for ChildStdin` - `impl Send for ChildStdin` - `impl Sync for ChildStdin` - `impl Unpin for ChildStdin` - `impl UnsafeUnpin for ChildStdin` ### struct `nuclei::process::ChildStdout` https://nuclei.rs/api/nuclei/process/struct.ChildStdout.html ```rust pub struct ChildStdout(/* private fields */); ``` The child’s stdout. #### Trait Implementations - `impl AsyncRead for ChildStdout` - `impl Debug for ChildStdout` #### Auto Trait Implementations - `impl !Freeze for ChildStdout` - `impl !RefUnwindSafe for ChildStdout` - `impl !UnwindSafe for ChildStdout` - `impl Send for ChildStdout` - `impl Sync for ChildStdout` - `impl Unpin for ChildStdout` - `impl UnsafeUnpin for ChildStdout` ### struct `nuclei::process::Command` https://nuclei.rs/api/nuclei/process/struct.Command.html ```rust pub struct Command { /* private fields */ } ``` A process to spawn, as [`std::process::Command`](https://doc.rust-lang.org/1.99.1/std/process/struct.Command.html) describes it. #### Implementations `impl Command` ```rust pub fn new(program: impl AsRef) -> Self ``` A command for `program`, with its environment and working directory the process’s, and its standard streams inherited. ```rust pub fn arg(&mut self, arg: impl AsRef) -> &mut Self ``` Adds an argument. ```rust pub fn args(&mut self, args: I) -> &mut Self where I: IntoIterator, S: AsRef ``` Adds arguments. ```rust pub fn env( &mut self, key: impl AsRef, value: impl AsRef, ) -> &mut Self ``` Sets an environment variable of the child. ```rust pub fn envs(&mut self, vars: I) -> &mut Self where I: IntoIterator, K: AsRef, V: AsRef ``` Sets environment variables of the child. ```rust pub fn env_remove(&mut self, key: impl AsRef) -> &mut Self ``` Takes an environment variable out of the child’s environment. ```rust pub fn env_clear(&mut self) -> &mut Self ``` Starts the child with no environment but what is set after. ```rust pub fn current_dir(&mut self, dir: impl AsRef) -> &mut Self ``` Sets the child’s working directory. ```rust pub fn stdin(&mut self, cfg: impl Into) -> &mut Self ``` Sets the child’s stdin. ```rust pub fn stdout(&mut self, cfg: impl Into) -> &mut Self ``` Sets the child’s stdout. ```rust pub fn stderr(&mut self, cfg: impl Into) -> &mut Self ``` Sets the child’s stderr. ```rust pub fn kill_on_drop(&mut self, kill: bool) -> &mut Self ``` Whether the child is ended, as [`Child::start_kill`](https://nuclei.rs/api/nuclei/process/struct.Child.html#method.start_kill) ends it, when its [`Child`](https://nuclei.rs/api/nuclei/process/struct.Child.html) is dropped before it exits (default false: it runs on, and is still reaped once it exits). ```rust use nuclei::process::Command; let child = Command::new("sleep").arg("60").kill_on_drop(true).spawn()?; drop(child); // the child is ended here ``` ```rust pub fn get_kill_on_drop(&self) -> bool ``` Whether [`kill_on_drop`](https://nuclei.rs/api/nuclei/process/struct.Command.html#method.kill_on_drop) is set. ```rust pub fn as_std(&self) -> &Command ``` The std command underneath, for what this one does not mirror. ```rust pub fn as_std_mut(&mut self) -> &mut Command ``` The std command underneath, to change. ```rust pub fn into_std(self) -> Command ``` The std command underneath, taken. ```rust pub fn spawn(&mut self) -> Result ``` Spawns the child. Its piped streams are async. **Errors** When the child cannot start, or its pipes cannot be taken over. ```rust pub fn spawn_with( &mut self, with: impl FnOnce(&mut Command) -> Result, ) -> Result ``` Spawns the child through `with`, which starts it from the std command underneath: for a way to start a child this type does not mirror, such as a platform’s own spawn call with extra attributes. The child `with` returns is then this one’s, its piped streams async. ```rust use nuclei::process::Command; let mut child = Command::new("true").spawn_with(|std| std.spawn())?; assert!(child.wait().await?.success()); ``` **Errors** What `with` returns, and when the child’s pipes cannot be taken over. ```rust pub async fn status(&mut self) -> Result ``` Spawns the child and waits for its exit; its streams are inherited unless set. **Errors** As for [`spawn`](https://nuclei.rs/api/nuclei/process/struct.Command.html#method.spawn) and [`Child::wait`](https://nuclei.rs/api/nuclei/process/struct.Child.html#method.wait). ```rust pub async fn output(&mut self) -> Result ``` Spawns the child with its stdout and stderr piped (and its stdin empty, unless set), and collects both until its exit. **Errors** As for [`spawn`](https://nuclei.rs/api/nuclei/process/struct.Command.html#method.spawn) and [`Child::wait_with_output`](https://nuclei.rs/api/nuclei/process/struct.Child.html#method.wait_with_output). #### Trait Implementations - `impl Debug for Command` - `impl From for Command` #### Auto Trait Implementations - `impl !RefUnwindSafe for Command` - `impl !UnwindSafe for Command` - `impl Freeze for Command` - `impl Send for Command` - `impl Sync for Command` - `impl Unpin for Command` - `impl UnsafeUnpin for Command` ### struct `nuclei::process::ExitStatus` https://nuclei.rs/api/nuclei/process/struct.ExitStatus.html ```rust pub struct ExitStatus(/* private fields */); ``` Describes the result of a process after it has terminated. This `struct` is used to represent the exit status or other termination of a child process. Child processes are created via the [`Command`](https://doc.rust-lang.org/1.99.1/std/process/struct.Command.html) struct and their exit status is exposed through the [`status`](https://doc.rust-lang.org/1.99.1/std/process/struct.Command.html#method.status) method, or the [`wait`](https://doc.rust-lang.org/1.99.1/std/process/struct.Child.html#method.wait) method of a [`Child`](https://doc.rust-lang.org/1.99.1/std/process/struct.Child.html) process. An `ExitStatus` represents every possible disposition of a process. On Unix this is the **wait status**. It is *not* simply an *exit status* (a value passed to `exit`). For proper error reporting of failed processes, print the value of `ExitStatus` or `ExitStatusError` using their implementations of [`Display`](https://doc.rust-lang.org/1.99.1/core/fmt/trait.Display.html). **Differences from `ExitCode`** [`ExitCode`](https://doc.rust-lang.org/1.99.1/std/process/struct.ExitCode.html) is intended for terminating the currently running process, via the `Termination` trait, in contrast to `ExitStatus`, which represents the termination of a child process. These APIs are separate due to platform compatibility differences and their expected usage; it is not generally possible to exactly reproduce an `ExitStatus` from a child for the current process after the fact. #### Implementations `impl ExitStatus` ```rust pub fn exit_ok(&self) -> Result<(), ExitStatusError> ``` 🔬This is a nightly-only experimental API. (`exit_status_error`) Was termination successful? Returns a `Result`. **Examples** ```rust #![feature(exit_status_error)] use std::process::Command; let status = Command::new("ls") .arg("/dev/nonexistent") .status() .expect("ls command should execute successfully"); println!("ls: {status}"); status.exit_ok().expect_err("/dev/nonexistent could be listed!"); ``` ```rust pub fn success(&self) -> bool ``` Was termination successful? Signal termination is not considered a success, and success is defined as a zero exit status. **Examples** ```rust use std::process::Command; let status = Command::new("mkdir") .arg("projects") .status() .expect("mkdir command should execute successfully"); if status.success() { println!("'projects/' directory created"); } else { println!("failed to create 'projects/' directory: {status}"); } ``` ```rust pub fn code(&self) -> Option ``` Returns the exit code of the process, if any. In Unix terms the return value is the **exit status**: the value passed to `exit`, if the process finished by calling `exit`. Note that on Unix the exit status is truncated to 8 bits, and that values that didn’t come from a program’s call to `exit` may be invented by the runtime system (often, for example, 255, 254, 127 or 126). On Unix, this will return `None` if the process was terminated by a signal. [`ExitStatusExt`](https://doc.rust-lang.org/1.99.1/std/os/unix/process/trait.ExitStatusExt.html) is an extension trait for extracting any such signal, and other details, from the `ExitStatus`. **Examples** ```rust use std::process::Command; let status = Command::new("mkdir") .arg("projects") .status() .expect("mkdir command should execute successfully"); match status.code() { Some(code) => println!("Exited with status code: {code}"), None => println!("Process terminated by signal") } ``` #### Trait Implementations - `impl Clone for ExitStatus` - `impl Copy for ExitStatus` - `impl Debug for ExitStatus` - `impl Default for ExitStatus` - `impl Display for ExitStatus` - `impl Eq for ExitStatus` - `impl ExitStatusExt for ExitStatus` - `impl From for ExitStatus` - `impl PartialEq for ExitStatus` - `impl StructuralPartialEq for ExitStatus` #### Auto Trait Implementations - `impl Freeze for ExitStatus` - `impl RefUnwindSafe for ExitStatus` - `impl Send for ExitStatus` - `impl Sync for ExitStatus` - `impl Unpin for ExitStatus` - `impl UnsafeUnpin for ExitStatus` - `impl UnwindSafe for ExitStatus` ### struct `nuclei::process::Output` https://nuclei.rs/api/nuclei/process/struct.Output.html ```rust pub struct Output { pub status: ExitStatus, pub stdout: Vec, pub stderr: Vec, } ``` The output of a finished process. This is returned in a Result by either the [`output`](https://doc.rust-lang.org/1.99.1/std/process/struct.Command.html#method.output) method of a [`Command`](https://doc.rust-lang.org/1.99.1/std/process/struct.Command.html), or the [`wait_with_output`](https://doc.rust-lang.org/1.99.1/std/process/struct.Child.html#method.wait_with_output) method of a [`Child`](https://doc.rust-lang.org/1.99.1/std/process/struct.Child.html) process. #### Fields `status: ExitStatus` The status (exit code) of the process. `stdout: Vec` The data that the process wrote to stdout. `stderr: Vec` The data that the process wrote to stderr. #### Implementations `impl Output` ```rust pub fn exit_ok(self) -> Result ``` 🔬This is a nightly-only experimental API. (`exit_status_error`) Returns an error if a nonzero exit status was received. If the [`Command`](https://doc.rust-lang.org/1.99.1/std/process/struct.Command.html) exited successfully, `self` is returned. This is equivalent to calling [`exit_ok`](https://nuclei.rs/api/nuclei/process/struct.ExitStatus.html#method.exit_ok) on [`Output.status`](https://nuclei.rs/api/nuclei/process/struct.Output.html#structfield.status). Note that this will throw away the [`Output::stderr`](https://nuclei.rs/api/nuclei/process/struct.Output.html#structfield.stderr) field in the error case. If the child process outputs useful informantion to stderr, you can: - Use `cmd.stderr(Stdio::inherit())` to forward the stderr child process to the parent’s stderr, usually printing it to console where the user can see it. This is usually correct for command-line applications. - Capture `stderr` using a custom error type. This is usually correct for libraries. **Examples** ```rust #![feature(exit_status_error)] use std::process::Command; assert!(Command::new("false").output().unwrap().exit_ok().is_err()); ``` #### Trait Implementations - `impl Clone for Output` - `impl Debug for Output` - `impl Eq for Output` - `impl PartialEq for Output` - `impl StructuralPartialEq for Output` #### Auto Trait Implementations - `impl Freeze for Output` - `impl RefUnwindSafe for Output` - `impl Send for Output` - `impl Sync for Output` - `impl Unpin for Output` - `impl UnsafeUnpin for Output` - `impl UnwindSafe for Output` ### struct `nuclei::process::Stdio` https://nuclei.rs/api/nuclei/process/struct.Stdio.html ```rust pub struct Stdio(/* private fields */); ``` Describes what to do with a standard I/O stream for a child process when passed to the [`stdin`](https://doc.rust-lang.org/1.99.1/std/process/struct.Command.html#method.stdin), [`stdout`](https://doc.rust-lang.org/1.99.1/std/process/struct.Command.html#method.stdout), and [`stderr`](https://doc.rust-lang.org/1.99.1/std/process/struct.Command.html#method.stderr) methods of [`Command`](https://doc.rust-lang.org/1.99.1/std/process/struct.Command.html). #### Implementations `impl Stdio` ```rust pub fn piped() -> Stdio ``` A new pipe should be arranged to connect the parent and child processes. **Examples** With stdout: ```rust use std::process::{Command, Stdio}; let output = Command::new("echo") .arg("Hello, world!") .stdout(Stdio::piped()) .output() .expect("process should execute successfully"); assert_eq!(String::from_utf8_lossy(&output.stdout), "Hello, world!\n"); // Nothing echoed to console ``` With stdin: ```rust use std::io::Write; use std::process::{Command, Stdio}; let mut child = Command::new("rev") .stdin(Stdio::piped()) .stdout(Stdio::piped()) .spawn() .expect("rev command should start"); let mut stdin = child.stdin.take().expect("child stdin should be retrievable"); std::thread::spawn(move || { stdin.write_all("Hello, world!".as_bytes()).expect("writing to child stdin should succeed"); }); let output = child.wait_with_output().expect("child stdout should be able to be read"); assert_eq!(String::from_utf8_lossy(&output.stdout), "!dlrow ,olleH"); ``` Writing more than a pipe buffer’s worth of input to stdin without also reading stdout and stderr at the same time may cause a deadlock. This is an issue when running any program that doesn’t guarantee that it reads its entire stdin before writing more than a pipe buffer’s worth of output. The size of a pipe buffer varies on different targets. ```rust pub fn inherit() -> Stdio ``` The child inherits from the corresponding parent descriptor. **Examples** With stdout: ```rust use std::process::{Command, Stdio}; let output = Command::new("echo") .arg("Hello, world!") .stdout(Stdio::inherit()) .output() .expect("process should execute successfully"); assert_eq!(String::from_utf8_lossy(&output.stdout), ""); // "Hello, world!" echoed to console ``` With stdin: ```rust use std::process::{Command, Stdio}; use std::io::{self, Write}; let output = Command::new("rev") .stdin(Stdio::inherit()) .stdout(Stdio::piped()) .output()?; print!("You piped in the reverse of: "); io::stdout().write_all(&output.stdout)?; ``` ```rust pub fn null() -> Stdio ``` This stream will be ignored. This is the equivalent of attaching the stream to `/dev/null`. **Examples** With stdout: ```rust use std::process::{Command, Stdio}; let output = Command::new("echo") .arg("Hello, world!") .stdout(Stdio::null()) .output() .expect("process should execute successfully"); assert_eq!(String::from_utf8_lossy(&output.stdout), ""); // Nothing echoed to console ``` With stdin: ```rust use std::process::{Command, Stdio}; let output = Command::new("rev") .stdin(Stdio::null()) .stdout(Stdio::piped()) .output() .expect("process should execute successfully"); assert_eq!(String::from_utf8_lossy(&output.stdout), ""); // Ignores any piped-in input ``` ```rust pub fn makes_pipe(&self) -> bool ``` 🔬This is a nightly-only experimental API. (`stdio_makes_pipe`) Returns `true` if this requires [`Command`](https://doc.rust-lang.org/1.99.1/std/process/struct.Command.html) to create a new pipe. **Example** ```rust #![feature(stdio_makes_pipe)] use std::process::Stdio; let io = Stdio::piped(); assert_eq!(io.makes_pipe(), true); ``` #### Trait Implementations - `impl Debug for Stdio` - `impl From for Stdio` - `impl From for Stdio` - `impl From for Stdio` - `impl From for Stdio` - `impl From for Stdio` - `impl From for Stdio` - `impl From for Stdio` - `impl From for Stdio` - `impl From for Stdio` - `impl FromRawFd for Stdio` #### Auto Trait Implementations - `impl Freeze for Stdio` - `impl RefUnwindSafe for Stdio` - `impl Send for Stdio` - `impl Sync for Stdio` - `impl Unpin for Stdio` - `impl UnsafeUnpin for Stdio` - `impl UnwindSafe for Stdio` ## Module `nuclei::runtime` https://nuclei.rs/api/nuclei/runtime/index.html nuclei’s own runtime: shards, tasks, `block_on`, `spawn` and the blocking pool. nuclei’s own runtime: thread-per-core shards that run tasks, a blocking pool, and the functions that place work on them. A [`Runtime`](https://nuclei.rs/api/nuclei/runtime/struct.Runtime.html) runs one shard per worker thread. A shard owns its run queue, its timers and its poller, and a task stays on the shard it was placed on: [`spawn`](https://nuclei.rs/api/nuclei/runtime/fn.spawn.html) keeps it near the spawning thread’s other tasks within a margin of load (see [`Builder::local_spawn_margin`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.local_spawn_margin)), [`spawn_local`](https://nuclei.rs/api/nuclei/runtime/fn.spawn_local.html) keeps it on the calling thread. [`block_on`](https://nuclei.rs/api/nuclei/runtime/fn.block_on.html) runs a future on the calling thread and nests: called from a task, it keeps the shard running its other tasks until the future completes. [`RuntimeHandle::spawn_on_worker`](https://nuclei.rs/api/nuclei/runtime/struct.RuntimeHandle.html#method.spawn_on_worker), [`RuntimeHandle::on_each_worker`](https://nuclei.rs/api/nuclei/runtime/struct.RuntimeHandle.html#method.on_each_worker) and [`task::Builder::worker`](https://nuclei.rs/api/nuclei/task/struct.Builder.html#method.worker) place a task on a worker the caller names, where it stays; [`shard_local!`](https://nuclei.rs/api/nuclei/macro.shard_local.html) keeps a [`ShardLocal`](https://nuclei.rs/api/nuclei/runtime/struct.ShardLocal.html) value per worker, which moves with the worker’s shard when a handoff gives the shard to another thread. The free functions use the runtime the calling thread is inside, or the process default runtime, which starts on first use with no configuration (one worker per core). [`Builder`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html) sets everything else, and [`Runtime::stats`](https://nuclei.rs/api/nuclei/runtime/struct.Runtime.html#method.stats) reads one runtime’s counters. ```rust use nuclei::runtime::{Runtime, spawn}; let runtime = Runtime::builder().worker_threads(2).build().unwrap(); let sum = runtime.block_on(async { let tasks: Vec<_> = (0..4u64).map(|n| spawn(async move { n * n })).collect(); let mut sum = 0; for task in tasks { sum += task.await; } sum }); assert_eq!(sum, 14); ``` ### Structs - [Builder](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html): Builds a [`Runtime`](https://nuclei.rs/api/nuclei/runtime/struct.Runtime.html). Every setting is optional: an unset one takes the default, which needs no configuration to work well. - [EnterGuard](https://nuclei.rs/api/nuclei/runtime/struct.EnterGuard.html): The runtime [`Runtime::enter`](https://nuclei.rs/api/nuclei/runtime/struct.Runtime.html#method.enter) set on this thread, until it drops: the free functions ([`spawn`](https://nuclei.rs/api/nuclei/runtime/fn.spawn.html), …) use that runtime meanwhile. It stays on the thread that made it. - [FallibleTask](https://nuclei.rs/api/nuclei/runtime/struct.FallibleTask.html): A spawned task whose output is `None` when the task ended without one. - [RngSeed](https://nuclei.rs/api/nuclei/runtime/struct.RngSeed.html): A seed for a runtime’s random choices: where a task spawned from outside its workers goes, and which branch of a fair [`select!`](https://nuclei.rs/api/nuclei/macro.select.html) is polled first. - [Runtime](https://nuclei.rs/api/nuclei/runtime/struct.Runtime.html): A runtime: worker shards and a blocking pool. Dropping it stops the workers, drops the tasks they still hold, and waits for the threads to exit; then, on the dropping thread, for what the handles those tasks held left behind (the bytes a socket’s write-behind holds, a file’s writes) to land, each for at most a minute, so nothing they accepted is lost. - [RuntimeHandle](https://nuclei.rs/api/nuclei/runtime/struct.RuntimeHandle.html): A cloneable handle to a [`Runtime`](https://nuclei.rs/api/nuclei/runtime/struct.Runtime.html), to spawn on it from anywhere. It does not keep the runtime running. - [RuntimeId](https://nuclei.rs/api/nuclei/runtime/struct.RuntimeId.html): A runtime’s id, distinct among the runtimes of the process. - [ShardAccessError](https://nuclei.rs/api/nuclei/runtime/struct.ShardAccessError.html): A [`ShardLocal`](https://nuclei.rs/api/nuclei/runtime/struct.ShardLocal.html) was used where it has no value: off a worker, or by its own initializer. - [ShardLocal](https://nuclei.rs/api/nuclei/runtime/struct.ShardLocal.html): A value per worker shard, declared with [`shard_local!`](https://nuclei.rs/api/nuclei/macro.shard_local.html). - [Task](https://nuclei.rs/api/nuclei/runtime/struct.Task.html): A spawned task. - [TaskMeta](https://nuclei.rs/api/nuclei/runtime/struct.TaskMeta.html): What a task hook is told about the task. - [TryCurrentError](https://nuclei.rs/api/nuclei/runtime/struct.TryCurrentError.html): [`RuntimeHandle::try_current`](https://nuclei.rs/api/nuclei/runtime/struct.RuntimeHandle.html#method.try_current) found no runtime set on this thread. ### Enums - [UnhandledPanic](https://nuclei.rs/api/nuclei/runtime/enum.UnhandledPanic.html): What a runtime does when one of its tasks panics ([`Builder::unhandled_panic`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.unhandled_panic)). ### Functions - [block_on](https://nuclei.rs/api/nuclei/runtime/fn.block_on.html): Runs `future` to its end on the calling thread, running other tasks of the thread’s shard meanwhile. - [spawn](https://nuclei.rs/api/nuclei/runtime/fn.spawn.html): Spawns a task on the runtime this thread is inside, or on the default runtime. Spawned on a worker, the task stays on that worker unless it holds more live tasks than another shard by the runtime’s [`local_spawn_margin`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.local_spawn_margin); spawned anywhere else, it goes to the spawning thread’s home shard by the same rule (the first spawn takes the less loaded of two shards picked at random). The task stays on its shard. - [spawn_blocking](https://nuclei.rs/api/nuclei/runtime/fn.spawn_blocking.html): Runs `f` on the blocking pool of the runtime this thread is inside, or of the default runtime, so it never holds a shard up. - [spawn_local](https://nuclei.rs/api/nuclei/runtime/fn.spawn_local.html): Spawns a task that stays on the calling thread: a worker’s shard, or the thread’s own (where it runs while the thread is inside `block_on`). The future need not be `Send`. - [worker_index](https://nuclei.rs/api/nuclei/runtime/fn.worker_index.html): The index of the worker this code runs on (0, 1, … among the workers of its runtime), `None` off the workers (in `block_on`’s own thread, on the blocking pool, outside any runtime). ### struct `nuclei::runtime::Builder` https://nuclei.rs/api/nuclei/runtime/struct.Builder.html Also exported as `nuclei::Builder`. ```rust pub struct Builder { /* private fields */ } ``` Builds a [`Runtime`](https://nuclei.rs/api/nuclei/runtime/struct.Runtime.html). Every setting is optional: an unset one takes the default, which needs no configuration to work well. ```rust let runtime = nuclei::Builder::new().worker_threads(2).build().unwrap(); assert_eq!(runtime.block_on(async { 1 + 1 }), 2); ``` #### Implementations `impl Builder` ```rust pub fn new() -> Self ``` A builder with every setting at its default. ```rust pub fn worker_threads(self, n: usize) -> Self ``` Worker threads, each running one shard. The default is one per core of [`worker_cores`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.worker_cores) when it is set, else one per core the process may run on, held to [`max_worker_threads`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.max_worker_threads) when that is set. Zero runs every task on the thread that spawns it, while that thread is inside `block_on`. ```rust pub fn thread_name(self, name: impl Into) -> Self ``` The name of every thread the runtime starts (default `nuclei-worker` and `nuclei-blocking`). ```rust pub fn thread_name_fn( self, f: impl Fn() -> String + Send + Sync + 'static, ) -> Self ``` A function naming each thread the runtime starts. ```rust pub fn thread_stack_size(self, bytes: usize) -> Self ``` The stack size of every thread the runtime starts, in bytes (default 8 MiB). At least 128 KiB; [`build`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.build) fails with `InvalidInput` below. ```rust pub fn max_nesting(self, depth: usize) -> Self ``` How deep `block_on` may nest on one thread (default 256). A call one level deeper panics instead of running the thread out of stack. At least 1; [`build`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.build) fails with `InvalidInput` below. ```rust pub fn max_blocking_threads(self, n: usize) -> Self ``` The most threads the blocking pool runs at once (default 512). At least 1; [`build`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.build) fails with `InvalidInput` below. ```rust pub fn thread_keep_alive(self, keep_alive: Duration) -> Self ``` How long an idle blocking thread waits for work before it exits (default 10 seconds). ```rust pub fn local_spawn_margin(self, margin: usize) -> Self ``` How many more live tasks than another shard a spawning thread’s shard may hold and still take a task it spawns (default 32). A task spawned on a worker stays on it (so a task that waits for what it spawned keeps it on its own thread), and a task spawned on any other thread goes to that thread’s home shard (where its spawns went last), unless that shard holds that many more tasks than a shard picked at random; then it goes to the other, which becomes the home. Zero balances strictly; a larger margin keeps more work together. ```rust pub fn max_worker_threads(self, n: usize) -> Self ``` The most worker threads the runtime may start over its life, the ones it starts with included (default four times the workers it starts with): what `spawn_more_threads` may add up to. A stopped worker’s place is not taken again. Below an explicit [`worker_threads`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.worker_threads), [`build`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.build) fails with `InvalidInput`; with `worker_threads` unset, the runtime starts with at most this many. ```rust pub fn io_buffer_cap(self, bytes: usize) -> Self ``` The most bytes each worker’s IO buffers hold (default 64 MiB). Reads that had to wait land in these buffers, and writes that had to wait are copied into them; at the cap, IO waits for buffers to come back, so a worker’s IO memory never grows past it. On io_uring the worker’s receive buffers count against the cap too ([`recv_buffers`](https://nuclei.rs/api/nuclei/config/struct.IoUringConfiguration.html#structfield.recv_buffers) of [`recv_buffer_size`](https://nuclei.rs/api/nuclei/config/struct.IoUringConfiguration.html#structfield.recv_buffer_size) bytes, 4 MiB by default, with their descriptors), and the rest is left for the others. A cap that leaves less than 512 bytes beside the receive buffers is refused with `InvalidInput` when the worker starts; otherwise any value is accepted, and a request that cannot fit under a cap too small for it fails with an error that names this setting. ```rust pub fn backend(self, backend: IoBackend) -> Self ``` The kernel interface the workers run their IO on. Unset, it is the process’s: the `backend` of [`NucleiConfig`](https://nuclei.rs/api/nuclei/config/struct.NucleiConfig.html), or io_uring where the kernel lets this process have it and the platform’s poller otherwise. A backend this process cannot have makes [`build`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.build) fail with the reason. A non-empty `NUCLEI_BACKEND` overrides it. ```rust pub fn io_uring(self, config: IoUringConfiguration) -> Self ``` The settings the workers’ io_uring rings are made with, for this runtime alone (default: the process’s, from [`Proactor::with_config`](https://nuclei.rs/api/nuclei/struct.Proactor.html#method.with_config)). Checked in [`build`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.build), which fails with `InvalidInput` naming the setting a ring cannot work with, on every platform; only the workers of a runtime whose IO runs on io_uring make rings. Whether io_uring is chosen when no backend is named is decided with these settings. The shard of a thread inside `block_on` keeps the process’s settings: it serves every runtime the thread enters. ```rust pub fn start_paused(self, paused: bool) -> Self ``` Whether the runtime’s clock starts paused (default false): see [`time::pause`](https://nuclei.rs/api/nuclei/time/fn.pause.html). Its tasks then see time move only as they [`advance`](https://nuclei.rs/api/nuclei/time/fn.advance.html) it, or as it jumps to the next timer whenever every shard of the runtime is idle. ```rust pub fn handoff_after(self, after: Option) -> Self ``` How long one poll of a task may run on a worker before the worker’s other tasks go on without it (default 10 ms; `None`: never). A task that blocks inside its poll (a blocking call, a long loop without an `.await`) then holds up only itself: its worker’s shard, with every other task, timer and IO of it, goes to another thread on the same core, and the blocked task carries on once its poll returns. At least 1 ms; [`build`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.build) fails with `InvalidInput` below. Tasks that `spawn_local` keeps on the blocked thread wait for it. The watch costs each poll two plain stores and a load, and each call a task makes into its worker (a wake, a spawn, a send or a receive) two loads and two stores; with it on, an io_uring worker’s ring takes submissions from any thread. ```rust pub fn pin_workers(self, pin: bool) -> Self ``` Whether each worker thread is pinned to its own core (Linux and Windows; default true). A pinned shard keeps its cache warm; unpinned, the scheduler may move it. With [`worker_cores`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.worker_cores) set, each worker is pinned to its core of that list, or, unpinned, runs on any core of the list. ```rust pub fn record_latencies(self, record: bool) -> Self ``` Counts how long each task poll runs, and (with the `io-stats` feature) how long each IO operation waits for the kernel, by kind, in log2 histograms each worker’s [`ShardStats`](https://nuclei.rs/api/nuclei/stats/struct.ShardStats.html) carries (default false: no clock is read for it). The poll times cost two clock reads and a call around every poll, of every runtime of the process while one records them; the IO latencies two clock reads per operation of this runtime’s workers. ```rust pub fn count_io(self, count: bool) -> Self ``` Counts each worker’s IO operations (reads, writes, the bytes of each, accepts) in its [`ShardStats::io`](https://nuclei.rs/api/nuclei/stats/struct.ShardStats.html#structfield.io) (default false: `io` is `None`). With the `io-stats` feature only, which costs every IO call a few instructions, counted or not: off, a count is one load of a flag per operation; on, a few plain thread-local adds per operation and a drain each time a shard publishes its counts, on every thread of the process while one runtime counts. ```rust pub fn build(self) -> Result ``` Starts the runtime. **Errors** `InvalidInput` naming a setting that no runtime can work with, or that does not fit with another; the reason when the backend cannot be had, a worker’s poller cannot be made or its thread cannot start. ```rust pub fn build_global(self) -> Result ``` Starts the runtime and makes it the process default, the one the free functions ([`spawn`](https://nuclei.rs/api/nuclei/runtime/fn.spawn.html), [`block_on`](https://nuclei.rs/api/nuclei/runtime/fn.block_on.html), …) use outside any other runtime. **Errors** As for [`build`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.build), and `AlreadyExists` when the default runtime is already running (it was built, or a free function started it). `impl Builder` ```rust pub fn worker_cores(self, cores: impl IntoIterator) -> Self ``` The cores the workers run on, in the order the workers take them: worker `k` runs on `cores[k % cores.len()]`, pinned to it, or, with [`pin_workers(false)`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.pin_workers), on any core of the list. The worker count defaults to the list’s length. Every core must be one the process may run on and the list must not be empty; [`build`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.build) fails with `InvalidInput` otherwise. Pinning takes effect on Linux and Windows; elsewhere the list sets the worker count and is checked against the cores the machine has. ```rust pub fn blocking_cores(self, cores: impl IntoIterator) -> Self ``` The cores the blocking pool’s threads run on, any of them (default: the cores of the thread that builds the runtime). Checked as [`worker_cores`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.worker_cores) are, and in effect on Linux and Windows. `impl Builder` ```rust pub fn write_behind_linger(self, linger: Duration) -> Self ``` How long the bytes a dropped handle wrote behind may take to reach the kernel (default one minute): a task delivers them after the drop, as the kernel delivers what a closed socket holds. Past it the rest is given up, and a TCP stream’s connection is reset, so its peer reads an error rather than the end of a stream cut short. [`get_mut`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.get_mut) and [`into_inner`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.into_inner) wait for the bytes as long at most, and the runtime’s drop waits for the tasks. More than zero; [`build`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.build) fails with `InvalidInput` at zero. ```rust pub fn zero_copy_threshold(self, bytes: usize) -> Self ``` The least a [`write_zero_copy`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.write_zero_copy) must have left to send for its next send to go zero-copy, in bytes (default 1 MiB): below it, the kernel copies the bytes, as it does for every write. Copying costs less than pinning the pages for small writes; where the threshold pays depends on the machine and its network. Only io_uring sends zero-copy, on the runtime’s workers: every value is accepted, and `0` sends every write zero-copy, `usize::MAX` none. ```rust pub fn send_file_chunk(self, bytes: usize) -> Self ``` The most bytes one call of a [`send_file`](https://nuclei.rs/api/nuclei/io/struct.Handle.html#method.send_file) sends (default 1 MiB). Each call runs on the blocking pool and may stall on a cold page there, so this bounds how long a pool thread is held, and how much a cancelled `send_file` still sends after its future went; where the system has no call for it, each chunk is read into a buffer of this size. From 1 byte to `0x7ffff000` (what one `sendfile(2)` sends); [`build`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.build) fails with `InvalidInput` outside. `impl Builder` ```rust pub fn on_thread_start(self, f: impl Fn() + Send + Sync + 'static) -> Self ``` Called on each thread the runtime starts (workers and blocking-pool threads), on that thread, before it does anything else. ```rust pub fn on_thread_stop(self, f: impl Fn() + Send + Sync + 'static) -> Self ``` Called on each thread the runtime starts, on that thread, as it ends (after a panic too). ```rust pub fn on_thread_park(self, f: impl Fn() + Send + Sync + 'static) -> Self ``` Called on a worker thread just before it sleeps with nothing to run. ```rust pub fn on_thread_unpark(self, f: impl Fn() + Send + Sync + 'static) -> Self ``` Called on a worker thread just after it wakes from a sleep. ```rust pub fn on_task_spawn( self, f: impl Fn(&TaskMeta<'_>) + Send + Sync + 'static, ) -> Self ``` Called with each task this runtime spawns (not the blocking pool’s jobs), on the spawning thread, once the task exists. ```rust pub fn on_before_task_poll( self, f: impl Fn(&TaskMeta<'_>) + Send + Sync + 'static, ) -> Self ``` Called just before each poll of a task of this runtime, on the thread that polls it. ```rust pub fn on_after_task_poll( self, f: impl Fn(&TaskMeta<'_>) + Send + Sync + 'static, ) -> Self ``` Called just after each poll of a task of this runtime, on the thread that polled it. ```rust pub fn on_task_terminate( self, f: impl Fn(&TaskMeta<'_>) + Send + Sync + 'static, ) -> Self ``` Called when a task of this runtime is done with: its future completed or was dropped by a cancel, on the thread that dropped it. ```rust pub fn on_long_poll( self, f: impl Fn(&TaskMeta<'_>) + Send + Sync + 'static, ) -> Self ``` Called with each poll of a task of this runtime that its worker’s watch sees run past [`handoff_after`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.handoff_after), on the watch’s own thread: the task’s id and name say which one holds its worker up. The task is the innermost one whose poll was running when the watch looked; the poll may have ended by the time the hook runs. A poll is told once, unless a `block_on` inside it ran a long poll of its own and the shard stayed on that thread: the outer poll may then be told again as it goes on. The shard is handed on first, so a slow hook delays no rescue, but every other worker waits for its next look while the hook runs: keep it short. A panic in it is caught (after the panic hook reported it) and the watch goes on. Only workers are watched; with `handoff_after(None)` [`build`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.build) fails with `InvalidInput`. ```rust pub fn event_interval(self, runs: u32) -> Self ``` Task runs between a worker’s looks at its timers and IO when it is busy (default 61): lower answers IO sooner, higher runs tasks with fewer interruptions. At least 1; [`build`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.build) fails with `InvalidInput` at 0. ```rust pub fn global_queue_interval(self, runs: u32) -> Self ``` Task runs between the times a worker takes from its inbox (tasks woken by other threads) before its own queue (default 31). At least 1; [`build`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.build) fails with `InvalidInput` at 0. ```rust pub fn max_io_events_per_tick(self, events: usize) -> Self ``` The most IO events a worker takes from its driver in one look (default: all that are ready). At least 1; [`build`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.build) fails with `InvalidInput` at 0. ```rust pub fn disable_lifo_slot(self) -> Self ``` Turns off each worker’s LIFO slot, where a task woken by the task running on the worker goes to run next. Without it the woken task goes to the back of the worker’s queue: fairer when the queue is long, slower for a task that hands work to another and waits for it. ```rust pub fn rng_seed(self, seed: RngSeed) -> Self ``` Seeds the runtime’s random choices, so that they repeat run after run; see [`RngSeed`](https://nuclei.rs/api/nuclei/runtime/struct.RngSeed.html). ```rust pub fn unhandled_panic(self, policy: UnhandledPanic) -> Self ``` What the runtime does when one of its tasks panics (default [`UnhandledPanic::Ignore`](https://nuclei.rs/api/nuclei/runtime/enum.UnhandledPanic.html#variant.Ignore): the panic goes to the task’s handle). ```rust use nuclei::runtime::{Runtime, UnhandledPanic}; let rt = Runtime::builder() .unhandled_panic(UnhandledPanic::ShutdownRuntime) .build() .unwrap(); let ran = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { rt.block_on(async { let _task = nuclei::spawn(async { panic!("a task fails") }); core::future::pending::<()>().await }) })); assert!(ran.is_err(), "the block_on panics once the task did"); ``` #### Trait Implementations - `impl Debug for Builder` - `impl Default for Builder` #### Auto Trait Implementations - `impl !RefUnwindSafe for Builder` - `impl !UnwindSafe for Builder` - `impl Freeze for Builder` - `impl Send for Builder` - `impl Sync for Builder` - `impl Unpin for Builder` - `impl UnsafeUnpin for Builder` ### struct `nuclei::runtime::EnterGuard` https://nuclei.rs/api/nuclei/runtime/struct.EnterGuard.html ```rust pub struct EnterGuard<'a> { /* private fields */ } ``` The runtime [`Runtime::enter`](https://nuclei.rs/api/nuclei/runtime/struct.Runtime.html#method.enter) set on this thread, until it drops: the free functions ([`spawn`](https://nuclei.rs/api/nuclei/runtime/fn.spawn.html), …) use that runtime meanwhile. It stays on the thread that made it. #### Trait Implementations - `impl Debug for EnterGuard<'_>` #### Auto Trait Implementations - `impl<'a> !RefUnwindSafe for EnterGuard<'a>` - `impl<'a> !Send for EnterGuard<'a>` - `impl<'a> !Sync for EnterGuard<'a>` - `impl<'a> !UnwindSafe for EnterGuard<'a>` - `impl<'a> Freeze for EnterGuard<'a>` - `impl<'a> Unpin for EnterGuard<'a>` - `impl<'a> UnsafeUnpin for EnterGuard<'a>` ### struct `nuclei::runtime::FallibleTask` https://nuclei.rs/api/nuclei/runtime/struct.FallibleTask.html Also exported as `nuclei::FallibleTask`. ```rust pub struct FallibleTask { /* private fields */ } ``` A spawned task whose output is `None` when the task ended without one. Made by [`Task::fallible`](https://nuclei.rs/api/nuclei/runtime/struct.Task.html#method.fallible): awaiting it returns `Some(output)`, or `None` where awaiting the [`Task`](https://nuclei.rs/api/nuclei/runtime/struct.Task.html) would panic. #### Implementations `impl FallibleTask` ```rust pub fn detach(self) ``` Lets the task run to its end without a handle; see [`Task::detach`](https://nuclei.rs/api/nuclei/runtime/struct.Task.html#method.detach). ```rust pub async fn cancel(self) -> Option ``` Cancels the task; see [`Task::cancel`](https://nuclei.rs/api/nuclei/runtime/struct.Task.html#method.cancel). ```rust pub fn is_finished(&self) -> bool ``` Whether the task completed or was cancelled. ```rust pub fn id(&self) -> Id ``` The task’s id. #### Trait Implementations - `impl Debug for FallibleTask` - `impl Future for FallibleTask` #### Auto Trait Implementations - `impl Freeze for FallibleTask` - `impl RefUnwindSafe for FallibleTask` - `impl Send for FallibleTask where T: Send` - `impl Sync for FallibleTask` - `impl Unpin for FallibleTask` - `impl UnsafeUnpin for FallibleTask` - `impl UnwindSafe for FallibleTask` ### struct `nuclei::runtime::RngSeed` https://nuclei.rs/api/nuclei/runtime/struct.RngSeed.html ```rust pub struct RngSeed(/* private fields */); ``` A seed for a runtime’s random choices: where a task spawned from outside its workers goes, and which branch of a fair [`select!`](https://nuclei.rs/api/nuclei/macro.select.html) is polled first. A runtime built with [`Builder::rng_seed`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.rng_seed) seeds each of its workers, and each thread in its `block_on`, from the seed: run after run, such a thread draws the same numbers, so its choices repeat as long as what it chooses among is the same. The threads still interleave as the system runs them. ```rust use nuclei::runtime::{RngSeed, Runtime}; let seed = RngSeed::from_bytes(b"a run to repeat"); assert_eq!(seed, RngSeed::from_bytes(b"a run to repeat")); let rt = Runtime::builder().rng_seed(seed).build().unwrap(); ``` #### Implementations `impl RngSeed` ```rust pub fn new() -> Self ``` A seed different each time. ```rust pub fn from_bytes(bytes: &[u8]) -> Self ``` The seed of `bytes`: the same bytes give the same seed on every system. #### Trait Implementations - `impl Clone for RngSeed` - `impl Copy for RngSeed` - `impl Debug for RngSeed` - `impl Default for RngSeed` - `impl Eq for RngSeed` - `impl PartialEq for RngSeed` - `impl StructuralPartialEq for RngSeed` #### Auto Trait Implementations - `impl Freeze for RngSeed` - `impl RefUnwindSafe for RngSeed` - `impl Send for RngSeed` - `impl Sync for RngSeed` - `impl Unpin for RngSeed` - `impl UnsafeUnpin for RngSeed` - `impl UnwindSafe for RngSeed` ### struct `nuclei::runtime::Runtime` https://nuclei.rs/api/nuclei/runtime/struct.Runtime.html Also exported as `nuclei::Runtime`. ```rust pub struct Runtime { /* private fields */ } ``` A runtime: worker shards and a blocking pool. Dropping it stops the workers, drops the tasks they still hold, and waits for the threads to exit; then, on the dropping thread, for what the handles those tasks held left behind (the bytes a socket’s write-behind holds, a file’s writes) to land, each for at most a minute, so nothing they accepted is lost. #### Implementations `impl Runtime` ```rust pub fn enter(&self) -> EnterGuard<'_> ``` Sets this runtime on the calling thread until the guard drops, so the free functions use it outside `block_on`. ```rust let runtime = nuclei::Runtime::builder().worker_threads(1).build().unwrap(); let _guard = runtime.enter(); let task = nuclei::spawn(async { 2 + 2 }); assert_eq!(runtime.block_on(task), 4); ``` ```rust pub fn id(&self) -> RuntimeId ``` The runtime’s id. ```rust pub fn shutdown_background(self) ``` Stops the workers and returns at once: the worker threads drop their tasks and exit on their own, without being waited for, and what the handles of those tasks left behind is delivered on threads of its own. `impl Runtime` ```rust pub fn stats(&self) -> Stats ``` A snapshot of this runtime’s counters: [`Stats::shards`](https://nuclei.rs/api/nuclei/stats/struct.Stats.html#structfield.shards) lists its workers (stopped ones included) by place, and the blocking counts are its pool’s. The errors of threads that run no shard and the receive buffers missing are the process’s, as in [`stats()`](https://nuclei.rs/api/nuclei/stats/fn.stats.html): they belong to no runtime. The shard of a thread inside this runtime’s `block_on` serves every runtime the thread enters, so only [`stats()`](https://nuclei.rs/api/nuclei/stats/fn.stats.html) lists it. `impl Runtime` ```rust pub fn builder() -> Builder ``` A builder with every setting at its default. ```rust pub fn new() -> Result ``` Starts a runtime with every setting at its default. **Errors** As for [`Builder::build`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.build). ```rust pub fn handle(&self) -> RuntimeHandle ``` A handle to spawn on this runtime from anywhere. ```rust pub fn block_on(&self, future: F) -> F::Output ``` Runs `future` to its end on the calling thread; see [`block_on`](https://nuclei.rs/api/nuclei/runtime/fn.block_on.html). ```rust pub fn spawn(&self, future: F) -> Task where F: Future + Send + 'static, F::Output: Send + 'static ``` Spawns a task on one of the runtime’s shards; see [`spawn`](https://nuclei.rs/api/nuclei/runtime/fn.spawn.html). ```rust pub fn spawn_blocking(&self, f: F) -> Task where F: FnOnce() -> T + Send + 'static, T: Send + 'static ``` Runs `f` on the runtime’s blocking pool; see [`spawn_blocking`](https://nuclei.rs/api/nuclei/runtime/fn.spawn_blocking.html). ```rust pub fn shutdown_timeout(self, timeout: Duration) ``` Stops the workers and waits for them up to `timeout`; workers still running a task then are left to exit on their own. What the handles of the tasks dropped left behind gets the rest of `timeout` to land, on this thread; what has not by then is given up. #### Trait Implementations - `impl Debug for Runtime` - `impl Drop for Runtime` #### Auto Trait Implementations - `impl !RefUnwindSafe for Runtime` - `impl !UnwindSafe for Runtime` - `impl Freeze for Runtime` - `impl Send for Runtime` - `impl Sync for Runtime` - `impl Unpin for Runtime` - `impl UnsafeUnpin for Runtime` ### struct `nuclei::runtime::RuntimeHandle` https://nuclei.rs/api/nuclei/runtime/struct.RuntimeHandle.html Also exported as `nuclei::RuntimeHandle`. ```rust pub struct RuntimeHandle { /* private fields */ } ``` A cloneable handle to a [`Runtime`](https://nuclei.rs/api/nuclei/runtime/struct.Runtime.html), to spawn on it from anywhere. It does not keep the runtime running. #### Implementations `impl RuntimeHandle` ```rust pub fn enter(&self) -> EnterGuard<'_> ``` Sets the handle’s runtime on the calling thread until the guard drops. ```rust pub fn id(&self) -> RuntimeId ``` The runtime’s id. ```rust pub fn try_current() -> Result ``` The handle of the runtime set on this thread (inside its `block_on`, on one of its workers, or under [`enter`](https://nuclei.rs/api/nuclei/runtime/struct.RuntimeHandle.html#method.enter)); unlike [`current`](https://nuclei.rs/api/nuclei/runtime/struct.RuntimeHandle.html#method.current) it never falls back to the default runtime. `impl RuntimeHandle` ```rust pub fn workers(&self) -> usize ``` The workers the runtime has started, stopped ones included: the indices [`spawn_on_worker`](https://nuclei.rs/api/nuclei/runtime/struct.RuntimeHandle.html#method.spawn_on_worker) takes are `0..workers()`. ```rust pub fn spawn_on_worker( &self, worker: usize, future: F, ) -> Result> where F: Future + Send + 'static, F::Output: Send + 'static ``` Spawns `future` on worker `worker`, where it stays: a handoff of the worker’s shard moves the task with it, so it runs on that worker for its whole life. **Errors** `InvalidInput` when the runtime has no such worker, or the worker stopped (or is stopping) and takes no new task. ```rust pub fn spawn_local_on_worker( &self, worker: usize, make: M, ) -> Result> where M: FnOnce() -> F + Send + 'static, F: Future + 'static, F::Output: Send + 'static ``` Runs `make` on worker `worker` and spawns the future it makes there, which need not be `Send`: it stays on the thread that made it, as a [`spawn_local`](https://nuclei.rs/api/nuclei/runtime/fn.spawn_local.html) task does. A handoff of the worker’s shard leaves such a future on the thread that made it, off the worker: it finishes there, where [`worker_index`](https://nuclei.rs/api/nuclei/runtime/fn.worker_index.html) answers `None` and shard-local values are out of reach. The handle is that of the task that makes the future on the worker and waits for it: its id is not the one [`task::id`](https://nuclei.rs/api/nuclei/task/fn.id.html) answers inside the future, and dropping it cancels both. **Errors** As for [`spawn_on_worker`](https://nuclei.rs/api/nuclei/runtime/struct.RuntimeHandle.html#method.spawn_on_worker). ```rust pub fn on_each_worker(&self, make: M) -> JoinSet where M: Fn() -> F + Send + Sync + 'static, F: Future + 'static, F::Output: Send + 'static ``` Runs `make` on every worker that takes tasks and spawns the future it makes there, as [`spawn_local_on_worker`](https://nuclei.rs/api/nuclei/runtime/struct.RuntimeHandle.html#method.spawn_local_on_worker) does: the set holds one task per worker. A runtime with no worker gives an empty set. `impl RuntimeHandle` ```rust pub fn stats(&self) -> Stats ``` A snapshot of the counters of the handle’s runtime; see [`Runtime::stats`](https://nuclei.rs/api/nuclei/runtime/struct.Runtime.html#method.stats). `impl RuntimeHandle` ```rust pub fn block_on(&self, future: F) -> F::Output ``` Runs `future` to its end on the calling thread; see [`block_on`](https://nuclei.rs/api/nuclei/runtime/fn.block_on.html). ```rust pub fn spawn(&self, future: F) -> Task where F: Future + Send + 'static, F::Output: Send + 'static ``` Spawns a task on one of the runtime’s shards; see [`spawn`](https://nuclei.rs/api/nuclei/runtime/fn.spawn.html). ```rust pub fn spawn_blocking(&self, f: F) -> Task where F: FnOnce() -> T + Send + 'static, T: Send + 'static ``` Runs `f` on the runtime’s blocking pool; see [`spawn_blocking`](https://nuclei.rs/api/nuclei/runtime/fn.spawn_blocking.html). ```rust pub fn current() -> Self ``` The handle of the runtime this thread is inside, or of the default runtime (started now if it is not running yet). #### Trait Implementations - `impl Clone for RuntimeHandle` - `impl Debug for RuntimeHandle` #### Auto Trait Implementations - `impl !RefUnwindSafe for RuntimeHandle` - `impl !UnwindSafe for RuntimeHandle` - `impl Freeze for RuntimeHandle` - `impl Send for RuntimeHandle` - `impl Sync for RuntimeHandle` - `impl Unpin for RuntimeHandle` - `impl UnsafeUnpin for RuntimeHandle` ### struct `nuclei::runtime::RuntimeId` https://nuclei.rs/api/nuclei/runtime/struct.RuntimeId.html ```rust pub struct RuntimeId(/* private fields */); ``` A runtime’s id, distinct among the runtimes of the process. #### Trait Implementations - `impl Clone for RuntimeId` - `impl Copy for RuntimeId` - `impl Debug for RuntimeId` - `impl Display for RuntimeId` - `impl Eq for RuntimeId` - `impl Hash for RuntimeId` - `impl Ord for RuntimeId` - `impl PartialEq for RuntimeId` - `impl PartialOrd for RuntimeId` - `impl StructuralPartialEq for RuntimeId` #### Auto Trait Implementations - `impl Freeze for RuntimeId` - `impl RefUnwindSafe for RuntimeId` - `impl Send for RuntimeId` - `impl Sync for RuntimeId` - `impl Unpin for RuntimeId` - `impl UnsafeUnpin for RuntimeId` - `impl UnwindSafe for RuntimeId` ### struct `nuclei::runtime::ShardAccessError` https://nuclei.rs/api/nuclei/runtime/struct.ShardAccessError.html ```rust pub struct ShardAccessError { /* private fields */ } ``` A [`ShardLocal`](https://nuclei.rs/api/nuclei/runtime/struct.ShardLocal.html) was used where it has no value: off a worker, or by its own initializer. #### Implementations `impl ShardAccessError` ```rust pub fn is_initializing(&self) -> bool ``` Whether the value was being made: its initializer used it. #### Trait Implementations - `impl Clone for ShardAccessError` - `impl Copy for ShardAccessError` - `impl Debug for ShardAccessError` - `impl Display for ShardAccessError` - `impl Eq for ShardAccessError` - `impl Error for ShardAccessError` - `impl PartialEq for ShardAccessError` - `impl StructuralPartialEq for ShardAccessError` #### Auto Trait Implementations - `impl Freeze for ShardAccessError` - `impl RefUnwindSafe for ShardAccessError` - `impl Send for ShardAccessError` - `impl Sync for ShardAccessError` - `impl Unpin for ShardAccessError` - `impl UnsafeUnpin for ShardAccessError` - `impl UnwindSafe for ShardAccessError` ### struct `nuclei::runtime::ShardLocal` https://nuclei.rs/api/nuclei/runtime/struct.ShardLocal.html ```rust pub struct ShardLocal { /* private fields */ } ``` A value per worker shard, declared with [`shard_local!`](https://nuclei.rs/api/nuclei/macro.shard_local.html). Each worker of each runtime has its own value, made by the declaration’s expression the first time code running on that worker uses it, and dropped with the worker’s shard. Only code running on a worker (its tasks, and `block_on` called from them) reaches a value: a thread’s own shard in `block_on`, the blocking pool and any other thread have none. A task spawned on a worker stays on that worker’s shard, and a handoff moves the shard with its values, so the task always sees one value. A task kept on a thread by `spawn_local` whose worker’s shard was handed on runs on that thread’s own shard, off the worker: it gets [`ShardAccessError`](https://nuclei.rs/api/nuclei/runtime/struct.ShardAccessError.html) there. #### Implementations `impl ShardLocal` ```rust pub fn with(&'static self, f: impl FnOnce(&T) -> R) -> R ``` Runs `f` on this worker’s value, made now if this is its first use here. While `f` runs the shard stays on this thread, even across a `block_on` inside `f`: keep `f` short, as a blocking `f` holds the whole worker up. **Panics** Off a worker, or when the value’s own initializer uses it; [`try_with`](https://nuclei.rs/api/nuclei/runtime/struct.ShardLocal.html#method.try_with) answers the error instead. ```rust pub fn try_with( &'static self, f: impl FnOnce(&T) -> R, ) -> Result ``` Runs `f` on this worker’s value, as [`with`](https://nuclei.rs/api/nuclei/runtime/struct.ShardLocal.html#method.with) does, or answers a [`ShardAccessError`](https://nuclei.rs/api/nuclei/runtime/struct.ShardAccessError.html) off a worker or while the value’s own initializer runs. #### Trait Implementations - `impl Debug for ShardLocal` #### Auto Trait Implementations - `impl !Freeze for ShardLocal` - `impl RefUnwindSafe for ShardLocal` - `impl Send for ShardLocal` - `impl Sync for ShardLocal` - `impl Unpin for ShardLocal` - `impl UnsafeUnpin for ShardLocal` - `impl UnwindSafe for ShardLocal` ### struct `nuclei::runtime::Task` https://nuclei.rs/api/nuclei/runtime/struct.Task.html Also exported as `nuclei::Task`. ```rust pub struct Task { /* private fields */ } ``` A spawned task. Awaiting it gives the task’s output. Dropping it cancels the task: its future is dropped without being polled again. [`detach`](https://nuclei.rs/api/nuclei/runtime/struct.Task.html#method.detach) lets the task run to its end without a handle. If the task’s future panics, awaiting the handle resumes the panic. **Panics** Awaiting a task that was cancelled before it completed (through an [`AbortHandle`](https://nuclei.rs/api/nuclei/task/struct.AbortHandle.html), or by its runtime’s shutdown) panics; [`join`](https://nuclei.rs/api/nuclei/runtime/struct.Task.html#method.join) answers a [`JoinError`](https://nuclei.rs/api/nuclei/task/struct.JoinError.html) instead, and [`fallible`](https://nuclei.rs/api/nuclei/runtime/struct.Task.html#method.fallible) gives a handle that returns `None`. #### Implementations `impl Task` ```rust pub fn detach(self) ``` Lets the task run to its end without a handle; its output is dropped. ```rust pub async fn cancel(self) -> Option ``` Cancels the task and waits for its future to be dropped. Returns the output if the task had already completed. ```rust pub fn fallible(self) -> FallibleTask ``` A handle that returns `None` where this one panics: when the task was cancelled, or its runtime dropped it before it completed. ```rust pub fn is_finished(&self) -> bool ``` Whether the task completed or was cancelled. Awaiting a finished task returns at once. ```rust pub fn id(&self) -> Id ``` The task’s id. ```rust pub fn abort(&self) ``` Cancels the task without waiting: its future is dropped where it runs, and awaiting the handle then finds no output (unless the task had completed). [`join`](https://nuclei.rs/api/nuclei/runtime/struct.Task.html#method.join) reports it as a cancelled [`JoinError`](https://nuclei.rs/api/nuclei/task/struct.JoinError.html). ```rust pub fn abort_handle(&self) -> AbortHandle ``` A handle that cancels the task from anywhere, without the [`Task`](https://nuclei.rs/api/nuclei/runtime/struct.Task.html): it can be cloned and sent to another thread, and outlives the handle. ```rust pub fn join(self) -> Join ``` A future that gives the task’s output, or a [`JoinError`](https://nuclei.rs/api/nuclei/task/struct.JoinError.html) saying why there is none: the task was cancelled (its runtime dropped it too), or its future panicked, with the payload. #### Trait Implementations - `impl Debug for Task` - `impl Drop for Task` - `impl Future for Task` - `impl RefUnwindSafe for Task` - `impl Send for Task` - `impl Sync for Task` - `impl Unpin for Task` - `impl UnwindSafe for Task` #### Auto Trait Implementations - `impl Freeze for Task` - `impl UnsafeUnpin for Task` ### struct `nuclei::runtime::TaskMeta` https://nuclei.rs/api/nuclei/runtime/struct.TaskMeta.html ```rust pub struct TaskMeta<'a> { /* private fields */ } ``` What a task hook is told about the task. #### Implementations `impl TaskMeta<'_>` ```rust pub fn id(&self) -> Id ``` The task’s id. ```rust pub fn name(&self) -> Option<&str> ``` The task’s name, as [`task::Builder::name`](https://nuclei.rs/api/nuclei/task/struct.Builder.html#method.name) gave it; `None` for a task spawned without one. #### Trait Implementations - `impl<'a> Debug for TaskMeta<'a>` #### Auto Trait Implementations - `impl<'a> Freeze for TaskMeta<'a>` - `impl<'a> RefUnwindSafe for TaskMeta<'a>` - `impl<'a> Send for TaskMeta<'a>` - `impl<'a> Sync for TaskMeta<'a>` - `impl<'a> Unpin for TaskMeta<'a>` - `impl<'a> UnsafeUnpin for TaskMeta<'a>` - `impl<'a> UnwindSafe for TaskMeta<'a>` ### struct `nuclei::runtime::TryCurrentError` https://nuclei.rs/api/nuclei/runtime/struct.TryCurrentError.html ```rust pub struct TryCurrentError { /* private fields */ } ``` [`RuntimeHandle::try_current`](https://nuclei.rs/api/nuclei/runtime/struct.RuntimeHandle.html#method.try_current) found no runtime set on this thread. #### Implementations `impl TryCurrentError` ```rust pub fn is_missing_context(&self) -> bool ``` Whether no runtime was set on the thread (the one reason today). #### Trait Implementations - `impl Clone for TryCurrentError` - `impl Copy for TryCurrentError` - `impl Debug for TryCurrentError` - `impl Display for TryCurrentError` - `impl Eq for TryCurrentError` - `impl Error for TryCurrentError` - `impl PartialEq for TryCurrentError` - `impl StructuralPartialEq for TryCurrentError` #### Auto Trait Implementations - `impl Freeze for TryCurrentError` - `impl RefUnwindSafe for TryCurrentError` - `impl Send for TryCurrentError` - `impl Sync for TryCurrentError` - `impl Unpin for TryCurrentError` - `impl UnsafeUnpin for TryCurrentError` - `impl UnwindSafe for TryCurrentError` ### enum `nuclei::runtime::UnhandledPanic` https://nuclei.rs/api/nuclei/runtime/enum.UnhandledPanic.html ```rust #[non_exhaustive]pub enum UnhandledPanic { Ignore, ShutdownRuntime, } ``` What a runtime does when one of its tasks panics ([`Builder::unhandled_panic`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.unhandled_panic)). #### Variants (Non-exhaustive) Non-exhaustive enums could have additional variants added in future. Therefore, when matching against variants of non-exhaustive enums, an extra wildcard arm must be added to account for any future variants. ```rust Ignore ``` The panic is the task’s outcome, for whoever awaits it; the runtime runs on. ```rust ShutdownRuntime ``` The runtime shuts down at once: its workers stop and drop their tasks, and every `block_on` of it panics, those running and every later one. The panicked task’s handle still reports the panic. #### Trait Implementations - `impl Clone for UnhandledPanic` - `impl Copy for UnhandledPanic` - `impl Debug for UnhandledPanic` - `impl Default for UnhandledPanic` - `impl Eq for UnhandledPanic` - `impl PartialEq for UnhandledPanic` - `impl StructuralPartialEq for UnhandledPanic` #### Auto Trait Implementations - `impl Freeze for UnhandledPanic` - `impl RefUnwindSafe for UnhandledPanic` - `impl Send for UnhandledPanic` - `impl Sync for UnhandledPanic` - `impl Unpin for UnhandledPanic` - `impl UnsafeUnpin for UnhandledPanic` - `impl UnwindSafe for UnhandledPanic` ### fn `nuclei::runtime::block_on` https://nuclei.rs/api/nuclei/runtime/fn.block_on.html Also exported as `nuclei::block_on`. ```rust pub fn block_on(future: F) -> F::Output ``` Runs `future` to its end on the calling thread, running other tasks of the thread’s shard meanwhile. On a worker thread (inside a task) the call nests: the worker’s shard keeps running its other tasks, timers and IO until `future` completes. The task that called it is not polled again until the call returns, so a `future` that waits for that very task never completes. **Panics** When nested deeper than the runtime’s `max_nesting` (256 by default), or when the thread’s shard cannot start (its poller cannot be made). ### fn `nuclei::runtime::spawn` https://nuclei.rs/api/nuclei/runtime/fn.spawn.html Also exported as `nuclei::spawn`, `nuclei::task::spawn`. ```rust pub fn spawn(future: F) -> Task where F: Future + Send + 'static, F::Output: Send + 'static, ``` Spawns a task on the runtime this thread is inside, or on the default runtime. Spawned on a worker, the task stays on that worker unless it holds more live tasks than another shard by the runtime’s [`local_spawn_margin`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.local_spawn_margin); spawned anywhere else, it goes to the spawning thread’s home shard by the same rule (the first spawn takes the less loaded of two shards picked at random). The task stays on its shard. Dropping the returned [`Task`](https://nuclei.rs/api/nuclei/runtime/struct.Task.html) cancels it; call [`Task::detach`](https://nuclei.rs/api/nuclei/runtime/struct.Task.html#method.detach) to let it run on its own. Awaiting a task that was cancelled (through an [`AbortHandle`](https://nuclei.rs/api/nuclei/task/struct.AbortHandle.html), or by its runtime’s shutdown) panics; [`Task::join`](https://nuclei.rs/api/nuclei/runtime/struct.Task.html#method.join) and [`Task::fallible`](https://nuclei.rs/api/nuclei/runtime/struct.Task.html#method.fallible) answer it instead. **Panics** When the default runtime or this thread’s shard cannot start (its poller cannot be made); [`task::Builder::spawn`](https://nuclei.rs/api/nuclei/task/struct.Builder.html#method.spawn) answers the error instead. ### fn `nuclei::runtime::spawn_blocking` https://nuclei.rs/api/nuclei/runtime/fn.spawn_blocking.html Also exported as `nuclei::spawn_blocking`, `nuclei::task::spawn_blocking`. ```rust pub fn spawn_blocking(f: F) -> Task where F: FnOnce() -> T + Send + 'static, T: Send + 'static, ``` Runs `f` on the blocking pool of the runtime this thread is inside, or of the default runtime, so it never holds a shard up. **Panics** When the default runtime cannot start. ### fn `nuclei::runtime::spawn_local` https://nuclei.rs/api/nuclei/runtime/fn.spawn_local.html Also exported as `nuclei::spawn_local`, `nuclei::task::spawn_local`. ```rust pub fn spawn_local(future: F) -> Task where F: Future + 'static, F::Output: 'static, ``` Spawns a task that stays on the calling thread: a worker’s shard, or the thread’s own (where it runs while the thread is inside `block_on`). The future need not be `Send`. **Panics** When this thread’s shard cannot start (its poller cannot be made); [`task::Builder::spawn_local`](https://nuclei.rs/api/nuclei/task/struct.Builder.html#method.spawn_local) answers the error instead. ### fn `nuclei::runtime::worker_index` https://nuclei.rs/api/nuclei/runtime/fn.worker_index.html ```rust pub fn worker_index() -> Option ``` The index of the worker this code runs on (0, 1, … among the workers of its runtime), `None` off the workers (in `block_on`’s own thread, on the blocking pool, outside any runtime). ## Module `nuclei::signal` https://nuclei.rs/api/nuclei/signal/index.html Signals (unix) and console control events (Windows), as streams. Signals: a stream of the deliveries of one signal (unix) or console control event (Windows), and [`ctrl_c`](https://nuclei.rs/api/nuclei/signal/fn.ctrl_c.html). Each signal has a count of its deliveries, which the process’s handler raises. A listener remembers the count it last saw: a poll that finds the count moved is one item, however many deliveries that was. A listener that waits registers its waker, then looks at the count once more; whoever dispatches looks at the count after the delivery raised it, then wakes the listeners of each signal whose count moved, so no delivery is missed (the register-then-look pattern of the sync module). On unix a signal handler may do little: it raises the count and writes to one wake descriptor of the process, never closed, which every shard with a listener reads through a pump task of its own and then dispatches (see `unix`). On Windows the console control handler runs on a thread of its own and dispatches itself. ### Modules - [unix](https://nuclei.rs/api/nuclei/signal/unix/index.html): Unix signals as streams: [`signal`](https://nuclei.rs/api/nuclei/signal/unix/fn.signal.html) listens to one [`SignalKind`](https://nuclei.rs/api/nuclei/signal/unix/struct.SignalKind.html). ### Functions - [ctrl_c](https://nuclei.rs/api/nuclei/signal/fn.ctrl_c.html): Completes once the process gets a Ctrl-C: `SIGINT` on unix, the console’s `CTRL_C_EVENT` on Windows. Listening starts with the first poll; on unix the default action of `SIGINT` (ending the process) is replaced for good from then on. ### fn `nuclei::signal::ctrl_c` https://nuclei.rs/api/nuclei/signal/fn.ctrl_c.html ```rust pub async fn ctrl_c() -> Result<()> ``` Completes once the process gets a Ctrl-C: `SIGINT` on unix, the console’s `CTRL_C_EVENT` on Windows. Listening starts with the first poll; on unix the default action of `SIGINT` (ending the process) is replaced for good from then on. **Errors** When the handler cannot be installed. ## Module `nuclei::signal::unix` https://nuclei.rs/api/nuclei/signal/unix/index.html Unix signals as streams: [`signal`](https://nuclei.rs/api/nuclei/signal/unix/fn.signal.html) listens to one [`SignalKind`](https://nuclei.rs/api/nuclei/signal/unix/struct.SignalKind.html). The first listener of a signal installs the process’s handler for it (`SA_SIGINFO | SA_RESTART | SA_ONSTACK`), which stays for good and chains to the handler that was there before. The handler raises the signal’s count, then writes to the process’s wake descriptor: an eventfd on Linux, a pipe elsewhere, made once, non-blocking, and never closed, so a handler never writes to a descriptor that went or that another file reuses. Both are async-signal-safe; errno is kept. Each shard a listener is polled on runs a pump: a task of the runtime’s own that reads the wake descriptor through the shard’s driver and then dispatches. The pump drains the descriptor before it looks at the counts, and the handler raises the count before it writes, so a delivery whose write the pump read is in the counts it sees, and a later one writes again. A listener polled where no shard runs is served by a pump on a runtime worker. ### Structs - [Signal](https://nuclei.rs/api/nuclei/signal/unix/struct.Signal.html): The deliveries of one signal, as a stream: each item stands for one delivery or more since the item before. - [SignalKind](https://nuclei.rs/api/nuclei/signal/unix/struct.SignalKind.html): A unix signal a [`Signal`](https://nuclei.rs/api/nuclei/signal/unix/struct.Signal.html) listens to. ### Functions - [signal](https://nuclei.rs/api/nuclei/signal/unix/fn.signal.html): Listens to `kind` from now on. ### struct `nuclei::signal::unix::Signal` https://nuclei.rs/api/nuclei/signal/unix/struct.Signal.html ```rust pub struct Signal { /* private fields */ } ``` The deliveries of one signal, as a stream: each item stands for one delivery or more since the item before. #### Implementations `impl Signal` ```rust pub async fn recv(&mut self) -> Option<()> ``` Waits for the next delivery. Always `Some`: the stream never ends. ```rust pub fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll> ``` Ready with `Some` once the signal was delivered since the last item. #### Trait Implementations - `impl Debug for Signal` - `impl Stream for Signal` #### Auto Trait Implementations - `impl !RefUnwindSafe for Signal` - `impl !UnwindSafe for Signal` - `impl Freeze for Signal` - `impl Send for Signal` - `impl Sync for Signal` - `impl Unpin for Signal` - `impl UnsafeUnpin for Signal` ### struct `nuclei::signal::unix::SignalKind` https://nuclei.rs/api/nuclei/signal/unix/struct.SignalKind.html ```rust pub struct SignalKind(/* private fields */); ``` A unix signal a [`Signal`](https://nuclei.rs/api/nuclei/signal/unix/struct.Signal.html) listens to. #### Implementations `impl SignalKind` ```rust pub const fn from_raw(signum: c_int) -> Self ``` The signal numbered `signum`. ```rust pub const fn as_raw(self) -> c_int ``` The signal’s number. ```rust pub const fn alarm() -> Self ``` `SIGALRM`. ```rust pub const fn child() -> Self ``` `SIGCHLD`. ```rust pub const fn hangup() -> Self ``` `SIGHUP`. ```rust pub const fn interrupt() -> Self ``` `SIGINT`: Ctrl-C at a terminal. ```rust pub const fn pipe() -> Self ``` `SIGPIPE`. ```rust pub const fn quit() -> Self ``` `SIGQUIT`. ```rust pub const fn terminate() -> Self ``` `SIGTERM`. ```rust pub const fn user_defined1() -> Self ``` `SIGUSR1`. ```rust pub const fn user_defined2() -> Self ``` `SIGUSR2`. ```rust pub const fn window_change() -> Self ``` `SIGWINCH`: the terminal’s size changed. #### Trait Implementations - `impl Clone for SignalKind` - `impl Copy for SignalKind` - `impl Debug for SignalKind` - `impl Eq for SignalKind` - `impl From for SignalKind` - `impl Hash for SignalKind` - `impl PartialEq for SignalKind` - `impl StructuralPartialEq for SignalKind` #### Auto Trait Implementations - `impl Freeze for SignalKind` - `impl RefUnwindSafe for SignalKind` - `impl Send for SignalKind` - `impl Sync for SignalKind` - `impl Unpin for SignalKind` - `impl UnsafeUnpin for SignalKind` - `impl UnwindSafe for SignalKind` ### fn `nuclei::signal::unix::signal` https://nuclei.rs/api/nuclei/signal/unix/fn.signal.html ```rust pub fn signal(kind: SignalKind) -> Result ``` Listens to `kind` from now on. **Errors** When `kind` is no signal number, is one no handler can take (`SIGKILL`, `SIGSTOP`) or whose handler cannot return (`SIGILL`, `SIGFPE`, `SIGSEGV`), or when the handler or the wake descriptor cannot be made. ## Module `nuclei::stats` https://nuclei.rs/api/nuclei/stats/index.html What the runtime is doing: a snapshot of every shard’s counters, taken by [`stats()`](https://nuclei.rs/api/nuclei/stats/fn.stats.html), or of one runtime’s by [`Runtime::stats`](https://nuclei.rs/api/nuclei/runtime/struct.Runtime.html#method.stats). A runtime built with [`Builder::record_latencies`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.record_latencies) adds a [`Histogram`](https://nuclei.rs/api/nuclei/stats/struct.Histogram.html) of its poll times, and with the `io-stats` feature each worker’s IO counts and latencies. The snapshot covers every shard alive in the process: each runtime’s workers, and the shard of each thread that runs `block_on` (made on its first need, gone with the thread). A shard’s counts are read without stopping it, one at a time, so they need not agree with each other to the operation. Most are counted in the shard’s own memory and published for snapshots: by a shard about to wait for work, so a quiet shard’s are current, and by a busy one at least once every few hundred task runs. Errors are counted as they happen. Taking a snapshot costs a read of each shard’s counters; a running shard pays nothing for it. ### Structs - [ErrorCounts](https://nuclei.rs/api/nuclei/stats/struct.ErrorCounts.html): IO errors counted by [`io::ErrorKind`](https://doc.rust-lang.org/1.99.1/core/io/error/enum.ErrorKind.html), and two kinds of failure counted apart. - [Histogram](https://nuclei.rs/api/nuclei/stats/struct.Histogram.html): A log2 histogram of durations: bucket `i` counts the samples from `2^i` nanoseconds up to (and not including) `2^(i+1)`; the first bucket also counts samples under a nanosecond. - [IoCounts](https://nuclei.rs/api/nuclei/stats/struct.IoCounts.html): The IO operations a shard’s thread completed: see [`ShardStats::io`](https://nuclei.rs/api/nuclei/stats/struct.ShardStats.html#structfield.io). With the `io-stats` feature only. - [IoLatencies](https://nuclei.rs/api/nuclei/stats/struct.IoLatencies.html): How long each kind of a shard’s IO operations took, from their submission to the kernel to their completion: see [`ShardStats::io_latencies`](https://nuclei.rs/api/nuclei/stats/struct.ShardStats.html#structfield.io_latencies). - [ShardStats](https://nuclei.rs/api/nuclei/stats/struct.ShardStats.html): One shard’s counters. Those marked “published” are as the shard last published them (see [the module](https://nuclei.rs/api/nuclei/stats/index.html)). - [Stats](https://nuclei.rs/api/nuclei/stats/struct.Stats.html): A snapshot of the runtime’s counters: [`stats()`](https://nuclei.rs/api/nuclei/stats/fn.stats.html). ### Functions - [stats](https://nuclei.rs/api/nuclei/stats/fn.stats.html): A snapshot of the counters of every shard alive in the process and of the blocking pools. See [`Stats`](https://nuclei.rs/api/nuclei/stats/struct.Stats.html). ### struct `nuclei::stats::ErrorCounts` https://nuclei.rs/api/nuclei/stats/struct.ErrorCounts.html ```rust #[non_exhaustive]pub struct ErrorCounts { pub refused_registrations: u64, pub accepts_out_of_descriptors: u64, /* private fields */ } ``` IO errors counted by [`io::ErrorKind`](https://doc.rust-lang.org/1.99.1/core/io/error/enum.ErrorKind.html), and two kinds of failure counted apart. An error counted is one an operation on a socket, pipe or file ended with, as the system gave it: not a “try again” the driver answers by waiting, nor the cancel of an operation whose task went away. #### Fields (Non-exhaustive) Non-exhaustive structs could have additional fields added in future. Therefore, non-exhaustive structs cannot be constructed in external crates using the traditional `Struct { .. }` syntax; cannot be matched against without a wildcard `..`; and struct update syntax will not work. `refused_registrations: u64` Handles the shard could not register: the kernel refused to watch the descriptor, or to let the shard’s driver take it. `accepts_out_of_descriptors: u64` Accepts that failed because the process or the system had no file descriptor left (counted among the errors by kind too). #### Implementations `impl ErrorCounts` ```rust pub fn get(&self, kind: ErrorKind) -> u64 ``` Errors of `kind`. The kinds are counted apart from a fixed table holding every stable kind the system’s IO errors map to; one outside it is counted, and read, as [`io::ErrorKind::Other`](https://doc.rust-lang.org/1.99.1/core/io/error/enum.ErrorKind.html#variant.Other). ```rust pub fn iter(&self) -> impl Iterator + '_ ``` Each kind with errors, and how many, in the table’s fixed order. #### Trait Implementations - `impl Clone for ErrorCounts` - `impl Debug for ErrorCounts` - `impl Default for ErrorCounts` - `impl Eq for ErrorCounts` - `impl PartialEq for ErrorCounts` - `impl StructuralPartialEq for ErrorCounts` #### Auto Trait Implementations - `impl Freeze for ErrorCounts` - `impl RefUnwindSafe for ErrorCounts` - `impl Send for ErrorCounts` - `impl Sync for ErrorCounts` - `impl Unpin for ErrorCounts` - `impl UnsafeUnpin for ErrorCounts` - `impl UnwindSafe for ErrorCounts` ### struct `nuclei::stats::Histogram` https://nuclei.rs/api/nuclei/stats/struct.Histogram.html ```rust pub struct Histogram { /* private fields */ } ``` A log2 histogram of durations: bucket `i` counts the samples from `2^i` nanoseconds up to (and not including) `2^(i+1)`; the first bucket also counts samples under a nanosecond. #### Implementations `impl Histogram` ```rust pub fn count(&self) -> u64 ``` The samples counted. ```rust pub fn buckets(&self) -> impl Iterator + '_ ``` Each bucket that holds samples: its lowest duration, the duration it ends before, and its count, from the shortest up. #### Trait Implementations - `impl Clone for Histogram` - `impl Debug for Histogram` - `impl Eq for Histogram` - `impl PartialEq for Histogram` - `impl StructuralPartialEq for Histogram` #### Auto Trait Implementations - `impl Freeze for Histogram` - `impl RefUnwindSafe for Histogram` - `impl Send for Histogram` - `impl Sync for Histogram` - `impl Unpin for Histogram` - `impl UnsafeUnpin for Histogram` - `impl UnwindSafe for Histogram` ### struct `nuclei::stats::IoCounts` https://nuclei.rs/api/nuclei/stats/struct.IoCounts.html ```rust #[non_exhaustive]pub struct IoCounts { pub reads: u64, pub writes: u64, pub bytes_read: u64, pub bytes_written: u64, pub accepts: u64, } ``` The IO operations a shard’s thread completed: see [`ShardStats::io`](https://nuclei.rs/api/nuclei/stats/struct.ShardStats.html#structfield.io). With the `io-stats` feature only. An operation is counted when the kernel completes it: a read or receive that returned bytes or the end of the stream, a write or send that took bytes, a connection accepted. A read served from the read-ahead is counted when the read-ahead’s own read completed, and a write taken into the write-behind when the write-behind’s own write did. Peeks and readiness probes are not counted. IO completed on a thread that runs no shard (the blocking pool’s own calls, a thread outside the runtime) is counted by no shard. #### Fields (Non-exhaustive) Non-exhaustive structs could have additional fields added in future. Therefore, non-exhaustive structs cannot be constructed in external crates using the traditional `Struct { .. }` syntax; cannot be matched against without a wildcard `..`; and struct update syntax will not work. `reads: u64` Reads and receives. `writes: u64` Writes and sends. `bytes_read: u64` Bytes the counted reads returned. `bytes_written: u64` Bytes the counted writes took. `accepts: u64` Connections accepted. #### Trait Implementations - `impl Clone for IoCounts` - `impl Copy for IoCounts` - `impl Debug for IoCounts` - `impl Default for IoCounts` - `impl Eq for IoCounts` - `impl PartialEq for IoCounts` - `impl StructuralPartialEq for IoCounts` #### Auto Trait Implementations - `impl Freeze for IoCounts` - `impl RefUnwindSafe for IoCounts` - `impl Send for IoCounts` - `impl Sync for IoCounts` - `impl Unpin for IoCounts` - `impl UnsafeUnpin for IoCounts` - `impl UnwindSafe for IoCounts` ### struct `nuclei::stats::IoLatencies` https://nuclei.rs/api/nuclei/stats/struct.IoLatencies.html ```rust #[non_exhaustive]pub struct IoLatencies { pub reads: Histogram, pub writes: Histogram, pub accepts: Histogram, pub connects: Histogram, pub files: Histogram, } ``` How long each kind of a shard’s IO operations took, from their submission to the kernel to their completion: see [`ShardStats::io_latencies`](https://nuclei.rs/api/nuclei/stats/struct.ShardStats.html#structfield.io_latencies). A multishot receive or accept is one operation for many arrivals and is not timed; nor is a cancelled operation or a readiness probe. File calls are timed on the ring, not the ones the blocking pool makes. #### Fields (Non-exhaustive) Non-exhaustive structs could have additional fields added in future. Therefore, non-exhaustive structs cannot be constructed in external crates using the traditional `Struct { .. }` syntax; cannot be matched against without a wildcard `..`; and struct update syntax will not work. `reads: Histogram` Reads and receives. `writes: Histogram` Writes and sends. `accepts: Histogram` Accepts, one connection each. `connects: Histogram` Connects. `files: Histogram` Reads and writes of files. #### Trait Implementations - `impl Clone for IoLatencies` - `impl Debug for IoLatencies` #### Auto Trait Implementations - `impl Freeze for IoLatencies` - `impl RefUnwindSafe for IoLatencies` - `impl Send for IoLatencies` - `impl Sync for IoLatencies` - `impl Unpin for IoLatencies` - `impl UnsafeUnpin for IoLatencies` - `impl UnwindSafe for IoLatencies` ### struct `nuclei::stats::ShardStats` https://nuclei.rs/api/nuclei/stats/struct.ShardStats.html ```rust #[non_exhaustive]pub struct ShardStats { pub worker: Option, pub runtime: Option, pub backend: IoBackend, pub tasks: usize, pub polls: u64, pub parks: u64, pub parked: Duration, pub busy: Duration, pub queue_depth: usize, pub remote_wakes: u64, pub ops_in_flight: usize, pub cq_overflows: u64, pub buffer_bytes: usize, pub buffer_cap: usize, pub buffer_exhausted: u64, pub timers: usize, pub handoffs: u64, pub longest_poll: Duration, pub budget_yields: u64, pub poll_times: Option, pub io_latencies: Option, pub io: Option, pub errors: ErrorCounts, } ``` One shard’s counters. Those marked “published” are as the shard last published them (see [the module](https://nuclei.rs/api/nuclei/stats/index.html)). #### Fields (Non-exhaustive) Non-exhaustive structs could have additional fields added in future. Therefore, non-exhaustive structs cannot be constructed in external crates using the traditional `Struct { .. }` syntax; cannot be matched against without a wildcard `..`; and struct update syntax will not work. `worker: Option` The shard’s place among its runtime’s workers; `None` for the shard of a thread that runs `block_on`. `runtime: Option` The runtime the shard is a worker of; `None` for the shard of a thread that runs `block_on`, which serves every runtime the thread enters. `backend: IoBackend` The kernel interface the shard’s IO runs on. `tasks: usize` Tasks placed on the shard and not done yet. `polls: u64` Task polls the shard has run (published). `parks: u64` Times the shard slept with nothing to run (published). `parked: Duration` Time the shard spent asleep, in all (published). `busy: Duration` Time since the shard was made that it did not spend asleep: running tasks, driving its IO and timers, spinning before a park (from the published time asleep). `queue_depth: usize` Runnables waiting in the shard’s own queue, its LIFO slot included (published). `remote_wakes: u64` Runnables of the shard’s tasks it took from other threads: a task woken there, or spawned onto it from there (published). `ops_in_flight: usize` IO operations the shard handed to the kernel that have not ended: on io_uring the operations submitted, on IOCP the ones issued. A readiness poller (epoll, kqueue) hands the kernel none, as its driver makes each call once the descriptor is ready: 0 there (published). `cq_overflows: u64` Times the shard found completions the kernel was holding for want of room in the ring’s completion queue (none is lost: the kernel keeps them until there is room); 0 on other backends (published). `buffer_bytes: usize` Bytes the shard’s IO buffers hold: its pool’s, in use and free, and on io_uring its receive buffers’ (published). `buffer_cap: usize` The most bytes the shard’s IO buffers may hold, its receive buffers included ([`Builder::io_buffer_cap`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.io_buffer_cap)). `buffer_exhausted: u64` Times a buffer was wanted while every byte under the pool’s cap was in use; the IO waits for one to come back (published). `timers: usize` Timers armed on the shard (published). `handoffs: u64` Times the shard went to another thread because the thread running it stayed in one poll past [`Builder::handoff_after`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.handoff_after). `longest_poll: Duration` The longest poll the runtime saw on the shard, at the resolution of its watch (a quarter of the handoff threshold); zero when no poll lasted that long, or with the handoff off. `budget_yields: u64` Times a task’s poll on the shard spent its budget of operations and yielded to the shard’s other tasks (see [`task::coop`](https://nuclei.rs/api/nuclei/task/coop/index.html)). `poll_times: Option` How long each task poll on the shard ran, while its runtime records it ([`Builder::record_latencies`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.record_latencies)); `None` when it does not, which is not a shard with no polls. `io_latencies: Option` How long the shard’s IO operations took from their submission to the kernel to their completion, by kind, while its runtime records latencies ([`Builder::record_latencies`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.record_latencies)); `None` when it does not, and `None` on a readiness backend (epoll, kqueue), whose calls are made once the kernel reports the descriptor ready, so there is no wait in the kernel per operation to time. With the `io-stats` feature only. `io: Option` The IO operations the shard’s thread completed, while its runtime counts them ([`Builder::count_io`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.count_io)); `None` when it does not, which is not a shard that did no IO (published). With the `io-stats` feature only. `errors: ErrorCounts` Errors of IO run on the shard. #### Trait Implementations - `impl Clone for ShardStats` - `impl Debug for ShardStats` #### Auto Trait Implementations - `impl Freeze for ShardStats` - `impl RefUnwindSafe for ShardStats` - `impl Send for ShardStats` - `impl Sync for ShardStats` - `impl Unpin for ShardStats` - `impl UnsafeUnpin for ShardStats` - `impl UnwindSafe for ShardStats` ### struct `nuclei::stats::Stats` https://nuclei.rs/api/nuclei/stats/struct.Stats.html ```rust #[non_exhaustive]pub struct Stats { pub shards: Vec, pub blocking_threads: usize, pub blocking_queue_depth: usize, pub off_shard_errors: ErrorCounts, pub receive_buffers_missing: u64, } ``` A snapshot of the runtime’s counters: [`stats()`](https://nuclei.rs/api/nuclei/stats/fn.stats.html). #### Fields (Non-exhaustive) Non-exhaustive structs could have additional fields added in future. Therefore, non-exhaustive structs cannot be constructed in external crates using the traditional `Struct { .. }` syntax; cannot be matched against without a wildcard `..`; and struct update syntax will not work. `shards: Vec` Every shard alive: the workers first, by their place in their runtime, then the shards of threads that run `block_on`. `blocking_threads: usize` Threads of the blocking pools alive now, at work or idle. `blocking_queue_depth: usize` Jobs waiting in the blocking pools’ queues for a thread to take them. `off_shard_errors: ErrorCounts` Errors of IO run on threads that run no shard: a handle polled outside nuclei’s `block_on` and its tasks, or a completion delivered while its shard was not running. `receive_buffers_missing: u64` Shards that started without the io_uring receive buffers their configuration asked for, because the system had no memory for them (most often the locked-memory limit); their reads use the pool’s buffers instead. #### Trait Implementations - `impl Clone for Stats` - `impl Debug for Stats` #### Auto Trait Implementations - `impl Freeze for Stats` - `impl RefUnwindSafe for Stats` - `impl Send for Stats` - `impl Sync for Stats` - `impl Unpin for Stats` - `impl UnsafeUnpin for Stats` - `impl UnwindSafe for Stats` ### fn `nuclei::stats::stats` https://nuclei.rs/api/nuclei/stats/fn.stats.html Also exported as `nuclei::stats`. ```rust pub fn stats() -> Stats ``` A snapshot of the counters of every shard alive in the process and of the blocking pools. See [`Stats`](https://nuclei.rs/api/nuclei/stats/struct.Stats.html). ```rust let stats = nuclei::stats(); for shard in &stats.shards { println!("{:?}: {} tasks, {} polls", shard.worker, shard.tasks, shard.polls); } ``` ## Module `nuclei::sync` https://nuclei.rs/api/nuclei/sync/index.html Runtime-independent synchronization primitives: futures and wakers only, usable from any executor. Nuclei’s runtime-independent synchronization primitives: locks, a semaphore, events, a barrier, once-cells and channels that never block a thread. Every wait in this module is a [`Future`](https://doc.rust-lang.org/1.99.1/core/future/future/trait.Future.html) built from futures and wakers only: async code awaits it, and any executor polls it with its own [`Waker`](https://doc.rust-lang.org/1.99.1/core/task/wake/struct.Waker.html). Every primitive also has `try_` forms that never wait. The core of this module makes no system call: no futex, no thread park, no sleep and no clock read. The one exception is inside the lock-free queues the primitives use, which recycle waiter nodes and yield the thread when they meet contention. The other exception is the `blocking_*` methods, which exist for threads that may block and park the calling thread until their wait is over. Called on a nuclei shard (inside one of its tasks) they run a nested `block_on` instead, so the shard keeps running its other tasks; called inside another runtime’s task they block the thread that task runs on. **Names and signatures** [`Mutex`](https://nuclei.rs/api/nuclei/sync/struct.Mutex.html), [`RwLock`](https://nuclei.rs/api/nuclei/sync/struct.RwLock.html), [`Semaphore`](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html), [`Notify`](https://nuclei.rs/api/nuclei/sync/struct.Notify.html), [`Barrier`](https://nuclei.rs/api/nuclei/sync/struct.Barrier.html), [`OnceCell`](https://nuclei.rs/api/nuclei/sync/struct.OnceCell.html) and [`SetOnce`](https://nuclei.rs/api/nuclei/sync/struct.SetOnce.html) take the names, signatures, error types and documented behavior of the established async `sync` API, so code written against that API compiles against these. The guards and errors sit at the same paths under `nuclei::sync`, and the waits are named futures (`Lock`, `Read`, `Acquire`, and so on) rather than opaque ones. A semaphore holds at most [`Semaphore::MAX_PERMITS`](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html#associatedconstant.MAX_PERMITS) permits, which is `usize::MAX >> 7`. What this module adds is the [`Event`](https://nuclei.rs/api/nuclei/sync/struct.Event.html), the [`Latch`](https://nuclei.rs/api/nuclei/sync/struct.Latch.html), the [`Lazy`](https://nuclei.rs/api/nuclei/sync/struct.Lazy.html) value, the upgradable read of the [`RwLock`](https://nuclei.rs/api/nuclei/sync/struct.RwLock.html), the reentrant locks and `OnceCell::get_or_init_racy`. The [`mpsc`](https://nuclei.rs/api/nuclei/sync/mpsc/index.html) channels follow the same rule for the established channel API, with their own progress notes. The [`local`](https://nuclei.rs/api/nuclei/sync/local/index.html) module adds single-shard twins of the channels, the semaphore and the mutex, with no atomic instruction on any path, and [`mesh`](https://nuclei.rs/api/nuclei/sync/mesh/index.html) a full mesh of bounded channels between a fixed number of parties. **What every primitive guarantees** - **No runtime.** A contended acquire queues a waiter, registers the caller’s `Waker` and returns `Pending`. What a wake does belongs to the caller’s executor. Within one poll, a contended acquire of a lock or a semaphore may first spin for a short while (up to the lock’s spin budget, a count of pause instructions it adapts to how long holds last, about 5 microseconds at most on the cores it was tuned on): before it queues, and again after a retry it lost. The spin makes no system call, reads no clock, and ends in the same queueing or the same `Pending` as before. Locks whose holders keep them across long waits of their own do not spin, and their contended callers queue at once: the once-cell’s initializer turn, for example. - **Fast under contention.** The locks and the semaphore let a caller take what is free even while others wait, so a release never waits for a suspended task to run: the thread that released takes the lock straight back. - **Bounded bypass.** A release wakes the oldest waiters it could serve to compete again. One that loses [`MAX_BYPASS`](https://nuclei.rs/api/nuclei/sync/constant.MAX_BYPASS.html) times is owed a handoff: nobody gets in ahead of it, and the next release hands it what it waits for directly. Fairness is counted, never timed. - **Cancellation-safe.** Dropping a pending future withdraws its waiter. If something was handed to it concurrently, the drop passes it on. No wakeup is lost. (A [`Barrier`](https://nuclei.rs/api/nuclei/sync/struct.Barrier.html) wait is the one exception: an arrival that was counted stays counted.) - **Cooperative on a nuclei shard.** In a task on a nuclei shard (or in `block_on`’s own future), a receive of [`mpsc`](https://nuclei.rs/api/nuclei/sync/mpsc/index.html), [`oneshot`](https://nuclei.rs/api/nuclei/sync/oneshot/index.html), [`broadcast`](https://nuclei.rs/api/nuclei/sync/broadcast/index.html) or [`watch`](https://nuclei.rs/api/nuclei/sync/watch/index.html) that completes spends one operation of the task’s cooperative budget, as IO does ([`task::coop`](https://nuclei.rs/api/nuclei/task/coop/index.html)), and so does an acquire of a semaphore, a lock (the reentrant ones too) or a bounded send that completes at its first attempt. When the budget is spent the call completes nothing, wakes its task and returns `Pending`, so a loop on a channel or a lock that is always ready yields to the shard’s other tasks. A wait that queued and was granted spends nothing: giving the grant back would cost it its place. The `try_` forms never spend, and off a nuclei shard there is no budget. The events, latches, barriers, once-cells and `Notify` keep no budget. - **Reentrancy by [`Owner`](https://nuclei.rs/api/nuclei/sync/struct.Owner.html).** The reentrant locks are keyed by an owner token rather than a thread, because a task can move between threads and many tasks can share one. - **Every target.** State lives in word-sized atomics (in plain cells in [`local`](https://nuclei.rs/api/nuclei/sync/local/index.html), whose types stay on one thread). On single-threaded wasm the same code runs on one thread, where only interleaved tasks contend. The fast paths allocate nothing; a waiter node comes from a per-primitive free list and reaches the allocator only when that list is empty. **How a wait works** Each primitive keeps one state word, a lock-free stack of arriving waiters and a FIFO of the waiters already sorted. Uncontended calls touch the state word only, one atomic read-modify-write each. Anything that can make a waiter runnable (a release, a new waiter, a cancellation) takes the drain role with one compare-and-swap, or, when another thread holds it, leaves a mark for the holder and returns, so no call ever waits for another. The holder wakes what the state allows (or, while a handoff is owed, grants it in queue order), rechecks until nothing changed while it worked, and calls the wakers after it has given the role up. **Progress** Every operation is lock-free, not wait-free. No call waits for another thread, and some call always completes; but a call may do work on behalf of others, and how much depends on them. - Uncontended, an acquire and a release are one atomic read-modify-write each. - A call that can make a waiter runnable (a release with waiters, a new waiter, a cancellation, a notification, a semaphore’s `close`, a write guard’s `downgrade`, `add_permits`) may serve the queue itself. It returns after one pass over the queue, plus at most one more pass for each of these that lands while it works: a waiter that queues, a waiter that withdraws, a waiter that claims the handoff it is owed, and a release that finds a node queued. - `forget_permits` wakes nobody: it is a compare-and-swap loop on the state word, which retries only when another call changed the word first. A barrier’s arrival is one `fetch_add`, followed, for the arrival that completes a group, by the pass that wakes the group. - A release over an empty queue earns no pass; a release that finds a node queued earns one. So releases alone never keep a thread at work. Waiters that keep queueing or withdrawing can, one pass each: every such pass is another thread’s own operation getting done, which is what lock-free means, and there is no cap on the passes of one call. Besides the primitives, this module re-exports a lock-free map ([`HopscotchMap`](https://nuclei.rs/api/nuclei/sync/struct.HopscotchMap.html)), queues ([`SegQueue`](https://nuclei.rs/api/nuclei/sync/struct.SegQueue.html), [`ArrayQueue`](https://nuclei.rs/api/nuclei/sync/struct.ArrayQueue.html)) and [`Atom`](https://nuclei.rs/api/nuclei/sync/struct.Atom.html), so one module holds every synchronization structure. ### Modules - [broadcast](https://nuclei.rs/api/nuclei/sync/broadcast/index.html): A multi-producer, multi-consumer broadcast channel: each value sent reaches every receiver that exists when it is sent. - [futures](https://nuclei.rs/api/nuclei/sync/futures/index.html): Named future types, at the conventional `sync::futures` path. - [local](https://nuclei.rs/api/nuclei/sync/local/index.html): Synchronization primitives for the tasks of one shard. - [mesh](https://nuclei.rs/api/nuclei/sync/mesh/index.html): A full mesh of bounded channels between a fixed number of parties. - [mpsc](https://nuclei.rs/api/nuclei/sync/mpsc/index.html): Multi-producer, single-consumer channels for sending values between tasks. - [oneshot](https://nuclei.rs/api/nuclei/sync/oneshot/index.html): A channel that carries one value from one sender to one receiver. - [watch](https://nuclei.rs/api/nuclei/sync/watch/index.html): A multi-producer, multi-consumer channel that retains only the *last* sent value. ### Structs - [Acquire](https://nuclei.rs/api/nuclei/sync/struct.Acquire.html): The future [`Semaphore::acquire`](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html#method.acquire) and [`Semaphore::acquire_many`](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html#method.acquire_many) return. - [AcquireError](https://nuclei.rs/api/nuclei/sync/struct.AcquireError.html): Error returned from [`Semaphore::acquire`](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html#method.acquire) and the other waits for permits. - [AcquireOwned](https://nuclei.rs/api/nuclei/sync/struct.AcquireOwned.html): The future [`Semaphore::acquire_owned`](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html#method.acquire_owned) and [`Semaphore::acquire_many_owned`](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html#method.acquire_many_owned) return. - [ArrayQueue](https://nuclei.rs/api/nuclei/sync/struct.ArrayQueue.html): A bounded lock-free queue, from the kovan-queue crate: see its docs. A bounded multi-producer multi-consumer queue. - [Atom](https://nuclei.rs/api/nuclei/sync/struct.Atom.html): An atomically swapped value, from the kovan crate: see its docs. A single-value container with safe memory reclamation: loads, stores and swaps are wait-free, and [`rcu()`](https://nuclei.rs/api/nuclei/sync/struct.Atom.html#method.rcu) is lock-free (it retries only after another thread’s write). - [Barrier](https://nuclei.rs/api/nuclei/sync/struct.Barrier.html): A barrier that releases its waiters in groups of `n`. - [BarrierWait](https://nuclei.rs/api/nuclei/sync/struct.BarrierWait.html): The future [`Barrier::wait`](https://nuclei.rs/api/nuclei/sync/struct.Barrier.html#method.wait) returns. - [BarrierWaitResult](https://nuclei.rs/api/nuclei/sync/struct.BarrierWaitResult.html): What a completed [`Barrier::wait`](https://nuclei.rs/api/nuclei/sync/struct.Barrier.html#method.wait) reports. - [CancellationToken](https://nuclei.rs/api/nuclei/sync/struct.CancellationToken.html): A token which can be used to signal a cancellation request to one or more tasks. - [DropGuard](https://nuclei.rs/api/nuclei/sync/struct.DropGuard.html): A wrapper for a [`CancellationToken`](https://nuclei.rs/api/nuclei/sync/struct.CancellationToken.html) which cancels it on drop, created by [`CancellationToken::drop_guard`](https://nuclei.rs/api/nuclei/sync/struct.CancellationToken.html#method.drop_guard). - [DropGuardRef](https://nuclei.rs/api/nuclei/sync/struct.DropGuardRef.html): A wrapper for a borrowed [`CancellationToken`](https://nuclei.rs/api/nuclei/sync/struct.CancellationToken.html) which cancels it on drop, created by [`CancellationToken::drop_guard_ref`](https://nuclei.rs/api/nuclei/sync/struct.CancellationToken.html#method.drop_guard_ref). - [Event](https://nuclei.rs/api/nuclei/sync/struct.Event.html): An event that is set once and stays set. - [EventWait](https://nuclei.rs/api/nuclei/sync/struct.EventWait.html): The future [`Event::wait`](https://nuclei.rs/api/nuclei/sync/struct.Event.html#method.wait) returns. - [HopscotchMap](https://nuclei.rs/api/nuclei/sync/struct.HopscotchMap.html): A concurrent hash map, from the kovan-map crate: see its docs. A concurrent, lock-free hash map based on Hopscotch Hashing. - [Latch](https://nuclei.rs/api/nuclei/sync/struct.Latch.html): A latch that opens when its count reaches zero, and stays open. - [LatchWait](https://nuclei.rs/api/nuclei/sync/struct.LatchWait.html): The future [`Latch::wait`](https://nuclei.rs/api/nuclei/sync/struct.Latch.html#method.wait) returns. - [Lazy](https://nuclei.rs/api/nuclei/sync/struct.Lazy.html): A value built by `F` on first access. - [Lock](https://nuclei.rs/api/nuclei/sync/struct.Lock.html): The future [`Mutex::lock`](https://nuclei.rs/api/nuclei/sync/struct.Mutex.html#method.lock) returns. - [LockOwned](https://nuclei.rs/api/nuclei/sync/struct.LockOwned.html): The future [`Mutex::lock_owned`](https://nuclei.rs/api/nuclei/sync/struct.Mutex.html#method.lock_owned) returns. - [MappedMutexGuard](https://nuclei.rs/api/nuclei/sync/struct.MappedMutexGuard.html): A guard for a component of a [`Mutex`](https://nuclei.rs/api/nuclei/sync/struct.Mutex.html)’s value, made by [`MutexGuard::map`](https://nuclei.rs/api/nuclei/sync/struct.MutexGuard.html#method.map); unlocks on drop. The release makes the progress [`MutexGuard`](https://nuclei.rs/api/nuclei/sync/struct.MutexGuard.html)’s does. - [Mutex](https://nuclei.rs/api/nuclei/sync/struct.Mutex.html): A mutual-exclusion lock whose wait is a future. - [MutexGuard](https://nuclei.rs/api/nuclei/sync/struct.MutexGuard.html): Exclusive access to a [`Mutex`](https://nuclei.rs/api/nuclei/sync/struct.Mutex.html)’s value; unlocks on drop. - [Notified](https://nuclei.rs/api/nuclei/sync/struct.Notified.html): The future [`Notify::notified`](https://nuclei.rs/api/nuclei/sync/struct.Notify.html#method.notified) returns. - [Notify](https://nuclei.rs/api/nuclei/sync/struct.Notify.html): Wakes tasks waiting for an event that carries no value. - [OnceCell](https://nuclei.rs/api/nuclei/sync/struct.OnceCell.html): A cell that is written at most once. - [OwnedMappedMutexGuard](https://nuclei.rs/api/nuclei/sync/struct.OwnedMappedMutexGuard.html): A guard for a component `U` of the value of a [`Mutex`](https://nuclei.rs/api/nuclei/sync/struct.Mutex.html) held through an `Arc`, made by [`OwnedMutexGuard::map`](https://nuclei.rs/api/nuclei/sync/struct.OwnedMutexGuard.html#method.map); unlocks on drop. The release makes the progress [`MutexGuard`](https://nuclei.rs/api/nuclei/sync/struct.MutexGuard.html)’s does. - [OwnedMutexGuard](https://nuclei.rs/api/nuclei/sync/struct.OwnedMutexGuard.html): Exclusive access to a [`Mutex`](https://nuclei.rs/api/nuclei/sync/struct.Mutex.html) held through an `Arc`; unlocks on drop. The release makes the progress [`MutexGuard`](https://nuclei.rs/api/nuclei/sync/struct.MutexGuard.html)’s does. - [OwnedNotified](https://nuclei.rs/api/nuclei/sync/struct.OwnedNotified.html): The future [`Notify::notified_owned`](https://nuclei.rs/api/nuclei/sync/struct.Notify.html#method.notified_owned) returns: [`Notified`](https://nuclei.rs/api/nuclei/sync/struct.Notified.html) that keeps its `Notify` alive itself. - [OwnedRwLockMappedWriteGuard](https://nuclei.rs/api/nuclei/sync/struct.OwnedRwLockMappedWriteGuard.html): Exclusive access to a component `U` of the value of a [`RwLock`](https://nuclei.rs/api/nuclei/sync/struct.RwLock.html) held through an `Arc`, made by [`OwnedRwLockWriteGuard::map`](https://nuclei.rs/api/nuclei/sync/struct.OwnedRwLockWriteGuard.html#method.map); releases on drop. The release makes the progress [`RwLockReadGuard`](https://nuclei.rs/api/nuclei/sync/struct.RwLockReadGuard.html)’s does. - [OwnedRwLockReadGuard](https://nuclei.rs/api/nuclei/sync/struct.OwnedRwLockReadGuard.html): Shared access to a [`RwLock`](https://nuclei.rs/api/nuclei/sync/struct.RwLock.html) held through an `Arc`, to its value or to a component `U` of it; releases on drop. The release makes the progress [`RwLockReadGuard`](https://nuclei.rs/api/nuclei/sync/struct.RwLockReadGuard.html)’s does. - [OwnedRwLockWriteGuard](https://nuclei.rs/api/nuclei/sync/struct.OwnedRwLockWriteGuard.html): Exclusive access to a [`RwLock`](https://nuclei.rs/api/nuclei/sync/struct.RwLock.html)’s value through an [`Arc`](https://doc.rust-lang.org/1.99.1/alloc/sync/struct.Arc.html) the guard holds; releases on drop. Made by [`RwLock::write_owned`](https://nuclei.rs/api/nuclei/sync/struct.RwLock.html#method.write_owned). The release makes the progress [`RwLockReadGuard`](https://nuclei.rs/api/nuclei/sync/struct.RwLockReadGuard.html)’s does. - [OwnedSemaphorePermit](https://nuclei.rs/api/nuclei/sync/struct.OwnedSemaphorePermit.html): Permits taken from a [`Semaphore`](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html) held through an `Arc`. The release makes the progress [`SemaphorePermit`](https://nuclei.rs/api/nuclei/sync/struct.SemaphorePermit.html)’s does. - [Owner](https://nuclei.rs/api/nuclei/sync/struct.Owner.html): A token that identifies the holder of a reentrant lock. - [Read](https://nuclei.rs/api/nuclei/sync/struct.Read.html): The future [`RwLock::read`](https://nuclei.rs/api/nuclei/sync/struct.RwLock.html#method.read) returns. - [ReadHeldByOwner](https://nuclei.rs/api/nuclei/sync/struct.ReadHeldByOwner.html): Why a [`ReentrantRwLock::write`](https://nuclei.rs/api/nuclei/sync/struct.ReentrantRwLock.html#method.write) failed: its owner reads without writing, so the write would wait for a read only that owner can end. Release the reads first, or take the write before reading. - [ReadOwned](https://nuclei.rs/api/nuclei/sync/struct.ReadOwned.html): The future [`RwLock::read_owned`](https://nuclei.rs/api/nuclei/sync/struct.RwLock.html#method.read_owned) returns. It keeps its place in the queue, and the bypasses it counted, for as long as it lives; dropping it withdraws the wait and passes on a lock handed to it meanwhile. - [ReentrantMutex](https://nuclei.rs/api/nuclei/sync/struct.ReentrantMutex.html): A mutex the owner holding it can lock again without waiting. - [ReentrantMutexGuard](https://nuclei.rs/api/nuclei/sync/struct.ReentrantMutexGuard.html): Shared access to a [`ReentrantMutex`](https://nuclei.rs/api/nuclei/sync/struct.ReentrantMutex.html)’s value; drops one level of the hold. The drop of the last level releases the lock, which is lock-free, not wait-free: with waiters it returns after one pass over the queue, plus at most one for each operation of another thread that lands on the queue meanwhile (see [Progress](https://nuclei.rs/api/nuclei/sync/index.html#progress)). - [ReentrantMutexLock](https://nuclei.rs/api/nuclei/sync/struct.ReentrantMutexLock.html): The future [`ReentrantMutex::lock`](https://nuclei.rs/api/nuclei/sync/struct.ReentrantMutex.html#method.lock) returns. - [ReentrantRead](https://nuclei.rs/api/nuclei/sync/struct.ReentrantRead.html): The future [`ReentrantRwLock::read`](https://nuclei.rs/api/nuclei/sync/struct.ReentrantRwLock.html#method.read) returns. - [ReentrantReadGuard](https://nuclei.rs/api/nuclei/sync/struct.ReentrantReadGuard.html): One read of a [`ReentrantRwLock`](https://nuclei.rs/api/nuclei/sync/struct.ReentrantRwLock.html); drops one level of the owner’s reads. The drop of the last level releases the read, which is lock-free, not wait-free: with waiters it returns after one pass over the queue, plus at most one for each operation of another thread that lands on the queue meanwhile (see [Progress](https://nuclei.rs/api/nuclei/sync/index.html#progress)). - [ReentrantRwLock](https://nuclei.rs/api/nuclei/sync/struct.ReentrantRwLock.html): A reader-writer lock its holders may lock again, with the bounded bypass of [`RwLock`](https://nuclei.rs/api/nuclei/sync/struct.RwLock.html). - [ReentrantWrite](https://nuclei.rs/api/nuclei/sync/struct.ReentrantWrite.html): The future [`ReentrantRwLock::write`](https://nuclei.rs/api/nuclei/sync/struct.ReentrantRwLock.html#method.write) returns. - [ReentrantWriteGuard](https://nuclei.rs/api/nuclei/sync/struct.ReentrantWriteGuard.html): One write of a [`ReentrantRwLock`](https://nuclei.rs/api/nuclei/sync/struct.ReentrantRwLock.html); drops one level of the owner’s writes. The drop of the last level releases the write, with the progress [`ReentrantReadGuard`](https://nuclei.rs/api/nuclei/sync/struct.ReentrantReadGuard.html)’s release makes. - [RwLock](https://nuclei.rs/api/nuclei/sync/struct.RwLock.html): A reader-writer lock whose waits are futures. - [RwLockMappedWriteGuard](https://nuclei.rs/api/nuclei/sync/struct.RwLockMappedWriteGuard.html): Exclusive access to a component of a [`RwLock`](https://nuclei.rs/api/nuclei/sync/struct.RwLock.html)’s value, made by [`RwLockWriteGuard::map`](https://nuclei.rs/api/nuclei/sync/struct.RwLockWriteGuard.html#method.map); releases on drop. The release makes the progress [`RwLockReadGuard`](https://nuclei.rs/api/nuclei/sync/struct.RwLockReadGuard.html)’s does. - [RwLockReadGuard](https://nuclei.rs/api/nuclei/sync/struct.RwLockReadGuard.html): Shared access to a [`RwLock`](https://nuclei.rs/api/nuclei/sync/struct.RwLock.html)’s value, or to a component of it; releases on drop. - [RwLockUpgradableReadGuard](https://nuclei.rs/api/nuclei/sync/struct.RwLockUpgradableReadGuard.html): The upgradable read of a [`RwLock`](https://nuclei.rs/api/nuclei/sync/struct.RwLock.html): shared access that can become exclusive without a writer getting in between. Releases on drop, with the progress [`RwLockReadGuard`](https://nuclei.rs/api/nuclei/sync/struct.RwLockReadGuard.html)’s release makes. - [RwLockWriteGuard](https://nuclei.rs/api/nuclei/sync/struct.RwLockWriteGuard.html): Exclusive access to a [`RwLock`](https://nuclei.rs/api/nuclei/sync/struct.RwLock.html)’s value; releases on drop. The release makes the progress [`RwLockReadGuard`](https://nuclei.rs/api/nuclei/sync/struct.RwLockReadGuard.html)’s does. - [SegQueue](https://nuclei.rs/api/nuclei/sync/struct.SegQueue.html): An unbounded lock-free queue and its pop error, from the kovan-queue crate: see its docs. An unbounded, lock-free, linearizable FIFO queue for many producers and many consumers. - [Semaphore](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html): A counting semaphore whose waits are futures. - [SemaphorePermit](https://nuclei.rs/api/nuclei/sync/struct.SemaphorePermit.html): Permits taken from a [`Semaphore`](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html), returned when dropped. - [SetOnce](https://nuclei.rs/api/nuclei/sync/struct.SetOnce.html): A cell that is set once, and that readers can wait on until it is. - [SetOnceError](https://nuclei.rs/api/nuclei/sync/struct.SetOnceError.html): Error returned from [`SetOnce::set`](https://nuclei.rs/api/nuclei/sync/struct.SetOnce.html#method.set): the cell was set already, or another `set` is setting it now. The value comes back. - [ThreadOwner](https://nuclei.rs/api/nuclei/sync/struct.ThreadOwner.html): The calling thread’s [`Owner`](https://nuclei.rs/api/nuclei/sync/struct.Owner.html), from [`Owner::thread`](https://nuclei.rs/api/nuclei/sync/struct.Owner.html#method.thread). - [TryLockError](https://nuclei.rs/api/nuclei/sync/struct.TryLockError.html): Error returned from [`Mutex::try_lock`](https://nuclei.rs/api/nuclei/sync/struct.Mutex.html#method.try_lock), [`RwLock::try_read`](https://nuclei.rs/api/nuclei/sync/struct.RwLock.html#method.try_read) and [`RwLock::try_write`](https://nuclei.rs/api/nuclei/sync/struct.RwLock.html#method.try_write) and their `_owned` forms. - [UpgradableRead](https://nuclei.rs/api/nuclei/sync/struct.UpgradableRead.html): The future [`RwLock::upgradable_read`](https://nuclei.rs/api/nuclei/sync/struct.RwLock.html#method.upgradable_read) returns. - [Upgrade](https://nuclei.rs/api/nuclei/sync/struct.Upgrade.html): The future [`RwLockUpgradableReadGuard::upgrade`](https://nuclei.rs/api/nuclei/sync/struct.RwLockUpgradableReadGuard.html#method.upgrade) returns. Dropping it before it completes releases the upgradable read. - [WaitForCancellationFuture](https://nuclei.rs/api/nuclei/sync/struct.WaitForCancellationFuture.html): A future that resolves once the corresponding [`CancellationToken`](https://nuclei.rs/api/nuclei/sync/struct.CancellationToken.html) is cancelled. - [WaitForCancellationFutureOwned](https://nuclei.rs/api/nuclei/sync/struct.WaitForCancellationFutureOwned.html): A future that resolves once the corresponding [`CancellationToken`](https://nuclei.rs/api/nuclei/sync/struct.CancellationToken.html) is cancelled, and owns the token. - [Write](https://nuclei.rs/api/nuclei/sync/struct.Write.html): The future [`RwLock::write`](https://nuclei.rs/api/nuclei/sync/struct.RwLock.html#method.write) returns. - [WriteOwned](https://nuclei.rs/api/nuclei/sync/struct.WriteOwned.html): The future [`RwLock::write_owned`](https://nuclei.rs/api/nuclei/sync/struct.RwLock.html#method.write_owned) returns. It keeps its place in the queue, and the bypasses it counted, for as long as it lives; dropping it withdraws the wait and passes on a handoff made to it meanwhile. ### Enums - [SetError](https://nuclei.rs/api/nuclei/sync/enum.SetError.html): Errors that can be returned from [`OnceCell::set`](https://nuclei.rs/api/nuclei/sync/struct.OnceCell.html#method.set). - [TryAcquireError](https://nuclei.rs/api/nuclei/sync/enum.TryAcquireError.html): Error returned from [`Semaphore::try_acquire`](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html#method.try_acquire) and the other attempts that never wait. - [TryPopError](https://nuclei.rs/api/nuclei/sync/enum.TryPopError.html): An unbounded lock-free queue and its pop error, from the kovan-queue crate: see its docs. Why [`SegQueue::try_pop`](https://nuclei.rs/api/nuclei/sync/struct.SegQueue.html#method.try_pop) returned no value. ### Constants - [MAX_BYPASS](https://nuclei.rs/api/nuclei/sync/constant.MAX_BYPASS.html): How many times a waiter can be passed over before it is owed a handoff: a woken waiter that loses its retry this many times is handed the next release directly, and nobody barges past it meanwhile. ### struct `nuclei::sync::Acquire` https://nuclei.rs/api/nuclei/sync/struct.Acquire.html ```rust pub struct Acquire<'a> { /* private fields */ } ``` The future [`Semaphore::acquire`](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html#method.acquire) and [`Semaphore::acquire_many`](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html#method.acquire_many) return. Dropping it withdraws the wait, and passes on permits handed to it meanwhile. #### Trait Implementations - `impl Debug for Acquire<'_>` - `impl Drop for Acquire<'_>` - `impl<'a> Future for Acquire<'a>` #### Auto Trait Implementations - `impl<'a> !RefUnwindSafe for Acquire<'a>` - `impl<'a> !UnwindSafe for Acquire<'a>` - `impl<'a> Freeze for Acquire<'a>` - `impl<'a> Send for Acquire<'a>` - `impl<'a> Sync for Acquire<'a>` - `impl<'a> Unpin for Acquire<'a>` - `impl<'a> UnsafeUnpin for Acquire<'a>` ### struct `nuclei::sync::AcquireError` https://nuclei.rs/api/nuclei/sync/struct.AcquireError.html ```rust pub struct AcquireError(/* private fields */); ``` Error returned from [`Semaphore::acquire`](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html#method.acquire) and the other waits for permits. A wait can only fail if the semaphore has been [closed](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html#method.close). #### Trait Implementations - `impl Debug for AcquireError` - `impl Display for AcquireError` - `impl Error for AcquireError` #### Auto Trait Implementations - `impl Freeze for AcquireError` - `impl RefUnwindSafe for AcquireError` - `impl Send for AcquireError` - `impl Sync for AcquireError` - `impl Unpin for AcquireError` - `impl UnsafeUnpin for AcquireError` - `impl UnwindSafe for AcquireError` ### struct `nuclei::sync::AcquireOwned` https://nuclei.rs/api/nuclei/sync/struct.AcquireOwned.html ```rust pub struct AcquireOwned { /* private fields */ } ``` The future [`Semaphore::acquire_owned`](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html#method.acquire_owned) and [`Semaphore::acquire_many_owned`](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html#method.acquire_many_owned) return. #### Trait Implementations - `impl Debug for AcquireOwned` - `impl Drop for AcquireOwned` - `impl Future for AcquireOwned` #### Auto Trait Implementations - `impl !RefUnwindSafe for AcquireOwned` - `impl !UnwindSafe for AcquireOwned` - `impl Freeze for AcquireOwned` - `impl Send for AcquireOwned` - `impl Sync for AcquireOwned` - `impl Unpin for AcquireOwned` - `impl UnsafeUnpin for AcquireOwned` ### struct `nuclei::sync::ArrayQueue` https://nuclei.rs/api/nuclei/sync/struct.ArrayQueue.html ```rust pub struct ArrayQueue { /* private fields */ } ``` A bounded lock-free queue, from the kovan-queue crate: see its docs. A bounded multi-producer multi-consumer queue. #### Implementations `impl ArrayQueue` ```rust pub fn new(cap: usize) -> ArrayQueue ``` Creates a new bounded queue with the given capacity. The capacity will be rounded up to the next power of two. ```rust pub fn push(&self, value: T) -> Result<(), T> ``` Pushes an element into the queue. ```rust pub fn pop(&self) -> Option ``` Pops an element from the queue. ```rust pub fn capacity(&self) -> usize ``` Returns the capacity of the queue. ```rust pub fn is_empty(&self) -> bool ``` Returns `true` if the queue is empty. ```rust pub fn is_full(&self) -> bool ``` Returns `true` if the queue is full. #### Trait Implementations - `impl Drop for ArrayQueue` - `impl Send for ArrayQueue where T: Send` - `impl Sync for ArrayQueue where T: Send` #### Auto Trait Implementations - `impl !Freeze for ArrayQueue` - `impl !RefUnwindSafe for ArrayQueue` - `impl Unpin for ArrayQueue` - `impl UnsafeUnpin for ArrayQueue` - `impl UnwindSafe for ArrayQueue where T: UnwindSafe` ### struct `nuclei::sync::Atom` https://nuclei.rs/api/nuclei/sync/struct.Atom.html ```rust pub struct Atomwhere T: Send + Sync + 'static,{ /* private fields */ } ``` An atomically swapped value, from the kovan crate: see its docs. A single-value container with safe memory reclamation: loads, stores and swaps are wait-free, and [`rcu()`](https://nuclei.rs/api/nuclei/sync/struct.Atom.html#method.rcu) is lock-free (it retries only after another thread’s write). Provides cheap reads via [`load()`](https://nuclei.rs/api/nuclei/sync/struct.Atom.html#method.load) and atomic writes via [`store()`](https://nuclei.rs/api/nuclei/sync/struct.Atom.html#method.store), [`swap()`](https://nuclei.rs/api/nuclei/sync/struct.Atom.html#method.swap), and [`rcu()`](https://nuclei.rs/api/nuclei/sync/struct.Atom.html#method.rcu). Old values are automatically retired through kovan’s wait-free reclamation. Unlike `ArcSwap`, `Atom` works with any `T: Send + Sync + 'static`: there is no requirement to wrap values in `Arc`. **Examples** ```rust use kovan::Atom; // Create and read let config = Atom::new(vec![1, 2, 3]); assert_eq!(config.load().len(), 3); // Atomic update: readers see old or new, never torn config.store(vec![4, 5, 6, 7]); assert_eq!(config.load().len(), 4); ``` #### Implementations `impl Atom where T: Send + Sync + 'static` ```rust pub fn new(val: T) -> Atom ``` Creates a new `Atom` containing `val`. The value is heap-allocated and managed by kovan’s reclamation system. **Examples** ```rust use kovan::Atom; let atom = Atom::new(42); ``` ```rust pub fn into_inner(self) -> T ``` Consumes the `Atom` and returns the inner value. This is safe because consuming `self` guarantees no concurrent access. **Examples** ```rust use kovan::Atom; let atom = Atom::new(String::from("hello")); let s = atom.into_inner(); assert_eq!(s, "hello"); ``` ```rust pub fn load(&self) -> AtomGuard<'_, T> ``` Loads the current value, returning a guard that dereferences to `&T`. This is the cheapest read operation: a pin, one atomic load and an epoch check against the pin’s cache. The returned [`AtomGuard`] keeps the value alive; it will not be reclaimed until the guard is dropped. **Consistency** Call `load()` once and reuse the guard for multiple accesses to ensure you see a consistent snapshot. Calling `load()` multiple times may return different values if another thread updated the `Atom` in between. **Examples** ```rust use kovan::Atom; let atom = Atom::new(42); let val = atom.load(); assert_eq!(*val, 42); ``` ```rust pub fn load_clone(&self) -> T where T: Clone ``` Loads and clones the current value. Equivalent to `atom.load().clone()` but expressed as a single call. Use this when you need an owned copy and `T: Clone`. **Examples** ```rust use kovan::Atom; let atom = Atom::new(vec![1, 2, 3]); let owned: Vec = atom.load_clone(); ``` ```rust pub fn peek(&self, f: impl FnOnce(&T) -> R) -> R ``` Calls a closure with a reference to the current value. This is useful when you want to inspect the value without holding onto a guard. The closure runs within a kovan critical section. **Examples** ```rust use kovan::Atom; let atom = Atom::new(vec![1, 2, 3]); let len = atom.peek(|v| v.len()); assert_eq!(len, 3); ``` ```rust pub fn store(&self, val: T) ``` Atomically replaces the current value. The old value is retired for safe reclamation: it will be freed once no reader holds a guard referencing it. **Examples** ```rust use kovan::Atom; let atom = Atom::new(1); atom.store(2); assert_eq!(*atom.load(), 2); ``` ```rust pub fn swap(&self, val: T) -> Removed ``` Atomically replaces the current value and returns the previous one wrapped in [`Removed`]. The old value stays in its node, where readers that loaded it before the swap still read it, and the returned [`Removed`] derefs to that same object. Unlike [`store()`](https://nuclei.rs/api/nuclei/sync/struct.Atom.html#method.store), the old node is not retired at once: dropping the `Removed` retires it, and `T`’s destructor runs once no reader is left. **Examples** ```rust use kovan::Atom; let atom = Atom::new(String::from("hello")); let old = atom.swap(String::from("world")); assert_eq!(*old, "hello"); assert_eq!(*atom.load(), "world"); ``` ```rust pub fn compare_and_swap<'a>( &'a self, current: &AtomGuard<'_, T>, new: T, ) -> Result, T> ``` Compare-and-swap: atomically replace the value if it hasn’t changed. Loads the current pointer, compares it to `current`’s pointer. If they match, stores `new` and retires the old value. Returns `Ok(guard)` with the new value on success, or `Err(new)` returning the rejected value. **Examples** ```rust use kovan::Atom; let atom = Atom::new(1); let current = atom.load(); // This succeeds because nobody changed it assert!(atom.compare_and_swap(¤t, 2).is_ok()); assert_eq!(*atom.load(), 2); ``` ```rust pub fn rcu(&self, f: F) where F: FnMut(&T) -> T ``` Read-Copy-Update: atomically apply a transformation. Loads the current value, calls `f(&T)` to produce a new value, then attempts a CAS. If another thread modified the value between the load and CAS, the operation retries automatically. The closure `f` may be called multiple times on contention. Keep it cheap: do expensive work before calling `rcu`. **Examples** ```rust use kovan::Atom; let counter = Atom::new(0u64); // Thread-safe increment (retries on contention) counter.rcu(|val| val + 1); assert_eq!(*counter.load(), 1); ``` ```rust pub fn map<'a, R, F>(&'a self, f: F) -> AtomMap<'a, T, R, F> where R: 'a, F: Fn(&T) -> &R ``` Create a mapped view that projects into a field of `T`. Returns an [`AtomMap`] that loads `T` and applies `f` to project into a sub-field. Useful for passing configuration sub-sections to components without exposing the full `T`. **Keep `f` cheap**: it runs on every `load`. **Examples** ```rust use kovan::Atom; struct Config { db_port: u16, workers: usize } let config = Atom::new(Config { db_port: 5432, workers: 4 }); let port_view = config.map(|c| &c.db_port); assert_eq!(*port_view.load(), 5432); ``` #### Trait Implementations - `impl Debug for Atom where T: Send + Sync + 'static + Debug` - `impl Default for Atom where T: Send + Sync + 'static + Default` - `impl Drop for Atom where T: Send + Sync + 'static` - `impl From for Atom where T: Send + Sync + 'static` - `impl Send for Atom where T: Send + Sync + 'static` - `impl Sync for Atom where T: Send + Sync + 'static` #### Auto Trait Implementations - `impl !Freeze for Atom` - `impl !RefUnwindSafe for Atom` - `impl !UnwindSafe for Atom` - `impl Unpin for Atom` - `impl UnsafeUnpin for Atom` ### struct `nuclei::sync::Barrier` https://nuclei.rs/api/nuclei/sync/struct.Barrier.html ```rust pub struct Barrier { /* private fields */ } ``` A barrier that releases its waiters in groups of `n`. The `n`-th [`wait`](https://nuclei.rs/api/nuclei/sync/struct.Barrier.html#method.wait) of a generation completes at once as its leader and wakes the other `n - 1`; the barrier then starts the next generation. A wait dropped before its generation completes stays counted: the generation completes once `n` parties have arrived, and the dropped one is simply not woken. (Taking the arrival back would race with the arrival that completes the generation.) ```rust use nuclei::sync::Barrier; use std::future::Future; use std::pin::pin; use std::task::{Context, Waker}; let barrier = Barrier::new(2); let mut cx = Context::from_waker(Waker::noop()); let mut first = pin!(barrier.wait()); assert!(first.as_mut().poll(&mut cx).is_pending()); let mut second = pin!(barrier.wait()); assert!(second.as_mut().poll(&mut cx).is_ready()); assert!(first.poll(&mut cx).is_ready()); ``` #### Implementations `impl Barrier` ```rust pub const fn new(n: usize) -> Self ``` A barrier for groups of `n` waits; `0` acts as `1`, as it does for `std::sync::Barrier`. ```rust pub fn wait(&self) -> BarrierWait<'_> ``` A future that completes when this wait’s generation is complete. #### Trait Implementations - `impl Debug for Barrier` - `impl Drop for Barrier` - `impl Send for Barrier` - `impl Sync for Barrier` #### Auto Trait Implementations - `impl !Freeze for Barrier` - `impl !RefUnwindSafe for Barrier` - `impl !UnwindSafe for Barrier` - `impl Unpin for Barrier` - `impl UnsafeUnpin for Barrier` ### struct `nuclei::sync::BarrierWait` https://nuclei.rs/api/nuclei/sync/struct.BarrierWait.html ```rust pub struct BarrierWait<'a> { /* private fields */ } ``` The future [`Barrier::wait`](https://nuclei.rs/api/nuclei/sync/struct.Barrier.html#method.wait) returns. #### Trait Implementations - `impl Debug for BarrierWait<'_>` - `impl Drop for BarrierWait<'_>` - `impl Future for BarrierWait<'_>` #### Auto Trait Implementations - `impl<'a> !RefUnwindSafe for BarrierWait<'a>` - `impl<'a> !UnwindSafe for BarrierWait<'a>` - `impl<'a> Freeze for BarrierWait<'a>` - `impl<'a> Send for BarrierWait<'a>` - `impl<'a> Sync for BarrierWait<'a>` - `impl<'a> Unpin for BarrierWait<'a>` - `impl<'a> UnsafeUnpin for BarrierWait<'a>` ### struct `nuclei::sync::BarrierWaitResult` https://nuclei.rs/api/nuclei/sync/struct.BarrierWaitResult.html ```rust pub struct BarrierWaitResult { /* private fields */ } ``` What a completed [`Barrier::wait`](https://nuclei.rs/api/nuclei/sync/struct.Barrier.html#method.wait) reports. #### Implementations `impl BarrierWaitResult` ```rust pub fn is_leader(&self) -> bool ``` True for exactly one wait per generation: the one that completed it. #### Trait Implementations - `impl Clone for BarrierWaitResult` - `impl Copy for BarrierWaitResult` - `impl Debug for BarrierWaitResult` - `impl Eq for BarrierWaitResult` - `impl PartialEq for BarrierWaitResult` - `impl StructuralPartialEq for BarrierWaitResult` #### Auto Trait Implementations - `impl Freeze for BarrierWaitResult` - `impl RefUnwindSafe for BarrierWaitResult` - `impl Send for BarrierWaitResult` - `impl Sync for BarrierWaitResult` - `impl Unpin for BarrierWaitResult` - `impl UnsafeUnpin for BarrierWaitResult` - `impl UnwindSafe for BarrierWaitResult` ### struct `nuclei::sync::CancellationToken` https://nuclei.rs/api/nuclei/sync/struct.CancellationToken.html ```rust pub struct CancellationToken { /* private fields */ } ``` A token which can be used to signal a cancellation request to one or more tasks. Tasks call [`cancelled`](https://nuclei.rs/api/nuclei/sync/struct.CancellationToken.html#method.cancelled) to get a future that completes when cancellation is requested, and [`cancel`](https://nuclei.rs/api/nuclei/sync/struct.CancellationToken.html#method.cancel) requests it. A clone is another handle to the same token: cancelling one cancels all. A [`child_token`](https://nuclei.rs/api/nuclei/sync/struct.CancellationToken.html#method.child_token) is cancelled with its parent, and can be cancelled alone. **The tree** A token is an `Arc` of a node. A node holds its own cancelled flag (an [`Event`](https://nuclei.rs/api/nuclei/sync/struct.Event.html), which also wakes the waiters), a *strong* handle to its parent node, and, once it has a child, a registry of its children that holds a *weak* handle to each of them. - A parent whose tokens are all gone stays alive as long as any child is, as a relay: cancelling a grandparent still reaches the grandchildren. A node nobody can cancel or wait on any more is freed. - Memory is bounded by the live tokens. A node removes itself from its parent’s registry when it is freed, so the registry holds only the children that exist. - Freeing a node walks up the chain of ancestors it was the last owner of, in a loop and not by recursion, so a chain of a million nested tokens can be dropped without overflowing the stack. **Cancelling** `cancel` sets the node’s flag, which wakes its waiters, and then walks the whole subtree with an explicit stack: it sets the flag of every descendant that is not set yet, and descends into every descendant, those some other call already set included. So: - When any `cancel` call returns, the token it was called on and every descendant that existed when the call began (its `child_token` had completed) are cancelled, and their waiters woken, whether this call or another one set the flag first. A call on an already cancelled token still walks its subtree, so it too returns with the subtree cancelled. - A descendant being created at the same moment is cancelled by the time both calls have returned: either the new child sees its parent cancelled and cancels itself, or the walk sees the child. - The price is the walk: every call visits every descendant once, so concurrent or repeated calls over one tree each pay for it. Cancel a large tree once. - Cancellation is not atomic over the tree: while a call runs, another thread can see a child cancelled and then a sibling not yet cancelled. **Progress** - Wait-free: [`is_cancelled`](https://nuclei.rs/api/nuclei/sync/struct.CancellationToken.html#method.is_cancelled) (one load), [`Clone`](https://doc.rust-lang.org/1.99.1/core/clone/trait.Clone.html), dropping a token that is not the last owner of its node, [`cancelled`](https://nuclei.rs/api/nuclei/sync/struct.CancellationToken.html#method.cancelled) and [`cancelled_owned`](https://nuclei.rs/api/nuclei/sync/struct.CancellationToken.html#method.cancelled_owned) themselves (they only build the future), and a poll of the future once the token is cancelled (one load). - Lock-free: [`cancel`](https://nuclei.rs/api/nuclei/sync/struct.CancellationToken.html#method.cancel) and the first poll of a future of an uncancelled token. Setting a flag is a lock-free queue operation, and the visit of the descendants reads each registry with the map’s iterator, which restarts a bucket whose walk was disturbed by a concurrent update. A `cancel` never waits for another `cancel`: each walks the subtree on its own. The time it takes grows with the number of descendants, whether or not they were cancelled already. - Neither wait-free nor lock-free: [`child_token`](https://nuclei.rs/api/nuclei/sync/struct.CancellationToken.html#method.child_token) and dropping the last owner of a node. They insert into or remove from the parent’s registry (a CAS that retries when another thread changed the same bucket), and the registry is a map that grows past 48 children: a write that meets the resize in progress waits for the thread resizing it. Waking a task calls its [`Waker`](https://doc.rust-lang.org/1.99.1/core/task/wake/struct.Waker.html), which is the executor’s and is not counted. ```rust use nuclei::sync::CancellationToken; use std::future::Future; use std::pin::pin; use std::task::{Context, Poll, Waker}; let token = CancellationToken::new(); let clone = token.clone(); let mut cx = Context::from_waker(Waker::noop()); let mut cancelled = pin!(clone.cancelled()); assert_eq!(cancelled.as_mut().poll(&mut cx), Poll::Pending); token.cancel(); assert_eq!(cancelled.as_mut().poll(&mut cx), Poll::Ready(())); ``` #### Implementations `impl CancellationToken` ```rust pub fn new() -> CancellationToken ``` Creates a new token in the non-cancelled state. ```rust pub fn child_token(&self) -> CancellationToken ``` Creates a token which is cancelled whenever this token is. Unlike a clone, cancelling the child does not cancel this token. If this token is already cancelled, the child is returned cancelled. Neither wait-free nor lock-free: it inserts into this token’s registry of children; see the [type docs](https://nuclei.rs/api/nuclei/sync/struct.CancellationToken.html). ```rust use nuclei::sync::CancellationToken; let token = CancellationToken::new(); let child = token.child_token(); child.cancel(); assert!(child.is_cancelled()); assert!(!token.is_cancelled()); token.cancel(); assert!(token.child_token().is_cancelled()); ``` ```rust pub fn cancel(&self) ``` Cancels this token and every token derived from it, waking all tasks waiting for cancellation. When the call returns, this token and every descendant that existed when it began are cancelled, even if another call cancelled some of them first: every call walks the whole subtree. Cancellation is not atomic over the tree, though: a thread running alongside the call can see `true` from [`is_cancelled`](https://nuclei.rs/api/nuclei/sync/struct.CancellationToken.html#method.is_cancelled) on one child and then `false` on another. See the [type docs](https://nuclei.rs/api/nuclei/sync/struct.CancellationToken.html). Lock-free. ```rust use nuclei::sync::CancellationToken; let token = CancellationToken::new(); let child = token.child_token(); let grandchild = child.child_token(); token.cancel(); assert!(child.is_cancelled() && grandchild.is_cancelled()); ``` ```rust pub fn is_cancelled(&self) -> bool ``` Whether the token is cancelled. One atomic load. ```rust use nuclei::sync::CancellationToken; let token = CancellationToken::new(); assert!(!token.is_cancelled()); token.cancel(); assert!(token.is_cancelled()); ``` ```rust pub fn cancelled(&self) -> WaitForCancellationFuture<'_> ``` A future that completes when cancellation is requested. Equivalent to `async fn cancelled(&self)`. It completes at once if the token is already cancelled. **Cancel safety** Cancel safe: dropping the future withdraws its wait and nothing else. ```rust use nuclei::sync::CancellationToken; use std::future::Future; use std::pin::pin; use std::task::{Context, Poll, Waker}; let token = CancellationToken::new(); token.cancel(); let mut cx = Context::from_waker(Waker::noop()); assert_eq!(pin!(token.cancelled()).poll(&mut cx), Poll::Ready(())); ``` ```rust pub fn cancelled_owned(self) -> WaitForCancellationFutureOwned ``` A future that completes when cancellation is requested, and owns the token. Equivalent to `async fn cancelled_owned(self)`. It completes at once if the token is already cancelled. **Cancel safety** Cancel safe. ```rust pub fn drop_guard(self) -> DropGuard ``` Creates a [`DropGuard`](https://nuclei.rs/api/nuclei/sync/struct.DropGuard.html) for this token: it cancels the token (and its children) when dropped, unless disarmed. ```rust use nuclei::sync::CancellationToken; let token = CancellationToken::new(); drop(token.clone().drop_guard()); assert!(token.is_cancelled()); ``` ```rust pub fn drop_guard_ref(&self) -> DropGuardRef<'_> ``` Creates a [`DropGuardRef`](https://nuclei.rs/api/nuclei/sync/struct.DropGuardRef.html) for this token: the borrowed counterpart of [`drop_guard`](https://nuclei.rs/api/nuclei/sync/struct.CancellationToken.html#method.drop_guard). ```rust pub async fn run_until_cancelled(&self, fut: F) -> Option where F: Future ``` Runs `fut` to completion and returns its output, unless the token is cancelled first: then it returns `None` and drops `fut`. **Fairness** On an already cancelled token this returns `None` without polling `fut`. After that, when `fut` completes and the token is cancelled together, the output of `fut` wins. **Cancel safety** Cancel safe only if `fut` is. ```rust pub async fn run_until_cancelled_owned(self, fut: F) -> Option where F: Future ``` Like [`run_until_cancelled`](https://nuclei.rs/api/nuclei/sync/struct.CancellationToken.html#method.run_until_cancelled), taking the token by value: the returned future owns it. #### Trait Implementations - `impl Clone for CancellationToken` - `impl Debug for CancellationToken` - `impl Default for CancellationToken` - `impl Eq for CancellationToken` - `impl Hash for CancellationToken` - `impl PartialEq for CancellationToken` - `impl RefUnwindSafe for CancellationToken` - `impl UnwindSafe for CancellationToken` #### Auto Trait Implementations - `impl Freeze for CancellationToken` - `impl Send for CancellationToken` - `impl Sync for CancellationToken` - `impl Unpin for CancellationToken` - `impl UnsafeUnpin for CancellationToken` ### struct `nuclei::sync::DropGuard` https://nuclei.rs/api/nuclei/sync/struct.DropGuard.html ```rust pub struct DropGuard { /* private fields */ } ``` A wrapper for a [`CancellationToken`](https://nuclei.rs/api/nuclei/sync/struct.CancellationToken.html) which cancels it on drop, created by [`CancellationToken::drop_guard`](https://nuclei.rs/api/nuclei/sync/struct.CancellationToken.html#method.drop_guard). ```rust use nuclei::sync::CancellationToken; let token = CancellationToken::new(); let guard = token.clone().drop_guard(); let still_alive = guard.disarm(); assert!(!token.is_cancelled()); drop(still_alive); assert!(!token.is_cancelled()); ``` #### Implementations `impl DropGuard` ```rust pub fn token(&self) -> &CancellationToken ``` Returns a reference to the token this guard wraps. ```rust pub fn disarm(self) -> CancellationToken ``` Returns the token and disarms this guard: it no longer cancels the token. Other guards of the same token are not affected. #### Trait Implementations - `impl Debug for DropGuard` - `impl Drop for DropGuard` #### Auto Trait Implementations - `impl Freeze for DropGuard` - `impl RefUnwindSafe for DropGuard` - `impl Send for DropGuard` - `impl Sync for DropGuard` - `impl Unpin for DropGuard` - `impl UnsafeUnpin for DropGuard` - `impl UnwindSafe for DropGuard` ### struct `nuclei::sync::DropGuardRef` https://nuclei.rs/api/nuclei/sync/struct.DropGuardRef.html ```rust pub struct DropGuardRef<'a> { /* private fields */ } ``` A wrapper for a borrowed [`CancellationToken`](https://nuclei.rs/api/nuclei/sync/struct.CancellationToken.html) which cancels it on drop, created by [`CancellationToken::drop_guard_ref`](https://nuclei.rs/api/nuclei/sync/struct.CancellationToken.html#method.drop_guard_ref). #### Implementations `impl<'a> DropGuardRef<'a>` ```rust pub fn token(&self) -> &CancellationToken ``` Returns a reference to the token this guard wraps. ```rust pub fn disarm(self) -> &'a CancellationToken ``` Returns the token and disarms this guard: it no longer cancels the token. Other guards of the same token are not affected. #### Trait Implementations - `impl<'a> Debug for DropGuardRef<'a>` - `impl Drop for DropGuardRef<'_>` #### Auto Trait Implementations - `impl<'a> Freeze for DropGuardRef<'a>` - `impl<'a> RefUnwindSafe for DropGuardRef<'a>` - `impl<'a> Send for DropGuardRef<'a>` - `impl<'a> Sync for DropGuardRef<'a>` - `impl<'a> Unpin for DropGuardRef<'a>` - `impl<'a> UnsafeUnpin for DropGuardRef<'a>` - `impl<'a> UnwindSafe for DropGuardRef<'a>` ### struct `nuclei::sync::Event` https://nuclei.rs/api/nuclei/sync/struct.Event.html ```rust pub struct Event { /* private fields */ } ``` An event that is set once and stays set. [`wait`](https://nuclei.rs/api/nuclei/sync/struct.Event.html#method.wait) completes as soon as the event is set, whether that happened before or after the wait began; [`set`](https://nuclei.rs/api/nuclei/sync/struct.Event.html#method.set) wakes every waiter. Checking is one atomic load. ```rust use nuclei::sync::Event; let ready = Event::new(); assert!(!ready.is_set()); ready.set(); assert!(ready.is_set()); ``` #### Implementations `impl Event` ```rust pub const fn new() -> Self ``` An event that is not set. ```rust pub fn set(&self) ``` Sets the event and wakes every waiter. Setting it again does nothing. ```rust pub fn is_set(&self) -> bool ``` Whether the event is set. ```rust pub fn wait(&self) -> EventWait<'_> ``` A future that completes once the event is set. #### Trait Implementations - `impl Debug for Event` - `impl Default for Event` - `impl Drop for Event` - `impl Send for Event` - `impl Sync for Event` #### Auto Trait Implementations - `impl !Freeze for Event` - `impl !RefUnwindSafe for Event` - `impl !UnwindSafe for Event` - `impl Unpin for Event` - `impl UnsafeUnpin for Event` ### struct `nuclei::sync::EventWait` https://nuclei.rs/api/nuclei/sync/struct.EventWait.html ```rust pub struct EventWait<'a> { /* private fields */ } ``` The future [`Event::wait`](https://nuclei.rs/api/nuclei/sync/struct.Event.html#method.wait) returns. #### Trait Implementations - `impl Debug for EventWait<'_>` - `impl Drop for EventWait<'_>` - `impl Future for EventWait<'_>` #### Auto Trait Implementations - `impl<'a> !RefUnwindSafe for EventWait<'a>` - `impl<'a> !UnwindSafe for EventWait<'a>` - `impl<'a> Freeze for EventWait<'a>` - `impl<'a> Send for EventWait<'a>` - `impl<'a> Sync for EventWait<'a>` - `impl<'a> Unpin for EventWait<'a>` - `impl<'a> UnsafeUnpin for EventWait<'a>` ### struct `nuclei::sync::HopscotchMap` https://nuclei.rs/api/nuclei/sync/struct.HopscotchMap.html ```rust pub struct HopscotchMapwhere K: 'static, V: 'static,{ /* private fields */ } ``` A concurrent hash map, from the kovan-map crate: see its docs. A concurrent, lock-free hash map based on Hopscotch Hashing. #### Implementations `impl HopscotchMap where K: Hash + Eq + Clone + MaybeSend + 'static, V: Clone + MaybeSend + 'static, S: BuildHasher` ```rust pub fn remove_if(&self, key: &Q, pred: F) -> Option where K: Borrow, Q: Hash + Eq + ?Sized, F: FnOnce(&V) -> bool ``` Removes the key’s entry if `pred` holds for its value, returning the value removed. Answers `None` when the key is absent or `pred` refused its value, and then changes nothing. Linearizable and exact: `pred` runs exactly once when the key is present (never when it is absent), on the value the key holds at the operation’s linearization point, while the key’s home is held, so no write of the key lands between the check and the unlink. A slow `pred` stalls every writer of that home (and a resize) until it returns, and `pred` must not write to this map (a write to a key of the same home would wait for itself). A `pred` that panics leaves the map unchanged. **Examples** ```rust use kovan_map::HopscotchMap; let map = HopscotchMap::new(); map.insert(1, 10); assert_eq!(map.remove_if(&2, |_| true), None); // absent assert_eq!(map.remove_if(&1, |v| *v > 10), None); // refused, kept assert_eq!(map.get(&1), Some(10)); assert_eq!(map.remove_if(&1, |v| *v == 10), Some(10)); assert_eq!(map.get(&1), None); ``` ```rust pub fn compare_and_remove(&self, key: &Q, expected: &V) -> Option where K: Borrow, Q: Hash + Eq + ?Sized, V: PartialEq ``` Removes the key’s entry if its value equals `expected`, returning the value removed: [`remove_if`](https://nuclei.rs/api/nuclei/sync/struct.HopscotchMap.html#method.remove_if) with an equality predicate. **Examples** ```rust use kovan_map::HopscotchMap; let map = HopscotchMap::new(); map.insert("job", 3); assert_eq!(map.compare_and_remove("job", &4), None); assert_eq!(map.compare_and_remove("job", &3), Some(3)); assert!(map.is_empty()); ``` ```rust pub fn replace_if(&self, key: K, value: V, pred: F) -> Result> where F: FnOnce(&V) -> bool ``` Replaces the key’s value with `value` if `pred` holds for the present one. `Ok` with the value replaced when it replaced; `Err(Some(current))` when `pred` refused the present value `current`; `Err(None)` when the key is absent (nothing is inserted). Either `Err` drops `key` and `value`. Linearizable and exact, as [`remove_if`](https://nuclei.rs/api/nuclei/sync/struct.HopscotchMap.html#method.remove_if): `pred` runs exactly once when the key is present, under the key’s home guard, on the value the replace would replace, and the same cautions hold for a slow, writing or panicking `pred`. Allocates only when it replaces. **Examples** ```rust use kovan_map::HopscotchMap; let map = HopscotchMap::new(); assert_eq!(map.replace_if(1, 20, |_| true), Err(None)); // absent: not inserted map.insert(1, 10); assert_eq!(map.replace_if(1, 20, |v| *v > 10), Err(Some(10))); assert_eq!(map.replace_if(1, 20, |v| *v == 10), Ok(10)); assert_eq!(map.get(&1), Some(20)); ``` ```rust pub fn compare_and_swap( &self, key: K, expected: &V, value: V, ) -> Result> where V: PartialEq ``` Replaces the key’s value with `value` if the present one equals `expected`: [`replace_if`](https://nuclei.rs/api/nuclei/sync/struct.HopscotchMap.html#method.replace_if) with an equality predicate, answered the same way. **Examples** ```rust use kovan_map::HopscotchMap; let map = HopscotchMap::new(); map.insert(7, 1); assert_eq!(map.compare_and_swap(7, &2, 3), Err(Some(1))); assert_eq!(map.compare_and_swap(7, &1, 3), Ok(1)); assert_eq!(map.compare_and_swap(8, &1, 3), Err(None)); assert_eq!(map.get(&7), Some(3)); ``` ```rust pub fn compute(&self, key: K, f: F) -> Option where F: FnOnce(Option<&V>) -> Option ``` One atomic read-modify-write of the key: `f` sees the present value (`None` when the key is absent) and answers the value the key holds next, `Some(new)` to insert or replace, `None` to remove (or leave the key absent). Answers the value the map holds for the key after the call. `f` runs exactly once, under the key’s home guard, so no write of the key lands between what `f` saw and what it wrote: the operation is linearizable. A slow `f` stalls every writer of that home (and a resize) until it returns, and `f` must not write to this map (a write to a key of the same home would wait for itself). An `f` that panics leaves the map unchanged. Allocates only when it links an entry (`f` answered `Some`). **Examples** ```rust use kovan_map::HopscotchMap; let hits = HopscotchMap::new(); let bump = |seen: Option<&u32>| Some(seen.map_or(1, |n| n + 1)); assert_eq!(hits.compute("page", bump), Some(1)); assert_eq!(hits.compute("page", bump), Some(2)); // `None` removes the key. assert_eq!(hits.compute("page", |_| None), None); assert_eq!(hits.get("page"), None); ``` `impl HopscotchMap where K: Eq + 'static, V: 'static` ```rust pub fn iter(&self) -> HopscotchIter<'_, K, V, S> ``` Returns an iterator over the map entries. The iterator walks the table that is current when it is created, to its end, even when a resize replaces that table meanwhile (the walk’s position means nothing in another table, whose layout differs). An entry present from the iterator’s creation to its end is yielded exactly once: a resize neither skips nor repeats it, and a displacement, which moves an entry to a higher slot of its neighborhood, links it there before unlinking it from its old slot (so the walk meets it) and the walk recognizes a key it already met there (so it is not repeated). An insert publishes its entry’s hop bit before it links the entry, so an entry the walk finds in a slot is one a lookup finds too. An entry inserted, removed or updated concurrently may or may not be reflected, and no key is yielded twice. The iterator’s own loop (`fold`, and `for_each`, `count` and the other folds built on it) reads a group of slots before it yields their entries, so a write its closure makes is one of those concurrent writes too. ```rust pub fn keys(&self) -> HopscotchKeys<'_, K, V, S> ``` Returns an iterator over the map keys. ```rust pub fn values(&self) -> HopscotchValues<'_, K, V, S> ``` Returns an iterator over the map values (clones `V`). `impl HopscotchMap where K: 'static, V: 'static` ```rust pub fn with_hasher(hasher: S) -> HopscotchMap ``` Creates a new `HopscotchMap` with the specified hasher and default capacity. ```rust pub fn with_capacity_and_hasher( capacity: usize, hasher: S, ) -> HopscotchMap ``` Creates a new `HopscotchMap` with the specified capacity and hasher. ```rust pub fn len(&self) -> usize ``` Returns the number of elements in the map. ```rust pub fn is_empty(&self) -> bool ``` Returns `true` if the map contains no elements. ```rust pub fn capacity(&self) -> usize ``` Returns the current capacity of the map. ```rust pub fn hasher(&self) -> &S ``` Get the underlying hasher. `impl HopscotchMap where K: 'static, V: 'static` ```rust pub fn new() -> HopscotchMap ``` Creates a new `HopscotchMap` with default capacity and hasher. ```rust pub fn with_capacity(capacity: usize) -> HopscotchMap ``` Creates a new `HopscotchMap` with the specified capacity and default hasher. `impl HopscotchMap where K: Hash + Eq + Clone + MaybeSend + 'static, V: Clone + MaybeSend + 'static, S: BuildHasher` ```rust pub fn get(&self, key: &Q) -> Option where K: Borrow, Q: Hash + Eq + ?Sized ``` Returns the value corresponding to the key. ```rust pub fn insert(&self, key: K, value: V) -> Option ``` Inserts a key-value pair into the map, returning the value it replaced. Linearizable at the write under the key’s home guard; the answer is exactly the value that write replaced. ```rust pub fn get_or_insert(&self, key: K, value: V) -> V ``` Returns the value corresponding to the key, or inserts the given value if the key is not present. Linearizable and exact: of the callers racing for an absent key, the one whose write links the key’s entry (under the key’s home guard) gets its own value back, and every other gets the value it found there (the winner’s, unless a later write already replaced it). A present key is answered by a lookup that takes no guard. ```rust pub fn insert_if_absent(&self, key: K, value: V) -> Option ``` Insert a key-value pair only if the key does not exist. Returns `None` if inserted, `Some(existing_value)` if the key already exists. Exact: `None` exactly when this call linked the key’s entry, `Some` with the value it found under the key’s home guard otherwise; never both, and a resize in flight changes neither (a write that landed is final). A call that finds the key present drops its own key and value, once. ```rust pub fn force_remove(&self, key: &Q) -> Option where K: Borrow, Q: Hash + Eq + ?Sized ``` Remove **all** nodes matching `key`, returning the most recent value if the key was present. Every write of a home runs under its writer guard, so a key has at most one entry and this removes what [`remove`](https://nuclei.rs/api/nuclei/sync/struct.HopscotchMap.html#method.remove) removes. It keeps removing until a scan finds no match, so the key is absent at the linearization point of the final scan, and it is kept for parity with `HashMap::force_remove`. Note: a concurrent `insert` of the same key can land after the final scan, as with any removal under contention. ```rust pub fn remove(&self, key: &Q) -> Option where K: Borrow, Q: Hash + Eq + ?Sized ``` Removes a key from the map, returning the value at the key if the key was previously in the map. Linearizable at the unlink under the key’s home guard: [`remove_if`](https://nuclei.rs/api/nuclei/sync/struct.HopscotchMap.html#method.remove_if) with a predicate that always holds, one write path for both. ```rust pub fn clear(&self) ``` Clears the map, removing all key-value pairs. ```rust pub fn contains_key(&self, key: &Q) -> bool where K: Borrow, Q: Hash + Eq + ?Sized ``` Returns `true` if the key is present. ```rust pub fn extend(&self, iter: I) where I: IntoIterator ``` Insert all `(K, V)` pairs from `iter`. Takes `&self` (concurrent map). #### Trait Implementations - `impl Clone for HopscotchMap where K: Hash + Eq + Clone + MaybeSend + 'static, V: Clone + MaybeSend + 'static, S: BuildHasher + Clone` - `impl Debug for HopscotchMap where K: Eq + Clone + Debug + 'static, V: Clone + Debug + 'static` - `impl Default for HopscotchMap where K: 'static, V: 'static, S: Default` - `impl Drop for HopscotchMap` - `impl Eq for HopscotchMap where K: Hash + Eq + Clone + MaybeSend + 'static, V: Clone + Eq + MaybeSend + 'static, S: BuildHasher` - `impl<'a, K, V, S> Extend<(&'a K, &'a V)> for HopscotchMap where K: Hash + Eq + Copy + MaybeSend + 'static, V: Copy + MaybeSend + 'static, S: BuildHasher` - `impl Extend<(K, V)> for HopscotchMap where K: Hash + Eq + Clone + MaybeSend + 'static, V: Clone + MaybeSend + 'static, S: BuildHasher` - `impl FromIterator<(K, V)> for HopscotchMap where K: Hash + Eq + Clone + MaybeSend + 'static, V: Clone + MaybeSend + 'static, S: BuildHasher + Default` - `impl IntoIterator for HopscotchMap where K: 'static, V: 'static` - `impl<'a, K, V, S> IntoIterator for &'a HopscotchMap where K: Eq + Clone + 'static, V: Clone + 'static` - `impl PartialEq for HopscotchMap where K: Hash + Eq + Clone + MaybeSend + 'static, V: Clone + PartialEq + MaybeSend + 'static, S: BuildHasher` - `impl RefUnwindSafe for HopscotchMap where K: RefUnwindSafe, V: RefUnwindSafe, S: RefUnwindSafe` - `impl Send for HopscotchMap where K: Send, V: Send, S: Send` - `impl Sync for HopscotchMap where K: Send + Sync, V: Send + Sync, S: Send + Sync` - `impl UnwindSafe for HopscotchMap where K: UnwindSafe, V: UnwindSafe, S: UnwindSafe` #### Auto Trait Implementations - `impl !Freeze for HopscotchMap` - `impl Unpin for HopscotchMap where S: Unpin` - `impl UnsafeUnpin for HopscotchMap where S: UnsafeUnpin` ### struct `nuclei::sync::Latch` https://nuclei.rs/api/nuclei/sync/struct.Latch.html ```rust pub struct Latch { /* private fields */ } ``` A latch that opens when its count reaches zero, and stays open. ```rust use nuclei::sync::Latch; let done = Latch::new(2); done.count_down(); assert!(!done.is_set()); done.count_down(); assert!(done.is_set()); ``` #### Implementations `impl Latch` ```rust pub const fn new(count: usize) -> Self ``` A latch that opens after `count` calls to [`count_down`](https://nuclei.rs/api/nuclei/sync/struct.Latch.html#method.count_down); open at once when `count` is zero. ```rust pub fn count_down(&self) ``` Lowers the count by one, opening the latch when it reaches zero. Does nothing once the latch is open. ```rust pub fn count(&self) -> usize ``` The count still to go. ```rust pub fn is_set(&self) -> bool ``` Whether the latch is open. ```rust pub fn wait(&self) -> LatchWait<'_> ``` A future that completes once the latch is open. #### Trait Implementations - `impl Debug for Latch` #### Auto Trait Implementations - `impl !Freeze for Latch` - `impl !RefUnwindSafe for Latch` - `impl !UnwindSafe for Latch` - `impl Send for Latch` - `impl Sync for Latch` - `impl Unpin for Latch` - `impl UnsafeUnpin for Latch` ### struct `nuclei::sync::LatchWait` https://nuclei.rs/api/nuclei/sync/struct.LatchWait.html ```rust pub struct LatchWait<'a>(/* private fields */); ``` The future [`Latch::wait`](https://nuclei.rs/api/nuclei/sync/struct.Latch.html#method.wait) returns. #### Trait Implementations - `impl<'a> Debug for LatchWait<'a>` - `impl Future for LatchWait<'_>` #### Auto Trait Implementations - `impl<'a> !RefUnwindSafe for LatchWait<'a>` - `impl<'a> !UnwindSafe for LatchWait<'a>` - `impl<'a> Freeze for LatchWait<'a>` - `impl<'a> Send for LatchWait<'a>` - `impl<'a> Sync for LatchWait<'a>` - `impl<'a> Unpin for LatchWait<'a>` - `impl<'a> UnsafeUnpin for LatchWait<'a>` ### struct `nuclei::sync::Lazy` https://nuclei.rs/api/nuclei/sync/struct.Lazy.html ```rust pub struct Lazy T> { /* private fields */ } ``` A value built by `F` on first access. Built on [`OnceCell::get_or_init_racy`](https://nuclei.rs/api/nuclei/sync/struct.OnceCell.html#method.get_or_init_racy): threads that reach an unbuilt `Lazy` at the same moment each run `F`, one result is kept and the others are dropped, and nobody waits for anybody. `F` therefore runs at least once and possibly more than once, so it is `Fn` and should be free of side effects that must not repeat. ```rust use nuclei::sync::Lazy; static TABLE: Lazy> = Lazy::new(|| (0..4).collect()); assert_eq!(TABLE.len(), 4); ``` #### Implementations `impl Lazy` ```rust pub const fn new(init: F) -> Self ``` A `Lazy` that builds its value with `init`. `impl T> Lazy` ```rust pub fn force(this: &Self) -> &T ``` The value, building it if nobody has yet. #### Trait Implementations - `impl Debug for Lazy` - `impl T> Deref for Lazy` #### Auto Trait Implementations - `impl T> !Freeze for Lazy` - `impl T> !RefUnwindSafe for Lazy` - `impl T> !UnwindSafe for Lazy` - `impl Send for Lazy where F: Send, T: Send` - `impl Sync for Lazy where F: Sync, T: Send + Sync` - `impl Unpin for Lazy where F: Unpin, T: Unpin` - `impl UnsafeUnpin for Lazy where F: UnsafeUnpin, T: UnsafeUnpin` ### struct `nuclei::sync::Lock` https://nuclei.rs/api/nuclei/sync/struct.Lock.html ```rust pub struct Lock<'a, T: ?Sized> { /* private fields */ } ``` The future [`Mutex::lock`](https://nuclei.rs/api/nuclei/sync/struct.Mutex.html#method.lock) returns. #### Trait Implementations - `impl Debug for Lock<'_, T>` - `impl Drop for Lock<'_, T>` - `impl<'a, T: ?Sized> Future for Lock<'a, T>` #### Auto Trait Implementations - `impl<'a, T> !RefUnwindSafe for Lock<'a, T>` - `impl<'a, T> !UnwindSafe for Lock<'a, T>` - `impl<'a, T> Freeze for Lock<'a, T> where T: ?Sized` - `impl<'a, T> Send for Lock<'a, T> where T: Send + ?Sized` - `impl<'a, T> Sync for Lock<'a, T> where T: Send + ?Sized` - `impl<'a, T> Unpin for Lock<'a, T> where T: ?Sized` - `impl<'a, T> UnsafeUnpin for Lock<'a, T> where T: ?Sized` ### struct `nuclei::sync::LockOwned` https://nuclei.rs/api/nuclei/sync/struct.LockOwned.html ```rust pub struct LockOwned { /* private fields */ } ``` The future [`Mutex::lock_owned`](https://nuclei.rs/api/nuclei/sync/struct.Mutex.html#method.lock_owned) returns. #### Trait Implementations - `impl Debug for LockOwned` - `impl Drop for LockOwned` - `impl Future for LockOwned` #### Auto Trait Implementations - `impl !RefUnwindSafe for LockOwned` - `impl !UnwindSafe for LockOwned` - `impl Freeze for LockOwned where T: ?Sized` - `impl Send for LockOwned where T: Send + ?Sized` - `impl Sync for LockOwned where T: Send + ?Sized` - `impl Unpin for LockOwned where T: ?Sized` - `impl UnsafeUnpin for LockOwned where T: ?Sized` ### struct `nuclei::sync::MappedMutexGuard` https://nuclei.rs/api/nuclei/sync/struct.MappedMutexGuard.html ```rust pub struct MappedMutexGuard<'a, T: ?Sized> { /* private fields */ } ``` A guard for a component of a [`Mutex`](https://nuclei.rs/api/nuclei/sync/struct.Mutex.html)’s value, made by [`MutexGuard::map`](https://nuclei.rs/api/nuclei/sync/struct.MutexGuard.html#method.map); unlocks on drop. The release makes the progress [`MutexGuard`](https://nuclei.rs/api/nuclei/sync/struct.MutexGuard.html)’s does. #### Implementations `impl<'a, T: ?Sized> MappedMutexGuard<'a, T>` ```rust pub fn map(this: Self, f: F) -> MappedMutexGuard<'a, U> where U: ?Sized, F: FnOnce(&mut T) -> &mut U ``` A guard for a component of the component. It cannot fail: this guard already holds the lock. An associated function, `MappedMutexGuard::map(guard, f)`: a method would shadow methods of the locked data. ```rust pub fn try_map(this: Self, f: F) -> Result, Self> where U: ?Sized, F: FnOnce(&mut T) -> Option<&mut U> ``` [`map`](https://nuclei.rs/api/nuclei/sync/struct.MappedMutexGuard.html#method.map) that gives the guard back when `f` finds no component, with the lock still held. #### Trait Implementations - `impl Debug for MappedMutexGuard<'_, T>` - `impl Deref for MappedMutexGuard<'_, T>` - `impl DerefMut for MappedMutexGuard<'_, T>` - `impl Display for MappedMutexGuard<'_, T>` - `impl Drop for MappedMutexGuard<'_, T>` - `impl Send for MappedMutexGuard<'_, T>` - `impl Sync for MappedMutexGuard<'_, T>` #### Auto Trait Implementations - `impl<'a, T> !RefUnwindSafe for MappedMutexGuard<'a, T>` - `impl<'a, T> !UnwindSafe for MappedMutexGuard<'a, T>` - `impl<'a, T> Freeze for MappedMutexGuard<'a, T> where T: ?Sized` - `impl<'a, T> Unpin for MappedMutexGuard<'a, T> where T: ?Sized` - `impl<'a, T> UnsafeUnpin for MappedMutexGuard<'a, T> where T: ?Sized` ### struct `nuclei::sync::Mutex` https://nuclei.rs/api/nuclei/sync/struct.Mutex.html ```rust pub struct Mutex { /* private fields */ } ``` A mutual-exclusion lock whose wait is a future. Uncontended, [`try_lock`](https://nuclei.rs/api/nuclei/sync/struct.Mutex.html#method.try_lock) and a guard’s drop are one atomic read-modify-write each and allocate nothing. A caller takes the lock whenever it is free, even while others wait; under contention [`lock`](https://nuclei.rs/api/nuclei/sync/struct.Mutex.html#method.lock) spins briefly within the poll (see the [module docs](https://nuclei.rs/api/nuclei/sync/index.html#what-every-primitive-guarantees)), then queues and returns `Pending`. An unlock wakes the oldest waiter to try again; a waiter that loses [`MAX_BYPASS`](https://nuclei.rs/api/nuclei/sync/constant.MAX_BYPASS.html) times is handed the lock directly, and `try_lock` fails until it has had it. It does not poison: a panic in a holder unlocks it. ```rust use nuclei::sync::Mutex; let counter = Mutex::new(0u32); *counter.try_lock().expect("uncontended") += 1; assert_eq!(counter.into_inner(), 1); ``` #### Implementations `impl Mutex` ```rust pub const fn new(value: T) -> Self ``` An unlocked mutex holding `value`. ```rust pub const fn const_new(value: T) -> Self ``` An unlocked mutex holding `value`, usable in a `static`. ```rust pub fn into_inner(self) -> T ``` Consumes the mutex and returns its value. `impl Mutex` ```rust pub fn try_lock(&self) -> Result, TryLockError> ``` Locks the mutex if it is free and no handoff is owed. **Errors** [`TryLockError`](https://nuclei.rs/api/nuclei/sync/struct.TryLockError.html) when the mutex is locked or owed to a waiter. ```rust pub fn try_lock_owned( self: Arc, ) -> Result, TryLockError> ``` [`try_lock`](https://nuclei.rs/api/nuclei/sync/struct.Mutex.html#method.try_lock) through an `Arc`, so the guard can outlive the borrow. **Errors** [`TryLockError`](https://nuclei.rs/api/nuclei/sync/struct.TryLockError.html) when the mutex is locked or owed to a waiter. ```rust pub fn lock(&self) -> Lock<'_, T> ``` Waits for the lock. Uncontended, the first poll is one load and one atomic read-modify-write. Contended, a poll may spin for up to the lock’s spin budget before it queues, and again after a retry it lost, before it returns `Pending`; it is lock-free, not wait-free: see [Progress](https://nuclei.rs/api/nuclei/sync/index.html#progress). Dropping the future withdraws the wait, and passes on a lock handed to it meanwhile. ```rust pub fn lock_owned(self: Arc) -> LockOwned ``` [`lock`](https://nuclei.rs/api/nuclei/sync/struct.Mutex.html#method.lock) through an `Arc`, so the guard can outlive the borrow. ```rust pub fn blocking_lock(&self) -> MutexGuard<'_, T> ``` [`lock`](https://nuclei.rs/api/nuclei/sync/struct.Mutex.html#method.lock) for a thread that may block: it parks the calling thread until the lock is free. On a nuclei shard (inside one of its tasks) it does not park the thread: it runs a nested `block_on`, so the shard keeps running its other tasks meanwhile. Inside another runtime’s task it blocks that task’s executor thread, so do not: the task that would unlock may be the one that thread was running. **Panics** On `wasm32`, where no other thread can unlock, when the lock is held: the call could never end. ```rust pub fn blocking_lock_owned(self: Arc) -> OwnedMutexGuard ``` [`blocking_lock`](https://nuclei.rs/api/nuclei/sync/struct.Mutex.html#method.blocking_lock) through an `Arc`, so the guard can outlive the borrow. **Panics** As for [`blocking_lock`](https://nuclei.rs/api/nuclei/sync/struct.Mutex.html#method.blocking_lock). ```rust pub fn get_mut(&mut self) -> &mut T ``` The value, borrowed mutably; `&mut self` proves no guard exists. #### Trait Implementations - `impl Debug for Mutex` - `impl Default for Mutex` - `impl From for Mutex` - `impl Send for Mutex` - `impl Sync for Mutex` #### Auto Trait Implementations - `impl !Freeze for Mutex` - `impl !RefUnwindSafe for Mutex` - `impl !UnwindSafe for Mutex` - `impl Unpin for Mutex where T: Unpin + ?Sized` - `impl UnsafeUnpin for Mutex where T: UnsafeUnpin + ?Sized` ### struct `nuclei::sync::MutexGuard` https://nuclei.rs/api/nuclei/sync/struct.MutexGuard.html ```rust pub struct MutexGuard<'a, T: ?Sized> { /* private fields */ } ``` Exclusive access to a [`Mutex`](https://nuclei.rs/api/nuclei/sync/struct.Mutex.html)’s value; unlocks on drop. The release is one atomic read-modify-write when no waiter needs telling. Otherwise it is lock-free, not wait-free: it returns after one pass over the queue, plus at most one for each operation of another thread that lands on the queue meanwhile (see [Progress](https://nuclei.rs/api/nuclei/sync/index.html#progress)). #### Implementations `impl<'a, T: ?Sized> MutexGuard<'a, T>` ```rust pub fn map(this: Self, f: F) -> MappedMutexGuard<'a, U> where U: ?Sized, F: FnOnce(&mut T) -> &mut U ``` A guard for a component of the locked data. It cannot fail: this guard already holds the lock. An associated function, `MutexGuard::map(guard, f)`: a method would shadow methods of the locked data. ```rust pub fn try_map(this: Self, f: F) -> Result, Self> where U: ?Sized, F: FnOnce(&mut T) -> Option<&mut U> ``` [`map`](https://nuclei.rs/api/nuclei/sync/struct.MutexGuard.html#method.map) that gives the guard back when `f` finds no component, with the lock still held. ```rust pub fn mutex(this: &Self) -> &'a Mutex ``` The mutex this guard locks, for a caller that wants to unlock and lock again. #### Trait Implementations - `impl Debug for MutexGuard<'_, T>` - `impl Deref for MutexGuard<'_, T>` - `impl DerefMut for MutexGuard<'_, T>` - `impl Display for MutexGuard<'_, T>` - `impl Drop for MutexGuard<'_, T>` #### Auto Trait Implementations - `impl<'a, T> !RefUnwindSafe for MutexGuard<'a, T>` - `impl<'a, T> !UnwindSafe for MutexGuard<'a, T>` - `impl<'a, T> Freeze for MutexGuard<'a, T> where T: ?Sized` - `impl<'a, T> Send for MutexGuard<'a, T> where T: Send + ?Sized` - `impl<'a, T> Sync for MutexGuard<'a, T> where T: Send + Sync + ?Sized` - `impl<'a, T> Unpin for MutexGuard<'a, T> where T: ?Sized` - `impl<'a, T> UnsafeUnpin for MutexGuard<'a, T> where T: ?Sized` ### struct `nuclei::sync::Notified` https://nuclei.rs/api/nuclei/sync/struct.Notified.html ```rust pub struct Notified<'a> { /* private fields */ } ``` The future [`Notify::notified`](https://nuclei.rs/api/nuclei/sync/struct.Notify.html#method.notified) returns. It is fused: once it completes, polling it again is ready at once. Dropping it after a `notify_one` or `notify_last` reached it, but before it completed, passes that notification to the next waiter. #### Implementations `impl Notified<'_>` ```rust pub fn enable(self: Pin<&mut Self>) -> bool ``` Adds this future to the waiters that receive `notify_one` and `notify_last`, as its first poll would, without registering a waker. Polling does the same; this is for a caller that must be queued before it checks a condition, so a notification sent in between is not stored as a permit for someone else. `notify_waiters` is received from creation on, enabled or not. Returns true if the future is ready, which any later poll then reports at once. That is so when: 1. `notify_waiters` was called since the future was created; 2. this is the first `enable` or poll and the `Notify` held a permit, which the call consumes; or 3. the future was enabled or polled before and has since been notified. ```rust use nuclei::sync::Notify; use std::pin::pin; let notify = Notify::new(); let mut waiting = pin!(notify.notified()); assert!(!waiting.as_mut().enable(), "nothing was sent yet"); notify.notify_one(); assert!(waiting.as_mut().enable(), "the one sent after enable is its"); ``` #### Trait Implementations - `impl Debug for Notified<'_>` - `impl Drop for Notified<'_>` - `impl Future for Notified<'_>` #### Auto Trait Implementations - `impl<'a> !RefUnwindSafe for Notified<'a>` - `impl<'a> !UnwindSafe for Notified<'a>` - `impl<'a> Freeze for Notified<'a>` - `impl<'a> Send for Notified<'a>` - `impl<'a> Sync for Notified<'a>` - `impl<'a> Unpin for Notified<'a>` - `impl<'a> UnsafeUnpin for Notified<'a>` ### struct `nuclei::sync::Notify` https://nuclei.rs/api/nuclei/sync/struct.Notify.html ```rust pub struct Notify { /* private fields */ } ``` Wakes tasks waiting for an event that carries no value. [`notify_one`](https://nuclei.rs/api/nuclei/sync/struct.Notify.html#method.notify_one) wakes the oldest waiter, or, when nobody waits, stores one permit that the next [`notified`](https://nuclei.rs/api/nuclei/sync/struct.Notify.html#method.notified) consumes at once, so a notification sent just before the wait is not lost. [`notify_last`](https://nuclei.rs/api/nuclei/sync/struct.Notify.html#method.notify_last) is the same for the newest waiter. [`notify_waiters`](https://nuclei.rs/api/nuclei/sync/struct.Notify.html#method.notify_waiters) wakes every waiter that exists when it is called and stores nothing. A [`Notified`](https://nuclei.rs/api/nuclei/sync/struct.Notified.html) future receives `notify_waiters` calls made any time after it was created, even before it is first polled. It receives `notify_one` and `notify_last` only once it is polled or [enabled](https://nuclei.rs/api/nuclei/sync/struct.Notified.html#method.enable). ```rust use nuclei::sync::Notify; use std::future::Future; use std::pin::pin; use std::task::{Context, Poll, Waker}; let notify = Notify::new(); notify.notify_one(); let mut cx = Context::from_waker(Waker::noop()); let waiting = pin!(notify.notified()); assert!(waiting.poll(&mut cx).is_ready(), "the stored permit is consumed"); ``` #### Implementations `impl Notify` ```rust pub const fn new() -> Self ``` A `Notify` with nobody waiting and no stored permit. ```rust pub const fn const_new() -> Self ``` A `Notify` with nobody waiting and no stored permit, usable in a `static`. ```rust pub fn notified(&self) -> Notified<'_> ``` A future that completes on the next notification. It is guaranteed to receive `notify_waiters` calls from the moment it is created, polled or not. It receives `notify_one` and `notify_last` from its first poll, or its first call to [`enable`](https://nuclei.rs/api/nuclei/sync/struct.Notified.html#method.enable). ```rust pub fn notified_owned(self: Arc) -> OwnedNotified ``` [`notified`](https://nuclei.rs/api/nuclei/sync/struct.Notify.html#method.notified) through an `Arc`, so the future can outlive the borrow and move between tasks. ```rust pub fn notify_one(&self) ``` Wakes the oldest waiter, or stores a permit when nobody waits. At most one permit is stored. ```rust pub fn notify_last(&self) ``` Wakes the newest waiter, or stores a permit when nobody waits: as [`notify_one`](https://nuclei.rs/api/nuclei/sync/struct.Notify.html#method.notify_one), but for the waiter that queued last instead of the one that queued first. ```rust pub fn notify_waiters(&self) ``` Wakes every task waiting now: every [`Notified`](https://nuclei.rs/api/nuclei/sync/struct.Notified.html) created before this call, whether or not it has been polled. Stores no permit. #### Trait Implementations - `impl Debug for Notify` - `impl Default for Notify` - `impl Drop for Notify` - `impl Send for Notify` - `impl Sync for Notify` #### Auto Trait Implementations - `impl !Freeze for Notify` - `impl !RefUnwindSafe for Notify` - `impl !UnwindSafe for Notify` - `impl Unpin for Notify` - `impl UnsafeUnpin for Notify` ### struct `nuclei::sync::OnceCell` https://nuclei.rs/api/nuclei/sync/struct.OnceCell.html ```rust pub struct OnceCell { /* private fields */ } ``` A cell that is written at most once. - [`set`](https://nuclei.rs/api/nuclei/sync/struct.OnceCell.html#method.set) publishes a value with one compare-and-swap and never waits. It fails with [`SetError::InitializingError`](https://nuclei.rs/api/nuclei/sync/enum.SetError.html#variant.InitializingError) while an asynchronous initializer holds the turn. - [`get_or_init_racy`](https://nuclei.rs/api/nuclei/sync/struct.OnceCell.html#method.get_or_init_racy) lets every caller that finds the cell empty build a value; one compare-and-swap publishes one of them and the others are dropped. - [`get_or_init`](https://nuclei.rs/api/nuclei/sync/struct.OnceCell.html#method.get_or_init) and [`get_or_try_init`](https://nuclei.rs/api/nuclei/sync/struct.OnceCell.html#method.get_or_try_init) run one initializer at a time; the others wait for it as futures. An initializer that fails or is dropped passes the turn to the next waiter. ```rust use nuclei::sync::{OnceCell, SetError}; static NAME: OnceCell = OnceCell::const_new(); assert!(NAME.set("first".to_owned()).is_ok()); assert_eq!( NAME.set("second".to_owned()), Err(SetError::AlreadyInitializedError("second".to_owned())) ); assert_eq!(NAME.get_or_init_racy(|| "unused".to_owned()), "first"); ``` #### Implementations `impl OnceCell` ```rust pub const fn new() -> Self ``` An empty cell. ```rust pub const fn const_new() -> Self ``` An empty cell, usable in a `static`. ```rust pub fn new_with(value: Option) -> Self ``` A cell that holds `value` if there is one, and is empty otherwise. ```rust pub const fn const_new_with(value: T) -> Self ``` A cell that already holds `value`, usable in a `static`. ```rust pub fn initialized(&self) -> bool ``` Whether the cell holds a value. ```rust pub fn get(&self) -> Option<&T> ``` The value, once published. ```rust pub fn get_mut(&mut self) -> Option<&mut T> ``` The value, borrowed mutably. ```rust pub fn into_inner(self) -> Option ``` Consumes the cell and returns its value, if it has one. ```rust pub fn take(&mut self) -> Option ``` Takes the value out of the cell, leaving it empty and ready to be set again. `None` if the cell is empty. ```rust pub fn set(&self, value: T) -> Result<(), SetError> ``` Publishes `value` unless the cell already holds one or a task is initializing it, in which case `value` comes back in the error. One compare-and-swap publishes; never waits. A successful publish also releases any task waiting in [`get_or_init`](https://nuclei.rs/api/nuclei/sync/struct.OnceCell.html#method.get_or_init). **Errors** [`SetError::AlreadyInitializedError`](https://nuclei.rs/api/nuclei/sync/enum.SetError.html#variant.AlreadyInitializedError) when the cell holds a value, [`SetError::InitializingError`](https://nuclei.rs/api/nuclei/sync/enum.SetError.html#variant.InitializingError) when an initializer holds the turn. ```rust pub fn get_or_init_racy(&self, init: impl FnOnce() -> T) -> &T ``` The value, building one with `init` if the cell is empty. Callers that race all build; one value is published and the rest are dropped. Never waits. A racing builder does not take the turn, so it also wins over an initializer that is running: that one’s value is dropped when it finishes. ```rust pub async fn get_or_init(&self, f: F) -> &T where F: FnOnce() -> Fut, Fut: Future ``` The value, running `f` to build it if the cell is empty. One initializer runs at a time; the rest wait. `f` is called only by the task that holds the turn, and not at all if the cell is full by then. If the future `f` returns is dropped or panics, the attempt is cancelled and the next waiter makes its own. This waits for ever if `f` tries to initialize the cell recursively. ```rust pub async fn get_or_try_init(&self, f: F) -> Result<&T, E> where F: FnOnce() -> Fut, Fut: Future> ``` The value, running `f` to build it if the cell is empty. One initializer runs at a time; when it fails, its error is returned and the next waiter tries its own. If the future `f` returns is dropped or panics, the attempt is cancelled and the next waiter makes its own. This waits for ever if `f` tries to initialize the cell recursively. #### Trait Implementations - `impl Clone for OnceCell` - `impl Debug for OnceCell` - `impl Default for OnceCell` - `impl Drop for OnceCell` - `impl Eq for OnceCell` - `impl From for OnceCell` - `impl PartialEq for OnceCell` - `impl Sync for OnceCell` #### Auto Trait Implementations - `impl !Freeze for OnceCell` - `impl !RefUnwindSafe for OnceCell` - `impl !UnwindSafe for OnceCell` - `impl Send for OnceCell where T: Send` - `impl Unpin for OnceCell where T: Unpin` - `impl UnsafeUnpin for OnceCell where T: UnsafeUnpin` ### struct `nuclei::sync::OwnedMappedMutexGuard` https://nuclei.rs/api/nuclei/sync/struct.OwnedMappedMutexGuard.html ```rust pub struct OwnedMappedMutexGuard { /* private fields */ } ``` A guard for a component `U` of the value of a [`Mutex`](https://nuclei.rs/api/nuclei/sync/struct.Mutex.html) held through an `Arc`, made by [`OwnedMutexGuard::map`](https://nuclei.rs/api/nuclei/sync/struct.OwnedMutexGuard.html#method.map); unlocks on drop. The release makes the progress [`MutexGuard`](https://nuclei.rs/api/nuclei/sync/struct.MutexGuard.html)’s does. #### Implementations `impl OwnedMappedMutexGuard` ```rust pub fn map(this: Self, f: F) -> OwnedMappedMutexGuard where S: ?Sized, F: FnOnce(&mut U) -> &mut S ``` A guard for a component of the component. It cannot fail: this guard already holds the lock. An associated function, `OwnedMappedMutexGuard::map(guard, f)`: a method would shadow methods of the locked data. ```rust pub fn try_map( this: Self, f: F, ) -> Result, Self> where S: ?Sized, F: FnOnce(&mut U) -> Option<&mut S> ``` [`map`](https://nuclei.rs/api/nuclei/sync/struct.OwnedMappedMutexGuard.html#method.map) that gives the guard back when `f` finds no component, with the lock still held. #### Trait Implementations - `impl Debug for OwnedMappedMutexGuard` - `impl Deref for OwnedMappedMutexGuard` - `impl DerefMut for OwnedMappedMutexGuard` - `impl Display for OwnedMappedMutexGuard` - `impl Drop for OwnedMappedMutexGuard` - `impl Send for OwnedMappedMutexGuard` - `impl Sync for OwnedMappedMutexGuard` #### Auto Trait Implementations - `impl !RefUnwindSafe for OwnedMappedMutexGuard` - `impl !UnwindSafe for OwnedMappedMutexGuard` - `impl Freeze for OwnedMappedMutexGuard where T: ?Sized, U: ?Sized` - `impl Unpin for OwnedMappedMutexGuard where T: ?Sized, U: ?Sized` - `impl UnsafeUnpin for OwnedMappedMutexGuard where T: ?Sized, U: ?Sized` ### struct `nuclei::sync::OwnedMutexGuard` https://nuclei.rs/api/nuclei/sync/struct.OwnedMutexGuard.html ```rust pub struct OwnedMutexGuard { /* private fields */ } ``` Exclusive access to a [`Mutex`](https://nuclei.rs/api/nuclei/sync/struct.Mutex.html) held through an `Arc`; unlocks on drop. The release makes the progress [`MutexGuard`](https://nuclei.rs/api/nuclei/sync/struct.MutexGuard.html)’s does. #### Implementations `impl OwnedMutexGuard` ```rust pub fn map(this: Self, f: F) -> OwnedMappedMutexGuard where U: ?Sized, F: FnOnce(&mut T) -> &mut U ``` A guard for a component of the locked data. It cannot fail: this guard already holds the lock. An associated function, `OwnedMutexGuard::map(guard, f)`: a method would shadow methods of the locked data. ```rust pub fn try_map( this: Self, f: F, ) -> Result, Self> where U: ?Sized, F: FnOnce(&mut T) -> Option<&mut U> ``` [`map`](https://nuclei.rs/api/nuclei/sync/struct.OwnedMutexGuard.html#method.map) that gives the guard back when `f` finds no component, with the lock still held. ```rust pub fn mutex(this: &Self) -> &Arc> ``` The `Arc` of the mutex this guard locks. #### Trait Implementations - `impl Debug for OwnedMutexGuard` - `impl Deref for OwnedMutexGuard` - `impl DerefMut for OwnedMutexGuard` - `impl Display for OwnedMutexGuard` - `impl Drop for OwnedMutexGuard` - `impl Sync for OwnedMutexGuard` #### Auto Trait Implementations - `impl !RefUnwindSafe for OwnedMutexGuard` - `impl !UnwindSafe for OwnedMutexGuard` - `impl Freeze for OwnedMutexGuard where T: ?Sized` - `impl Send for OwnedMutexGuard where T: Send + ?Sized` - `impl Unpin for OwnedMutexGuard where T: Unpin + ?Sized` - `impl UnsafeUnpin for OwnedMutexGuard where T: ?Sized` ### struct `nuclei::sync::OwnedNotified` https://nuclei.rs/api/nuclei/sync/struct.OwnedNotified.html ```rust pub struct OwnedNotified { /* private fields */ } ``` The future [`Notify::notified_owned`](https://nuclei.rs/api/nuclei/sync/struct.Notify.html#method.notified_owned) returns: [`Notified`](https://nuclei.rs/api/nuclei/sync/struct.Notified.html) that keeps its `Notify` alive itself. #### Implementations `impl OwnedNotified` ```rust pub fn enable(self: Pin<&mut Self>) -> bool ``` As [`Notified::enable`](https://nuclei.rs/api/nuclei/sync/struct.Notified.html#method.enable). #### Trait Implementations - `impl Debug for OwnedNotified` - `impl Drop for OwnedNotified` - `impl Future for OwnedNotified` #### Auto Trait Implementations - `impl !RefUnwindSafe for OwnedNotified` - `impl !UnwindSafe for OwnedNotified` - `impl Freeze for OwnedNotified` - `impl Send for OwnedNotified` - `impl Sync for OwnedNotified` - `impl Unpin for OwnedNotified` - `impl UnsafeUnpin for OwnedNotified` ### struct `nuclei::sync::OwnedRwLockMappedWriteGuard` https://nuclei.rs/api/nuclei/sync/struct.OwnedRwLockMappedWriteGuard.html ```rust pub struct OwnedRwLockMappedWriteGuard { /* private fields */ } ``` Exclusive access to a component `U` of the value of a [`RwLock`](https://nuclei.rs/api/nuclei/sync/struct.RwLock.html) held through an `Arc`, made by [`OwnedRwLockWriteGuard::map`](https://nuclei.rs/api/nuclei/sync/struct.OwnedRwLockWriteGuard.html#method.map); releases on drop. The release makes the progress [`RwLockReadGuard`](https://nuclei.rs/api/nuclei/sync/struct.RwLockReadGuard.html)’s does. #### Implementations `impl OwnedRwLockMappedWriteGuard` ```rust pub fn map(this: Self, f: F) -> OwnedRwLockMappedWriteGuard where V: ?Sized, F: FnOnce(&mut U) -> &mut V ``` A guard for a component of the component. It cannot fail: this guard already holds the write. An associated function, `OwnedRwLockMappedWriteGuard::map(guard, f)`: a method would shadow methods of the locked data. ```rust pub fn try_map( this: Self, f: F, ) -> Result, Self> where V: ?Sized, F: FnOnce(&mut U) -> Option<&mut V> ``` [`map`](https://nuclei.rs/api/nuclei/sync/struct.OwnedRwLockMappedWriteGuard.html#method.map) that gives the guard back when `f` finds no component, with the write still held. ```rust pub fn rwlock(this: &Self) -> &Arc> ``` The `Arc` of the lock this guard holds the write of. #### Trait Implementations - `impl Debug for OwnedRwLockMappedWriteGuard` - `impl Deref for OwnedRwLockMappedWriteGuard` - `impl DerefMut for OwnedRwLockMappedWriteGuard` - `impl Display for OwnedRwLockMappedWriteGuard` - `impl Drop for OwnedRwLockMappedWriteGuard` - `impl Send for OwnedRwLockMappedWriteGuard` - `impl Sync for OwnedRwLockMappedWriteGuard` #### Auto Trait Implementations - `impl !RefUnwindSafe for OwnedRwLockMappedWriteGuard` - `impl !UnwindSafe for OwnedRwLockMappedWriteGuard` - `impl Freeze for OwnedRwLockMappedWriteGuard where T: ?Sized, U: ?Sized` - `impl Unpin for OwnedRwLockMappedWriteGuard where T: Unpin + ?Sized, U: ?Sized` - `impl UnsafeUnpin for OwnedRwLockMappedWriteGuard where T: ?Sized, U: ?Sized` ### struct `nuclei::sync::OwnedRwLockReadGuard` https://nuclei.rs/api/nuclei/sync/struct.OwnedRwLockReadGuard.html ```rust pub struct OwnedRwLockReadGuard { /* private fields */ } ``` Shared access to a [`RwLock`](https://nuclei.rs/api/nuclei/sync/struct.RwLock.html) held through an `Arc`, to its value or to a component `U` of it; releases on drop. The release makes the progress [`RwLockReadGuard`](https://nuclei.rs/api/nuclei/sync/struct.RwLockReadGuard.html)’s does. #### Implementations `impl OwnedRwLockReadGuard` ```rust pub fn map(this: Self, f: F) -> OwnedRwLockReadGuard where V: ?Sized, F: FnOnce(&U) -> &V ``` A guard for a component of the locked data. It cannot fail: this guard already holds a read. An associated function, `OwnedRwLockReadGuard::map(guard, f)`: a method would shadow methods of the locked data. ```rust pub fn try_map( this: Self, f: F, ) -> Result, Self> where V: ?Sized, F: FnOnce(&U) -> Option<&V> ``` [`map`](https://nuclei.rs/api/nuclei/sync/struct.OwnedRwLockReadGuard.html#method.map) that gives the guard back when `f` finds no component, with the read still held. ```rust pub fn rwlock(this: &Self) -> &Arc> ``` The `Arc` of the lock this guard holds a read of. #### Trait Implementations - `impl Debug for OwnedRwLockReadGuard` - `impl Deref for OwnedRwLockReadGuard` - `impl Display for OwnedRwLockReadGuard` - `impl Drop for OwnedRwLockReadGuard` - `impl Send for OwnedRwLockReadGuard` - `impl Sync for OwnedRwLockReadGuard` #### Auto Trait Implementations - `impl !RefUnwindSafe for OwnedRwLockReadGuard` - `impl !UnwindSafe for OwnedRwLockReadGuard` - `impl Freeze for OwnedRwLockReadGuard where T: ?Sized, U: ?Sized` - `impl Unpin for OwnedRwLockReadGuard where T: Unpin + ?Sized, U: ?Sized` - `impl UnsafeUnpin for OwnedRwLockReadGuard where T: ?Sized, U: ?Sized` ### struct `nuclei::sync::OwnedRwLockWriteGuard` https://nuclei.rs/api/nuclei/sync/struct.OwnedRwLockWriteGuard.html ```rust pub struct OwnedRwLockWriteGuard { /* private fields */ } ``` Exclusive access to a [`RwLock`](https://nuclei.rs/api/nuclei/sync/struct.RwLock.html)’s value through an [`Arc`](https://doc.rust-lang.org/1.99.1/alloc/sync/struct.Arc.html) the guard holds; releases on drop. Made by [`RwLock::write_owned`](https://nuclei.rs/api/nuclei/sync/struct.RwLock.html#method.write_owned). The release makes the progress [`RwLockReadGuard`](https://nuclei.rs/api/nuclei/sync/struct.RwLockReadGuard.html)’s does. #### Implementations `impl OwnedRwLockWriteGuard` ```rust pub fn map(this: Self, f: F) -> OwnedRwLockMappedWriteGuard where U: ?Sized, F: FnOnce(&mut T) -> &mut U ``` A guard for a component of the locked data. It cannot fail: this guard already holds the write. An associated function, `OwnedRwLockWriteGuard::map(guard, f)`: a method would shadow methods of the locked data. ```rust pub fn downgrade_map(this: Self, f: F) -> OwnedRwLockReadGuard where U: ?Sized, F: FnOnce(&T) -> &U ``` A read guard for a component of the locked data, made while the write is turned into a read in one step, as [`downgrade`](https://nuclei.rs/api/nuclei/sync/struct.OwnedRwLockWriteGuard.html#method.downgrade) does. Inside `f` the write is still held, yet `f` is given only a `&T`: a `&mut T` could be kept past the downgrade through interior mutability. ```rust pub fn try_map( this: Self, f: F, ) -> Result, Self> where U: ?Sized, F: FnOnce(&mut T) -> Option<&mut U> ``` [`map`](https://nuclei.rs/api/nuclei/sync/struct.OwnedRwLockWriteGuard.html#method.map) that gives the guard back when `f` finds no component, with the write still held. ```rust pub fn try_downgrade_map( this: Self, f: F, ) -> Result, Self> where U: ?Sized, F: FnOnce(&T) -> Option<&U> ``` [`downgrade_map`](https://nuclei.rs/api/nuclei/sync/struct.OwnedRwLockWriteGuard.html#method.downgrade_map) that gives the guard back when `f` finds no component: the lock is then neither released nor downgraded. ```rust pub fn into_mapped(this: Self) -> OwnedRwLockMappedWriteGuard ``` This guard as an [`OwnedRwLockMappedWriteGuard`](https://nuclei.rs/api/nuclei/sync/struct.OwnedRwLockMappedWriteGuard.html), for a struct field that holds one. The same as `OwnedRwLockWriteGuard::map(guard, |me| me)`. ```rust pub fn downgrade(self) -> OwnedRwLockReadGuard ``` Turns the write into a read in one step, so no writer gets in between. See [`RwLockWriteGuard::downgrade`](https://nuclei.rs/api/nuclei/sync/struct.RwLockWriteGuard.html#method.downgrade). ```rust pub fn rwlock(this: &Self) -> &Arc> ``` The `Arc` of the lock this guard holds the write of. #### Trait Implementations - `impl Debug for OwnedRwLockWriteGuard` - `impl Deref for OwnedRwLockWriteGuard` - `impl DerefMut for OwnedRwLockWriteGuard` - `impl Display for OwnedRwLockWriteGuard` - `impl Drop for OwnedRwLockWriteGuard` - `impl Send for OwnedRwLockWriteGuard` - `impl Sync for OwnedRwLockWriteGuard` #### Auto Trait Implementations - `impl !RefUnwindSafe for OwnedRwLockWriteGuard` - `impl !UnwindSafe for OwnedRwLockWriteGuard` - `impl Freeze for OwnedRwLockWriteGuard where T: ?Sized` - `impl Unpin for OwnedRwLockWriteGuard where T: Unpin + ?Sized` - `impl UnsafeUnpin for OwnedRwLockWriteGuard where T: ?Sized` ### struct `nuclei::sync::OwnedSemaphorePermit` https://nuclei.rs/api/nuclei/sync/struct.OwnedSemaphorePermit.html ```rust pub struct OwnedSemaphorePermit { /* private fields */ } ``` Permits taken from a [`Semaphore`](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html) held through an `Arc`. The release makes the progress [`SemaphorePermit`](https://nuclei.rs/api/nuclei/sync/struct.SemaphorePermit.html)’s does. #### Implementations `impl OwnedSemaphorePermit` ```rust pub fn forget(self) ``` Keeps the permits out of the semaphore for good. ```rust pub fn merge(&mut self, other: Self) ``` Merges `other` into this permit, so one drop returns both. **Panics** When the permits come from different semaphores, or their total overflows `usize`. ```rust pub fn split(&mut self, n: usize) -> Option ``` Splits `n` permits off this one, or returns `None` when it holds fewer than `n`. ```rust pub fn semaphore(&self) -> &Arc ``` The semaphore these permits came from. ```rust pub fn num_permits(&self) -> usize ``` How many permits this holds. ```rust pub fn count(&self) -> usize ``` How many permits this holds; the same as [`num_permits`](https://nuclei.rs/api/nuclei/sync/struct.OwnedSemaphorePermit.html#method.num_permits). #### Trait Implementations - `impl Debug for OwnedSemaphorePermit` - `impl Drop for OwnedSemaphorePermit` #### Auto Trait Implementations - `impl !RefUnwindSafe for OwnedSemaphorePermit` - `impl !UnwindSafe for OwnedSemaphorePermit` - `impl Freeze for OwnedSemaphorePermit` - `impl Send for OwnedSemaphorePermit` - `impl Sync for OwnedSemaphorePermit` - `impl Unpin for OwnedSemaphorePermit` - `impl UnsafeUnpin for OwnedSemaphorePermit` ### struct `nuclei::sync::Owner` https://nuclei.rs/api/nuclei/sync/struct.Owner.html ```rust pub struct Owner { /* private fields */ } ``` A token that identifies the holder of a reentrant lock. [`Owner::new`](https://nuclei.rs/api/nuclei/sync/struct.Owner.html#method.new) makes a token for a task or any caller-defined scope; [`Owner::thread`](https://nuclei.rs/api/nuclei/sync/struct.Owner.html#method.thread) gives the calling thread’s own token, for code that runs on a fixed thread. A token can move to another thread with its task, but it is neither `Clone` nor `Sync`, so it is only ever in one place. ```rust use nuclei::sync::{Owner, ReentrantMutex}; use std::cell::RefCell; let lock = ReentrantMutex::new(RefCell::new(Vec::new())); let me = Owner::new(); let outer = lock.try_lock(&me).expect("free"); let inner = lock.try_lock(&me).expect("the same owner re-enters"); inner.borrow_mut().push(1); drop(inner); assert!(lock.try_lock(&Owner::new()).is_none(), "another owner waits"); drop(outer); ``` #### Implementations `impl Owner` ```rust pub fn new() -> Self ``` A token no other owner has ever had. ```rust pub fn thread() -> ThreadOwner ``` The calling thread’s token: the same owner for every call on this thread, for as long as it lives. #### Trait Implementations - `impl Debug for Owner` - `impl Default for Owner` #### Auto Trait Implementations - `impl !RefUnwindSafe for Owner` - `impl !Sync for Owner` - `impl Freeze for Owner` - `impl Send for Owner` - `impl Unpin for Owner` - `impl UnsafeUnpin for Owner` - `impl UnwindSafe for Owner` ### struct `nuclei::sync::Read` https://nuclei.rs/api/nuclei/sync/struct.Read.html ```rust pub struct Read<'a, T: ?Sized> { /* private fields */ } ``` The future [`RwLock::read`](https://nuclei.rs/api/nuclei/sync/struct.RwLock.html#method.read) returns. #### Trait Implementations - `impl Debug for Read<'_, T>` - `impl Drop for Read<'_, T>` - `impl<'a, T: ?Sized> Future for Read<'a, T>` #### Auto Trait Implementations - `impl<'a, T> !RefUnwindSafe for Read<'a, T>` - `impl<'a, T> !UnwindSafe for Read<'a, T>` - `impl<'a, T> Freeze for Read<'a, T> where T: ?Sized` - `impl<'a, T> Send for Read<'a, T> where T: Send + Sync + ?Sized` - `impl<'a, T> Sync for Read<'a, T> where T: Send + Sync + ?Sized` - `impl<'a, T> Unpin for Read<'a, T> where T: ?Sized` - `impl<'a, T> UnsafeUnpin for Read<'a, T> where T: ?Sized` ### struct `nuclei::sync::ReadHeldByOwner` https://nuclei.rs/api/nuclei/sync/struct.ReadHeldByOwner.html ```rust #[non_exhaustive]pub struct ReadHeldByOwner; ``` Why a [`ReentrantRwLock::write`](https://nuclei.rs/api/nuclei/sync/struct.ReentrantRwLock.html#method.write) failed: its owner reads without writing, so the write would wait for a read only that owner can end. Release the reads first, or take the write before reading. #### Trait Implementations - `impl Clone for ReadHeldByOwner` - `impl Copy for ReadHeldByOwner` - `impl Debug for ReadHeldByOwner` - `impl Display for ReadHeldByOwner` - `impl Eq for ReadHeldByOwner` - `impl Error for ReadHeldByOwner` - `impl PartialEq for ReadHeldByOwner` - `impl StructuralPartialEq for ReadHeldByOwner` #### Auto Trait Implementations - `impl Freeze for ReadHeldByOwner` - `impl RefUnwindSafe for ReadHeldByOwner` - `impl Send for ReadHeldByOwner` - `impl Sync for ReadHeldByOwner` - `impl Unpin for ReadHeldByOwner` - `impl UnsafeUnpin for ReadHeldByOwner` - `impl UnwindSafe for ReadHeldByOwner` ### struct `nuclei::sync::ReadOwned` https://nuclei.rs/api/nuclei/sync/struct.ReadOwned.html ```rust pub struct ReadOwned { /* private fields */ } ``` The future [`RwLock::read_owned`](https://nuclei.rs/api/nuclei/sync/struct.RwLock.html#method.read_owned) returns. It keeps its place in the queue, and the bypasses it counted, for as long as it lives; dropping it withdraws the wait and passes on a lock handed to it meanwhile. #### Trait Implementations - `impl Debug for ReadOwned` - `impl Drop for ReadOwned` - `impl Future for ReadOwned` #### Auto Trait Implementations - `impl !RefUnwindSafe for ReadOwned` - `impl !UnwindSafe for ReadOwned` - `impl Freeze for ReadOwned where T: ?Sized` - `impl Send for ReadOwned where T: Send + Sync + ?Sized` - `impl Sync for ReadOwned where T: Send + Sync + ?Sized` - `impl Unpin for ReadOwned where T: ?Sized` - `impl UnsafeUnpin for ReadOwned where T: ?Sized` ### struct `nuclei::sync::ReentrantMutex` https://nuclei.rs/api/nuclei/sync/struct.ReentrantMutex.html ```rust pub struct ReentrantMutex { /* private fields */ } ``` A mutex the owner holding it can lock again without waiting. Each lock by the holding owner deepens a count; the mutex unlocks when the last of its guards drops, and then wakes the oldest waiting owner, with the bounded bypass of [`Mutex`](https://nuclei.rs/api/nuclei/sync/struct.Mutex.html). A guard gives `&T`, since two guards of one owner are alive at once; mutate through a `Cell` or `RefCell` inside. Guards and lock futures borrow their [`Owner`](https://nuclei.rs/api/nuclei/sync/struct.Owner.html), so they stay on its thread (see the `Owner` docs): a task that holds or awaits one is not `Send` meanwhile. ```rust use nuclei::sync::{Owner, ReentrantMutex}; use std::cell::Cell; let lock = ReentrantMutex::new(Cell::new(0)); let me = Owner::new(); let a = lock.try_lock(&me).expect("free"); let b = lock.try_lock(&me).expect("re-entered"); b.set(a.get() + 1); drop((a, b)); assert_eq!(lock.into_inner().get(), 1); ``` #### Implementations `impl ReentrantMutex` ```rust pub const fn new(value: T) -> Self ``` An unlocked mutex holding `value`. ```rust pub fn into_inner(self) -> T ``` Consumes the mutex and returns its value. `impl ReentrantMutex` ```rust pub fn try_lock<'a>( &'a self, owner: &'a Owner, ) -> Option> ``` Locks the mutex if `owner` holds it, or if it is free and no handoff is owed. ```rust pub fn lock<'a>(&'a self, owner: &'a Owner) -> ReentrantMutexLock<'a, T> ``` Waits for the lock, at once if `owner` already holds it. A contended wait is lock-free, not wait-free: see [Progress](https://nuclei.rs/api/nuclei/sync/index.html#progress). ```rust pub fn get_mut(&mut self) -> &mut T ``` The value, borrowed mutably; `&mut self` proves no guard exists. #### Trait Implementations - `impl Debug for ReentrantMutex` - `impl Default for ReentrantMutex` - `impl Send for ReentrantMutex` - `impl Sync for ReentrantMutex` #### Auto Trait Implementations - `impl !Freeze for ReentrantMutex` - `impl !RefUnwindSafe for ReentrantMutex` - `impl !UnwindSafe for ReentrantMutex` - `impl Unpin for ReentrantMutex where T: Unpin + ?Sized` - `impl UnsafeUnpin for ReentrantMutex where T: UnsafeUnpin + ?Sized` ### struct `nuclei::sync::ReentrantMutexGuard` https://nuclei.rs/api/nuclei/sync/struct.ReentrantMutexGuard.html ```rust pub struct ReentrantMutexGuard<'a, T: ?Sized> { /* private fields */ } ``` Shared access to a [`ReentrantMutex`](https://nuclei.rs/api/nuclei/sync/struct.ReentrantMutex.html)’s value; drops one level of the hold. The drop of the last level releases the lock, which is lock-free, not wait-free: with waiters it returns after one pass over the queue, plus at most one for each operation of another thread that lands on the queue meanwhile (see [Progress](https://nuclei.rs/api/nuclei/sync/index.html#progress)). #### Trait Implementations - `impl Debug for ReentrantMutexGuard<'_, T>` - `impl Deref for ReentrantMutexGuard<'_, T>` - `impl Drop for ReentrantMutexGuard<'_, T>` #### Auto Trait Implementations - `impl<'a, T> !RefUnwindSafe for ReentrantMutexGuard<'a, T>` - `impl<'a, T> !Send for ReentrantMutexGuard<'a, T>` - `impl<'a, T> !Sync for ReentrantMutexGuard<'a, T>` - `impl<'a, T> !UnwindSafe for ReentrantMutexGuard<'a, T>` - `impl<'a, T> Freeze for ReentrantMutexGuard<'a, T> where T: ?Sized` - `impl<'a, T> Unpin for ReentrantMutexGuard<'a, T> where T: ?Sized` - `impl<'a, T> UnsafeUnpin for ReentrantMutexGuard<'a, T> where T: ?Sized` ### struct `nuclei::sync::ReentrantMutexLock` https://nuclei.rs/api/nuclei/sync/struct.ReentrantMutexLock.html ```rust pub struct ReentrantMutexLock<'a, T: ?Sized> { /* private fields */ } ``` The future [`ReentrantMutex::lock`](https://nuclei.rs/api/nuclei/sync/struct.ReentrantMutex.html#method.lock) returns. #### Trait Implementations - `impl Debug for ReentrantMutexLock<'_, T>` - `impl Drop for ReentrantMutexLock<'_, T>` - `impl<'a, T: ?Sized> Future for ReentrantMutexLock<'a, T>` #### Auto Trait Implementations - `impl<'a, T> !RefUnwindSafe for ReentrantMutexLock<'a, T>` - `impl<'a, T> !Send for ReentrantMutexLock<'a, T>` - `impl<'a, T> !Sync for ReentrantMutexLock<'a, T>` - `impl<'a, T> !UnwindSafe for ReentrantMutexLock<'a, T>` - `impl<'a, T> Freeze for ReentrantMutexLock<'a, T> where T: ?Sized` - `impl<'a, T> Unpin for ReentrantMutexLock<'a, T> where T: ?Sized` - `impl<'a, T> UnsafeUnpin for ReentrantMutexLock<'a, T> where T: ?Sized` ### struct `nuclei::sync::ReentrantRead` https://nuclei.rs/api/nuclei/sync/struct.ReentrantRead.html ```rust pub struct ReentrantRead<'a, T: ?Sized> { /* private fields */ } ``` The future [`ReentrantRwLock::read`](https://nuclei.rs/api/nuclei/sync/struct.ReentrantRwLock.html#method.read) returns. #### Trait Implementations - `impl Debug for ReentrantRead<'_, T>` - `impl Drop for ReentrantRead<'_, T>` - `impl<'a, T: ?Sized> Future for ReentrantRead<'a, T>` #### Auto Trait Implementations - `impl<'a, T> !RefUnwindSafe for ReentrantRead<'a, T>` - `impl<'a, T> !Send for ReentrantRead<'a, T>` - `impl<'a, T> !Sync for ReentrantRead<'a, T>` - `impl<'a, T> !UnwindSafe for ReentrantRead<'a, T>` - `impl<'a, T> Freeze for ReentrantRead<'a, T> where T: ?Sized` - `impl<'a, T> Unpin for ReentrantRead<'a, T> where T: ?Sized` - `impl<'a, T> UnsafeUnpin for ReentrantRead<'a, T> where T: ?Sized` ### struct `nuclei::sync::ReentrantReadGuard` https://nuclei.rs/api/nuclei/sync/struct.ReentrantReadGuard.html ```rust pub struct ReentrantReadGuard<'a, T: ?Sized> { /* private fields */ } ``` One read of a [`ReentrantRwLock`](https://nuclei.rs/api/nuclei/sync/struct.ReentrantRwLock.html); drops one level of the owner’s reads. The drop of the last level releases the read, which is lock-free, not wait-free: with waiters it returns after one pass over the queue, plus at most one for each operation of another thread that lands on the queue meanwhile (see [Progress](https://nuclei.rs/api/nuclei/sync/index.html#progress)). #### Trait Implementations - `impl Debug for ReentrantReadGuard<'_, T>` - `impl Deref for ReentrantReadGuard<'_, T>` - `impl Drop for ReentrantReadGuard<'_, T>` #### Auto Trait Implementations - `impl<'a, T> !RefUnwindSafe for ReentrantReadGuard<'a, T>` - `impl<'a, T> !Send for ReentrantReadGuard<'a, T>` - `impl<'a, T> !Sync for ReentrantReadGuard<'a, T>` - `impl<'a, T> !UnwindSafe for ReentrantReadGuard<'a, T>` - `impl<'a, T> Freeze for ReentrantReadGuard<'a, T> where T: ?Sized` - `impl<'a, T> Unpin for ReentrantReadGuard<'a, T> where T: ?Sized` - `impl<'a, T> UnsafeUnpin for ReentrantReadGuard<'a, T> where T: ?Sized` ### struct `nuclei::sync::ReentrantRwLock` https://nuclei.rs/api/nuclei/sync/struct.ReentrantRwLock.html ```rust pub struct ReentrantRwLock { /* private fields */ } ``` A reader-writer lock its holders may lock again, with the bounded bypass of [`RwLock`](https://nuclei.rs/api/nuclei/sync/struct.RwLock.html). Both guards give `&T`, since one owner may hold several at once; the write side excludes every other owner, so mutate through interior mutability that is `Sync` (an atomic, a [`Mutex`](https://nuclei.rs/api/nuclei/sync/struct.Mutex.html)), as readers on other threads share the value. Guards and lock futures borrow their [`Owner`](https://nuclei.rs/api/nuclei/sync/struct.Owner.html) and stay on its thread. ```rust use nuclei::sync::{Owner, ReentrantRwLock}; use std::sync::atomic::{AtomicU32, Ordering}; let lock = ReentrantRwLock::new(AtomicU32::new(0)); let me = Owner::new(); let write = lock.try_write(&me).expect("free"); let read = lock.try_read(&me).expect("a writer may also read"); write.store(7, Ordering::Relaxed); drop(write); assert!(lock.try_write(&Owner::new()).is_none(), "the read is still held"); assert_eq!(read.load(Ordering::Relaxed), 7); ``` #### Implementations `impl ReentrantRwLock` ```rust pub const fn new(value: T) -> Self ``` An unlocked lock holding `value`. ```rust pub fn into_inner(self) -> T ``` Consumes the lock and returns its value. `impl ReentrantRwLock` ```rust pub fn try_read<'a>( &'a self, owner: &'a Owner, ) -> Option> ``` Reads if `owner` already reads or writes, or if no writer holds the lock and no handoff is owed. ```rust pub fn try_write<'a>( &'a self, owner: &'a Owner, ) -> Option> ``` Writes if `owner` already writes, or if nobody holds the lock and no handoff is owed. `None` too while `owner` reads without writing. ```rust pub fn read<'a>(&'a self, owner: &'a Owner) -> ReentrantRead<'a, T> ``` Waits to read, at once if `owner` already reads or writes. A contended wait is lock-free, not wait-free: see [Progress](https://nuclei.rs/api/nuclei/sync/index.html#progress). ```rust pub fn write<'a>(&'a self, owner: &'a Owner) -> ReentrantWrite<'a, T> ``` Waits to write, at once if `owner` already writes. Fails with [`ReadHeldByOwner`](https://nuclei.rs/api/nuclei/sync/struct.ReadHeldByOwner.html) when `owner` reads without writing: the write would wait for that read, which only `owner` can end. A contended wait is lock-free, not wait-free: see [Progress](https://nuclei.rs/api/nuclei/sync/index.html#progress). ```rust pub fn get_mut(&mut self) -> &mut T ``` The value, borrowed mutably; `&mut self` proves no guard exists. #### Trait Implementations - `impl Debug for ReentrantRwLock` - `impl Default for ReentrantRwLock` - `impl Send for ReentrantRwLock` - `impl Sync for ReentrantRwLock` #### Auto Trait Implementations - `impl !Freeze for ReentrantRwLock` - `impl !RefUnwindSafe for ReentrantRwLock` - `impl !UnwindSafe for ReentrantRwLock` - `impl Unpin for ReentrantRwLock where T: Unpin + ?Sized` - `impl UnsafeUnpin for ReentrantRwLock where T: UnsafeUnpin + ?Sized` ### struct `nuclei::sync::ReentrantWrite` https://nuclei.rs/api/nuclei/sync/struct.ReentrantWrite.html ```rust pub struct ReentrantWrite<'a, T: ?Sized> { /* private fields */ } ``` The future [`ReentrantRwLock::write`](https://nuclei.rs/api/nuclei/sync/struct.ReentrantRwLock.html#method.write) returns. #### Trait Implementations - `impl Debug for ReentrantWrite<'_, T>` - `impl Drop for ReentrantWrite<'_, T>` - `impl<'a, T: ?Sized> Future for ReentrantWrite<'a, T>` #### Auto Trait Implementations - `impl<'a, T> !RefUnwindSafe for ReentrantWrite<'a, T>` - `impl<'a, T> !Send for ReentrantWrite<'a, T>` - `impl<'a, T> !Sync for ReentrantWrite<'a, T>` - `impl<'a, T> !UnwindSafe for ReentrantWrite<'a, T>` - `impl<'a, T> Freeze for ReentrantWrite<'a, T> where T: ?Sized` - `impl<'a, T> Unpin for ReentrantWrite<'a, T> where T: ?Sized` - `impl<'a, T> UnsafeUnpin for ReentrantWrite<'a, T> where T: ?Sized` ### struct `nuclei::sync::ReentrantWriteGuard` https://nuclei.rs/api/nuclei/sync/struct.ReentrantWriteGuard.html ```rust pub struct ReentrantWriteGuard<'a, T: ?Sized> { /* private fields */ } ``` One write of a [`ReentrantRwLock`](https://nuclei.rs/api/nuclei/sync/struct.ReentrantRwLock.html); drops one level of the owner’s writes. The drop of the last level releases the write, with the progress [`ReentrantReadGuard`](https://nuclei.rs/api/nuclei/sync/struct.ReentrantReadGuard.html)’s release makes. #### Trait Implementations - `impl Debug for ReentrantWriteGuard<'_, T>` - `impl Deref for ReentrantWriteGuard<'_, T>` - `impl Drop for ReentrantWriteGuard<'_, T>` #### Auto Trait Implementations - `impl<'a, T> !RefUnwindSafe for ReentrantWriteGuard<'a, T>` - `impl<'a, T> !Send for ReentrantWriteGuard<'a, T>` - `impl<'a, T> !Sync for ReentrantWriteGuard<'a, T>` - `impl<'a, T> !UnwindSafe for ReentrantWriteGuard<'a, T>` - `impl<'a, T> Freeze for ReentrantWriteGuard<'a, T> where T: ?Sized` - `impl<'a, T> Unpin for ReentrantWriteGuard<'a, T> where T: ?Sized` - `impl<'a, T> UnsafeUnpin for ReentrantWriteGuard<'a, T> where T: ?Sized` ### struct `nuclei::sync::RwLock` https://nuclei.rs/api/nuclei/sync/struct.RwLock.html ```rust pub struct RwLock { /* private fields */ } ``` A reader-writer lock whose waits are futures. Uncontended, a read or write lock and its release are one atomic read-modify-write each and allocate nothing. Under contention a caller takes the lock whenever it is free to it, even past queued waiters, so a release never waits for a suspended task; a waiter passed over [`MAX_BYPASS`](https://nuclei.rs/api/nuclei/sync/constant.MAX_BYPASS.html) times is handed the lock next, and nobody gets in ahead of it meanwhile, so neither readers nor writers starve. [`upgradable_read`](https://nuclei.rs/api/nuclei/sync/struct.RwLock.html#method.upgradable_read) takes a read that can later become the write without letting a writer in between. One upgradable read exists at a time; it shares the lock with plain readers, and plain read guards cannot upgrade. A write guard becomes a read guard, with no writer in between, through [`RwLockWriteGuard::downgrade`](https://nuclei.rs/api/nuclei/sync/struct.RwLockWriteGuard.html#method.downgrade). ```rust use nuclei::sync::RwLock; let lock = RwLock::new(5); let a = lock.try_read().expect("free"); let b = lock.try_read().expect("readers share"); assert!(lock.try_write().is_err()); drop((a, b)); *lock.try_write().expect("free again") += 1; assert_eq!(lock.into_inner(), 6); ``` #### Implementations `impl RwLock` ```rust pub const fn new(value: T) -> Self ``` An unlocked lock holding `value`. ```rust pub const fn const_new(value: T) -> Self ``` An unlocked lock holding `value`, usable in a `static`. ```rust pub const fn with_max_readers(value: T, max_reads: u32) -> Self ``` An unlocked lock holding `value` that admits at most `max_reads` readers at once: a reader that finds them all inside waits for one to leave, as one held back by a writer does. **Panics** When `max_reads` is `0` or is bigger than `u32::MAX >> 3`. (A target whose word is narrower than 64 bits caps it lower, at the readers its state word can count: `2^23 - 1` on 32 bits.) ```rust pub const fn const_with_max_readers(value: T, max_reads: u32) -> Self ``` [`with_max_readers`](https://nuclei.rs/api/nuclei/sync/struct.RwLock.html#method.with_max_readers), usable in a `static`. **Panics** As for [`with_max_readers`](https://nuclei.rs/api/nuclei/sync/struct.RwLock.html#method.with_max_readers). ```rust pub fn into_inner(self) -> T ``` Consumes the lock and returns its value. `impl RwLock` ```rust pub fn try_read(&self) -> Result, TryLockError> ``` Shares the lock if no writer holds it, no upgrade is under way, the readers have room and no handoff is owed. **Errors** [`TryLockError`](https://nuclei.rs/api/nuclei/sync/struct.TryLockError.html) when any of those fails. ```rust pub fn try_read_owned( self: Arc, ) -> Result, TryLockError> ``` [`try_read`](https://nuclei.rs/api/nuclei/sync/struct.RwLock.html#method.try_read) through an `Arc`, so the guard can outlive the borrow. **Errors** [`TryLockError`](https://nuclei.rs/api/nuclei/sync/struct.TryLockError.html) when the lock cannot be shared now. ```rust pub fn try_write(&self) -> Result, TryLockError> ``` Takes the lock alone if nobody holds it and no handoff is owed. **Errors** [`TryLockError`](https://nuclei.rs/api/nuclei/sync/struct.TryLockError.html) when any reader or writer holds the lock, or a waiter is owed it. ```rust pub fn try_write_owned( self: Arc, ) -> Result, TryLockError> ``` [`try_write`](https://nuclei.rs/api/nuclei/sync/struct.RwLock.html#method.try_write) through an `Arc`, so the guard can outlive the borrow. **Errors** [`TryLockError`](https://nuclei.rs/api/nuclei/sync/struct.TryLockError.html) when the lock cannot be taken alone now. ```rust pub fn try_upgradable_read(&self) -> Option> ``` Takes the upgradable read if no writer and no other upgradable read holds the lock and no handoff is owed. ```rust pub fn read(&self) -> Read<'_, T> ``` Waits to share the lock. Uncontended, the first poll is one atomic read-modify-write. Contended, it is lock-free, not wait-free: see [Progress](https://nuclei.rs/api/nuclei/sync/index.html#progress). Dropping the future withdraws the wait, and passes on a lock handed to it meanwhile. ```rust pub fn read_owned(self: Arc) -> ReadOwned ``` [`read`](https://nuclei.rs/api/nuclei/sync/struct.RwLock.html#method.read) through an `Arc`, so the guard can outlive the borrow. ```rust pub fn write(&self) -> Write<'_, T> ``` Waits to hold the lock alone. Uncontended, the first poll is one atomic read-modify-write. Contended, it is lock-free, not wait-free: see [Progress](https://nuclei.rs/api/nuclei/sync/index.html#progress). Dropping the future withdraws the wait, and passes on a lock handed to it meanwhile. ```rust pub fn write_owned(self: Arc) -> WriteOwned ``` Waits to hold the lock alone, with a guard that keeps the lock alive itself, so the future and the guard can outlive the borrow that made them: a wait kept across calls, or a guard returned to a caller. ```rust pub fn blocking_read(&self) -> RwLockReadGuard<'_, T> ``` [`read`](https://nuclei.rs/api/nuclei/sync/struct.RwLock.html#method.read) for a thread that may block: it parks the calling thread until the lock can be shared. On a nuclei shard (inside one of its tasks) it does not park the thread: it runs a nested `block_on`, so the shard keeps running its other tasks meanwhile. Inside another runtime’s task it blocks that task’s executor thread, so do not: the task that would release may be the one that thread was running. **Panics** On `wasm32`, where no other thread can release, when the lock cannot be shared at once: the call could never end. ```rust pub fn blocking_write(&self) -> RwLockWriteGuard<'_, T> ``` [`write`](https://nuclei.rs/api/nuclei/sync/struct.RwLock.html#method.write) for a thread that may block: see [`blocking_read`](https://nuclei.rs/api/nuclei/sync/struct.RwLock.html#method.blocking_read). **Panics** On `wasm32`, where no other thread can release, when the lock is held at all: the call could never end. ```rust pub fn upgradable_read(&self) -> UpgradableRead<'_, T> ``` Waits for the upgradable read. It makes the progress [`read`](https://nuclei.rs/api/nuclei/sync/struct.RwLock.html#method.read) does. ```rust pub fn get_mut(&mut self) -> &mut T ``` The value, borrowed mutably; `&mut self` proves no guard exists. #### Trait Implementations - `impl Debug for RwLock` - `impl Default for RwLock` - `impl From for RwLock` - `impl Send for RwLock` - `impl Sync for RwLock` #### Auto Trait Implementations - `impl !Freeze for RwLock` - `impl !RefUnwindSafe for RwLock` - `impl !UnwindSafe for RwLock` - `impl Unpin for RwLock where T: Unpin + ?Sized` - `impl UnsafeUnpin for RwLock where T: UnsafeUnpin + ?Sized` ### struct `nuclei::sync::RwLockMappedWriteGuard` https://nuclei.rs/api/nuclei/sync/struct.RwLockMappedWriteGuard.html ```rust pub struct RwLockMappedWriteGuard<'a, T: ?Sized> { /* private fields */ } ``` Exclusive access to a component of a [`RwLock`](https://nuclei.rs/api/nuclei/sync/struct.RwLock.html)’s value, made by [`RwLockWriteGuard::map`](https://nuclei.rs/api/nuclei/sync/struct.RwLockWriteGuard.html#method.map); releases on drop. The release makes the progress [`RwLockReadGuard`](https://nuclei.rs/api/nuclei/sync/struct.RwLockReadGuard.html)’s does. #### Implementations `impl<'a, T: ?Sized> RwLockMappedWriteGuard<'a, T>` ```rust pub fn map(this: Self, f: F) -> RwLockMappedWriteGuard<'a, U> where U: ?Sized, F: FnOnce(&mut T) -> &mut U ``` A guard for a component of the component. It cannot fail: this guard already holds the write. An associated function, `RwLockMappedWriteGuard::map(guard, f)`: a method would shadow methods of the locked data. ```rust pub fn try_map( this: Self, f: F, ) -> Result, Self> where U: ?Sized, F: FnOnce(&mut T) -> Option<&mut U> ``` [`map`](https://nuclei.rs/api/nuclei/sync/struct.RwLockMappedWriteGuard.html#method.map) that gives the guard back when `f` finds no component, with the write still held. #### Trait Implementations - `impl Debug for RwLockMappedWriteGuard<'_, T>` - `impl Deref for RwLockMappedWriteGuard<'_, T>` - `impl DerefMut for RwLockMappedWriteGuard<'_, T>` - `impl Display for RwLockMappedWriteGuard<'_, T>` - `impl Drop for RwLockMappedWriteGuard<'_, T>` - `impl Send for RwLockMappedWriteGuard<'_, T>` - `impl Sync for RwLockMappedWriteGuard<'_, T>` #### Auto Trait Implementations - `impl<'a, T> !RefUnwindSafe for RwLockMappedWriteGuard<'a, T>` - `impl<'a, T> !UnwindSafe for RwLockMappedWriteGuard<'a, T>` - `impl<'a, T> Freeze for RwLockMappedWriteGuard<'a, T> where T: ?Sized` - `impl<'a, T> Unpin for RwLockMappedWriteGuard<'a, T> where T: ?Sized` - `impl<'a, T> UnsafeUnpin for RwLockMappedWriteGuard<'a, T> where T: ?Sized` ### struct `nuclei::sync::RwLockReadGuard` https://nuclei.rs/api/nuclei/sync/struct.RwLockReadGuard.html ```rust pub struct RwLockReadGuard<'a, T: ?Sized> { /* private fields */ } ``` Shared access to a [`RwLock`](https://nuclei.rs/api/nuclei/sync/struct.RwLock.html)’s value, or to a component of it; releases on drop. The release is one atomic read-modify-write when no waiter needs telling. Otherwise it is lock-free, not wait-free: it returns after one pass over the queue, plus at most one for each operation of another thread that lands on the queue meanwhile (see [Progress](https://nuclei.rs/api/nuclei/sync/index.html#progress)). #### Implementations `impl<'a, T: ?Sized> RwLockReadGuard<'a, T>` ```rust pub fn map(this: Self, f: F) -> RwLockReadGuard<'a, U> where U: ?Sized, F: FnOnce(&T) -> &U ``` A guard for a component of the locked data. It cannot fail: this guard already holds a read. An associated function, `RwLockReadGuard::map(guard, f)`: a method would shadow methods of the locked data. ```rust pub fn try_map(this: Self, f: F) -> Result, Self> where U: ?Sized, F: FnOnce(&T) -> Option<&U> ``` [`map`](https://nuclei.rs/api/nuclei/sync/struct.RwLockReadGuard.html#method.map) that gives the guard back when `f` finds no component, with the read still held. #### Trait Implementations - `impl Debug for RwLockReadGuard<'_, T>` - `impl Deref for RwLockReadGuard<'_, T>` - `impl Display for RwLockReadGuard<'_, T>` - `impl Drop for RwLockReadGuard<'_, T>` - `impl Send for RwLockReadGuard<'_, T>` - `impl Sync for RwLockReadGuard<'_, T>` #### Auto Trait Implementations - `impl<'a, T> !RefUnwindSafe for RwLockReadGuard<'a, T>` - `impl<'a, T> !UnwindSafe for RwLockReadGuard<'a, T>` - `impl<'a, T> Freeze for RwLockReadGuard<'a, T> where T: ?Sized` - `impl<'a, T> Unpin for RwLockReadGuard<'a, T> where T: ?Sized` - `impl<'a, T> UnsafeUnpin for RwLockReadGuard<'a, T> where T: ?Sized` ### struct `nuclei::sync::RwLockUpgradableReadGuard` https://nuclei.rs/api/nuclei/sync/struct.RwLockUpgradableReadGuard.html ```rust pub struct RwLockUpgradableReadGuard<'a, T: ?Sized> { /* private fields */ } ``` The upgradable read of a [`RwLock`](https://nuclei.rs/api/nuclei/sync/struct.RwLock.html): shared access that can become exclusive without a writer getting in between. Releases on drop, with the progress [`RwLockReadGuard`](https://nuclei.rs/api/nuclei/sync/struct.RwLockReadGuard.html)’s release makes. It moves to another thread only when `T` is `Send` as well as `Sync`: an upgrade turns it into `&mut T`, so moving it can move the value. A value that may be shared but not moved, such as a [`std::sync::MutexGuard`](https://doc.rust-lang.org/1.99.1/std/sync/poison/mutex/struct.MutexGuard.html), keeps the guard on its thread: ```rust use nuclei::sync::RwLockUpgradableReadGuard; use std::sync::MutexGuard; fn moves() {} moves::>>>(); ``` #### Implementations `impl<'a, T: ?Sized> RwLockUpgradableReadGuard<'a, T>` ```rust pub fn upgrade(self) -> Upgrade<'a, T> ``` Waits for the readers inside to leave, holding new readers back meanwhile, then holds the write. ```rust pub fn try_upgrade(self) -> Result, Self> ``` Holds the write at once if no reader is inside; otherwise hands the upgradable read back. #### Trait Implementations - `impl Debug for RwLockUpgradableReadGuard<'_, T>` - `impl Deref for RwLockUpgradableReadGuard<'_, T>` - `impl Drop for RwLockUpgradableReadGuard<'_, T>` - `impl Send for RwLockUpgradableReadGuard<'_, T>` - `impl Sync for RwLockUpgradableReadGuard<'_, T>` #### Auto Trait Implementations - `impl<'a, T> !RefUnwindSafe for RwLockUpgradableReadGuard<'a, T>` - `impl<'a, T> !UnwindSafe for RwLockUpgradableReadGuard<'a, T>` - `impl<'a, T> Freeze for RwLockUpgradableReadGuard<'a, T> where T: ?Sized` - `impl<'a, T> Unpin for RwLockUpgradableReadGuard<'a, T> where T: ?Sized` - `impl<'a, T> UnsafeUnpin for RwLockUpgradableReadGuard<'a, T> where T: ?Sized` ### struct `nuclei::sync::RwLockWriteGuard` https://nuclei.rs/api/nuclei/sync/struct.RwLockWriteGuard.html ```rust pub struct RwLockWriteGuard<'a, T: ?Sized> { /* private fields */ } ``` Exclusive access to a [`RwLock`](https://nuclei.rs/api/nuclei/sync/struct.RwLock.html)’s value; releases on drop. The release makes the progress [`RwLockReadGuard`](https://nuclei.rs/api/nuclei/sync/struct.RwLockReadGuard.html)’s does. #### Implementations `impl<'a, T: ?Sized> RwLockWriteGuard<'a, T>` ```rust pub fn map(this: Self, f: F) -> RwLockMappedWriteGuard<'a, U> where U: ?Sized, F: FnOnce(&mut T) -> &mut U ``` A guard for a component of the locked data. It cannot fail: this guard already holds the write. An associated function, `RwLockWriteGuard::map(guard, f)`: a method would shadow methods of the locked data. ```rust pub fn downgrade_map(this: Self, f: F) -> RwLockReadGuard<'a, U> where U: ?Sized, F: FnOnce(&T) -> &U ``` A read guard for a component of the locked data, made while the write is turned into a read in one step, as [`downgrade`](https://nuclei.rs/api/nuclei/sync/struct.RwLockWriteGuard.html#method.downgrade) does. Inside `f` the write is still held, yet `f` is given only a `&T`: a `&mut T` could be kept past the downgrade through interior mutability. ```rust pub fn try_map( this: Self, f: F, ) -> Result, Self> where U: ?Sized, F: FnOnce(&mut T) -> Option<&mut U> ``` [`map`](https://nuclei.rs/api/nuclei/sync/struct.RwLockWriteGuard.html#method.map) that gives the guard back when `f` finds no component, with the write still held. ```rust pub fn try_downgrade_map( this: Self, f: F, ) -> Result, Self> where U: ?Sized, F: FnOnce(&T) -> Option<&U> ``` [`downgrade_map`](https://nuclei.rs/api/nuclei/sync/struct.RwLockWriteGuard.html#method.downgrade_map) that gives the guard back when `f` finds no component: the lock is then neither released nor downgraded. ```rust pub fn into_mapped(this: Self) -> RwLockMappedWriteGuard<'a, T> ``` This guard as a [`RwLockMappedWriteGuard`](https://nuclei.rs/api/nuclei/sync/struct.RwLockMappedWriteGuard.html), for a struct field that holds one. The same as `RwLockWriteGuard::map(guard, |me| me)`. ```rust pub fn downgrade(self) -> RwLockReadGuard<'a, T> ``` Turns the write into a read in one step, so no writer gets in between. This does not necessarily let more readers in: a writer may be next in line. The readers queued behind a writer-free front share the lock now, and are woken to do so. It makes the progress a release does (see [`RwLockReadGuard`](https://nuclei.rs/api/nuclei/sync/struct.RwLockReadGuard.html)). ```rust use nuclei::sync::RwLock; let lock = RwLock::new(1); let mut write = lock.try_write().expect("free"); *write += 1; let read = write.downgrade(); assert_eq!(*read, 2); assert!(lock.try_write().is_err(), "the read is still held"); assert!(lock.try_read().is_ok(), "readers share it"); ``` #### Trait Implementations - `impl Debug for RwLockWriteGuard<'_, T>` - `impl Deref for RwLockWriteGuard<'_, T>` - `impl DerefMut for RwLockWriteGuard<'_, T>` - `impl Display for RwLockWriteGuard<'_, T>` - `impl Drop for RwLockWriteGuard<'_, T>` - `impl Send for RwLockWriteGuard<'_, T>` - `impl Sync for RwLockWriteGuard<'_, T>` #### Auto Trait Implementations - `impl<'a, T> !RefUnwindSafe for RwLockWriteGuard<'a, T>` - `impl<'a, T> !UnwindSafe for RwLockWriteGuard<'a, T>` - `impl<'a, T> Freeze for RwLockWriteGuard<'a, T> where T: ?Sized` - `impl<'a, T> Unpin for RwLockWriteGuard<'a, T> where T: ?Sized` - `impl<'a, T> UnsafeUnpin for RwLockWriteGuard<'a, T> where T: ?Sized` ### struct `nuclei::sync::SegQueue` https://nuclei.rs/api/nuclei/sync/struct.SegQueue.html ```rust pub struct SegQueue { /* private fields */ } ``` An unbounded lock-free queue and its pop error, from the kovan-queue crate: see its docs. An unbounded, lock-free, linearizable FIFO queue for many producers and many consumers. Values come out in one total order consistent with real time: a push that returned before another push started comes out first, so one producer’s values always come out in the order it pushed them. ```rust use kovan_queue::seg_queue::SegQueue; let q = SegQueue::new(); q.push(1); q.push(2); assert_eq!(q.pop(), Some(1)); assert_eq!(q.pop(), Some(2)); assert_eq!(q.pop(), None); ``` #### Implementations `impl SegQueue` ```rust pub fn new() -> SegQueue ``` Creates a new unbounded queue. ```rust pub fn push(&self, value: T) ``` Pushes an element into the queue. ```rust pub fn pop(&self) -> Option ``` Pops an element from the queue. Returns `None` when the queue held no value at some moment during the call. Never waits for a producer: a cell whose producer has claimed it but not written is taken out of play, and that producer pushes again. ```rust pub fn try_pop(&self) -> Result ``` Pops an element without waiting and without making any producer push again. Returns [`TryPopError::Empty`](https://nuclei.rs/api/nuclei/sync/enum.TryPopError.html#variant.Empty) when the queue held no value at some moment during the call, and [`TryPopError::Busy`](https://nuclei.rs/api/nuclei/sync/enum.TryPopError.html#variant.Busy) when the queue’s next cell was claimed by a push that had not written its value yet. `Busy` lets a single consumer tell “nothing to wait for” from “a value is about to land”: it can register a waker, check once more, and park until the producer, after its push returns, wakes it. ```rust use kovan_queue::seg_queue::{SegQueue, TryPopError}; let q = SegQueue::new(); assert_eq!(q.try_pop(), Err(TryPopError::Empty)); q.push(7); assert_eq!(q.try_pop(), Ok(7)); ``` ```rust pub fn len(&self) -> usize ``` Returns the number of elements in the queue. Counts the cells claimed by pushes and not yet by pops, so a push in progress counts and a pop in progress does not. This is an approximation in concurrent scenarios: elements may be pushed or popped by other threads between the moment the length is read and the moment the caller acts on the returned value. With no operation in progress it is exact. ```rust pub fn is_empty(&self) -> bool ``` Returns `true` if the queue is empty. The answer [`pop`](https://nuclei.rs/api/nuclei/sync/struct.SegQueue.html#method.pop) would give at the same moment, without taking anything: `true` when no value was in the queue at some moment during the call, `false` when a push had claimed the next cell (a push in progress counts, as it does for [`len`](https://nuclei.rs/api/nuclei/sync/struct.SegQueue.html#method.len)). An approximation in concurrent scenarios, exact with no operation in progress. #### Trait Implementations - `impl Default for SegQueue` - `impl Drop for SegQueue` - `impl Send for SegQueue where T: Send` - `impl Sync for SegQueue where T: Send` #### Auto Trait Implementations - `impl !Freeze for SegQueue` - `impl !RefUnwindSafe for SegQueue` - `impl !UnwindSafe for SegQueue` - `impl Unpin for SegQueue where T: Unpin` - `impl UnsafeUnpin for SegQueue` ### struct `nuclei::sync::Semaphore` https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html ```rust pub struct Semaphore { /* private fields */ } ``` A counting semaphore whose waits are futures. A request for `n` permits takes them whenever `n` are free, even while others wait; under contention [`acquire_many`](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html#method.acquire_many) queues. A release wakes the oldest waiters the freed permits could serve, stopping at the first that does not fit, so a large request at the front is not skipped for smaller ones behind it. A waiter that loses [`MAX_BYPASS`](https://nuclei.rs/api/nuclei/sync/constant.MAX_BYPASS.html) times is owed a handoff: until it is served, [`try_acquire`](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html#method.try_acquire) fails and releases go to the waiters in queue order. [`close`](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html#method.close) ends every wait with an [`AcquireError`](https://nuclei.rs/api/nuclei/sync/struct.AcquireError.html) and makes later acquires fail at once. ```rust use nuclei::sync::{Semaphore, TryAcquireError}; let budget = Semaphore::new(4); let first = budget.try_acquire_many(3).expect("three of four are free"); assert_eq!(budget.try_acquire_many(2).unwrap_err(), TryAcquireError::NoPermits); drop(first); assert_eq!(budget.available_permits(), 4); ``` #### Implementations `impl Semaphore` ```rust pub const MAX_PERMITS: usize = MAX ``` The most permits a semaphore can hold: `usize::MAX >> 7`. The state word keeps seven low bits for the wait queue and the closed flag, so this is `2^57 - 1` on a 64-bit target and `2^25 - 1` on a 32-bit one. ```rust pub const fn new(permits: usize) -> Self ``` A semaphore holding `permits` permits. **Panics** When `permits` exceeds [`MAX_PERMITS`](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html#associatedconstant.MAX_PERMITS). ```rust pub const fn const_new(permits: usize) -> Self ``` A semaphore holding `permits` permits, usable in a `static`. **Panics** When `permits` exceeds [`MAX_PERMITS`](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html#associatedconstant.MAX_PERMITS). ```rust pub fn available_permits(&self) -> usize ``` The permits free right now. ```rust pub fn add_permits(&self, n: usize) ``` Adds `n` new permits, handing them to waiters first. It makes the progress a returned permit does (see [`SemaphorePermit`](https://nuclei.rs/api/nuclei/sync/struct.SemaphorePermit.html)). Permits added to a closed semaphore are counted, but nothing is handed out. **Panics** When the semaphore would hold more than [`MAX_PERMITS`](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html#associatedconstant.MAX_PERMITS). ```rust pub fn forget_permits(&self, n: usize) -> usize ``` Removes up to `n` free permits for good and returns how many it removed, which is fewer than `n` when fewer are free. Permits held by outstanding [`SemaphorePermit`](https://nuclei.rs/api/nuclei/sync/struct.SemaphorePermit.html)s are not touched. ```rust pub fn acquire(&self) -> Acquire<'_> ``` Waits for one permit. Uncontended, the first poll is one atomic read-modify-write. Contended, it is lock-free, not wait-free: see [Progress](https://nuclei.rs/api/nuclei/sync/index.html#progress). Completes with an [`AcquireError`](https://nuclei.rs/api/nuclei/sync/struct.AcquireError.html) once the semaphore is [closed](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html#method.close). ```rust pub fn acquire_many(&self, n: u32) -> Acquire<'_> ``` Waits for `n` permits, which it takes together. Completes with an [`AcquireError`](https://nuclei.rs/api/nuclei/sync/struct.AcquireError.html) once the semaphore is [closed](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html#method.close). **Panics** When `n` exceeds [`MAX_PERMITS`](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html#associatedconstant.MAX_PERMITS), which only a target with a word narrower than 64 bits allows and which no semaphore can ever satisfy. ```rust pub fn acquire_owned(self: Arc) -> AcquireOwned ``` Waits for one permit through an `Arc`, so the permit can outlive the borrow. Completes with an [`AcquireError`](https://nuclei.rs/api/nuclei/sync/struct.AcquireError.html) once the semaphore is [closed](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html#method.close). ```rust pub fn acquire_many_owned(self: Arc, n: u32) -> AcquireOwned ``` Waits for `n` permits through an `Arc`, so the permits can outlive the borrow. **Panics** When `n` exceeds [`MAX_PERMITS`](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html#associatedconstant.MAX_PERMITS), as for [`acquire_many`](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html#method.acquire_many). ```rust pub fn try_acquire(&self) -> Result, TryAcquireError> ``` Takes one permit if it is free and no handoff is owed. ```rust pub fn try_acquire_many( &self, n: u32, ) -> Result, TryAcquireError> ``` Takes `n` permits together if they are free and no handoff is owed. **Panics** When `n` exceeds [`MAX_PERMITS`](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html#associatedconstant.MAX_PERMITS), as for [`acquire_many`](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html#method.acquire_many). ```rust pub fn try_acquire_owned( self: Arc, ) -> Result ``` Takes one permit through an `Arc` if it is free and no handoff is owed. ```rust pub fn try_acquire_many_owned( self: Arc, n: u32, ) -> Result ``` Takes `n` permits together through an `Arc` if they are free and no handoff is owed. **Panics** When `n` exceeds [`MAX_PERMITS`](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html#associatedconstant.MAX_PERMITS), as for [`acquire_many`](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html#method.acquire_many). ```rust pub fn blocking_acquire(&self) -> Result, AcquireError> ``` [`acquire`](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html#method.acquire) for a thread that may block: it parks the calling thread until the permit is free. On a nuclei shard (inside one of its tasks) it does not park the thread: it runs a nested `block_on`, so the shard keeps running its other tasks meanwhile. Inside another runtime’s task it blocks that task’s executor thread, so do not. **Panics** On `wasm32`, where no other thread can return a permit, when the permit is not free: the call could never end. ```rust pub fn blocking_acquire_many( &self, n: u32, ) -> Result, AcquireError> ``` [`acquire_many`](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html#method.acquire_many) for a thread that may block: see [`blocking_acquire`](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html#method.blocking_acquire). **Panics** As for [`blocking_acquire`](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html#method.blocking_acquire), and when `n` exceeds [`MAX_PERMITS`](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html#associatedconstant.MAX_PERMITS). ```rust pub fn blocking_acquire_owned( self: Arc, ) -> Result ``` [`acquire_owned`](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html#method.acquire_owned) for a thread that may block: see [`blocking_acquire`](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html#method.blocking_acquire). **Panics** As for [`blocking_acquire`](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html#method.blocking_acquire). ```rust pub fn blocking_acquire_many_owned( self: Arc, n: u32, ) -> Result ``` [`acquire_many_owned`](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html#method.acquire_many_owned) for a thread that may block: see [`blocking_acquire`](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html#method.blocking_acquire). **Panics** As for [`blocking_acquire`](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html#method.blocking_acquire), and when `n` exceeds [`MAX_PERMITS`](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html#associatedconstant.MAX_PERMITS). ```rust pub fn close(&self) ``` Closes the semaphore. Every wait still queued ends in an [`AcquireError`](https://nuclei.rs/api/nuclei/sync/struct.AcquireError.html), and every later acquire fails at once: `try_acquire` and its siblings return [`TryAcquireError::Closed`](https://nuclei.rs/api/nuclei/sync/enum.TryAcquireError.html#variant.Closed), whatever permits are free. A wait that was handed its permits before the close keeps them. Permits returned or added afterwards are counted, and [`available_permits`](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html#method.available_permits) shows them, but none is ever handed out. Closing twice does nothing. It makes the progress a returned permit does (see [`SemaphorePermit`](https://nuclei.rs/api/nuclei/sync/struct.SemaphorePermit.html)). ```rust pub fn is_closed(&self) -> bool ``` Whether [`close`](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html#method.close) was called. #### Trait Implementations - `impl Debug for Semaphore` #### Auto Trait Implementations - `impl !Freeze for Semaphore` - `impl !RefUnwindSafe for Semaphore` - `impl !UnwindSafe for Semaphore` - `impl Send for Semaphore` - `impl Sync for Semaphore` - `impl Unpin for Semaphore` - `impl UnsafeUnpin for Semaphore` ### struct `nuclei::sync::SemaphorePermit` https://nuclei.rs/api/nuclei/sync/struct.SemaphorePermit.html ```rust pub struct SemaphorePermit<'a> { /* private fields */ } ``` Permits taken from a [`Semaphore`](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html), returned when dropped. The release is one atomic read-modify-write when no waiter needs telling. Otherwise it is lock-free, not wait-free: it returns after one pass over the queue, plus at most one for each operation of another thread that lands on the queue meanwhile (see [Progress](https://nuclei.rs/api/nuclei/sync/index.html#progress)). #### Implementations `impl<'a> SemaphorePermit<'a>` ```rust pub fn forget(self) ``` Keeps the permits out of the semaphore for good. ```rust pub fn merge(&mut self, other: Self) ``` Merges `other` into this permit, so one drop returns both. **Panics** When the permits come from different semaphores, or their total overflows `usize`. ```rust pub fn split(&mut self, n: usize) -> Option ``` Splits `n` permits off this one, or returns `None` when it holds fewer than `n`. ```rust pub fn semaphore(&self) -> &'a Semaphore ``` The semaphore these permits came from. ```rust pub fn num_permits(&self) -> usize ``` How many permits this holds. ```rust pub fn count(&self) -> usize ``` How many permits this holds; the same as [`num_permits`](https://nuclei.rs/api/nuclei/sync/struct.SemaphorePermit.html#method.num_permits). #### Trait Implementations - `impl Debug for SemaphorePermit<'_>` - `impl Drop for SemaphorePermit<'_>` #### Auto Trait Implementations - `impl<'a> !RefUnwindSafe for SemaphorePermit<'a>` - `impl<'a> !UnwindSafe for SemaphorePermit<'a>` - `impl<'a> Freeze for SemaphorePermit<'a>` - `impl<'a> Send for SemaphorePermit<'a>` - `impl<'a> Sync for SemaphorePermit<'a>` - `impl<'a> Unpin for SemaphorePermit<'a>` - `impl<'a> UnsafeUnpin for SemaphorePermit<'a>` ### struct `nuclei::sync::SetOnce` https://nuclei.rs/api/nuclei/sync/struct.SetOnce.html ```rust pub struct SetOnce { /* private fields */ } ``` A cell that is set once, and that readers can wait on until it is. It is a [`OnceCell`](https://nuclei.rs/api/nuclei/sync/struct.OnceCell.html) that nobody initializes asynchronously, paired with an [`Event`](https://nuclei.rs/api/nuclei/sync/struct.Event.html) that [`wait`](https://nuclei.rs/api/nuclei/sync/struct.SetOnce.html#method.wait) sleeps on: [`set`](https://nuclei.rs/api/nuclei/sync/struct.SetOnce.html#method.set) publishes the value with one compare-and-swap, and then sets the event, which wakes every waiter. ```rust use nuclei::sync::SetOnce; static GREETING: SetOnce<&str> = SetOnce::const_new(); assert!(GREETING.get().is_none()); assert!(GREETING.set("hello").is_ok()); assert_eq!(GREETING.get(), Some(&"hello")); assert!(GREETING.set("again").is_err()); ``` #### Implementations `impl SetOnce` ```rust pub const fn new() -> Self ``` An unset cell. ```rust pub const fn const_new() -> Self ``` An unset cell, usable in a `static`. ```rust pub fn new_with(value: Option) -> Self ``` A cell that holds `value` if there is one, and is unset otherwise. ```rust pub const fn const_new_with(value: T) -> Self ``` A cell that is set to `value` already, usable in a `static`. ```rust pub fn initialized(&self) -> bool ``` Whether the cell holds a value. ```rust pub fn get(&self) -> Option<&T> ``` The value, once set. ```rust pub fn set(&self, value: T) -> Result<(), SetOnceError> ``` Sets the value, and wakes every task waiting in [`wait`](https://nuclei.rs/api/nuclei/sync/struct.SetOnce.html#method.wait). One compare-and-swap publishes; never waits. **Errors** [`SetOnceError`](https://nuclei.rs/api/nuclei/sync/struct.SetOnceError.html) with the value when the cell is set already, or another call is setting it at this moment. ```rust pub fn into_inner(self) -> Option ``` Consumes the cell and returns its value, if it has one. ```rust pub async fn wait(&self) -> &T ``` Waits until the cell is set, and returns the value: at once if it is set already. Dropping the future withdraws the wait. #### Trait Implementations - `impl Clone for SetOnce` - `impl Debug for SetOnce` - `impl Default for SetOnce` - `impl Eq for SetOnce` - `impl From for SetOnce` - `impl PartialEq for SetOnce` #### Auto Trait Implementations - `impl !Freeze for SetOnce` - `impl !RefUnwindSafe for SetOnce` - `impl !UnwindSafe for SetOnce` - `impl Send for SetOnce where T: Send` - `impl Sync for SetOnce where T: Send + Sync` - `impl Unpin for SetOnce where T: Unpin` - `impl UnsafeUnpin for SetOnce where T: UnsafeUnpin` ### struct `nuclei::sync::SetOnceError` https://nuclei.rs/api/nuclei/sync/struct.SetOnceError.html ```rust pub struct SetOnceError(pub T); ``` Error returned from [`SetOnce::set`](https://nuclei.rs/api/nuclei/sync/struct.SetOnce.html#method.set): the cell was set already, or another `set` is setting it now. The value comes back. #### Tuple Fields `0: T` #### Trait Implementations - `impl Debug for SetOnceError` - `impl Display for SetOnceError` - `impl Eq for SetOnceError` - `impl Error for SetOnceError` - `impl PartialEq for SetOnceError` - `impl StructuralPartialEq for SetOnceError` #### Auto Trait Implementations - `impl Freeze for SetOnceError where T: Freeze` - `impl RefUnwindSafe for SetOnceError where T: RefUnwindSafe` - `impl Send for SetOnceError where T: Send` - `impl Sync for SetOnceError where T: Sync` - `impl Unpin for SetOnceError where T: Unpin` - `impl UnsafeUnpin for SetOnceError where T: UnsafeUnpin` - `impl UnwindSafe for SetOnceError where T: UnwindSafe` ### struct `nuclei::sync::ThreadOwner` https://nuclei.rs/api/nuclei/sync/struct.ThreadOwner.html ```rust pub struct ThreadOwner { /* private fields */ } ``` The calling thread’s [`Owner`](https://nuclei.rs/api/nuclei/sync/struct.Owner.html), from [`Owner::thread`](https://nuclei.rs/api/nuclei/sync/struct.Owner.html#method.thread). It cannot leave its thread, since another call on the thread would produce the same owner. #### Trait Implementations - `impl Debug for ThreadOwner` - `impl Deref for ThreadOwner` #### Auto Trait Implementations - `impl !RefUnwindSafe for ThreadOwner` - `impl !Send for ThreadOwner` - `impl !Sync for ThreadOwner` - `impl Freeze for ThreadOwner` - `impl Unpin for ThreadOwner` - `impl UnsafeUnpin for ThreadOwner` - `impl UnwindSafe for ThreadOwner` ### struct `nuclei::sync::TryLockError` https://nuclei.rs/api/nuclei/sync/struct.TryLockError.html ```rust pub struct TryLockError(/* private fields */); ``` Error returned from [`Mutex::try_lock`](https://nuclei.rs/api/nuclei/sync/struct.Mutex.html#method.try_lock), [`RwLock::try_read`](https://nuclei.rs/api/nuclei/sync/struct.RwLock.html#method.try_read) and [`RwLock::try_write`](https://nuclei.rs/api/nuclei/sync/struct.RwLock.html#method.try_write) and their `_owned` forms. `Mutex::try_lock` fails when the mutex is locked, or is owed to a waiter that was passed over too often. `RwLock::try_read` fails when a writer holds the lock, an upgrade is under way, or a waiter is owed the lock. `RwLock::try_write` fails when any reader or writer holds it, or a waiter is owed it. #### Trait Implementations - `impl Debug for TryLockError` - `impl Display for TryLockError` - `impl Error for TryLockError` #### Auto Trait Implementations - `impl Freeze for TryLockError` - `impl RefUnwindSafe for TryLockError` - `impl Send for TryLockError` - `impl Sync for TryLockError` - `impl Unpin for TryLockError` - `impl UnsafeUnpin for TryLockError` - `impl UnwindSafe for TryLockError` ### struct `nuclei::sync::UpgradableRead` https://nuclei.rs/api/nuclei/sync/struct.UpgradableRead.html ```rust pub struct UpgradableRead<'a, T: ?Sized> { /* private fields */ } ``` The future [`RwLock::upgradable_read`](https://nuclei.rs/api/nuclei/sync/struct.RwLock.html#method.upgradable_read) returns. #### Trait Implementations - `impl Debug for UpgradableRead<'_, T>` - `impl Drop for UpgradableRead<'_, T>` - `impl<'a, T: ?Sized> Future for UpgradableRead<'a, T>` #### Auto Trait Implementations - `impl<'a, T> !RefUnwindSafe for UpgradableRead<'a, T>` - `impl<'a, T> !UnwindSafe for UpgradableRead<'a, T>` - `impl<'a, T> Freeze for UpgradableRead<'a, T> where T: ?Sized` - `impl<'a, T> Send for UpgradableRead<'a, T> where T: Send + Sync + ?Sized` - `impl<'a, T> Sync for UpgradableRead<'a, T> where T: Send + Sync + ?Sized` - `impl<'a, T> Unpin for UpgradableRead<'a, T> where T: ?Sized` - `impl<'a, T> UnsafeUnpin for UpgradableRead<'a, T> where T: ?Sized` ### struct `nuclei::sync::Upgrade` https://nuclei.rs/api/nuclei/sync/struct.Upgrade.html ```rust pub struct Upgrade<'a, T: ?Sized> { /* private fields */ } ``` The future [`RwLockUpgradableReadGuard::upgrade`](https://nuclei.rs/api/nuclei/sync/struct.RwLockUpgradableReadGuard.html#method.upgrade) returns. Dropping it before it completes releases the upgradable read. #### Trait Implementations - `impl Debug for Upgrade<'_, T>` - `impl Drop for Upgrade<'_, T>` - `impl<'a, T: ?Sized> Future for Upgrade<'a, T>` - `impl Send for Upgrade<'_, T>` - `impl Sync for Upgrade<'_, T>` #### Auto Trait Implementations - `impl<'a, T> !RefUnwindSafe for Upgrade<'a, T>` - `impl<'a, T> !UnwindSafe for Upgrade<'a, T>` - `impl<'a, T> Freeze for Upgrade<'a, T> where T: ?Sized` - `impl<'a, T> Unpin for Upgrade<'a, T> where T: ?Sized` - `impl<'a, T> UnsafeUnpin for Upgrade<'a, T> where T: ?Sized` ### struct `nuclei::sync::WaitForCancellationFuture` https://nuclei.rs/api/nuclei/sync/struct.WaitForCancellationFuture.html ```rust pub struct WaitForCancellationFuture<'a> { /* private fields */ } ``` A future that resolves once the corresponding [`CancellationToken`](https://nuclei.rs/api/nuclei/sync/struct.CancellationToken.html) is cancelled. Created by [`CancellationToken::cancelled`](https://nuclei.rs/api/nuclei/sync/struct.CancellationToken.html#method.cancelled). #### Trait Implementations - `impl Debug for WaitForCancellationFuture<'_>` - `impl Future for WaitForCancellationFuture<'_>` #### Auto Trait Implementations - `impl<'a> !RefUnwindSafe for WaitForCancellationFuture<'a>` - `impl<'a> !UnwindSafe for WaitForCancellationFuture<'a>` - `impl<'a> Freeze for WaitForCancellationFuture<'a>` - `impl<'a> Send for WaitForCancellationFuture<'a>` - `impl<'a> Sync for WaitForCancellationFuture<'a>` - `impl<'a> Unpin for WaitForCancellationFuture<'a>` - `impl<'a> UnsafeUnpin for WaitForCancellationFuture<'a>` ### struct `nuclei::sync::WaitForCancellationFutureOwned` https://nuclei.rs/api/nuclei/sync/struct.WaitForCancellationFutureOwned.html ```rust pub struct WaitForCancellationFutureOwned { /* private fields */ } ``` A future that resolves once the corresponding [`CancellationToken`](https://nuclei.rs/api/nuclei/sync/struct.CancellationToken.html) is cancelled, and owns the token. Created by [`CancellationToken::cancelled_owned`](https://nuclei.rs/api/nuclei/sync/struct.CancellationToken.html#method.cancelled_owned). #### Trait Implementations - `impl Debug for WaitForCancellationFutureOwned` - `impl Future for WaitForCancellationFutureOwned` #### Auto Trait Implementations - `impl !RefUnwindSafe for WaitForCancellationFutureOwned` - `impl !UnwindSafe for WaitForCancellationFutureOwned` - `impl Freeze for WaitForCancellationFutureOwned` - `impl Send for WaitForCancellationFutureOwned` - `impl Sync for WaitForCancellationFutureOwned` - `impl Unpin for WaitForCancellationFutureOwned` - `impl UnsafeUnpin for WaitForCancellationFutureOwned` ### struct `nuclei::sync::Write` https://nuclei.rs/api/nuclei/sync/struct.Write.html ```rust pub struct Write<'a, T: ?Sized> { /* private fields */ } ``` The future [`RwLock::write`](https://nuclei.rs/api/nuclei/sync/struct.RwLock.html#method.write) returns. #### Trait Implementations - `impl Debug for Write<'_, T>` - `impl Drop for Write<'_, T>` - `impl<'a, T: ?Sized> Future for Write<'a, T>` #### Auto Trait Implementations - `impl<'a, T> !RefUnwindSafe for Write<'a, T>` - `impl<'a, T> !UnwindSafe for Write<'a, T>` - `impl<'a, T> Freeze for Write<'a, T> where T: ?Sized` - `impl<'a, T> Send for Write<'a, T> where T: Send + Sync + ?Sized` - `impl<'a, T> Sync for Write<'a, T> where T: Send + Sync + ?Sized` - `impl<'a, T> Unpin for Write<'a, T> where T: ?Sized` - `impl<'a, T> UnsafeUnpin for Write<'a, T> where T: ?Sized` ### struct `nuclei::sync::WriteOwned` https://nuclei.rs/api/nuclei/sync/struct.WriteOwned.html ```rust pub struct WriteOwned { /* private fields */ } ``` The future [`RwLock::write_owned`](https://nuclei.rs/api/nuclei/sync/struct.RwLock.html#method.write_owned) returns. It keeps its place in the queue, and the bypasses it counted, for as long as it lives; dropping it withdraws the wait and passes on a handoff made to it meanwhile. #### Trait Implementations - `impl Debug for WriteOwned` - `impl Drop for WriteOwned` - `impl Future for WriteOwned` #### Auto Trait Implementations - `impl !RefUnwindSafe for WriteOwned` - `impl !UnwindSafe for WriteOwned` - `impl Freeze for WriteOwned where T: ?Sized` - `impl Send for WriteOwned where T: Send + Sync + ?Sized` - `impl Sync for WriteOwned where T: Send + Sync + ?Sized` - `impl Unpin for WriteOwned where T: ?Sized` - `impl UnsafeUnpin for WriteOwned where T: ?Sized` ### enum `nuclei::sync::SetError` https://nuclei.rs/api/nuclei/sync/enum.SetError.html ```rust pub enum SetError { AlreadyInitializedError(T), InitializingError(T), } ``` Errors that can be returned from [`OnceCell::set`](https://nuclei.rs/api/nuclei/sync/struct.OnceCell.html#method.set). #### Variants ```rust AlreadyInitializedError(T) ``` The cell was already initialized when [`OnceCell::set`](https://nuclei.rs/api/nuclei/sync/struct.OnceCell.html#method.set) was called. ```rust InitializingError(T) ``` The cell is currently being initialized. #### Implementations `impl SetError` ```rust pub fn is_already_init_err(&self) -> bool ``` Whether this is [`SetError::AlreadyInitializedError`](https://nuclei.rs/api/nuclei/sync/enum.SetError.html#variant.AlreadyInitializedError). ```rust pub fn is_initializing_err(&self) -> bool ``` Whether this is [`SetError::InitializingError`](https://nuclei.rs/api/nuclei/sync/enum.SetError.html#variant.InitializingError). #### Trait Implementations - `impl Debug for SetError` - `impl Display for SetError` - `impl Eq for SetError` - `impl Error for SetError` - `impl PartialEq for SetError` - `impl StructuralPartialEq for SetError` #### Auto Trait Implementations - `impl Freeze for SetError where T: Freeze` - `impl RefUnwindSafe for SetError where T: RefUnwindSafe` - `impl Send for SetError where T: Send` - `impl Sync for SetError where T: Sync` - `impl Unpin for SetError where T: Unpin` - `impl UnsafeUnpin for SetError where T: UnsafeUnpin` - `impl UnwindSafe for SetError where T: UnwindSafe` ### enum `nuclei::sync::TryAcquireError` https://nuclei.rs/api/nuclei/sync/enum.TryAcquireError.html ```rust pub enum TryAcquireError { Closed, NoPermits, } ``` Error returned from [`Semaphore::try_acquire`](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html#method.try_acquire) and the other attempts that never wait. #### Variants ```rust Closed ``` The semaphore has been [closed](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html#method.close) and cannot issue new permits. ```rust NoPermits ``` The semaphore has no available permits. #### Trait Implementations - `impl Debug for TryAcquireError` - `impl Display for TryAcquireError` - `impl Eq for TryAcquireError` - `impl Error for TryAcquireError` - `impl PartialEq for TryAcquireError` - `impl StructuralPartialEq for TryAcquireError` #### Auto Trait Implementations - `impl Freeze for TryAcquireError` - `impl RefUnwindSafe for TryAcquireError` - `impl Send for TryAcquireError` - `impl Sync for TryAcquireError` - `impl Unpin for TryAcquireError` - `impl UnsafeUnpin for TryAcquireError` - `impl UnwindSafe for TryAcquireError` ### enum `nuclei::sync::TryPopError` https://nuclei.rs/api/nuclei/sync/enum.TryPopError.html ```rust pub enum TryPopError { Empty, Busy, } ``` An unbounded lock-free queue and its pop error, from the kovan-queue crate: see its docs. Why [`SegQueue::try_pop`](https://nuclei.rs/api/nuclei/sync/struct.SegQueue.html#method.try_pop) returned no value. #### Variants ```rust Empty ``` The queue holds no value. ```rust Busy ``` A push has claimed the queue’s next cell and not written its value yet: a value is on its way. A single consumer can register a waker and park; the producer wakes it once its push returns. #### Trait Implementations - `impl Clone for TryPopError` - `impl Copy for TryPopError` - `impl Debug for TryPopError` - `impl Display for TryPopError` - `impl Eq for TryPopError` - `impl Error for TryPopError` - `impl Hash for TryPopError` - `impl PartialEq for TryPopError` - `impl StructuralPartialEq for TryPopError` #### Auto Trait Implementations - `impl Freeze for TryPopError` - `impl RefUnwindSafe for TryPopError` - `impl Send for TryPopError` - `impl Sync for TryPopError` - `impl Unpin for TryPopError` - `impl UnsafeUnpin for TryPopError` - `impl UnwindSafe for TryPopError` ### const `nuclei::sync::MAX_BYPASS` https://nuclei.rs/api/nuclei/sync/constant.MAX_BYPASS.html ```rust pub const MAX_BYPASS: u32 = 16; ``` How many times a waiter can be passed over before it is owed a handoff: a woken waiter that loses its retry this many times is handed the next release directly, and nobody barges past it meanwhile. ## Module `nuclei::sync::broadcast` https://nuclei.rs/api/nuclei/sync/broadcast/index.html A multi-producer, multi-consumer broadcast channel: each value sent reaches every receiver that exists when it is sent. [`channel`](https://nuclei.rs/api/nuclei/sync/broadcast/fn.channel.html) returns a [`Sender`](https://nuclei.rs/api/nuclei/sync/broadcast/struct.Sender.html) and a [`Receiver`](https://nuclei.rs/api/nuclei/sync/broadcast/struct.Receiver.html) around a capacity. [`Sender::send`](https://nuclei.rs/api/nuclei/sync/broadcast/struct.Sender.html#method.send) puts a value in the channel for every receiver; each [`Receiver`](https://nuclei.rs/api/nuclei/sync/broadcast/struct.Receiver.html) takes the values in order with [`Receiver::recv`](https://nuclei.rs/api/nuclei/sync/broadcast/struct.Receiver.html#method.recv), cloning them (`T: Clone`). The channel holds the last `capacity` values (rounded up to a power of two): a receiver that falls further behind loses the oldest ones, and its next receive reports how many with [`RecvError::Lagged`](https://nuclei.rs/api/nuclei/sync/broadcast/error/enum.RecvError.html#variant.Lagged) before it goes on from the oldest value still held. The channel closes once every sender is gone: receivers take what is left, then get [`RecvError::Closed`](https://nuclei.rs/api/nuclei/sync/broadcast/error/enum.RecvError.html#variant.Closed). The API is the established async broadcast-channel API; nothing here needs a runtime. ```rust use nuclei::sync::broadcast; let (tx, mut rx1) = broadcast::channel(16); let mut rx2 = tx.subscribe(); tx.send(10).unwrap(); tx.send(20).unwrap(); assert_eq!(rx1.try_recv(), Ok(10)); assert_eq!(rx2.try_recv(), Ok(10)); assert_eq!(rx1.try_recv(), Ok(20)); ``` **Values live in nodes published lock-free** The channel is a ring of `capacity` slots, each an atomic pointer holding the node of the latest value sent to it with that value’s position. A sender takes the next position with one `fetch_add`, publishes its node into the position’s slot with a compare-and-swap that never replaces a later position, and retires the node it replaced. A receive is a protected load of its slot and a clone of the value: it writes nothing another thread reads, so receivers never contend with one another or with the senders. Two consequences, both differing from the lock-based API: - The channel needs `T: Send + Sync + 'static`: values are shared by reference between threads and reclaimed later. - A value is dropped when a later send takes its slot (or the channel goes), not as soon as every receiver has taken it: the channel holds up to `capacity` values whatever the receivers have read. [`Sender::len`](https://nuclei.rs/api/nuclei/sync/broadcast/struct.Sender.html#method.len) still counts what the slowest receiver has yet to take. Under the `recycle` feature its nodes come from a per-thread cache instead of the global allocator. **Progress** - Wait-free: [`Receiver::try_recv`](https://nuclei.rs/api/nuclei/sync/broadcast/struct.Receiver.html#method.try_recv), [`Receiver::len`](https://nuclei.rs/api/nuclei/sync/broadcast/struct.Receiver.html#method.len), [`Receiver::is_empty`](https://nuclei.rs/api/nuclei/sync/broadcast/struct.Receiver.html#method.is_empty), [`Sender::receiver_count`](https://nuclei.rs/api/nuclei/sync/broadcast/struct.Sender.html#method.receiver_count), [`Sender::same_channel`](https://nuclei.rs/api/nuclei/sync/broadcast/struct.Sender.html#method.same_channel), [`Sender::subscribe`](https://nuclei.rs/api/nuclei/sync/broadcast/struct.Sender.html#method.subscribe), [`Receiver::resubscribe`](https://nuclei.rs/api/nuclei/sync/broadcast/struct.Receiver.html#method.resubscribe), [`Sender::downgrade`](https://nuclei.rs/api/nuclei/sync/broadcast/struct.Sender.html#method.downgrade), the sender counts, and the clones and drops but the last sender’s and the last receiver’s. - Lock-free: [`Sender::send`](https://nuclei.rs/api/nuclei/sync/broadcast/struct.Sender.html#method.send) (its compare-and-swap is retried only if a send a whole ring later published into the same slot meanwhile, and it ends by waking the waiting receivers through [`Notify::notify_waiters`](https://nuclei.rs/api/nuclei/sync/struct.Notify.html), which is lock-free); [`Sender::len`](https://nuclei.rs/api/nuclei/sync/broadcast/struct.Sender.html#method.len) and [`Sender::is_empty`](https://nuclei.rs/api/nuclei/sync/broadcast/struct.Sender.html#method.is_empty) (they look at every receiver); polling [`Receiver::recv`](https://nuclei.rs/api/nuclei/sync/broadcast/struct.Receiver.html#method.recv) and [`Sender::closed`](https://nuclei.rs/api/nuclei/sync/broadcast/struct.Sender.html#method.closed) (a poll may queue a waiter); [`WeakSender::upgrade`](https://nuclei.rs/api/nuclei/sync/broadcast/struct.WeakSender.html#method.upgrade) (a compare-and-swap on the sender count, retried when a sender was cloned or dropped meanwhile); and the last sender’s or receiver’s drop, for its wake. ### Re-exports - `pub use self::error::RecvError;` - `pub use self::error::SendError;` - `pub use self::error::TryRecvError;` ### Modules - [error](https://nuclei.rs/api/nuclei/sync/broadcast/error/index.html): Error types of the broadcast channel. ### Structs - [Receiver](https://nuclei.rs/api/nuclei/sync/broadcast/struct.Receiver.html): Receives the values of the channel, in order. - [Sender](https://nuclei.rs/api/nuclei/sync/broadcast/struct.Sender.html): Sends values to every [`Receiver`](https://nuclei.rs/api/nuclei/sync/broadcast/struct.Receiver.html) of the channel. - [WeakSender](https://nuclei.rs/api/nuclei/sync/broadcast/struct.WeakSender.html): A sender that does not keep the channel open. ### Functions - [channel](https://nuclei.rs/api/nuclei/sync/broadcast/fn.channel.html): Creates a broadcast channel holding the last `capacity` values (rounded up to a power of two), returning a sender and a first receiver. ### struct `nuclei::sync::broadcast::Receiver` https://nuclei.rs/api/nuclei/sync/broadcast/struct.Receiver.html ```rust pub struct Receiver { /* private fields */ } ``` Receives the values of the channel, in order. Created by [`channel`](https://nuclei.rs/api/nuclei/sync/broadcast/fn.channel.html), [`Sender::subscribe`](https://nuclei.rs/api/nuclei/sync/broadcast/struct.Sender.html#method.subscribe) or [`Receiver::resubscribe`](https://nuclei.rs/api/nuclei/sync/broadcast/struct.Receiver.html#method.resubscribe); each takes every value sent after it was made. #### Implementations `impl Receiver` ```rust pub fn len(&self) -> usize ``` How many values were sent that this receiver has yet to take; past the capacity, its next receive reports a lag. ```rust pub fn is_empty(&self) -> bool ``` Whether this receiver took every value sent. ```rust pub fn resubscribe(&self) -> Self ``` A new receiver, which takes the values sent from now on. `impl Receiver` ```rust pub fn try_recv(&mut self) -> Result ``` Takes the next value, if one came, without waiting. **Errors** [`TryRecvError::Empty`](https://nuclei.rs/api/nuclei/sync/broadcast/error/enum.TryRecvError.html#variant.Empty) when none came since the last one taken; [`TryRecvError::Lagged`](https://nuclei.rs/api/nuclei/sync/broadcast/error/enum.TryRecvError.html#variant.Lagged) once, when the receiver lost values, before it goes on from the oldest one still held; [`TryRecvError::Closed`](https://nuclei.rs/api/nuclei/sync/broadcast/error/enum.TryRecvError.html#variant.Closed) once every sender is gone and every value was taken. ```rust use nuclei::sync::broadcast::{self, error::TryRecvError}; let (tx, mut rx) = broadcast::channel(2); for i in 0..3 { tx.send(i).unwrap(); } assert_eq!(rx.try_recv(), Err(TryRecvError::Lagged(1))); assert_eq!(rx.try_recv(), Ok(1)); assert_eq!(rx.try_recv(), Ok(2)); assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); drop(tx); assert_eq!(rx.try_recv(), Err(TryRecvError::Closed)); ``` ```rust pub async fn recv(&mut self) -> Result ``` Waits for the next value and takes it. **Errors** [`RecvError::Lagged`](https://nuclei.rs/api/nuclei/sync/broadcast/error/enum.RecvError.html#variant.Lagged) once, when the receiver lost values, before it goes on from the oldest one still held; [`RecvError::Closed`](https://nuclei.rs/api/nuclei/sync/broadcast/error/enum.RecvError.html#variant.Closed) once every sender is gone and every value was taken. **Cancel safety** Dropping the future takes nothing: the next receive gets the value. **Cooperative scheduling** On a nuclei shard a receive that completes spends one operation of its task’s budget; with the budget spent it takes nothing and yields to the shard’s other tasks first (see `nuclei::task::coop`). ```rust pub fn blocking_recv(&mut self) -> Result ``` Receives the next value from a thread that may block. Like [`recv`](https://nuclei.rs/api/nuclei/sync/broadcast/struct.Receiver.html#method.recv), but it parks the calling thread while no value came and the channel is open. On a nuclei shard (inside one of its tasks) it does not park the thread: it runs a nested `block_on`, so the shard keeps running its other tasks meanwhile. Inside another runtime’s task it blocks that task’s thread. **Errors** As for [`recv`](https://nuclei.rs/api/nuclei/sync/broadcast/struct.Receiver.html#method.recv). **Panics** On `wasm32`, where no other thread can send, when no value came and the channel is open: the call could never end. ```rust use nuclei::sync::broadcast::{self, RecvError}; let (tx, mut rx) = broadcast::channel::(4); let receiver = std::thread::spawn(move || { assert_eq!(rx.blocking_recv(), Ok(10)); assert_eq!(rx.blocking_recv(), Err(RecvError::Closed)); }); tx.send(10).unwrap(); drop(tx); receiver.join().unwrap(); ``` #### Trait Implementations - `impl Debug for Receiver` - `impl Drop for Receiver` #### Auto Trait Implementations - `impl !RefUnwindSafe for Receiver` - `impl !UnwindSafe for Receiver` - `impl Freeze for Receiver` - `impl Send for Receiver` - `impl Sync for Receiver` - `impl Unpin for Receiver` - `impl UnsafeUnpin for Receiver` ### struct `nuclei::sync::broadcast::Sender` https://nuclei.rs/api/nuclei/sync/broadcast/struct.Sender.html ```rust pub struct Sender { /* private fields */ } ``` Sends values to every [`Receiver`](https://nuclei.rs/api/nuclei/sync/broadcast/struct.Receiver.html) of the channel. Created by [`channel`](https://nuclei.rs/api/nuclei/sync/broadcast/fn.channel.html). Clone it for more producers. The channel closes for the receivers when the last sender is dropped. #### Implementations `impl Sender` ```rust pub fn new(capacity: usize) -> Self ``` A sender of a new channel holding the last `capacity` values (rounded up to a power of two), with no receiver yet: each comes from [`subscribe`](https://nuclei.rs/api/nuclei/sync/broadcast/struct.Sender.html#method.subscribe). **Panics** When `capacity` is zero, or above `usize::MAX / 2`. ```rust use nuclei::sync::broadcast::Sender; let tx = Sender::new(4); assert!(tx.send(1).is_err(), "no receiver yet"); let mut rx = tx.subscribe(); tx.send(2).unwrap(); assert_eq!(rx.try_recv(), Ok(2)); ``` ```rust pub fn send(&self, value: T) -> Result> ``` Sends `value` to every receiver there is now, returning how many. A send never waits: the channel holds the last `capacity` values, and a receiver too far behind loses the oldest. **Errors** When there is no receiver; the value is handed back. ```rust use nuclei::sync::broadcast; let (tx, rx) = broadcast::channel(2); assert_eq!(tx.send("a"), Ok(1)); drop(rx); assert_eq!(tx.send("b").unwrap_err().0, "b"); ``` ```rust pub fn subscribe(&self) -> Receiver ``` A new receiver, which takes the values sent from now on. ```rust use nuclei::sync::broadcast; let (tx, _rx) = broadcast::channel(2); tx.send(1).unwrap(); let mut late = tx.subscribe(); tx.send(2).unwrap(); assert_eq!(late.try_recv(), Ok(2)); ``` ```rust pub fn receiver_count(&self) -> usize ``` How many receivers there are. ```rust pub fn downgrade(&self) -> WeakSender ``` A [`WeakSender`](https://nuclei.rs/api/nuclei/sync/broadcast/struct.WeakSender.html) of the channel, which does not keep it open. The sender itself stays. ```rust pub fn strong_count(&self) -> usize ``` How many [`Sender`](https://nuclei.rs/api/nuclei/sync/broadcast/struct.Sender.html)s exist. ```rust pub fn weak_count(&self) -> usize ``` How many [`WeakSender`](https://nuclei.rs/api/nuclei/sync/broadcast/struct.WeakSender.html)s exist. ```rust pub fn len(&self) -> usize ``` How many values the slowest receiver has yet to take, at most the capacity (older ones are lost to it); zero with no receiver. ```rust use nuclei::sync::broadcast; let (tx, mut rx) = broadcast::channel(4); tx.send(1).unwrap(); tx.send(2).unwrap(); assert_eq!(tx.len(), 2); rx.try_recv().unwrap(); assert_eq!(tx.len(), 1); ``` ```rust pub fn is_empty(&self) -> bool ``` Whether every receiver took every value it can still take. ```rust pub fn same_channel(&self, other: &Self) -> bool ``` Whether `other` sends on the same channel. ```rust pub async fn closed(&self) ``` Completes once there is no receiver. ```rust use core::future::Future; use core::pin::pin; use core::task::{Context, Poll, Waker}; use nuclei::sync::broadcast; let (tx, rx) = broadcast::channel::(1); let mut cx = Context::from_waker(Waker::noop()); let mut closed = pin!(tx.closed()); assert_eq!(closed.as_mut().poll(&mut cx), Poll::Pending); drop(rx); assert_eq!(closed.as_mut().poll(&mut cx), Poll::Ready(())); ``` #### Trait Implementations - `impl Clone for Sender` - `impl Debug for Sender` - `impl Drop for Sender` #### Auto Trait Implementations - `impl !RefUnwindSafe for Sender` - `impl !UnwindSafe for Sender` - `impl Freeze for Sender` - `impl Send for Sender` - `impl Sync for Sender` - `impl Unpin for Sender` - `impl UnsafeUnpin for Sender` ### struct `nuclei::sync::broadcast::WeakSender` https://nuclei.rs/api/nuclei/sync/broadcast/struct.WeakSender.html ```rust pub struct WeakSender { /* private fields */ } ``` A sender that does not keep the channel open. Made by [`Sender::downgrade`](https://nuclei.rs/api/nuclei/sync/broadcast/struct.Sender.html#method.downgrade). Once every [`Sender`](https://nuclei.rs/api/nuclei/sync/broadcast/struct.Sender.html) is gone the channel is closed, whatever `WeakSender`s are left. A `WeakSender` sends nothing itself: [`upgrade`](https://nuclei.rs/api/nuclei/sync/broadcast/struct.WeakSender.html#method.upgrade) makes a [`Sender`](https://nuclei.rs/api/nuclei/sync/broadcast/struct.Sender.html) of it while one exists. ```rust use nuclei::sync::broadcast; let (tx, _rx) = broadcast::channel::(4); let weak = tx.downgrade(); assert!(weak.upgrade().is_some()); drop(tx); assert!(weak.upgrade().is_none()); ``` #### Implementations `impl WeakSender` ```rust pub fn upgrade(&self) -> Option> ``` A [`Sender`](https://nuclei.rs/api/nuclei/sync/broadcast/struct.Sender.html) of the channel, while one exists; `None` once the last is gone (the channel is closed then, for good). ```rust pub fn strong_count(&self) -> usize ``` How many [`Sender`](https://nuclei.rs/api/nuclei/sync/broadcast/struct.Sender.html)s exist. ```rust pub fn weak_count(&self) -> usize ``` How many [`WeakSender`](https://nuclei.rs/api/nuclei/sync/broadcast/struct.WeakSender.html)s exist. #### Trait Implementations - `impl Clone for WeakSender` - `impl Debug for WeakSender` - `impl Drop for WeakSender` #### Auto Trait Implementations - `impl !RefUnwindSafe for WeakSender` - `impl !UnwindSafe for WeakSender` - `impl Freeze for WeakSender` - `impl Send for WeakSender` - `impl Sync for WeakSender` - `impl Unpin for WeakSender` - `impl UnsafeUnpin for WeakSender` ### fn `nuclei::sync::broadcast::channel` https://nuclei.rs/api/nuclei/sync/broadcast/fn.channel.html ```rust pub fn channel( capacity: usize, ) -> (Sender, Receiver) ``` Creates a broadcast channel holding the last `capacity` values (rounded up to a power of two), returning a sender and a first receiver. **Panics** When `capacity` is zero, or above `usize::MAX / 2`. ```rust use nuclei::sync::broadcast; let (tx, mut rx) = broadcast::channel::(4); tx.send(1).unwrap(); assert_eq!(rx.try_recv(), Ok(1)); ``` ## Module `nuclei::sync::broadcast::error` https://nuclei.rs/api/nuclei/sync/broadcast/error/index.html Error types of the broadcast channel. ### Structs - [SendError](https://nuclei.rs/api/nuclei/sync/broadcast/error/struct.SendError.html): Error produced when sending a value fails: there is no receiver. ### Enums - [RecvError](https://nuclei.rs/api/nuclei/sync/broadcast/error/enum.RecvError.html): Error produced when a receive fails. - [TryRecvError](https://nuclei.rs/api/nuclei/sync/broadcast/error/enum.TryRecvError.html): Error produced when a receive that does not wait fails. ### struct `nuclei::sync::broadcast::error::SendError` https://nuclei.rs/api/nuclei/sync/broadcast/error/struct.SendError.html Also exported as `nuclei::sync::broadcast::SendError`. ```rust pub struct SendError(pub T); ``` Error produced when sending a value fails: there is no receiver. The value is handed back in the error. #### Tuple Fields `0: T` #### Trait Implementations - `impl Clone for SendError` - `impl Copy for SendError` - `impl Debug for SendError` - `impl Display for SendError` - `impl Eq for SendError` - `impl Error for SendError` - `impl PartialEq for SendError` - `impl StructuralPartialEq for SendError` #### Auto Trait Implementations - `impl Freeze for SendError where T: Freeze` - `impl RefUnwindSafe for SendError where T: RefUnwindSafe` - `impl Send for SendError where T: Send` - `impl Sync for SendError where T: Sync` - `impl Unpin for SendError where T: Unpin` - `impl UnsafeUnpin for SendError where T: UnsafeUnpin` - `impl UnwindSafe for SendError where T: UnwindSafe` ### enum `nuclei::sync::broadcast::error::RecvError` https://nuclei.rs/api/nuclei/sync/broadcast/error/enum.RecvError.html Also exported as `nuclei::sync::broadcast::RecvError`. ```rust pub enum RecvError { Closed, Lagged(u64), } ``` Error produced when a receive fails. #### Variants ```rust Closed ``` Every sender is gone and every value was taken. ```rust Lagged(u64) ``` The receiver fell behind by this many values, which are lost; the next receive takes the oldest value the channel still holds. #### Trait Implementations - `impl Clone for RecvError` - `impl Debug for RecvError` - `impl Display for RecvError` - `impl Eq for RecvError` - `impl Error for RecvError` - `impl PartialEq for RecvError` - `impl StructuralPartialEq for RecvError` #### Auto Trait Implementations - `impl Freeze for RecvError` - `impl RefUnwindSafe for RecvError` - `impl Send for RecvError` - `impl Sync for RecvError` - `impl Unpin for RecvError` - `impl UnsafeUnpin for RecvError` - `impl UnwindSafe for RecvError` ### enum `nuclei::sync::broadcast::error::TryRecvError` https://nuclei.rs/api/nuclei/sync/broadcast/error/enum.TryRecvError.html Also exported as `nuclei::sync::broadcast::TryRecvError`. ```rust pub enum TryRecvError { Empty, Closed, Lagged(u64), } ``` Error produced when a receive that does not wait fails. #### Variants ```rust Empty ``` No value has come since the last one this receiver took. ```rust Closed ``` Every sender is gone and every value was taken. ```rust Lagged(u64) ``` The receiver fell behind by this many values, which are lost; the next receive takes the oldest value the channel still holds. #### Trait Implementations - `impl Clone for TryRecvError` - `impl Debug for TryRecvError` - `impl Display for TryRecvError` - `impl Eq for TryRecvError` - `impl Error for TryRecvError` - `impl PartialEq for TryRecvError` - `impl StructuralPartialEq for TryRecvError` #### Auto Trait Implementations - `impl Freeze for TryRecvError` - `impl RefUnwindSafe for TryRecvError` - `impl Send for TryRecvError` - `impl Sync for TryRecvError` - `impl Unpin for TryRecvError` - `impl UnsafeUnpin for TryRecvError` - `impl UnwindSafe for TryRecvError` ## Module `nuclei::sync::futures` https://nuclei.rs/api/nuclei/sync/futures/index.html Named future types, at the conventional `sync::futures` path. ### Structs - [Notified](https://nuclei.rs/api/nuclei/sync/futures/struct.Notified.html): The future [`Notify::notified`](https://nuclei.rs/api/nuclei/sync/struct.Notify.html#method.notified) returns. - [OwnedNotified](https://nuclei.rs/api/nuclei/sync/futures/struct.OwnedNotified.html): The future [`Notify::notified_owned`](https://nuclei.rs/api/nuclei/sync/struct.Notify.html#method.notified_owned) returns: [`Notified`](https://nuclei.rs/api/nuclei/sync/struct.Notified.html) that keeps its `Notify` alive itself. ### struct `nuclei::sync::futures::Notified` https://nuclei.rs/api/nuclei/sync/futures/struct.Notified.html ```rust pub struct Notified<'a> { /* private fields */ } ``` The future [`Notify::notified`](https://nuclei.rs/api/nuclei/sync/struct.Notify.html#method.notified) returns. It is fused: once it completes, polling it again is ready at once. Dropping it after a `notify_one` or `notify_last` reached it, but before it completed, passes that notification to the next waiter. #### Implementations `impl Notified<'_>` ```rust pub fn enable(self: Pin<&mut Self>) -> bool ``` Adds this future to the waiters that receive `notify_one` and `notify_last`, as its first poll would, without registering a waker. Polling does the same; this is for a caller that must be queued before it checks a condition, so a notification sent in between is not stored as a permit for someone else. `notify_waiters` is received from creation on, enabled or not. Returns true if the future is ready, which any later poll then reports at once. That is so when: 1. `notify_waiters` was called since the future was created; 2. this is the first `enable` or poll and the `Notify` held a permit, which the call consumes; or 3. the future was enabled or polled before and has since been notified. ```rust use nuclei::sync::Notify; use std::pin::pin; let notify = Notify::new(); let mut waiting = pin!(notify.notified()); assert!(!waiting.as_mut().enable(), "nothing was sent yet"); notify.notify_one(); assert!(waiting.as_mut().enable(), "the one sent after enable is its"); ``` #### Trait Implementations - `impl Debug for Notified<'_>` - `impl Drop for Notified<'_>` - `impl Future for Notified<'_>` #### Auto Trait Implementations - `impl<'a> !RefUnwindSafe for Notified<'a>` - `impl<'a> !UnwindSafe for Notified<'a>` - `impl<'a> Freeze for Notified<'a>` - `impl<'a> Send for Notified<'a>` - `impl<'a> Sync for Notified<'a>` - `impl<'a> Unpin for Notified<'a>` - `impl<'a> UnsafeUnpin for Notified<'a>` ### struct `nuclei::sync::futures::OwnedNotified` https://nuclei.rs/api/nuclei/sync/futures/struct.OwnedNotified.html ```rust pub struct OwnedNotified { /* private fields */ } ``` The future [`Notify::notified_owned`](https://nuclei.rs/api/nuclei/sync/struct.Notify.html#method.notified_owned) returns: [`Notified`](https://nuclei.rs/api/nuclei/sync/struct.Notified.html) that keeps its `Notify` alive itself. #### Implementations `impl OwnedNotified` ```rust pub fn enable(self: Pin<&mut Self>) -> bool ``` As [`Notified::enable`](https://nuclei.rs/api/nuclei/sync/struct.Notified.html#method.enable). #### Trait Implementations - `impl Debug for OwnedNotified` - `impl Drop for OwnedNotified` - `impl Future for OwnedNotified` #### Auto Trait Implementations - `impl !RefUnwindSafe for OwnedNotified` - `impl !UnwindSafe for OwnedNotified` - `impl Freeze for OwnedNotified` - `impl Send for OwnedNotified` - `impl Sync for OwnedNotified` - `impl Unpin for OwnedNotified` - `impl UnsafeUnpin for OwnedNotified` ## Module `nuclei::sync::local` https://nuclei.rs/api/nuclei/sync/local/index.html Synchronization primitives for the tasks of one shard. Everything here is for tasks that share one shard ([`task::spawn_local`](https://nuclei.rs/api/nuclei/runtime/fn.spawn_local.html), or the future `block_on` runs): the state sits in `Rc`s and plain cells, so the types are `!Send` and `!Sync`, and no path executes an atomic instruction or a fence. That makes them cheaper than their atomic twins in [`sync`](https://nuclei.rs/api/nuclei/sync/index.html): CI counts the instructions of a message and of a one-shot reply on both (`ci/op_budget.txt`). The names and signatures mirror the atomic ones, so code switches by changing the path: [`mpsc`](https://nuclei.rs/api/nuclei/sync/local/mpsc/index.html) for [`sync::mpsc`](https://nuclei.rs/api/nuclei/sync/mpsc/index.html), [`oneshot`](https://nuclei.rs/api/nuclei/sync/local/oneshot/index.html) for [`sync::oneshot`](https://nuclei.rs/api/nuclei/sync/oneshot/index.html), [`Semaphore`](https://nuclei.rs/api/nuclei/sync/local/struct.Semaphore.html) for [`sync::Semaphore`](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html) and [`Mutex`](https://nuclei.rs/api/nuclei/sync/local/struct.Mutex.html) for [`sync::Mutex`](https://nuclei.rs/api/nuclei/sync/struct.Mutex.html). The errors are the atomic ones. ```rust fn send(_: T) {} send(nuclei::sync::local::Mutex::new(0u8)); ``` **Fairness** Sends on a full bounded channel, acquires of the semaphore and locks of the mutex are served strictly in arrival order, with no barging: permits that come free are kept for the front waiter until its whole request fits, and `try_` forms fail while anyone waits. **Cancel safety** Dropping any future of this module at any await loses no value, no permit and no wakeup, and leaks nothing: a waiting future gives up its place in line (the next waiter is served if it was the front), and one that was already granted its permits or the lock passes them on. **Cooperative scheduling** The budget of [`task::coop`](https://nuclei.rs/api/nuclei/task/coop/index.html) applies as for the atomic twins: a receive, an acquire or a lock that completes spends one operation of the task’s budget, and a bounded send or reservation that completes at its first attempt does too. A wait that queued and was granted spends nothing. The `try_` forms never spend. **Interior mutability** The module keeps one rule. A cell is borrowed only inside one non-reentrant step, and nothing that can run user code (a [`Waker::wake`](https://doc.rust-lang.org/1.99.1/core/task/wake/struct.Waker.html#method.wake), a value’s `Drop`, a waker’s clone) runs while any of them is borrowed: the waker or the values are taken out first, the borrow ends, and then they are woken or dropped. After a wake the state is read again; no borrow is reused. ### Modules - [mpsc](https://nuclei.rs/api/nuclei/sync/local/mpsc/index.html): Multi-producer, single-consumer channels for the tasks of one shard. - [oneshot](https://nuclei.rs/api/nuclei/sync/local/oneshot/index.html): A channel that carries one value from one sender to one receiver, both on one shard. ### Structs - [Acquire](https://nuclei.rs/api/nuclei/sync/local/struct.Acquire.html): The wait for permits of [`Semaphore::acquire`](https://nuclei.rs/api/nuclei/sync/local/struct.Semaphore.html#method.acquire) and [`Semaphore::acquire_many`](https://nuclei.rs/api/nuclei/sync/local/struct.Semaphore.html#method.acquire_many). - [Lock](https://nuclei.rs/api/nuclei/sync/local/struct.Lock.html): The wait of [`Mutex::lock`](https://nuclei.rs/api/nuclei/sync/local/struct.Mutex.html#method.lock). - [Mutex](https://nuclei.rs/api/nuclei/sync/local/struct.Mutex.html): A mutual-exclusion lock whose wait is a future, for the tasks of one shard. - [MutexGuard](https://nuclei.rs/api/nuclei/sync/local/struct.MutexGuard.html): Holds a [`Mutex`](https://nuclei.rs/api/nuclei/sync/local/struct.Mutex.html) locked; unlocks it when dropped. - [Semaphore](https://nuclei.rs/api/nuclei/sync/local/struct.Semaphore.html): A counting semaphore whose waits are futures, for the tasks of one shard. - [SemaphorePermit](https://nuclei.rs/api/nuclei/sync/local/struct.SemaphorePermit.html): Permits taken from a [`Semaphore`](https://nuclei.rs/api/nuclei/sync/local/struct.Semaphore.html), returned when dropped. ### struct `nuclei::sync::local::Acquire` https://nuclei.rs/api/nuclei/sync/local/struct.Acquire.html ```rust pub struct Acquire<'a> { /* private fields */ } ``` The wait for permits of [`Semaphore::acquire`](https://nuclei.rs/api/nuclei/sync/local/struct.Semaphore.html#method.acquire) and [`Semaphore::acquire_many`](https://nuclei.rs/api/nuclei/sync/local/struct.Semaphore.html#method.acquire_many). Cancel safe: dropping it gives up its place in line; if its permits were already granted, they go back and the next waiter is served. #### Trait Implementations - `impl Debug for Acquire<'_>` - `impl Drop for Acquire<'_>` - `impl<'a> Future for Acquire<'a>` #### Auto Trait Implementations - `impl<'a> !RefUnwindSafe for Acquire<'a>` - `impl<'a> !Send for Acquire<'a>` - `impl<'a> !Sync for Acquire<'a>` - `impl<'a> !UnwindSafe for Acquire<'a>` - `impl<'a> Freeze for Acquire<'a>` - `impl<'a> Unpin for Acquire<'a>` - `impl<'a> UnsafeUnpin for Acquire<'a>` ### struct `nuclei::sync::local::Lock` https://nuclei.rs/api/nuclei/sync/local/struct.Lock.html ```rust pub struct Lock<'a, T: ?Sized> { /* private fields */ } ``` The wait of [`Mutex::lock`](https://nuclei.rs/api/nuclei/sync/local/struct.Mutex.html#method.lock). Cancel safe: dropping it gives up its place in line; if the lock was already handed to it, the lock passes to the next waiter. #### Trait Implementations - `impl Debug for Lock<'_, T>` - `impl<'a, T: ?Sized> Future for Lock<'a, T>` #### Auto Trait Implementations - `impl<'a, T> !RefUnwindSafe for Lock<'a, T>` - `impl<'a, T> !Send for Lock<'a, T>` - `impl<'a, T> !Sync for Lock<'a, T>` - `impl<'a, T> !UnwindSafe for Lock<'a, T>` - `impl<'a, T> Freeze for Lock<'a, T> where T: ?Sized` - `impl<'a, T> Unpin for Lock<'a, T> where T: ?Sized` - `impl<'a, T> UnsafeUnpin for Lock<'a, T> where T: ?Sized` ### struct `nuclei::sync::local::Mutex` https://nuclei.rs/api/nuclei/sync/local/struct.Mutex.html ```rust pub struct Mutex { /* private fields */ } ``` A mutual-exclusion lock whose wait is a future, for the tasks of one shard. Locking in arrival order: a [`lock`](https://nuclei.rs/api/nuclei/sync/local/struct.Mutex.html#method.lock) that has to wait is granted the lock by the unlock that frees it, and [`try_lock`](https://nuclei.rs/api/nuclei/sync/local/struct.Mutex.html#method.try_lock) fails while anyone waits. It is `!Send` and `!Sync`: share it between the tasks of a shard with an `Rc`. ```rust use nuclei::sync::local::Mutex; let counter = Mutex::new(0u32); *counter.try_lock().expect("uncontended") += 1; assert_eq!(counter.into_inner(), 1); ``` #### Implementations `impl Mutex` ```rust pub const fn new(value: T) -> Self ``` An unlocked mutex holding `value`. ```rust pub fn into_inner(self) -> T ``` Consumes the mutex and returns its value. `impl Mutex` ```rust pub fn lock(&self) -> Lock<'_, T> ``` Waits for the lock, and answers a guard that unlocks when dropped. ```rust pub fn try_lock(&self) -> Result, TryLockError> ``` Locks the mutex if it is free and nobody waits. **Errors** [`TryLockError`](https://nuclei.rs/api/nuclei/sync/struct.TryLockError.html) when the mutex is locked or owed to a waiter. ```rust pub fn get_mut(&mut self) -> &mut T ``` The value, through a unique borrow: no lock is needed. #### Trait Implementations - `impl Debug for Mutex` - `impl Default for Mutex` - `impl From for Mutex` #### Auto Trait Implementations - `impl !Freeze for Mutex` - `impl !RefUnwindSafe for Mutex` - `impl !Send for Mutex` - `impl !Sync for Mutex` - `impl Unpin for Mutex where T: Unpin + ?Sized` - `impl UnsafeUnpin for Mutex where T: UnsafeUnpin + ?Sized` - `impl UnwindSafe for Mutex where T: UnwindSafe + ?Sized` ### struct `nuclei::sync::local::MutexGuard` https://nuclei.rs/api/nuclei/sync/local/struct.MutexGuard.html ```rust pub struct MutexGuard<'a, T: ?Sized> { /* private fields */ } ``` Holds a [`Mutex`](https://nuclei.rs/api/nuclei/sync/local/struct.Mutex.html) locked; unlocks it when dropped. #### Trait Implementations - `impl Debug for MutexGuard<'_, T>` - `impl Deref for MutexGuard<'_, T>` - `impl DerefMut for MutexGuard<'_, T>` - `impl Drop for MutexGuard<'_, T>` #### Auto Trait Implementations - `impl<'a, T> !RefUnwindSafe for MutexGuard<'a, T>` - `impl<'a, T> !Send for MutexGuard<'a, T>` - `impl<'a, T> !Sync for MutexGuard<'a, T>` - `impl<'a, T> !UnwindSafe for MutexGuard<'a, T>` - `impl<'a, T> Freeze for MutexGuard<'a, T> where T: ?Sized` - `impl<'a, T> Unpin for MutexGuard<'a, T> where T: ?Sized` - `impl<'a, T> UnsafeUnpin for MutexGuard<'a, T> where T: ?Sized` ### struct `nuclei::sync::local::Semaphore` https://nuclei.rs/api/nuclei/sync/local/struct.Semaphore.html ```rust pub struct Semaphore { /* private fields */ } ``` A counting semaphore whose waits are futures, for the tasks of one shard. A request for `n` permits waits in line behind the requests that arrived before it, and is granted when it reaches the front and `n` permits are free. A large request at the front is therefore never bypassed by smaller ones behind it, and [`try_acquire`](https://nuclei.rs/api/nuclei/sync/local/struct.Semaphore.html#method.try_acquire) fails while anyone waits. [`close`](https://nuclei.rs/api/nuclei/sync/local/struct.Semaphore.html#method.close) ends every wait with an [`AcquireError`](https://nuclei.rs/api/nuclei/sync/struct.AcquireError.html). It is `!Send` and `!Sync`: share it between the tasks of a shard with an `Rc`. ```rust use nuclei::sync::TryAcquireError; use nuclei::sync::local::Semaphore; let budget = Semaphore::new(4); let first = budget.try_acquire_many(3).expect("three of four are free"); assert_eq!(budget.try_acquire_many(2).unwrap_err(), TryAcquireError::NoPermits); drop(first); assert_eq!(budget.available_permits(), 4); ``` #### Implementations `impl Semaphore` ```rust pub const MAX_PERMITS: usize ``` The most permits a semaphore can hold: `usize::MAX >> 3`. ```rust pub const fn new(permits: usize) -> Self ``` A semaphore holding `permits` permits. **Panics** When `permits` exceeds [`MAX_PERMITS`](https://nuclei.rs/api/nuclei/sync/local/struct.Semaphore.html#associatedconstant.MAX_PERMITS). ```rust pub fn available_permits(&self) -> usize ``` The permits free right now, including the ones kept for the front waiter until its request fits. ```rust pub fn add_permits(&self, n: usize) ``` Adds `n` new permits, handing them to waiters first. Permits added to a closed semaphore are counted, but nothing is handed out. **Panics** When the semaphore would hold more than [`MAX_PERMITS`](https://nuclei.rs/api/nuclei/sync/local/struct.Semaphore.html#associatedconstant.MAX_PERMITS). ```rust pub fn forget_permits(&self, n: usize) -> usize ``` Removes up to `n` free permits for good and returns how many it removed, which is fewer than `n` when fewer are free. Permits held by outstanding [`SemaphorePermit`](https://nuclei.rs/api/nuclei/sync/local/struct.SemaphorePermit.html)s are not touched. ```rust pub fn acquire(&self) -> Acquire<'_> ``` Waits for one permit. Completes with an [`AcquireError`](https://nuclei.rs/api/nuclei/sync/struct.AcquireError.html) once the semaphore is [closed](https://nuclei.rs/api/nuclei/sync/local/struct.Semaphore.html#method.close). ```rust pub fn acquire_many(&self, n: u32) -> Acquire<'_> ``` Waits for `n` permits, which it takes together. Completes with an [`AcquireError`](https://nuclei.rs/api/nuclei/sync/struct.AcquireError.html) once the semaphore is [closed](https://nuclei.rs/api/nuclei/sync/local/struct.Semaphore.html#method.close). **Panics** When `n` exceeds [`MAX_PERMITS`](https://nuclei.rs/api/nuclei/sync/local/struct.Semaphore.html#associatedconstant.MAX_PERMITS), which only a target with a word narrower than 64 bits allows and which no semaphore can ever satisfy. ```rust pub fn try_acquire(&self) -> Result, TryAcquireError> ``` Takes one permit if it is free and nobody waits. ```rust pub fn try_acquire_many( &self, n: u32, ) -> Result, TryAcquireError> ``` Takes `n` permits together if they are free and nobody waits. **Panics** When `n` exceeds [`MAX_PERMITS`](https://nuclei.rs/api/nuclei/sync/local/struct.Semaphore.html#associatedconstant.MAX_PERMITS), as for [`acquire_many`](https://nuclei.rs/api/nuclei/sync/local/struct.Semaphore.html#method.acquire_many). ```rust pub fn close(&self) ``` Closes the semaphore. Every wait still queued ends in an [`AcquireError`](https://nuclei.rs/api/nuclei/sync/struct.AcquireError.html), and every later acquire fails at once: `try_acquire` and its sibling return [`TryAcquireError::Closed`](https://nuclei.rs/api/nuclei/sync/enum.TryAcquireError.html#variant.Closed), whatever permits are free. A wait that was granted its permits before the close keeps them. Permits returned or added afterwards are counted, and [`available_permits`](https://nuclei.rs/api/nuclei/sync/local/struct.Semaphore.html#method.available_permits) shows them, but none is ever handed out. Closing twice does nothing. ```rust pub fn is_closed(&self) -> bool ``` Whether [`close`](https://nuclei.rs/api/nuclei/sync/local/struct.Semaphore.html#method.close) was called. #### Trait Implementations - `impl Debug for Semaphore` #### Auto Trait Implementations - `impl !Freeze for Semaphore` - `impl !RefUnwindSafe for Semaphore` - `impl !Send for Semaphore` - `impl !Sync for Semaphore` - `impl Unpin for Semaphore` - `impl UnsafeUnpin for Semaphore` - `impl UnwindSafe for Semaphore` ### struct `nuclei::sync::local::SemaphorePermit` https://nuclei.rs/api/nuclei/sync/local/struct.SemaphorePermit.html ```rust pub struct SemaphorePermit<'a> { /* private fields */ } ``` Permits taken from a [`Semaphore`](https://nuclei.rs/api/nuclei/sync/local/struct.Semaphore.html), returned when dropped. #### Implementations `impl<'a> SemaphorePermit<'a>` ```rust pub fn forget(self) ``` Keeps the permits out of the semaphore for good. ```rust pub fn num_permits(&self) -> usize ``` How many permits this holds. ```rust pub fn merge(&mut self, other: Self) ``` Merges `other` into this permit, so one drop returns both. **Panics** When the permits come from different semaphores. #### Trait Implementations - `impl Debug for SemaphorePermit<'_>` - `impl Drop for SemaphorePermit<'_>` #### Auto Trait Implementations - `impl<'a> !RefUnwindSafe for SemaphorePermit<'a>` - `impl<'a> !Send for SemaphorePermit<'a>` - `impl<'a> !Sync for SemaphorePermit<'a>` - `impl<'a> !UnwindSafe for SemaphorePermit<'a>` - `impl<'a> Freeze for SemaphorePermit<'a>` - `impl<'a> Unpin for SemaphorePermit<'a>` - `impl<'a> UnsafeUnpin for SemaphorePermit<'a>` ## Module `nuclei::sync::local::mpsc` https://nuclei.rs/api/nuclei/sync/local/mpsc/index.html Multi-producer, single-consumer channels for the tasks of one shard. The names, signatures and error types follow [`sync::mpsc`](https://nuclei.rs/api/nuclei/sync/mpsc/index.html), so code switches by changing the path. The state sits in one `Rc` and plain cells, so the halves are `!Send` and no operation touches an atomic. The bounded flavor ([`channel`](https://nuclei.rs/api/nuclei/sync/local/mpsc/fn.channel.html)) holds at most a fixed number of messages and serves waiting sends strictly in arrival order; the unbounded one ([`unbounded_channel`](https://nuclei.rs/api/nuclei/sync/local/mpsc/fn.unbounded_channel.html)) never makes a send wait. What one sender sends comes out in the order it was sent. When every sender is dropped the stream ends: once the buffered values are received, `recv` returns `None`. If the receiver is dropped, its unread values are dropped with it and every later send fails with an error that holds the value; [`Receiver::close`](https://nuclei.rs/api/nuclei/sync/local/mpsc/struct.Receiver.html#method.close) first stops further sends and keeps the buffered values, and the slots reserved before it, usable. Left out, because a local channel never leaves its thread: the `blocking_*` methods (a blocking call there could only wait for itself) and `WeakSender`. Receives, and sends that complete at their first attempt, spend the cooperative budget (see [`task::coop`](https://nuclei.rs/api/nuclei/task/coop/index.html)) as the atomic channels do. ### Structs - [Permit](https://nuclei.rs/api/nuclei/sync/local/mpsc/struct.Permit.html): Room for one message, reserved before the message exists. - [Receiver](https://nuclei.rs/api/nuclei/sync/local/mpsc/struct.Receiver.html): Receives values from the associated [`Sender`](https://nuclei.rs/api/nuclei/sync/local/mpsc/struct.Sender.html)s. - [Sender](https://nuclei.rs/api/nuclei/sync/local/mpsc/struct.Sender.html): Sends values to the associated [`Receiver`](https://nuclei.rs/api/nuclei/sync/local/mpsc/struct.Receiver.html). - [UnboundedReceiver](https://nuclei.rs/api/nuclei/sync/local/mpsc/struct.UnboundedReceiver.html): Receives values from the associated [`UnboundedSender`](https://nuclei.rs/api/nuclei/sync/local/mpsc/struct.UnboundedSender.html)s. - [UnboundedSender](https://nuclei.rs/api/nuclei/sync/local/mpsc/struct.UnboundedSender.html): Sends values to the associated [`UnboundedReceiver`](https://nuclei.rs/api/nuclei/sync/local/mpsc/struct.UnboundedReceiver.html). ### Functions - [channel](https://nuclei.rs/api/nuclei/sync/local/mpsc/fn.channel.html): Creates a bounded channel that holds at most `buffer` messages, and answers its two halves. - [unbounded_channel](https://nuclei.rs/api/nuclei/sync/local/mpsc/fn.unbounded_channel.html): Creates an unbounded channel and answers its two halves. ### struct `nuclei::sync::local::mpsc::Permit` https://nuclei.rs/api/nuclei/sync/local/mpsc/struct.Permit.html ```rust pub struct Permit<'a, T> { /* private fields */ } ``` Room for one message, reserved before the message exists. The send through it never waits and never fails, even when the receiver was closed in the meantime. Dropping it without sending gives the slot back. ```rust use nuclei::sync::local::mpsc; let (tx, mut rx) = mpsc::channel(1); let permit = tx.try_reserve().unwrap(); permit.send("reserved"); assert_eq!(rx.try_recv(), Ok("reserved")); ``` #### Implementations `impl Permit<'_, T>` ```rust pub fn send(self, value: T) ``` Sends a value through the reserved slot, consuming the permit. #### Trait Implementations - `impl Debug for Permit<'_, T>` - `impl Drop for Permit<'_, T>` #### Auto Trait Implementations - `impl<'a, T> !RefUnwindSafe for Permit<'a, T>` - `impl<'a, T> !Send for Permit<'a, T>` - `impl<'a, T> !Sync for Permit<'a, T>` - `impl<'a, T> !UnwindSafe for Permit<'a, T>` - `impl<'a, T> Freeze for Permit<'a, T>` - `impl<'a, T> Unpin for Permit<'a, T>` - `impl<'a, T> UnsafeUnpin for Permit<'a, T>` ### struct `nuclei::sync::local::mpsc::Receiver` https://nuclei.rs/api/nuclei/sync/local/mpsc/struct.Receiver.html ```rust pub struct Receiver { /* private fields */ } ``` Receives values from the associated [`Sender`](https://nuclei.rs/api/nuclei/sync/local/mpsc/struct.Sender.html)s. Created by [`channel`](https://nuclei.rs/api/nuclei/sync/local/mpsc/fn.channel.html). Dropping it closes the channel and drops the values still queued. #### Implementations `impl Receiver` ```rust pub async fn recv(&mut self) -> Option ``` Receives the next value, waiting for one if the channel is open and empty. Answers `None` once the channel is closed and drained (no sender, and no reserved slot still to be used). Cancel safe: a dropped future loses no value. ```rust pub async fn recv_many(&mut self, buf: &mut Vec, limit: usize) -> usize ``` Receives up to `limit` values into `buf` and answers how many, waiting for at least one. Answers 0 when `limit` is 0 or the channel ended. Cancel safe: a dropped future loses no value. ```rust pub fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll> ``` Polls to receive the next value; the waker of `cx` is woken when a value arrives or the channel ends. ```rust pub fn poll_recv_many( &mut self, cx: &mut Context<'_>, buf: &mut Vec, limit: usize, ) -> Poll ``` Polls to receive up to `limit` values into `buf`; see [`recv_many`](https://nuclei.rs/api/nuclei/sync/local/mpsc/struct.Receiver.html#method.recv_many). ```rust pub fn try_recv(&mut self) -> Result ``` Receives the next value without waiting. **Errors** [`TryRecvError::Empty`](https://nuclei.rs/api/nuclei/sync/mpsc/error/enum.TryRecvError.html#variant.Empty) if a value may yet come, [`TryRecvError::Disconnected`](https://nuclei.rs/api/nuclei/sync/mpsc/error/enum.TryRecvError.html#variant.Disconnected) if the channel ended. ```rust pub fn close(&mut self) ``` Closes the receiving half without dropping it: no further value can be sent, and sends that wait fail. The values already buffered, and the slots reserved before the close, stay usable. ```rust pub fn is_closed(&self) -> bool ``` Whether the channel is closed: [`close`](https://nuclei.rs/api/nuclei/sync/local/mpsc/struct.Receiver.html#method.close) was called, or every sender is gone. Buffered values may still be received. ```rust pub fn is_empty(&self) -> bool ``` Whether the channel holds no value. ```rust pub fn len(&self) -> usize ``` How many values the channel holds. ```rust pub fn capacity(&self) -> usize ``` The channel’s current capacity: the slots that are free. ```rust pub fn max_capacity(&self) -> usize ``` The channel’s maximum capacity: the `buffer` it was created with. #### Trait Implementations - `impl Debug for Receiver` - `impl Drop for Receiver` #### Auto Trait Implementations - `impl !RefUnwindSafe for Receiver` - `impl !Send for Receiver` - `impl !Sync for Receiver` - `impl !UnwindSafe for Receiver` - `impl Freeze for Receiver` - `impl Unpin for Receiver` - `impl UnsafeUnpin for Receiver` ### struct `nuclei::sync::local::mpsc::Sender` https://nuclei.rs/api/nuclei/sync/local/mpsc/struct.Sender.html ```rust pub struct Sender { /* private fields */ } ``` Sends values to the associated [`Receiver`](https://nuclei.rs/api/nuclei/sync/local/mpsc/struct.Receiver.html). Created by [`channel`](https://nuclei.rs/api/nuclei/sync/local/mpsc/fn.channel.html). Cloning it counts one more sender. #### Implementations `impl Sender` ```rust pub async fn send(&self, value: T) -> Result<(), SendError> ``` Sends a value, waiting in line for room if the channel is full. **Errors** A [`SendError`](https://nuclei.rs/api/nuclei/sync/mpsc/error/struct.SendError.html) holding the value when the receiver is closed or gone. **Cancel safety** A dropped future sent nothing and drops its value; it holds no slot. ```rust use nuclei::sync::local::mpsc; nuclei::runtime::block_on(async { let (tx, mut rx) = mpsc::channel(1); tx.send(1).await.unwrap(); assert_eq!(rx.recv().await, Some(1)); }); ``` ```rust pub fn try_send(&self, value: T) -> Result<(), TrySendError> ``` Sends a value at once, or says why it cannot be sent. It never takes a slot ahead of a send or reservation that is waiting. **Errors** [`TrySendError::Full`](https://nuclei.rs/api/nuclei/sync/mpsc/error/enum.TrySendError.html#variant.Full) if no slot is free or a send is waiting, [`TrySendError::Closed`](https://nuclei.rs/api/nuclei/sync/mpsc/error/enum.TrySendError.html#variant.Closed) if the receiver closed or was dropped. Both hold the value back. ```rust pub async fn reserve(&self) -> Result, SendError<()>> ``` Waits in line for a slot and reserves it: the send through the [`Permit`](https://nuclei.rs/api/nuclei/sync/local/mpsc/struct.Permit.html) never waits and never fails. **Errors** A [`SendError`](https://nuclei.rs/api/nuclei/sync/mpsc/error/struct.SendError.html) when the receiver is closed or gone. **Cancel safety** A dropped future holds no slot. ```rust pub fn try_reserve(&self) -> Result, TrySendError<()>> ``` Reserves a slot at once if one is free and nobody waits. **Errors** [`TrySendError::Full`](https://nuclei.rs/api/nuclei/sync/mpsc/error/enum.TrySendError.html#variant.Full) if no slot is free or a send is waiting, [`TrySendError::Closed`](https://nuclei.rs/api/nuclei/sync/mpsc/error/enum.TrySendError.html#variant.Closed) if the receiver closed or was dropped. ```rust pub async fn closed(&self) ``` Completes when the receiver has been closed or dropped. Cancel safe; once the channel is closed every call completes at once. ```rust pub fn is_closed(&self) -> bool ``` Whether the receiver has been closed or dropped. ```rust pub fn same_channel(&self, other: &Self) -> bool ``` Whether both senders send to the same channel. ```rust pub fn capacity(&self) -> usize ``` The channel’s current capacity: the slots that are free. ```rust pub fn max_capacity(&self) -> usize ``` The channel’s maximum capacity: the `buffer` it was created with. #### Trait Implementations - `impl Clone for Sender` - `impl Debug for Sender` - `impl Drop for Sender` #### Auto Trait Implementations - `impl !RefUnwindSafe for Sender` - `impl !Send for Sender` - `impl !Sync for Sender` - `impl !UnwindSafe for Sender` - `impl Freeze for Sender` - `impl Unpin for Sender` - `impl UnsafeUnpin for Sender` ### struct `nuclei::sync::local::mpsc::UnboundedReceiver` https://nuclei.rs/api/nuclei/sync/local/mpsc/struct.UnboundedReceiver.html ```rust pub struct UnboundedReceiver { /* private fields */ } ``` Receives values from the associated [`UnboundedSender`](https://nuclei.rs/api/nuclei/sync/local/mpsc/struct.UnboundedSender.html)s. Created by [`unbounded_channel`](https://nuclei.rs/api/nuclei/sync/local/mpsc/fn.unbounded_channel.html). Dropping it closes the channel and drops the values still queued. #### Implementations `impl UnboundedReceiver` ```rust pub async fn recv(&mut self) -> Option ``` Receives the next value, waiting for one if the channel is open and empty. Answers `None` once the channel is closed and drained (no sender, and no reserved slot still to be used). Cancel safe: a dropped future loses no value. ```rust pub async fn recv_many(&mut self, buf: &mut Vec, limit: usize) -> usize ``` Receives up to `limit` values into `buf` and answers how many, waiting for at least one. Answers 0 when `limit` is 0 or the channel ended. Cancel safe: a dropped future loses no value. ```rust pub fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll> ``` Polls to receive the next value; the waker of `cx` is woken when a value arrives or the channel ends. ```rust pub fn poll_recv_many( &mut self, cx: &mut Context<'_>, buf: &mut Vec, limit: usize, ) -> Poll ``` Polls to receive up to `limit` values into `buf`; see [`recv_many`](https://nuclei.rs/api/nuclei/sync/local/mpsc/struct.UnboundedReceiver.html#method.recv_many). ```rust pub fn try_recv(&mut self) -> Result ``` Receives the next value without waiting. **Errors** [`TryRecvError::Empty`](https://nuclei.rs/api/nuclei/sync/mpsc/error/enum.TryRecvError.html#variant.Empty) if a value may yet come, [`TryRecvError::Disconnected`](https://nuclei.rs/api/nuclei/sync/mpsc/error/enum.TryRecvError.html#variant.Disconnected) if the channel ended. ```rust pub fn close(&mut self) ``` Closes the receiving half without dropping it: no further value can be sent, and sends that wait fail. The values already buffered, and the slots reserved before the close, stay usable. ```rust pub fn is_closed(&self) -> bool ``` Whether the channel is closed: [`close`](https://nuclei.rs/api/nuclei/sync/local/mpsc/struct.UnboundedReceiver.html#method.close) was called, or every sender is gone. Buffered values may still be received. ```rust pub fn is_empty(&self) -> bool ``` Whether the channel holds no value. ```rust pub fn len(&self) -> usize ``` How many values the channel holds. #### Trait Implementations - `impl Debug for UnboundedReceiver` - `impl Drop for UnboundedReceiver` #### Auto Trait Implementations - `impl !RefUnwindSafe for UnboundedReceiver` - `impl !Send for UnboundedReceiver` - `impl !Sync for UnboundedReceiver` - `impl !UnwindSafe for UnboundedReceiver` - `impl Freeze for UnboundedReceiver` - `impl Unpin for UnboundedReceiver` - `impl UnsafeUnpin for UnboundedReceiver` ### struct `nuclei::sync::local::mpsc::UnboundedSender` https://nuclei.rs/api/nuclei/sync/local/mpsc/struct.UnboundedSender.html ```rust pub struct UnboundedSender { /* private fields */ } ``` Sends values to the associated [`UnboundedReceiver`](https://nuclei.rs/api/nuclei/sync/local/mpsc/struct.UnboundedReceiver.html). Created by [`unbounded_channel`](https://nuclei.rs/api/nuclei/sync/local/mpsc/fn.unbounded_channel.html). Cloning it counts one more sender. #### Implementations `impl UnboundedSender` ```rust pub fn send(&self, value: T) -> Result<(), SendError> ``` Sends a value; it never waits. **Errors** A [`SendError`](https://nuclei.rs/api/nuclei/sync/mpsc/error/struct.SendError.html) holding the value when the receiver is closed or gone. ```rust pub async fn closed(&self) ``` Completes when the receiver has been closed or dropped. Cancel safe; once the channel is closed every call completes at once. ```rust pub fn is_closed(&self) -> bool ``` Whether the receiver has been closed or dropped. ```rust pub fn same_channel(&self, other: &Self) -> bool ``` Whether both senders send to the same channel. #### Trait Implementations - `impl Clone for UnboundedSender` - `impl Debug for UnboundedSender` - `impl Drop for UnboundedSender` #### Auto Trait Implementations - `impl !RefUnwindSafe for UnboundedSender` - `impl !Send for UnboundedSender` - `impl !Sync for UnboundedSender` - `impl !UnwindSafe for UnboundedSender` - `impl Freeze for UnboundedSender` - `impl Unpin for UnboundedSender` - `impl UnsafeUnpin for UnboundedSender` ### fn `nuclei::sync::local::mpsc::channel` https://nuclei.rs/api/nuclei/sync/local/mpsc/fn.channel.html ```rust pub fn channel(buffer: usize) -> (Sender, Receiver) ``` Creates a bounded channel that holds at most `buffer` messages, and answers its two halves. The halves belong to the tasks of one shard: they are `!Send`. A send on a full channel waits in line for room. **Panics** When `buffer` is zero, or more than [`Semaphore::MAX_PERMITS`](https://nuclei.rs/api/nuclei/sync/local/struct.Semaphore.html#associatedconstant.MAX_PERMITS). ```rust use nuclei::sync::local::mpsc; let (tx, mut rx) = mpsc::channel(2); tx.try_send(1).unwrap(); tx.try_send(2).unwrap(); assert!(tx.try_send(3).is_err()); assert_eq!(rx.try_recv(), Ok(1)); ``` ### fn `nuclei::sync::local::mpsc::unbounded_channel` https://nuclei.rs/api/nuclei/sync/local/mpsc/fn.unbounded_channel.html ```rust pub fn unbounded_channel() -> (UnboundedSender, UnboundedReceiver) ``` Creates an unbounded channel and answers its two halves. The halves belong to the tasks of one shard: they are `!Send`. ```rust use nuclei::sync::local::mpsc; let (tx, mut rx) = mpsc::unbounded_channel(); tx.send(1).unwrap(); tx.send(2).unwrap(); assert_eq!(rx.try_recv(), Ok(1)); assert_eq!(rx.try_recv(), Ok(2)); ``` ## Module `nuclei::sync::local::oneshot` https://nuclei.rs/api/nuclei/sync/local/oneshot/index.html A channel that carries one value from one sender to one receiver, both on one shard. The names, signatures and errors follow [`sync::oneshot`](https://nuclei.rs/api/nuclei/sync/oneshot/index.html), so code switches by changing the path. The state is one counted block of the thread’s cache (as an `Rc`, so no allocation in steady state) with a `Cell` of three bits (value sent, receiver closed, sender dropped), the value in a cell and the two wakers in cells: no atomic and no fence. The sender sends at most one value and never waits; the receiver is a [`Future`](https://doc.rust-lang.org/1.99.1/core/future/future/trait.Future.html) that completes with the value, or with a [`RecvError`](https://nuclei.rs/api/nuclei/sync/oneshot/error/struct.RecvError.html) when the sender is dropped without sending, and, like the atomic one, panics when polled again after it completed. A value that was sent and never received stays in the channel until the receiver is dropped, which drops it on the spot (outside any borrow). A receive that completes spends one operation of the cooperative budget (see [`task::coop`](https://nuclei.rs/api/nuclei/task/coop/index.html)). ### Re-exports - `pub use crate::sync::oneshot::error;` ### Structs - [Receiver](https://nuclei.rs/api/nuclei/sync/local/oneshot/struct.Receiver.html): Receives the value of the [`Sender`](https://nuclei.rs/api/nuclei/sync/local/oneshot/struct.Sender.html); a future. - [Sender](https://nuclei.rs/api/nuclei/sync/local/oneshot/struct.Sender.html): Sends one value to the [`Receiver`](https://nuclei.rs/api/nuclei/sync/local/oneshot/struct.Receiver.html). ### Functions - [channel](https://nuclei.rs/api/nuclei/sync/local/oneshot/fn.channel.html): Creates a one-shot channel and answers its two halves. ### struct `nuclei::sync::local::oneshot::Receiver` https://nuclei.rs/api/nuclei/sync/local/oneshot/struct.Receiver.html ```rust pub struct Receiver { /* private fields */ } ``` Receives the value of the [`Sender`](https://nuclei.rs/api/nuclei/sync/local/oneshot/struct.Sender.html); a future. Cancel safe: dropping the future before it completes loses nothing the channel still holds (a value sent later is dropped with the receiver). #### Implementations `impl Receiver` ```rust pub fn close(&mut self) ``` Closes the receiving half: a later send fails and gets its value back. A value sent before the close stays receivable. ```rust pub fn is_terminated(&self) -> bool ``` Whether the receiver completed or failed already. ```rust pub fn is_empty(&self) -> bool ``` Whether no value is waiting for the receiver. ```rust pub fn try_recv(&mut self) -> Result ``` Receives the value without waiting. **Errors** [`TryRecvError::Empty`](https://nuclei.rs/api/nuclei/sync/oneshot/error/enum.TryRecvError.html#variant.Empty) if no value was sent yet and the sender is still there; [`TryRecvError::Closed`](https://nuclei.rs/api/nuclei/sync/oneshot/error/enum.TryRecvError.html#variant.Closed) if the sender dropped without sending, the receiver was closed empty, or the value was received. #### Trait Implementations - `impl Debug for Receiver` - `impl Drop for Receiver` - `impl Future for Receiver` #### Auto Trait Implementations - `impl !RefUnwindSafe for Receiver` - `impl !Send for Receiver` - `impl !Sync for Receiver` - `impl !UnwindSafe for Receiver` - `impl Freeze for Receiver` - `impl Unpin for Receiver` - `impl UnsafeUnpin for Receiver` ### struct `nuclei::sync::local::oneshot::Sender` https://nuclei.rs/api/nuclei/sync/local/oneshot/struct.Sender.html ```rust pub struct Sender { /* private fields */ } ``` Sends one value to the [`Receiver`](https://nuclei.rs/api/nuclei/sync/local/oneshot/struct.Receiver.html). Dropping it without sending ends the receiver’s wait with a [`RecvError`](https://nuclei.rs/api/nuclei/sync/oneshot/error/struct.RecvError.html). #### Implementations `impl Sender` ```rust pub fn send(self, value: T) -> Result<(), T> ``` Sends the value and wakes the receiver. Never waits. **Errors** Gives the value back when the receiver is closed or gone. ```rust pub async fn closed(&mut self) ``` Completes when the receiver has been closed or dropped. Cancel safe. ```rust pub fn is_closed(&self) -> bool ``` Whether the receiver has been closed or dropped. ```rust pub fn poll_closed(&mut self, cx: &mut Context<'_>) -> Poll<()> ``` Polls whether the receiver has been closed or dropped; the waker of `cx` is woken when it is. #### Trait Implementations - `impl Debug for Sender` - `impl Drop for Sender` #### Auto Trait Implementations - `impl !RefUnwindSafe for Sender` - `impl !Send for Sender` - `impl !Sync for Sender` - `impl !UnwindSafe for Sender` - `impl Freeze for Sender` - `impl Unpin for Sender` - `impl UnsafeUnpin for Sender` ### fn `nuclei::sync::local::oneshot::channel` https://nuclei.rs/api/nuclei/sync/local/oneshot/fn.channel.html ```rust pub fn channel() -> (Sender, Receiver) ``` Creates a one-shot channel and answers its two halves. The halves belong to the tasks of one shard: they are `!Send`. ```rust use nuclei::sync::local::oneshot; nuclei::runtime::block_on(async { let (tx, rx) = oneshot::channel(); tx.send(3).unwrap(); assert_eq!(rx.await, Ok(3)); }); ``` ## Module `nuclei::sync::mesh` https://nuclei.rs/api/nuclei/sync/mesh/index.html A full mesh of bounded channels between a fixed number of parties. [`mesh`](https://nuclei.rs/api/nuclei/sync/mesh/fn.mesh.html) builds, for every ordered pair `(from, to)` of parties, one [`mpsc::channel`](https://nuclei.rs/api/nuclei/sync/mpsc/fn.channel.html) of the given capacity, and hands each party its ends: a [`Party`](https://nuclei.rs/api/nuclei/sync/mesh/struct.Party.html) keeps the sender to every party at the index of that party, and the receiver from every party at the index of that party. Parties are numbered `0..parties`. Self-loops are included: party `i` can send to itself, so “send to the owner of key `k`” needs no special case. The mesh only builds channels. Nothing here spawns anything or knows about workers: moving each [`Party`](https://nuclei.rs/api/nuclei/sync/mesh/struct.Party.html) into its own task or thread (a `Party` is `Send` when `T` is) is the caller’s, with any `spawn`. Backpressure is per pair: a send to a party whose channel from this one is full waits for that party to take a value, and does not hold up sends to other parties or from other parties. [`Party::recv`](https://nuclei.rs/api/nuclei/sync/mesh/struct.Party.html#method.recv) receives from any party and is fair: it polls the receivers round robin, starting after the one that delivered last, so a party that floods cannot starve a quiet one. A party’s own sender to itself keeps its self-loop open, so `recv` ends only after [`Party::close_senders`](https://nuclei.rs/api/nuclei/sync/mesh/struct.Party.html#method.close_senders) too, once every other party dropped its senders and everything sent was received. ```rust use nuclei::sync::mesh::mesh; nuclei::runtime::block_on(async { let mut parties = mesh::(2, 4); let mut b = parties.pop().unwrap(); let a = parties.pop().unwrap(); a.send_to(1, 7).await.unwrap(); assert_eq!(b.recv().await, Some((0, 7))); }); ``` ### Structs - [Party](https://nuclei.rs/api/nuclei/sync/mesh/struct.Party.html): One party of a [`mesh`](https://nuclei.rs/api/nuclei/sync/mesh/fn.mesh.html): its senders to every party and its receivers from every party, both indexed by the peer. ### Functions - [mesh](https://nuclei.rs/api/nuclei/sync/mesh/fn.mesh.html): Builds a full mesh of `parties` parties, each pair joined by a bounded channel of `capacity` messages in each direction. Entry `i` of the answer is party `i`. ### struct `nuclei::sync::mesh::Party` https://nuclei.rs/api/nuclei/sync/mesh/struct.Party.html ```rust pub struct Party { /* private fields */ } ``` One party of a [`mesh`](https://nuclei.rs/api/nuclei/sync/mesh/fn.mesh.html): its senders to every party and its receivers from every party, both indexed by the peer. #### Implementations `impl Party` ```rust pub fn index(&self) -> usize ``` This party’s index in the mesh. ```rust pub fn parties(&self) -> usize ``` How many parties the mesh has, this one included. ```rust pub fn sender(&self, to: usize) -> Option<&Sender> ``` The sender to party `to`, or `None` when `to` is not a party (or the senders were closed with [`close_senders`](https://nuclei.rs/api/nuclei/sync/mesh/struct.Party.html#method.close_senders)). ```rust pub fn receiver(&mut self, from: usize) -> Option<&mut Receiver> ``` The receiver from party `from`, or `None` when `from` is not a party. ```rust pub async fn send_to(&self, to: usize, value: T) -> Result<(), SendError> ``` Sends `value` to party `to`, waiting for room in the channel to it. **Errors** A [`SendError`](https://nuclei.rs/api/nuclei/sync/mpsc/error/struct.SendError.html) holding the value when `to` is not a party or its receiver is gone. ```rust pub fn try_send_to(&self, to: usize, value: T) -> Result<(), TrySendError> ``` Sends `value` to party `to` at once, or says why it cannot be sent. **Errors** [`TrySendError::Full`](https://nuclei.rs/api/nuclei/sync/mpsc/error/enum.TrySendError.html#variant.Full) when the channel to `to` is full; [`TrySendError::Closed`](https://nuclei.rs/api/nuclei/sync/mpsc/error/enum.TrySendError.html#variant.Closed) when `to` is not a party or its receiver is gone. Both hold the value back. ```rust pub fn close_senders(&mut self) ``` Drops every sender of this party, itself included (the self-loop). The party then only receives; its sends fail with their value. This is how a party lets [`recv`](https://nuclei.rs/api/nuclei/sync/mesh/struct.Party.html#method.recv) end. ```rust pub async fn recv_from(&mut self, from: usize) -> Option ``` Receives the next value from party `from`. Answers `None` when `from` is not a party, or that channel ended and was drained. ```rust pub async fn recv(&mut self) -> Option<(usize, T)> ``` Receives the next value from any party, with the index of the party that sent it. Answers `None` once every channel into this party ended and was drained. Cancel safe: a dropped future loses no value. ```rust pub fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll> ``` Polls for a value from any party. The receivers are polled round robin from the one after the last that delivered, so no party is starved, and each one that has nothing registers the waker of `cx`. ```rust pub fn try_recv(&mut self) -> Result<(usize, T), TryRecvError> ``` Receives a value from any party without waiting, in the order [`poll_recv`](https://nuclei.rs/api/nuclei/sync/mesh/struct.Party.html#method.poll_recv) uses. **Errors** [`TryRecvError::Empty`](https://nuclei.rs/api/nuclei/sync/mpsc/error/enum.TryRecvError.html#variant.Empty) when nothing is waiting and a value may yet come; [`TryRecvError::Disconnected`](https://nuclei.rs/api/nuclei/sync/mpsc/error/enum.TryRecvError.html#variant.Disconnected) only when every channel ended and was drained. ```rust pub fn into_parts(self) -> (Vec>, Vec>) ``` Takes the party apart: its senders and its receivers, indexed by peer. #### Trait Implementations - `impl Debug for Party` #### Auto Trait Implementations - `impl Freeze for Party` - `impl RefUnwindSafe for Party` - `impl Send for Party where T: Send` - `impl Sync for Party where T: Send` - `impl Unpin for Party` - `impl UnsafeUnpin for Party` - `impl UnwindSafe for Party` ### fn `nuclei::sync::mesh::mesh` https://nuclei.rs/api/nuclei/sync/mesh/fn.mesh.html ```rust pub fn mesh(parties: usize, capacity: usize) -> Vec> ``` Builds a full mesh of `parties` parties, each pair joined by a bounded channel of `capacity` messages in each direction. Entry `i` of the answer is party `i`. **Panics** When `capacity` is zero, as [`mpsc::channel`](https://nuclei.rs/api/nuclei/sync/mpsc/fn.channel.html) does. ```rust let parties = nuclei::sync::mesh::mesh::(3, 1); assert_eq!(parties.len(), 3); assert_eq!(parties[2].index(), 2); assert_eq!(parties[2].parties(), 3); ``` ## Module `nuclei::sync::mpsc` https://nuclei.rs/api/nuclei/sync/mpsc/index.html Multi-producer, single-consumer channels for sending values between tasks. The module has two flavors. The bounded one ([`channel`](https://nuclei.rs/api/nuclei/sync/mpsc/fn.channel.html)) holds at most a fixed number of messages, and a send waits for room, which is backpressure. The unbounded one ([`unbounded_channel`](https://nuclei.rs/api/nuclei/sync/mpsc/fn.unbounded_channel.html)) never makes a send wait, so [`UnboundedSender::send`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedSender.html#method.send) is an ordinary function that synchronous and asynchronous code can both call. The names, signatures, error types and documented behavior are those of the established async channel API, so code written against that API compiles against these; nothing here needs a runtime, and every wait is a plain [`Waker`](https://doc.rust-lang.org/1.99.1/core/task/wake/struct.Waker.html) handshake. ```rust use nuclei::sync::mpsc; let (tx, mut rx) = mpsc::channel(8); let senders: Vec<_> = (0..4) .map(|id| { let tx = tx.clone(); std::thread::spawn(move || { for n in 0..100 { tx.blocking_send((id, n)).expect("the receiver is still there"); } }) }) .collect(); drop(tx); let mut seen = [0; 4]; while let Some((id, _n)) = rx.blocking_recv() { seen[id] += 1; } assert_eq!(seen, [100; 4]); for sender in senders { sender.join().unwrap(); } ``` **Ordering** What one sender sends comes out in the order it was sent, as the established API promises. The message queue is a linearizable FIFO queue of cells: a send claims the next cell, and the receiver takes cells in the order they were claimed, so a send that returned before another began comes out first. Values that different senders send at the same time come out in the order their sends claimed cells. **Disconnection** When every sender is dropped, no value can be sent. That is the end of the stream: once the buffered values are received, `recv` returns `None`. If the receiver is dropped, its unread values are dropped with it, and every later send fails with an error that holds the value. **Clean shutdown** Dropping the receiver loses the values still buffered. For a clean shutdown the receiver calls `close` first, which stops further sends but keeps the buffered values (and any slot a sender reserved before) usable, then receives until `recv` returns `None`. **Weak senders** A [`WeakSender`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.WeakSender.html) does not keep the channel open: when only weak senders remain the channel is closed. [`WeakSender::upgrade`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.WeakSender.html#method.upgrade) gives a [`Sender`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html) while one exists. An actor can hold a weak handle to its own mailbox without keeping it alive. **Communicating between sync and async code** Every method that is not `async` can be called from any thread. For synchronous code on the receiving or sending end, the `blocking_*` methods park the calling thread until their wait is over. On a nuclei shard they run a nested `block_on` instead, which keeps the shard running its other tasks; do not call them from a task of another runtime, whose thread they block. **Differences from the established API** - [`Sender::send_timeout`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html#method.send_timeout) waits on nuclei’s own timers: on a thread that runs no nuclei shard, the default runtime fires it. - The `blocking_*` methods called from inside a task do not panic: on a nuclei shard they run a nested `block_on`, and inside another runtime’s task they block its thread (on `wasm32`, where nothing else can run, a call that would wait forever panics instead). - When the receiver closes, a reservation still waiting gives back the slots set aside for it at the close, where the established API keeps them with the failed wait until its future is dropped. So a closed receiver’s drain never waits for a failed reservation to be dropped. - [`Receiver::try_recv`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Receiver.html#method.try_recv) does not park the thread for a send that is in progress on another thread. Such a value is not in the channel yet, and its sender wakes the receiver when it is; the established API parks the thread until the send finishes. **Cooperative scheduling** On a nuclei shard, every receive that completes (`recv`, `recv_many` and the two `poll_` forms) spends one operation of its task’s cooperative budget, as IO does, and so does a send or a reservation that completes at its first attempt; one whose slots were granted after it waited in line spends nothing, as giving them back would cost it its place. When the budget is spent the call takes nothing, wakes its task and returns `Pending`, so a loop on a channel that is always ready yields to the shard’s other tasks within [`BUDGET`](https://nuclei.rs/api/nuclei/task/coop/constant.BUDGET.html) operations. [`Receiver::try_recv`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Receiver.html#method.try_recv), [`Sender::try_send`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html#method.try_send) and the other calls that never wait spend nothing, and off a nuclei shard there is no budget: nothing yields for it. **Progress** The message queue is built for its one receiver: a bounded channel’s is a ring of cells used lap after lap (a radix directory past 65,536 cells), an unbounded channel’s a radix directory of leaves. A send claims the next cell with one fetch-add, finds its segment (in the ring by its position, in the directory by at most one level per ten of a 64-bit position, making a missing node with one compare-and-swap that, lost, leaves another send’s), writes its value and marks the cell ready: the push is wait-free. A receive reads the next cell’s mark and takes the value, with no read-modify-write and nothing another thread contends for, and never waits for a sender: when the next cell is claimed by a send that has not written it yet, the receive finds nothing for now, registers its waker and returns `Pending`, and that send wakes it once its value is in. A sender the scheduler stops between its claim and its write holds back no one else’s value in the radix directory, unless the position right after it is stalled too: the receive takes the ready values past it (within 64 positions), each sender’s still in its order, and its own once written. In a bounded channel’s ring the values behind it wait until it runs again, as its cell holds their place in the lap; no call waits for it either way. - **Wait-free** (a bounded number of the caller’s own atomic steps, whatever other threads do): the accessors (`is_closed`, `len`, `is_empty`, `capacity`, `max_capacity`, the sender counts, `same_channel`), `clone`, `downgrade`, and dropping a sender or weak sender (the last sender’s drop also wakes the receiver, a two-step handshake on the waker cell). Registering the receiver’s waker is wait-free too, and so is [`UnboundedSender::send`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedSender.html#method.send): its admission is one fetch-add (taken back with one fetch-sub on a closed channel), its push the queue’s. - **Lock-free**: every bounded send, `try_send`, reservation and permit send, whose admission is the semaphore’s compare-and-swap (exact: it never refuses a free slot); `closed`; `WeakSender::upgrade` (a compare-and-swap loop on the sender count); and `Receiver::close`. A bounded wait that has to queue is lock-free for the reason every wait queue is (see the [parent module](https://nuclei.rs/api/nuclei/sync/index.html#progress)): its poll pushes a node, and may serve the queue for one pass plus one for each operation of another thread that lands meanwhile. - **When a waiting bounded send is served** is not a bound on its own calls. Its slot is set aside and granted by whichever thread serves the queue once the slot is free (the receiver taking a value, a permit dropped), so a thread the scheduler stops while it serves the queue delays that grant until it runs again, and a `try_send` fails meanwhile even if the last waiting send has just left. No call waits for it. - **Lock-free**: every receive (`recv`, `recv_many`, `try_recv`, `poll_recv`, `poll_recv_many`), none of which waits for a sender inside the call, and the receiver’s drop, which drops every value left and so takes time proportional to them. - A [`Waker`](https://doc.rust-lang.org/1.99.1/core/task/wake/struct.Waker.html) the channel calls is the executor’s, and so is what it does; the destructor of a value runs in the call that drops it; and the `blocking_*` methods park the thread until their wait is over, which is what they are for. **Cancel safety** `recv`, `recv_many` and `closed` are cancel safe: dropping the future loses nothing. `send` is cancel safe in the sense that a dropped future sent nothing, but it drops the value it held; `reserve` and its relatives hold no slot when dropped, and a dropped `reserve_owned` also drops its sender. **Fairness** The bounded channel serves waiting sends and reservations strictly in the order they began to wait, as the established API does. Slots that come free are set aside for the oldest waiting request until it has all it asked for, so a `reserve_many(n)` is not starved by smaller requests and nothing behind it is served first; a `try_send` or `try_reserve` never takes a slot while a request waits. Dropping a waiting future gives up its place and passes on whatever was set aside or granted to it, so no slot and no wakeup is lost. The unbounded channel never waits, so it has no order to keep. ### Modules - [error](https://nuclei.rs/api/nuclei/sync/mpsc/error/index.html): Error types of the multi-producer, single-consumer channels. ### Structs - [OwnedPermit](https://nuclei.rs/api/nuclei/sync/mpsc/struct.OwnedPermit.html): An owned permit to send one value into the channel. - [Permit](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Permit.html): Permits to send one value into the channel. - [PermitIterator](https://nuclei.rs/api/nuclei/sync/mpsc/struct.PermitIterator.html): An [`Iterator`](https://doc.rust-lang.org/1.99.1/core/iter/traits/iterator/trait.Iterator.html) of [`Permit`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Permit.html)s that holds `n` slots of the channel. - [Receiver](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Receiver.html): Receives values from the associated [`Sender`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html)s. - [Sender](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html): Sends values to the associated [`Receiver`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Receiver.html). - [UnboundedReceiver](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedReceiver.html): Receives values from the associated [`UnboundedSender`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedSender.html)s. - [UnboundedSender](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedSender.html): Sends values to the associated [`UnboundedReceiver`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedReceiver.html). - [WeakSender](https://nuclei.rs/api/nuclei/sync/mpsc/struct.WeakSender.html): A sender that does not keep the channel open. - [WeakUnboundedSender](https://nuclei.rs/api/nuclei/sync/mpsc/struct.WeakUnboundedSender.html): A sender that does not keep the channel open. ### Functions - [channel](https://nuclei.rs/api/nuclei/sync/mpsc/fn.channel.html): Creates a bounded channel for communicating between tasks with backpressure. - [unbounded_channel](https://nuclei.rs/api/nuclei/sync/mpsc/fn.unbounded_channel.html): Creates an unbounded channel for communicating between tasks without backpressure. ### struct `nuclei::sync::mpsc::OwnedPermit` https://nuclei.rs/api/nuclei/sync/mpsc/struct.OwnedPermit.html ```rust pub struct OwnedPermit { /* private fields */ } ``` An owned permit to send one value into the channel. The same as [`Permit`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Permit.html), except that it holds the [`Sender`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html) it was reserved from instead of borrowing it, so it has no lifetime. Returned by [`Sender::reserve_owned`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html#method.reserve_owned) and [`Sender::try_reserve_owned`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html#method.try_reserve_owned). It counts as a sender while it lives, so the channel does not end for the receiver while a permit is held. [`send`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.OwnedPermit.html#method.send) and [`release`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.OwnedPermit.html#method.release) hand the sender back; dropping the permit unused gives the slot back and drops the sender. **Progress** [`send`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.OwnedPermit.html#method.send) is lock-free, not wait-free, for the reason [`Permit::send`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Permit.html#method.send) is: it pushes onto the message queue. [`release`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.OwnedPermit.html#method.release) and the drop return the slot as dropping a [`Permit`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Permit.html) does (one atomic add when no sender waits, lock-free otherwise), and the drop then counts the sender out, which is wait-free. [`same_channel`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.OwnedPermit.html#method.same_channel) and [`same_channel_as_sender`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.OwnedPermit.html#method.same_channel_as_sender) are wait-free. ```rust use nuclei::sync::mpsc; let (tx, mut rx) = mpsc::channel(1); let permit = tx.try_reserve_owned().unwrap(); let tx = permit.send(123); assert_eq!(rx.try_recv(), Ok(123)); tx.try_send(456).unwrap(); ``` #### Implementations `impl OwnedPermit` ```rust pub fn send(self, value: T) -> Sender ``` Sends a value through the reserved slot, returning the sender the permit was reserved from. As for [`Permit::send`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Permit.html#method.send), it succeeds even if the receiver was closed after the reservation. ```rust use nuclei::sync::mpsc; let (tx, mut rx) = mpsc::channel(1); let permit = tx.try_reserve_owned().unwrap(); let tx = permit.send(456); assert_eq!(rx.try_recv(), Ok(456)); tx.try_send(789).unwrap(); ``` ```rust pub fn release(self) -> Sender ``` Gives the reserved slot back without sending, returning the sender. ```rust use nuclei::sync::mpsc; let (tx, _rx) = mpsc::channel(1); let permit = tx.clone().try_reserve_owned().unwrap(); assert!(tx.try_send(123).is_err(), "the permit holds the only slot"); let tx2 = permit.release(); tx.try_send(789).unwrap(); drop(tx2); ``` ```rust pub fn same_channel(&self, other: &Self) -> bool ``` Whether two permits belong to the same channel. ```rust use nuclei::sync::mpsc; let (tx, _rx) = mpsc::channel::<()>(2); let a = tx.clone().try_reserve_owned().unwrap(); let b = tx.clone().try_reserve_owned().unwrap(); assert!(a.same_channel(&b)); let (tx2, _rx2) = mpsc::channel::<()>(1); let c = tx2.try_reserve_owned().unwrap(); assert!(!c.same_channel(&a)); ``` ```rust pub fn same_channel_as_sender(&self, sender: &Sender) -> bool ``` Whether this permit belongs to the same channel as `sender`. ```rust use nuclei::sync::mpsc; let (tx, _rx) = mpsc::channel::<()>(1); let permit = tx.clone().try_reserve_owned().unwrap(); assert!(permit.same_channel_as_sender(&tx)); let (tx2, _rx2) = mpsc::channel::<()>(1); assert!(!permit.same_channel_as_sender(&tx2)); ``` #### Trait Implementations - `impl Debug for OwnedPermit` - `impl Drop for OwnedPermit` #### Auto Trait Implementations - `impl Freeze for OwnedPermit` - `impl RefUnwindSafe for OwnedPermit` - `impl Send for OwnedPermit where T: Send` - `impl Sync for OwnedPermit where T: Send` - `impl Unpin for OwnedPermit` - `impl UnsafeUnpin for OwnedPermit` - `impl UnwindSafe for OwnedPermit` ### struct `nuclei::sync::mpsc::Permit` https://nuclei.rs/api/nuclei/sync/mpsc/struct.Permit.html ```rust pub struct Permit<'a, T> { /* private fields */ } ``` Permits to send one value into the channel. Returned by [`Sender::reserve`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html#method.reserve) and [`Sender::try_reserve`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html#method.try_reserve); it guarantees room for one message before the message exists. The send through it never waits and never fails, even when the receiver was closed in the meantime (see [`Receiver::close`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Receiver.html#method.close)). Dropping it without sending gives the slot back. **Progress** [`send`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Permit.html#method.send) is lock-free, not wait-free: it pushes onto the message queue, which retries when it loses a slot to another sender. Dropping the permit is one atomic add on the semaphore when no sender waits, and lock-free when it serves waiting senders. ```rust use nuclei::sync::mpsc; let (tx, mut rx) = mpsc::channel(1); let permit = tx.try_reserve().unwrap(); permit.send("reserved"); assert_eq!(rx.try_recv(), Ok("reserved")); ``` #### Implementations `impl<'a, T> Permit<'a, T>` ```rust pub fn send(self, value: T) ``` Sends a value through the reserved slot, consuming the permit. The send succeeds even if the receiver was closed after the slot was reserved: closing keeps what is reserved receivable, so a clean shutdown loses nothing. (If the receiver was dropped, the value is dropped when the last sender is.) ```rust use nuclei::sync::mpsc; let (tx, mut rx) = mpsc::channel(1); let permit = tx.try_reserve().unwrap(); rx.close(); permit.send(456); assert_eq!(rx.try_recv(), Ok(456)); ``` #### Trait Implementations - `impl Debug for Permit<'_, T>` - `impl Drop for Permit<'_, T>` #### Auto Trait Implementations - `impl<'a, T> Freeze for Permit<'a, T>` - `impl<'a, T> RefUnwindSafe for Permit<'a, T>` - `impl<'a, T> Send for Permit<'a, T> where T: Send` - `impl<'a, T> Sync for Permit<'a, T> where T: Send` - `impl<'a, T> Unpin for Permit<'a, T>` - `impl<'a, T> UnsafeUnpin for Permit<'a, T>` - `impl<'a, T> UnwindSafe for Permit<'a, T>` ### struct `nuclei::sync::mpsc::PermitIterator` https://nuclei.rs/api/nuclei/sync/mpsc/struct.PermitIterator.html ```rust pub struct PermitIterator<'a, T> { /* private fields */ } ``` An [`Iterator`](https://doc.rust-lang.org/1.99.1/core/iter/traits/iterator/trait.Iterator.html) of [`Permit`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Permit.html)s that holds `n` slots of the channel. Returned by [`Sender::reserve_many`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html#method.reserve_many) and [`Sender::try_reserve_many`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html#method.try_reserve_many). Each item is one permit; dropping the iterator before it is exhausted gives the remaining slots back. It knows its length. **Progress** `next`, `len` and `size_hint` touch no shared state and are wait-free. Dropping the iterator returns all its remaining slots with one semaphore release: one atomic add when no sender waits, lock-free when it serves waiting senders. ```rust use nuclei::sync::mpsc; let (tx, mut rx) = mpsc::channel(3); let mut permits = tx.try_reserve_many(3).unwrap(); assert_eq!(permits.len(), 3); permits.next().unwrap().send(1); assert_eq!(tx.capacity(), 0); drop(permits); assert_eq!(tx.capacity(), 2, "the two unused slots came back"); assert_eq!(rx.try_recv(), Ok(1)); ``` #### Trait Implementations - `impl Debug for PermitIterator<'_, T>` - `impl Drop for PermitIterator<'_, T>` - `impl ExactSizeIterator for PermitIterator<'_, T>` - `impl FusedIterator for PermitIterator<'_, T>` - `impl<'a, T> Iterator for PermitIterator<'a, T>` #### Auto Trait Implementations - `impl<'a, T> Freeze for PermitIterator<'a, T>` - `impl<'a, T> RefUnwindSafe for PermitIterator<'a, T>` - `impl<'a, T> Send for PermitIterator<'a, T> where T: Send` - `impl<'a, T> Sync for PermitIterator<'a, T> where T: Send` - `impl<'a, T> Unpin for PermitIterator<'a, T>` - `impl<'a, T> UnsafeUnpin for PermitIterator<'a, T>` - `impl<'a, T> UnwindSafe for PermitIterator<'a, T>` ### struct `nuclei::sync::mpsc::Receiver` https://nuclei.rs/api/nuclei/sync/mpsc/struct.Receiver.html ```rust pub struct Receiver { /* private fields */ } ``` Receives values from the associated [`Sender`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html)s. Created by [`channel`](https://nuclei.rs/api/nuclei/sync/mpsc/fn.channel.html). There is exactly one receiver. **Progress** Wait-free: [`is_closed`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Receiver.html#method.is_closed), [`is_empty`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Receiver.html#method.is_empty), [`len`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Receiver.html#method.len), [`capacity`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Receiver.html#method.capacity), [`max_capacity`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Receiver.html#method.max_capacity), [`sender_strong_count`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Receiver.html#method.sender_strong_count) and [`sender_weak_count`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Receiver.html#method.sender_weak_count): each is a load. Lock-free: [`recv`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Receiver.html#method.recv), [`recv_many`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Receiver.html#method.recv_many), [`try_recv`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Receiver.html#method.try_recv) and the two `poll_` forms. Registering the waker is wait-free (the cell runs two read-modify-writes and no loop). Taking a value off the message queue is a compare-and-swap no other thread contends for, and never waits for a sender: a value whose send claimed its place and has not written it yet is not there, and its sender wakes the receiver once it is (see the [Progress](https://nuclei.rs/api/nuclei/sync/mpsc/index.html#progress) notes of the module). Giving the slot back to the senders is a semaphore release that, when senders wait, serves the queue and is lock-free. [`close`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Receiver.html#method.close) is lock-free; the drop is the same as a receive per value left, since it drops every value still queued, and so takes time proportional to them. `blocking_recv` and `blocking_recv_many` park the calling thread until a value arrives. #### Implementations `impl Receiver` ```rust pub fn recv(&mut self) -> impl Future> + '_ ``` Receives the next value. Returns `None` once the channel is closed and no buffered value is left, which means no value can ever be received again. The channel is closed when every sender has been dropped, or when [`close`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Receiver.html#method.close) is called. If the buffer is empty and the channel is open, it waits for a send or a close. If [`close`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Receiver.html#method.close) was called while a [`Permit`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Permit.html) or an [`OwnedPermit`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.OwnedPermit.html) was still held, the channel does not count as finished for `recv` until the permit is sent or dropped. **Cancel safety** Cancel safe. If the future is dropped (for instance when another branch of a `select` wins), no value was taken from the channel. ```rust use nuclei::sync::mpsc; let (tx, mut rx) = mpsc::channel(100); tx.try_send("hello").unwrap(); tx.try_send("world").unwrap(); drop(tx); assert_eq!(now(rx.recv()), Some("hello")); assert_eq!(now(rx.recv()), Some("world")); assert_eq!(now(rx.recv()), None); ``` ```rust pub async fn recv_many(&mut self, buffer: &mut Vec, limit: usize) -> usize ``` Receives the next values and appends them to `buffer`, taking at most `limit` of them in one call. Returns how many values it added. A `limit` of zero returns `0` at once. Otherwise it waits like [`recv`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Receiver.html#method.recv) until at least one value is there, then takes everything that is ready up to `limit` without waiting again, and returns `0` only when the channel is closed and empty. The capacity of `buffer` grows as needed. **Cancel safety** Cancel safe, as [`recv`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Receiver.html#method.recv): a dropped future took nothing. ```rust use nuclei::sync::mpsc; let (tx, mut rx) = mpsc::channel(100); for word in ["first", "second", "third"] { tx.try_send(word).unwrap(); } let mut buffer = Vec::new(); assert_eq!(now(rx.recv_many(&mut buffer, 2)), 2); assert_eq!(buffer, ["first", "second"]); assert_eq!(now(rx.recv_many(&mut buffer, 2)), 1); drop(tx); assert_eq!(now(rx.recv_many(&mut buffer, 2)), 0); ``` ```rust pub fn try_recv(&mut self) -> Result ``` Tries to receive the next value without waiting. **Errors** [`TryRecvError::Empty`](https://nuclei.rs/api/nuclei/sync/mpsc/error/enum.TryRecvError.html#variant.Empty) if the channel is empty but a sender or a permit still exists, so a value may yet come. [`TryRecvError::Disconnected`](https://nuclei.rs/api/nuclei/sync/mpsc/error/enum.TryRecvError.html#variant.Disconnected) if it is empty and nothing can send: every sender is gone, or the channel was closed and no permit is held. A value whose send is still in progress on another thread is not in the channel yet, nor are the values sent after it, which come out behind it. This call does not wait for them: the sender wakes the receiver once its value is in. ```rust use nuclei::sync::mpsc::{self, error::TryRecvError}; let (tx, mut rx) = mpsc::channel(100); tx.try_send("hello").unwrap(); assert_eq!(rx.try_recv(), Ok("hello")); assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); tx.try_send("hello").unwrap(); drop(tx); assert_eq!(rx.try_recv(), Ok("hello")); assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); ``` ```rust pub fn blocking_recv(&mut self) -> Option ``` Receives the next value from a thread that may block. Like [`recv`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Receiver.html#method.recv), but it parks the calling thread while the channel is empty and open. On a nuclei shard (inside one of its tasks) it does not park the thread: it runs a nested `block_on`, so the shard keeps running its other tasks meanwhile. Inside another runtime’s task it blocks that task’s thread. It works whether or not the senders use [`Sender::blocking_send`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html#method.blocking_send). **Panics** On `wasm32`, where no other thread can send, when the channel is empty and open: the call could never end. ```rust use nuclei::sync::mpsc; let (tx, mut rx) = mpsc::channel::(10); let receiver = std::thread::spawn(move || { assert_eq!(rx.blocking_recv(), Some(10)); assert_eq!(rx.blocking_recv(), None); }); tx.blocking_send(10).unwrap(); drop(tx); receiver.join().unwrap(); ``` ```rust pub fn blocking_recv_many(&mut self, buffer: &mut Vec, limit: usize) -> usize ``` [`recv_many`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Receiver.html#method.recv_many) for a thread that may block; see [`blocking_recv`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Receiver.html#method.blocking_recv). **Panics** As for [`blocking_recv`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Receiver.html#method.blocking_recv). ```rust pub fn close(&mut self) ``` Closes the receiving half without dropping it. No further value can be sent: a send fails and returns its value. A slot reserved before the close can still be used, and the values already buffered stay receivable, so a clean shutdown closes, then calls [`recv`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Receiver.html#method.recv) until it returns `None`. That happens once every reserved slot is sent or dropped. ```rust use nuclei::sync::mpsc::{self, error::TrySendError}; let (tx, mut rx) = mpsc::channel(20); tx.try_send(1).unwrap(); rx.close(); assert!(matches!(tx.try_send(2), Err(TrySendError::Closed(2)))); assert_eq!(rx.try_recv(), Ok(1), "the buffered value is still there"); ``` ```rust pub fn is_closed(&self) -> bool ``` Whether the channel is closed: [`close`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Receiver.html#method.close) was called, or every sender is gone. Buffered values may still be received. ```rust use nuclei::sync::mpsc; let (tx, mut rx) = mpsc::channel::<()>(10); assert!(!rx.is_closed()); rx.close(); assert!(rx.is_closed()); drop(tx); ``` ```rust pub fn is_empty(&self) -> bool ``` Whether the channel holds no value. ```rust use nuclei::sync::mpsc; let (tx, rx) = mpsc::channel(10); assert!(rx.is_empty()); tx.try_send(0).unwrap(); assert!(!rx.is_empty()); ``` ```rust pub fn len(&self) -> usize ``` How many values the channel holds. A snapshot: it is exact while no other thread is sending, and while one is it may be off by the values being sent at that moment. ```rust use nuclei::sync::mpsc; let (tx, rx) = mpsc::channel(10); assert_eq!(rx.len(), 0); tx.try_send(0).unwrap(); assert_eq!(rx.len(), 1); ``` ```rust pub fn capacity(&self) -> usize ``` The channel’s current capacity: the slots that are free. It goes down when a value is sent or a slot reserved, and up when a value is received or a permit dropped unused. Compare [`max_capacity`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Receiver.html#method.max_capacity), which never changes. ```rust use nuclei::sync::mpsc; let (tx, mut rx) = mpsc::channel::<()>(5); assert_eq!(rx.capacity(), 5); let permit = tx.try_reserve().unwrap(); assert_eq!(rx.capacity(), 4); assert_eq!(rx.len(), 0); permit.send(()); assert_eq!(rx.len(), 1); rx.try_recv().unwrap(); assert_eq!(rx.capacity(), 5); ``` ```rust pub fn max_capacity(&self) -> usize ``` The channel’s maximum capacity: the `buffer` it was created with. ```rust use nuclei::sync::mpsc; let (tx, rx) = mpsc::channel::<()>(5); let _permit = tx.try_reserve().unwrap(); assert_eq!(rx.max_capacity(), 5); assert_eq!(rx.capacity(), 4); ``` ```rust pub fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll> ``` Polls to receive the next value. Returns [`Poll::Pending`](https://doc.rust-lang.org/1.99.1/core/task/poll/enum.Poll.html#variant.Pending) if no value is available and the channel is open; [`Poll::Ready`](https://doc.rust-lang.org/1.99.1/core/task/poll/enum.Poll.html#variant.Ready)`(Some(value))` if one is; and [`Poll::Ready`](https://doc.rust-lang.org/1.99.1/core/task/poll/enum.Poll.html#variant.Ready)`(None)` if the channel is closed and every value sent before it closed was received. On `Pending`, the waker of `cx` is woken when a value arrives or the channel closes. Only the waker of the most recent call to `poll_recv` or [`poll_recv_many`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Receiver.html#method.poll_recv_many) is kept. ```rust pub fn poll_recv_many( &mut self, cx: &mut Context<'_>, buffer: &mut Vec, limit: usize, ) -> Poll ``` Polls to receive several values into `buffer`, at most `limit`. Returns [`Poll::Pending`](https://doc.rust-lang.org/1.99.1/core/task/poll/enum.Poll.html#variant.Pending) if no value is available and the channel is open; [`Poll::Ready`](https://doc.rust-lang.org/1.99.1/core/task/poll/enum.Poll.html#variant.Ready)`(count)` with the number of values added, which is at least one unless `limit` is zero or the channel is closed and empty. It takes everything that is ready, up to `limit`, in one call. The waker of `cx` is handled as for [`poll_recv`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Receiver.html#method.poll_recv). ```rust pub fn sender_strong_count(&self) -> usize ``` How many [`Sender`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html) handles exist. ```rust pub fn sender_weak_count(&self) -> usize ``` How many [`WeakSender`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.WeakSender.html) handles exist. #### Trait Implementations - `impl Debug for Receiver` - `impl Drop for Receiver` #### Auto Trait Implementations - `impl Freeze for Receiver` - `impl RefUnwindSafe for Receiver` - `impl Send for Receiver where T: Send` - `impl Sync for Receiver where T: Send` - `impl Unpin for Receiver` - `impl UnsafeUnpin for Receiver` - `impl UnwindSafe for Receiver` ### struct `nuclei::sync::mpsc::Sender` https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html ```rust pub struct Sender { /* private fields */ } ``` Sends values to the associated [`Receiver`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Receiver.html). Created by [`channel`](https://nuclei.rs/api/nuclei/sync/mpsc/fn.channel.html). Cloning it is a reference-count increment. **Progress** Wait-free (a bounded number of the caller’s own atomic steps whatever other threads do): [`is_closed`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html#method.is_closed), [`capacity`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html#method.capacity), [`max_capacity`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html#method.max_capacity), [`same_channel`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html#method.same_channel), [`strong_count`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html#method.strong_count), [`weak_count`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html#method.weak_count), [`downgrade`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html#method.downgrade), `clone` and `drop`. The drop of the last sender ends with a wake of the receiver’s waker cell, which is two atomic steps; what the waker then does belongs to the executor. Lock-free, not wait-free: [`try_send`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html#method.try_send), the `try_reserve` family, and every poll of [`send`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html#method.send) and the `reserve` family. A permit is taken with a compare-and-swap that retries when another thread changed the semaphore first; a wait that has to queue pushes a node on the semaphore’s lock-free arrival stack and may serve the queue (one pass, plus one for each operation of another thread that lands meanwhile); and the push of a value onto the message queue retries when it loses a slot to another sender and allocates a segment when the last one is full. Some thread’s call completes whenever any retries. [`closed`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html#method.closed) is lock-free for the same reason. A waiting reservation is granted by whichever thread serves the queue once its slots are free (the receiver taking a value, a permit dropped), so a thread the scheduler stops while it serves the queue delays that grant until it runs again; for that moment a `try_` attempt fails as well, even if the last waiting reservation has just left. No call waits for it. `blocking_send` parks the calling thread until there is room. #### Implementations `impl Sender` ```rust pub fn send( &self, value: T, ) -> impl Future>> + '_ ``` Sends a value, waiting until there is capacity. A successful send means the other end had not hung up when the value was published. `Ok` does not mean the value will be received: the receiver can hang up right after. **Errors** If the receiving half is closed, by [`Receiver::close`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Receiver.html#method.close) or by being dropped, the function returns an error that holds the value passed to `send`. **Cancel safety** If the returned future is dropped before it completes, the message was not sent, and the value is dropped. To keep the value, reserve capacity with [`reserve`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html#method.reserve) and send through the [`Permit`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Permit.html). Waiting sends and reservations are served in the order they began to wait. Dropping the future gives up its place, and a slot it was handed meanwhile goes on to the next one. ```rust use nuclei::sync::mpsc; let (tx, mut rx) = mpsc::channel(1); now(tx.send(1)).unwrap(); assert_eq!(rx.try_recv(), Ok(1)); drop(rx); let err = now(tx.send(2)).unwrap_err(); assert_eq!(err.0, 2); ``` ```rust pub async fn send_timeout( &self, value: T, timeout: Duration, ) -> Result<(), SendTimeoutError> ``` Sends a value, waiting for room at most `timeout`. As [`send`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html#method.send), with a deadline: the value comes back in [`SendTimeoutError::Timeout`](https://nuclei.rs/api/nuclei/sync/mpsc/error/enum.SendTimeoutError.html#variant.Timeout) if the channel stayed full until then, and in [`SendTimeoutError::Closed`](https://nuclei.rs/api/nuclei/sync/mpsc/error/enum.SendTimeoutError.html#variant.Closed) if the receiver is gone. The wait is on nuclei’s timers: on a thread that runs no nuclei shard, the default runtime fires it. **Cancel safety** As [`send`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html#method.send): a dropped future sent nothing, and drops its value. ```rust use std::time::Duration; use nuclei::sync::mpsc::{self, error::SendTimeoutError}; nuclei::runtime::block_on(async { let (tx, _rx) = mpsc::channel(1); tx.send_timeout(1, Duration::from_millis(10)).await.unwrap(); let full = tx.send_timeout(2, Duration::from_millis(10)).await; assert!(matches!(full, Err(SendTimeoutError::Timeout(2)))); }); ``` ```rust pub async fn closed(&self) ``` Completes when the receiver has been closed or dropped. This lets a producer learn that nobody wants its values any more and stop work early. **Cancel safety** Cancel safe. Once the channel is closed it stays closed, and every later call completes at once. ```rust use nuclei::sync::mpsc; let (tx, rx) = mpsc::channel::<()>(1); let mut cx = Context::from_waker(Waker::noop()); let mut closed = pin!(tx.closed()); assert_eq!(closed.as_mut().poll(&mut cx), Poll::Pending); drop(rx); assert_eq!(closed.as_mut().poll(&mut cx), Poll::Ready(())); ``` ```rust pub fn try_send(&self, message: T) -> Result<(), TrySendError> ``` Sends a value at once, or says why it cannot be sent. Unlike [`send`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html#method.send) it never waits: a full buffer is an error. It never takes a slot ahead of a send or reservation that is waiting. **Errors** [`TrySendError::Full`](https://nuclei.rs/api/nuclei/sync/mpsc/error/enum.TrySendError.html#variant.Full) if no slot is free or a send or reservation is waiting, [`TrySendError::Closed`](https://nuclei.rs/api/nuclei/sync/mpsc/error/enum.TrySendError.html#variant.Closed) if the receiver closed or was dropped. Both hold the value back. ```rust use nuclei::sync::mpsc::{self, error::TrySendError}; let (tx, mut rx) = mpsc::channel(1); tx.try_send("first").unwrap(); assert!(matches!(tx.try_send("second"), Err(TrySendError::Full("second")))); assert_eq!(rx.try_recv(), Ok("first")); ``` ```rust pub fn blocking_send(&self, value: T) -> Result<(), SendError> ``` Sends a value from a thread that may block. It parks the calling thread until there is room. On a nuclei shard (inside one of its tasks) it does not park the thread: it runs a nested `block_on`, so the shard keeps running its other tasks meanwhile. Inside another runtime’s task it blocks that task’s thread. It works whether or not the receiver uses [`Receiver::blocking_recv`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Receiver.html#method.blocking_recv). **Panics** On `wasm32`, where no other thread can make room, when the channel is full: the call could never end. ```rust use nuclei::sync::mpsc; let (tx, mut rx) = mpsc::channel::(1); let sender = std::thread::spawn(move || tx.blocking_send(10).unwrap()); assert_eq!(rx.blocking_recv(), Some(10)); sender.join().unwrap(); ``` ```rust pub fn is_closed(&self) -> bool ``` Whether the channel is closed: the receiver was closed or dropped. ```rust use nuclei::sync::mpsc; let (tx, rx) = mpsc::channel::<()>(42); let tx2 = tx.clone(); assert!(!tx.is_closed()); drop(rx); assert!(tx.is_closed() && tx2.is_closed()); ``` ```rust pub async fn reserve(&self) -> Result, SendError<()>> ``` Waits for capacity for one message and reserves it. A [`Permit`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Permit.html) tracks the reserved slot; [`Permit::send`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Permit.html#method.send) uses it, and dropping the permit unused gives the slot back. **Errors** A [`SendError`](https://nuclei.rs/api/nuclei/sync/mpsc/error/struct.SendError.html) if the receiver is closed or dropped, now or while waiting. **Cancel safety** Dropping the future gives up its place in the queue of waiters, and a slot it was handed meanwhile goes on to the next one. No slot is held by a dropped future. ```rust use nuclei::sync::mpsc; let (tx, mut rx) = mpsc::channel(1); let permit = now(tx.reserve()).unwrap(); assert!(tx.try_send(123).is_err(), "the only slot is reserved"); permit.send(456); assert_eq!(rx.try_recv(), Ok(456)); ``` ```rust pub async fn reserve_many( &self, n: usize, ) -> Result, SendError<()>> ``` Waits for capacity for `n` messages and reserves them. The returned [`PermitIterator`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.PermitIterator.html) yields `n` permits; dropping it before it is exhausted gives the rest back. Waiting requests are served in the order they began to wait, whatever each asks for: the slots that come free are set aside for the oldest one until it has all `n`, and nothing behind it is served first. Slots set aside for a request do not count in [`capacity`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html#method.capacity). **Errors** A [`SendError`](https://nuclei.rs/api/nuclei/sync/mpsc/error/struct.SendError.html) if the receiver is closed or dropped, now or while waiting, or if `n` is more than the channel can ever hold ([`max_capacity`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html#method.max_capacity)). `n == 0` succeeds with an empty iterator unless the channel is closed. **Cancel safety** As for [`reserve`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html#method.reserve): the slots set aside for a dropped request go on to the next one. ```rust use nuclei::sync::mpsc; let (tx, mut rx) = mpsc::channel(2); let mut permits = now(tx.reserve_many(2)).unwrap(); assert!(tx.try_send(123).is_err()); permits.next().unwrap().send(456); permits.next().unwrap().send(457); assert!(permits.next().is_none()); assert_eq!(rx.try_recv(), Ok(456)); assert_eq!(rx.try_recv(), Ok(457)); ``` ```rust pub async fn reserve_owned(self) -> Result, SendError<()>> ``` Waits for capacity for one message, moving the sender into the returned [`OwnedPermit`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.OwnedPermit.html). Unlike [`reserve`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html#method.reserve), the permit borrows nothing, so it can be stored or moved into another task. Cloning a sender first keeps a handle to send with meanwhile. [`OwnedPermit::send`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.OwnedPermit.html#method.send) and [`OwnedPermit::release`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.OwnedPermit.html#method.release) hand the sender back. **Errors** A [`SendError`](https://nuclei.rs/api/nuclei/sync/mpsc/error/struct.SendError.html) if the receiver is closed or dropped, now or while waiting. **Cancel safety** Dropping the future gives up its place in the queue of waiters, passes on a slot it was handed meanwhile, and drops the sender it holds. ```rust use nuclei::sync::mpsc; let (tx, mut rx) = mpsc::channel(1); let permit = now(tx.reserve_owned()).unwrap(); let tx = permit.send(123); assert_eq!(rx.try_recv(), Ok(123)); tx.try_send(456).unwrap(); ``` ```rust pub fn try_reserve(&self) -> Result, TrySendError<()>> ``` Reserves capacity for one message if there is any, without waiting. It never takes a slot ahead of a send or reservation that is waiting. **Errors** [`TrySendError::Full`](https://nuclei.rs/api/nuclei/sync/mpsc/error/enum.TrySendError.html#variant.Full) when no slot is free or a send or reservation is waiting, [`TrySendError::Closed`](https://nuclei.rs/api/nuclei/sync/mpsc/error/enum.TrySendError.html#variant.Closed) when the receiver closed or was dropped. ```rust use nuclei::sync::mpsc; let (tx, mut rx) = mpsc::channel(1); let permit = tx.try_reserve().unwrap(); assert!(tx.try_reserve().is_err(), "no slot is left"); permit.send("foo"); assert_eq!(rx.try_recv(), Ok("foo")); ``` ```rust pub fn try_reserve_many( &self, n: usize, ) -> Result, TrySendError<()>> ``` Reserves capacity for `n` messages if there is enough, without waiting. **Errors** [`TrySendError::Full`](https://nuclei.rs/api/nuclei/sync/mpsc/error/enum.TrySendError.html#variant.Full) when fewer than `n` slots are free, a send or reservation is waiting, or `n` is more than the channel can ever hold; [`TrySendError::Closed`](https://nuclei.rs/api/nuclei/sync/mpsc/error/enum.TrySendError.html#variant.Closed) when the receiver closed or was dropped. `n == 0` succeeds with an empty iterator unless the channel is closed. ```rust use nuclei::sync::mpsc; let (tx, mut rx) = mpsc::channel(2); let mut permits = tx.try_reserve_many(2).unwrap(); assert!(tx.try_send(123).is_err()); permits.next().unwrap().send(456); permits.next().unwrap().send(457); assert_eq!(rx.try_recv(), Ok(456)); assert_eq!(rx.try_recv(), Ok(457)); assert!(tx.try_reserve_many(3).is_err(), "more than the channel holds"); ``` ```rust pub fn try_reserve_owned(self) -> Result, TrySendError> ``` Reserves capacity for one message if there is any, moving the sender into the returned [`OwnedPermit`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.OwnedPermit.html). **Errors** On failure the sender is handed back inside the error: [`TrySendError::Full`](https://nuclei.rs/api/nuclei/sync/mpsc/error/enum.TrySendError.html#variant.Full) when no slot is free or a send or reservation is waiting, [`TrySendError::Closed`](https://nuclei.rs/api/nuclei/sync/mpsc/error/enum.TrySendError.html#variant.Closed) when the receiver closed or was dropped. ```rust use nuclei::sync::mpsc; let (tx, mut rx) = mpsc::channel(1); let permit = tx.clone().try_reserve_owned().unwrap(); assert!(tx.try_send(123).is_err()); permit.send(456); assert_eq!(rx.try_recv(), Ok(456)); ``` ```rust pub fn same_channel(&self, other: &Self) -> bool ``` Whether two senders belong to the same channel. ```rust use nuclei::sync::mpsc; let (tx, _rx) = mpsc::channel::<()>(1); let tx2 = tx.clone(); assert!(tx.same_channel(&tx2)); let (tx3, _rx3) = mpsc::channel::<()>(1); assert!(!tx3.same_channel(&tx2)); ``` ```rust pub fn capacity(&self) -> usize ``` The channel’s current capacity: the slots that are free. It goes down when a value is sent or a slot is reserved, and up when the receiver takes a value or a permit is dropped unused. A slot set aside for a waiting [`reserve_many`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html#method.reserve_many) is not free. Compare [`max_capacity`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html#method.max_capacity), which never changes. ```rust use nuclei::sync::mpsc; let (tx, mut rx) = mpsc::channel::<()>(5); assert_eq!(tx.capacity(), 5); let permit = tx.try_reserve().unwrap(); assert_eq!(tx.capacity(), 4); permit.send(()); rx.try_recv().unwrap(); assert_eq!(tx.capacity(), 5); ``` ```rust pub fn downgrade(&self) -> WeakSender ``` Converts the sender into a [`WeakSender`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.WeakSender.html), which does not keep the channel open. The sender itself stays. ```rust pub fn max_capacity(&self) -> usize ``` The channel’s maximum capacity: the `buffer` it was created with. ```rust use nuclei::sync::mpsc; let (tx, _rx) = mpsc::channel::<()>(5); let _permit = tx.try_reserve().unwrap(); assert_eq!(tx.max_capacity(), 5); assert_eq!(tx.capacity(), 4); ``` ```rust pub fn strong_count(&self) -> usize ``` How many [`Sender`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html) handles exist (an [`OwnedPermit`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.OwnedPermit.html) holds one). ```rust pub fn weak_count(&self) -> usize ``` How many [`WeakSender`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.WeakSender.html) handles exist. #### Trait Implementations - `impl Clone for Sender` - `impl Debug for Sender` - `impl Drop for Sender` #### Auto Trait Implementations - `impl Freeze for Sender` - `impl RefUnwindSafe for Sender` - `impl Send for Sender where T: Send` - `impl Sync for Sender where T: Send` - `impl Unpin for Sender` - `impl UnsafeUnpin for Sender` - `impl UnwindSafe for Sender` ### struct `nuclei::sync::mpsc::UnboundedReceiver` https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedReceiver.html ```rust pub struct UnboundedReceiver { /* private fields */ } ``` Receives values from the associated [`UnboundedSender`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedSender.html)s. Created by [`unbounded_channel`](https://nuclei.rs/api/nuclei/sync/mpsc/fn.unbounded_channel.html). There is exactly one receiver. **Progress** Wait-free: [`is_closed`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedReceiver.html#method.is_closed), [`is_empty`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedReceiver.html#method.is_empty), [`len`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedReceiver.html#method.len), [`sender_strong_count`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedReceiver.html#method.sender_strong_count) and [`sender_weak_count`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedReceiver.html#method.sender_weak_count): each is a load. Lock-free: [`recv`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedReceiver.html#method.recv), [`recv_many`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedReceiver.html#method.recv_many), [`try_recv`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedReceiver.html#method.try_recv) and the two `poll_` forms. Registering the waker is wait-free (the cell runs two read-modify-writes and no loop). Taking a value off the message queue is a compare-and-swap no other thread contends for, and never waits for a sender: a value whose send claimed its place and has not written it yet is not there, and its sender wakes the receiver once it is (see the [Progress](https://nuclei.rs/api/nuclei/sync/mpsc/index.html#progress) notes of the module). [`close`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedReceiver.html#method.close) is lock-free: one `fetch_or` on the count, then the set of the event that `closed` waits on, which takes that event’s drain role. The drop is the same as a receive per value left, since it drops every value still queued, and so takes time proportional to them. `blocking_recv` and `blocking_recv_many` park the calling thread until a value arrives. #### Implementations `impl UnboundedReceiver` ```rust pub async fn recv(&mut self) -> Option ``` Receives the next value. Returns `None` once the channel is closed and no buffered value is left, which means no value can ever be received again. The channel is closed when every sender has been dropped, or when [`close`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedReceiver.html#method.close) is called. If the channel is empty and open, it waits for a send or a close. **Cancel safety** Cancel safe. If the future is dropped (for instance when another branch of a `select` wins), no value was taken from the channel. ```rust use nuclei::sync::mpsc; let (tx, mut rx) = mpsc::unbounded_channel(); tx.send("hello").unwrap(); tx.send("world").unwrap(); drop(tx); assert_eq!(now(rx.recv()), Some("hello")); assert_eq!(now(rx.recv()), Some("world")); assert_eq!(now(rx.recv()), None); ``` ```rust pub async fn recv_many(&mut self, buffer: &mut Vec, limit: usize) -> usize ``` Receives the next values and appends them to `buffer`, taking at most `limit` of them in one call. Returns how many values it added. A `limit` of zero returns `0` at once. Otherwise it waits like [`recv`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedReceiver.html#method.recv) until at least one value is there, then takes everything that is ready up to `limit` without waiting again, and returns `0` only when the channel is closed and empty. The capacity of `buffer` grows as needed. **Cancel safety** Cancel safe, as [`recv`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedReceiver.html#method.recv): a dropped future took nothing. ```rust use nuclei::sync::mpsc; let (tx, mut rx) = mpsc::unbounded_channel(); for word in ["first", "second", "third"] { tx.send(word).unwrap(); } let mut buffer = Vec::new(); assert_eq!(now(rx.recv_many(&mut buffer, 2)), 2); assert_eq!(buffer, ["first", "second"]); assert_eq!(now(rx.recv_many(&mut buffer, 2)), 1); drop(tx); assert_eq!(now(rx.recv_many(&mut buffer, 2)), 0); ``` ```rust pub fn try_recv(&mut self) -> Result ``` Tries to receive the next value without waiting. **Errors** [`TryRecvError::Empty`](https://nuclei.rs/api/nuclei/sync/mpsc/error/enum.TryRecvError.html#variant.Empty) if the channel is empty but a sender still exists, so a value may yet come. [`TryRecvError::Disconnected`](https://nuclei.rs/api/nuclei/sync/mpsc/error/enum.TryRecvError.html#variant.Disconnected) if it is empty and nothing can send: every sender is gone, or the channel was closed. A value whose send is still in progress on another thread is not in the channel yet, nor are the values sent after it, which come out behind it. This call does not wait for them: the sender wakes the receiver once its value is in. ```rust use nuclei::sync::mpsc::{self, error::TryRecvError}; let (tx, mut rx) = mpsc::unbounded_channel(); tx.send("hello").unwrap(); assert_eq!(rx.try_recv(), Ok("hello")); assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); drop(tx); assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); ``` ```rust pub fn blocking_recv(&mut self) -> Option ``` Receives the next value from a thread that may block. Like [`recv`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedReceiver.html#method.recv), but it parks the calling thread while the channel is empty and open. On a nuclei shard (inside one of its tasks) it does not park the thread: it runs a nested `block_on`, so the shard keeps running its other tasks meanwhile. Inside another runtime’s task it blocks that task’s thread. **Panics** On `wasm32`, where no other thread can send, when the channel is empty and open: the call could never end. ```rust use nuclei::sync::mpsc; let (tx, mut rx) = mpsc::unbounded_channel::(); let receiver = std::thread::spawn(move || { assert_eq!(rx.blocking_recv(), Some(10)); assert_eq!(rx.blocking_recv(), None); }); tx.send(10).unwrap(); drop(tx); receiver.join().unwrap(); ``` ```rust pub fn blocking_recv_many(&mut self, buffer: &mut Vec, limit: usize) -> usize ``` [`recv_many`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedReceiver.html#method.recv_many) for a thread that may block; see [`blocking_recv`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedReceiver.html#method.blocking_recv). **Panics** As for [`blocking_recv`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedReceiver.html#method.blocking_recv). ```rust pub fn close(&mut self) ``` Closes the receiving half without dropping it. No further value can be sent: a send fails and returns its value. The values already buffered stay receivable, so a clean shutdown closes, then calls [`recv`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedReceiver.html#method.recv) until it returns `None`. A send that was already under way when the channel closed still completes and is received first. ```rust use nuclei::sync::mpsc; let (tx, mut rx) = mpsc::unbounded_channel(); tx.send(1).unwrap(); rx.close(); assert_eq!(tx.send(2).unwrap_err().0, 2); assert_eq!(rx.try_recv(), Ok(1), "the buffered value is still there"); ``` ```rust pub fn is_closed(&self) -> bool ``` Whether the channel is closed: [`close`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedReceiver.html#method.close) was called, or every sender is gone. Buffered values may still be received. ```rust use nuclei::sync::mpsc; let (tx, mut rx) = mpsc::unbounded_channel::<()>(); assert!(!rx.is_closed()); rx.close(); assert!(rx.is_closed()); drop(tx); ``` ```rust pub fn is_empty(&self) -> bool ``` Whether the channel holds no value. ```rust use nuclei::sync::mpsc; let (tx, rx) = mpsc::unbounded_channel(); assert!(rx.is_empty()); tx.send(()).unwrap(); assert!(!rx.is_empty()); ``` ```rust pub fn len(&self) -> usize ``` How many values the channel holds. A snapshot: it is exact while no other thread is sending, and while one is it may be off by the values being sent at that moment. ```rust use nuclei::sync::mpsc; let (tx, rx) = mpsc::unbounded_channel(); assert_eq!(rx.len(), 0); tx.send(()).unwrap(); assert_eq!(rx.len(), 1); ``` ```rust pub fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll> ``` Polls to receive the next value. Returns [`Poll::Pending`](https://doc.rust-lang.org/1.99.1/core/task/poll/enum.Poll.html#variant.Pending) if no value is available and the channel is open; [`Poll::Ready`](https://doc.rust-lang.org/1.99.1/core/task/poll/enum.Poll.html#variant.Ready)`(Some(value))` if one is; and [`Poll::Ready`](https://doc.rust-lang.org/1.99.1/core/task/poll/enum.Poll.html#variant.Ready)`(None)` if the channel is closed and every value sent before it closed was received. On `Pending`, the waker of `cx` is woken when a value arrives or the channel closes. Only the waker of the most recent call to `poll_recv` or [`poll_recv_many`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedReceiver.html#method.poll_recv_many) is kept. ```rust pub fn poll_recv_many( &mut self, cx: &mut Context<'_>, buffer: &mut Vec, limit: usize, ) -> Poll ``` Polls to receive several values into `buffer`, at most `limit`. Returns [`Poll::Pending`](https://doc.rust-lang.org/1.99.1/core/task/poll/enum.Poll.html#variant.Pending) if no value is available and the channel is open; [`Poll::Ready`](https://doc.rust-lang.org/1.99.1/core/task/poll/enum.Poll.html#variant.Ready)`(count)` with the number of values added, which is at least one unless `limit` is zero or the channel is closed and empty. It takes everything that is ready, up to `limit`, in one call. The waker of `cx` is handled as for [`poll_recv`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedReceiver.html#method.poll_recv). ```rust pub fn sender_strong_count(&self) -> usize ``` How many [`UnboundedSender`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedSender.html) handles exist. ```rust pub fn sender_weak_count(&self) -> usize ``` How many [`WeakUnboundedSender`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.WeakUnboundedSender.html) handles exist. #### Trait Implementations - `impl Debug for UnboundedReceiver` - `impl Drop for UnboundedReceiver` #### Auto Trait Implementations - `impl Freeze for UnboundedReceiver` - `impl RefUnwindSafe for UnboundedReceiver` - `impl Send for UnboundedReceiver where T: Send` - `impl Sync for UnboundedReceiver where T: Send` - `impl Unpin for UnboundedReceiver` - `impl UnsafeUnpin for UnboundedReceiver` - `impl UnwindSafe for UnboundedReceiver` ### struct `nuclei::sync::mpsc::UnboundedSender` https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedSender.html ```rust pub struct UnboundedSender { /* private fields */ } ``` Sends values to the associated [`UnboundedReceiver`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedReceiver.html). Created by [`unbounded_channel`](https://nuclei.rs/api/nuclei/sync/mpsc/fn.unbounded_channel.html). Cloning it is a reference-count increment. **Progress** Wait-free (a bounded number of the caller’s own atomic steps): [`is_closed`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedSender.html#method.is_closed), [`same_channel`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedSender.html#method.same_channel), [`strong_count`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedSender.html#method.strong_count), [`weak_count`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedSender.html#method.weak_count), [`downgrade`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedSender.html#method.downgrade), `clone` and `drop`. The drop of the last sender ends with a wake of the receiver’s waker cell, which is two atomic steps; what the waker then does belongs to the executor. Lock-free, not wait-free: [`send`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedSender.html#method.send). It admits the value with a compare-and-swap that retries when another sender or the receiver changed the count first, and then pushes onto the message queue, which retries when it loses a slot to another sender and allocates a segment when the last one is full. Some thread’s call completes whenever any retries. [`closed`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedSender.html#method.closed) is lock-free: a poll may queue a waiter. #### Implementations `impl UnboundedSender` ```rust pub fn send(&self, message: T) -> Result<(), SendError> ``` Sends a value, without waiting. A successful send means the other end had not hung up when the value was published. `Ok` does not mean the value will be received: the receiver can hang up right after. **Errors** If the receiving half is closed, by [`UnboundedReceiver::close`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedReceiver.html#method.close) or by being dropped, the function returns an error that holds the value. ```rust use nuclei::sync::mpsc; let (tx, mut rx) = mpsc::unbounded_channel(); tx.send("first").unwrap(); assert_eq!(rx.try_recv(), Ok("first")); drop(rx); assert_eq!(tx.send("second").unwrap_err().0, "second"); ``` ```rust pub async fn closed(&self) ``` Completes when the receiver has been closed or dropped. This lets a producer learn that nobody wants its values any more and stop work early. **Cancel safety** Cancel safe. Once the channel is closed it stays closed, and every later call completes at once. ```rust use nuclei::sync::mpsc; let (tx, rx) = mpsc::unbounded_channel::<()>(); let mut cx = Context::from_waker(Waker::noop()); let mut closed = pin!(tx.closed()); assert_eq!(closed.as_mut().poll(&mut cx), Poll::Pending); drop(rx); assert_eq!(closed.as_mut().poll(&mut cx), Poll::Ready(())); ``` ```rust pub fn is_closed(&self) -> bool ``` Whether the channel is closed: the receiver was closed or dropped. ```rust use nuclei::sync::mpsc; let (tx, rx) = mpsc::unbounded_channel::<()>(); assert!(!tx.is_closed()); drop(rx); assert!(tx.is_closed()); ``` ```rust pub fn same_channel(&self, other: &Self) -> bool ``` Whether two senders belong to the same channel. ```rust use nuclei::sync::mpsc; let (tx, _rx) = mpsc::unbounded_channel::<()>(); let tx2 = tx.clone(); assert!(tx.same_channel(&tx2)); let (tx3, _rx3) = mpsc::unbounded_channel::<()>(); assert!(!tx3.same_channel(&tx2)); ``` ```rust pub fn downgrade(&self) -> WeakUnboundedSender ``` Converts the sender into a [`WeakUnboundedSender`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.WeakUnboundedSender.html), which does not keep the channel open. The sender itself stays. ```rust pub fn strong_count(&self) -> usize ``` How many [`UnboundedSender`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedSender.html) handles exist. ```rust pub fn weak_count(&self) -> usize ``` How many [`WeakUnboundedSender`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.WeakUnboundedSender.html) handles exist. #### Trait Implementations - `impl Clone for UnboundedSender` - `impl Debug for UnboundedSender` - `impl Drop for UnboundedSender` #### Auto Trait Implementations - `impl Freeze for UnboundedSender` - `impl RefUnwindSafe for UnboundedSender` - `impl Send for UnboundedSender where T: Send` - `impl Sync for UnboundedSender where T: Send` - `impl Unpin for UnboundedSender` - `impl UnsafeUnpin for UnboundedSender` - `impl UnwindSafe for UnboundedSender` ### struct `nuclei::sync::mpsc::WeakSender` https://nuclei.rs/api/nuclei/sync/mpsc/struct.WeakSender.html ```rust pub struct WeakSender { /* private fields */ } ``` A sender that does not keep the channel open. When every [`Sender`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html) is dropped and only `WeakSender`s remain, the channel is closed for the receiver. A `WeakSender` sends nothing itself: [`upgrade`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.WeakSender.html#method.upgrade) turns it into a [`Sender`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html) while one exists. ```rust use nuclei::sync::mpsc; let (tx, _rx) = mpsc::channel::(15); let weak = tx.downgrade(); assert!(weak.upgrade().is_some()); drop(tx); assert!(weak.clone().upgrade().is_none()); ``` **Progress** `clone`, `drop`, [`strong_count`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.WeakSender.html#method.strong_count) and [`weak_count`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.WeakSender.html#method.weak_count) are wait-free. [`upgrade`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.WeakSender.html#method.upgrade) is lock-free, not wait-free: it is a compare-and-swap on the sender count that retries when a sender was cloned or dropped meanwhile. #### Implementations `impl WeakSender` ```rust pub fn upgrade(&self) -> Option> ``` Tries to turn the weak sender into a [`Sender`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html). Returns `Some` while at least one [`Sender`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html) (or [`OwnedPermit`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.OwnedPermit.html)) is alive, and `None` once the last is gone. ```rust pub fn strong_count(&self) -> usize ``` How many [`Sender`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html) handles exist. ```rust pub fn weak_count(&self) -> usize ``` How many [`WeakSender`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.WeakSender.html) handles exist. #### Trait Implementations - `impl Clone for WeakSender` - `impl Debug for WeakSender` - `impl Drop for WeakSender` #### Auto Trait Implementations - `impl Freeze for WeakSender` - `impl RefUnwindSafe for WeakSender` - `impl Send for WeakSender where T: Send` - `impl Sync for WeakSender where T: Send` - `impl Unpin for WeakSender` - `impl UnsafeUnpin for WeakSender` - `impl UnwindSafe for WeakSender` ### struct `nuclei::sync::mpsc::WeakUnboundedSender` https://nuclei.rs/api/nuclei/sync/mpsc/struct.WeakUnboundedSender.html ```rust pub struct WeakUnboundedSender { /* private fields */ } ``` A sender that does not keep the channel open. When every [`UnboundedSender`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedSender.html) is dropped and only `WeakUnboundedSender`s remain, the channel is closed for the receiver. [`upgrade`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.WeakUnboundedSender.html#method.upgrade) turns it into an [`UnboundedSender`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedSender.html) while one exists. ```rust use nuclei::sync::mpsc; let (tx, _rx) = mpsc::unbounded_channel::(); let weak = tx.downgrade(); assert!(weak.upgrade().is_some()); drop(tx); assert!(weak.clone().upgrade().is_none()); ``` **Progress** `clone`, `drop`, [`strong_count`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.WeakUnboundedSender.html#method.strong_count) and [`weak_count`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.WeakUnboundedSender.html#method.weak_count) are wait-free. [`upgrade`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.WeakUnboundedSender.html#method.upgrade) is lock-free, not wait-free: it is a compare-and-swap on the sender count that retries when a sender was cloned or dropped meanwhile. #### Implementations `impl WeakUnboundedSender` ```rust pub fn upgrade(&self) -> Option> ``` Tries to turn the weak sender into an [`UnboundedSender`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedSender.html). Returns `Some` while at least one [`UnboundedSender`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedSender.html) is alive, and `None` once the last is gone. ```rust pub fn strong_count(&self) -> usize ``` How many [`UnboundedSender`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedSender.html) handles exist. ```rust pub fn weak_count(&self) -> usize ``` How many [`WeakUnboundedSender`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.WeakUnboundedSender.html) handles exist. #### Trait Implementations - `impl Clone for WeakUnboundedSender` - `impl Debug for WeakUnboundedSender` - `impl Drop for WeakUnboundedSender` #### Auto Trait Implementations - `impl Freeze for WeakUnboundedSender` - `impl RefUnwindSafe for WeakUnboundedSender` - `impl Send for WeakUnboundedSender where T: Send` - `impl Sync for WeakUnboundedSender where T: Send` - `impl Unpin for WeakUnboundedSender` - `impl UnsafeUnpin for WeakUnboundedSender` - `impl UnwindSafe for WeakUnboundedSender` ### fn `nuclei::sync::mpsc::channel` https://nuclei.rs/api/nuclei/sync/mpsc/fn.channel.html ```rust pub fn channel(buffer: usize) -> (Sender, Receiver) ``` Creates a bounded channel for communicating between tasks with backpressure. The channel buffers up to `buffer` messages. Once the buffer is full, a send waits until a message is received. The buffer must hold at least one message. Everything sent on a [`Sender`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html) comes out of the [`Receiver`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Receiver.html), in the order it was sent (see [Ordering](https://nuclei.rs/api/nuclei/sync/mpsc/index.html#ordering)). The [`Sender`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html) can be cloned to send to the same channel from many places; only one [`Receiver`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Receiver.html) exists. If the [`Receiver`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Receiver.html) is closed or dropped, a send returns a [`SendError`](https://nuclei.rs/api/nuclei/sync/mpsc/error/struct.SendError.html) with the value. When every [`Sender`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html) is dropped, `recv` returns `None` once the buffered messages are received. **Panics** Panics if `buffer` is 0, or larger than [`Semaphore::MAX_PERMITS`](https://nuclei.rs/api/nuclei/sync/struct.Semaphore.html#associatedconstant.MAX_PERMITS). ```rust use nuclei::sync::mpsc; let (tx, mut rx) = mpsc::channel(4); let producer = std::thread::spawn(move || { for i in 0..10 { tx.blocking_send(i).expect("the receiver is still there"); } }); for i in 0..10 { assert_eq!(rx.blocking_recv(), Some(i)); } assert_eq!(rx.blocking_recv(), None); producer.join().unwrap(); ``` ### fn `nuclei::sync::mpsc::unbounded_channel` https://nuclei.rs/api/nuclei/sync/mpsc/fn.unbounded_channel.html ```rust pub fn unbounded_channel() -> (UnboundedSender, UnboundedReceiver) ``` Creates an unbounded channel for communicating between tasks without backpressure. A send never waits and never fails for lack of room, so [`UnboundedSender::send`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedSender.html#method.send) is an ordinary function, usable from synchronous and asynchronous code alike. The queue grows with the values sent faster than they are received, so memory is the only limit; use [`channel`](https://nuclei.rs/api/nuclei/sync/mpsc/fn.channel.html) where a producer can outrun the receiver. Everything sent on an [`UnboundedSender`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedSender.html) comes out of the [`UnboundedReceiver`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedReceiver.html), in the order it was sent (see [Ordering](https://nuclei.rs/api/nuclei/sync/mpsc/index.html#ordering)). The sender can be cloned; only one receiver exists. ```rust use nuclei::sync::mpsc; let (tx, mut rx) = mpsc::unbounded_channel(); let producer = std::thread::spawn(move || { for i in 0..10 { tx.send(i).expect("the receiver is still there"); } }); for i in 0..10 { assert_eq!(rx.blocking_recv(), Some(i)); } assert_eq!(rx.blocking_recv(), None); producer.join().unwrap(); ``` ## Module `nuclei::sync::mpsc::error` https://nuclei.rs/api/nuclei/sync/mpsc/error/index.html Error types of the multi-producer, single-consumer channels. They carry the unsent value back to the caller, so a failed send never loses it, and their `Display` text is the established one. ### Structs - [SendError](https://nuclei.rs/api/nuclei/sync/mpsc/error/struct.SendError.html): Error returned by [`Sender::send`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html#method.send), [`UnboundedSender::send`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedSender.html#method.send) and the other sends that wait. ### Enums - [SendTimeoutError](https://nuclei.rs/api/nuclei/sync/mpsc/error/enum.SendTimeoutError.html): Error returned by [`Sender::send_timeout`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html#method.send_timeout): the value was not sent, and comes back. - [TryRecvError](https://nuclei.rs/api/nuclei/sync/mpsc/error/enum.TryRecvError.html): Error returned by [`Receiver::try_recv`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Receiver.html#method.try_recv) and [`UnboundedReceiver::try_recv`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedReceiver.html#method.try_recv). - [TrySendError](https://nuclei.rs/api/nuclei/sync/mpsc/error/enum.TrySendError.html): Error returned by [`Sender::try_send`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html#method.try_send) and the other sends and reservations that never wait. ### struct `nuclei::sync::mpsc::error::SendError` https://nuclei.rs/api/nuclei/sync/mpsc/error/struct.SendError.html ```rust pub struct SendError(pub T); ``` Error returned by [`Sender::send`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html#method.send), [`UnboundedSender::send`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedSender.html#method.send) and the other sends that wait. The channel is closed: the receiver was dropped or closed. The value that could not be sent is returned in the error. ```rust use nuclei::sync::mpsc; let (tx, rx) = mpsc::unbounded_channel(); drop(rx); let err = tx.send("lost").unwrap_err(); assert_eq!(err.0, "lost"); assert_eq!(err.to_string(), "channel closed"); ``` #### Tuple Fields `0: T` #### Trait Implementations - `impl Clone for SendError` - `impl Copy for SendError` - `impl Debug for SendError` - `impl Display for SendError` - `impl Eq for SendError` - `impl Error for SendError` - `impl From> for TrySendError` - `impl PartialEq for SendError` - `impl StructuralPartialEq for SendError` #### Auto Trait Implementations - `impl Freeze for SendError where T: Freeze` - `impl RefUnwindSafe for SendError where T: RefUnwindSafe` - `impl Send for SendError where T: Send` - `impl Sync for SendError where T: Sync` - `impl Unpin for SendError where T: Unpin` - `impl UnsafeUnpin for SendError where T: UnsafeUnpin` - `impl UnwindSafe for SendError where T: UnwindSafe` ### enum `nuclei::sync::mpsc::error::SendTimeoutError` https://nuclei.rs/api/nuclei/sync/mpsc/error/enum.SendTimeoutError.html ```rust pub enum SendTimeoutError { Timeout(T), Closed(T), } ``` Error returned by [`Sender::send_timeout`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html#method.send_timeout): the value was not sent, and comes back. #### Variants ```rust Timeout(T) ``` The channel stayed full until the timeout. ```rust Closed(T) ``` The receive half of the channel was explicitly closed or has been dropped. #### Implementations `impl SendTimeoutError` ```rust pub fn into_inner(self) -> T ``` Consume the `SendTimeoutError`, returning the unsent value. #### Trait Implementations - `impl Clone for SendTimeoutError` - `impl Copy for SendTimeoutError` - `impl Debug for SendTimeoutError` - `impl Display for SendTimeoutError` - `impl Eq for SendTimeoutError` - `impl Error for SendTimeoutError` - `impl PartialEq for SendTimeoutError` - `impl StructuralPartialEq for SendTimeoutError` #### Auto Trait Implementations - `impl Freeze for SendTimeoutError where T: Freeze` - `impl RefUnwindSafe for SendTimeoutError where T: RefUnwindSafe` - `impl Send for SendTimeoutError where T: Send` - `impl Sync for SendTimeoutError where T: Sync` - `impl Unpin for SendTimeoutError where T: Unpin` - `impl UnsafeUnpin for SendTimeoutError where T: UnsafeUnpin` - `impl UnwindSafe for SendTimeoutError where T: UnwindSafe` ### enum `nuclei::sync::mpsc::error::TryRecvError` https://nuclei.rs/api/nuclei/sync/mpsc/error/enum.TryRecvError.html ```rust pub enum TryRecvError { Empty, Disconnected, } ``` Error returned by [`Receiver::try_recv`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Receiver.html#method.try_recv) and [`UnboundedReceiver::try_recv`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.UnboundedReceiver.html#method.try_recv). ```rust use nuclei::sync::mpsc::{self, error::TryRecvError}; let (tx, mut rx) = mpsc::unbounded_channel::(); assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); drop(tx); assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); ``` #### Variants ```rust Empty ``` This **channel** is currently empty, but the **Sender**(s) have not yet disconnected, so data may yet become available. ```rust Disconnected ``` The **channel**’s sending half has become disconnected, and there will never be any more data received on it. #### Trait Implementations - `impl Clone for TryRecvError` - `impl Copy for TryRecvError` - `impl Debug for TryRecvError` - `impl Display for TryRecvError` - `impl Eq for TryRecvError` - `impl Error for TryRecvError` - `impl PartialEq for TryRecvError` - `impl StructuralPartialEq for TryRecvError` #### Auto Trait Implementations - `impl Freeze for TryRecvError` - `impl RefUnwindSafe for TryRecvError` - `impl Send for TryRecvError` - `impl Sync for TryRecvError` - `impl Unpin for TryRecvError` - `impl UnsafeUnpin for TryRecvError` - `impl UnwindSafe for TryRecvError` ### enum `nuclei::sync::mpsc::error::TrySendError` https://nuclei.rs/api/nuclei/sync/mpsc/error/enum.TrySendError.html ```rust pub enum TrySendError { Full(T), Closed(T), } ``` Error returned by [`Sender::try_send`](https://nuclei.rs/api/nuclei/sync/mpsc/struct.Sender.html#method.try_send) and the other sends and reservations that never wait. ```rust use nuclei::sync::mpsc::{self, error::TrySendError}; let (tx, rx) = mpsc::channel(1); tx.try_send(1).unwrap(); assert!(matches!(tx.try_send(2), Err(TrySendError::Full(2)))); drop(rx); assert!(matches!(tx.try_send(3), Err(TrySendError::Closed(3)))); ``` #### Variants ```rust Full(T) ``` The data could not be sent on the channel because the channel is currently full and sending would require blocking. ```rust Closed(T) ``` The receive half of the channel was explicitly closed or has been dropped. #### Implementations `impl TrySendError` ```rust pub fn into_inner(self) -> T ``` Consume the `TrySendError`, returning the unsent value. #### Trait Implementations - `impl Clone for TrySendError` - `impl Copy for TrySendError` - `impl Debug for TrySendError` - `impl Display for TrySendError` - `impl Eq for TrySendError` - `impl Error for TrySendError` - `impl From> for TrySendError` - `impl PartialEq for TrySendError` - `impl StructuralPartialEq for TrySendError` #### Auto Trait Implementations - `impl Freeze for TrySendError where T: Freeze` - `impl RefUnwindSafe for TrySendError where T: RefUnwindSafe` - `impl Send for TrySendError where T: Send` - `impl Sync for TrySendError where T: Sync` - `impl Unpin for TrySendError where T: Unpin` - `impl UnsafeUnpin for TrySendError where T: UnsafeUnpin` - `impl UnwindSafe for TrySendError where T: UnwindSafe` ## Module `nuclei::sync::oneshot` https://nuclei.rs/api/nuclei/sync/oneshot/index.html A channel that carries one value from one sender to one receiver. [`channel`](https://nuclei.rs/api/nuclei/sync/oneshot/fn.channel.html) returns a [`Sender`](https://nuclei.rs/api/nuclei/sync/oneshot/struct.Sender.html) and a [`Receiver`](https://nuclei.rs/api/nuclei/sync/oneshot/struct.Receiver.html). The sender sends at most one value and never waits; the receiver is a [`Future`](https://doc.rust-lang.org/1.99.1/core/future/future/trait.Future.html) that completes with the value, or with a [`error::RecvError`](https://nuclei.rs/api/nuclei/sync/oneshot/error/struct.RecvError.html) when the sender is dropped without sending. The API is the established async one-shot channel API; nothing here needs a runtime, and every wait is a plain [`Waker`](https://doc.rust-lang.org/1.99.1/core/task/wake/struct.Waker.html) handshake. ```rust use nuclei::sync::oneshot; let (tx, rx) = oneshot::channel(); std::thread::spawn(move || { tx.send(3).expect("the receiver is still there"); }); assert_eq!(rx.blocking_recv(), Ok(3)); ``` If the sender is dropped without sending, the receiver fails: ```rust use nuclei::sync::oneshot; let (tx, rx) = oneshot::channel::(); drop(tx); assert!(rx.blocking_recv().is_err()); ``` A value that was sent but never received stays in the channel until the receiver is dropped, which drops it on the spot. **Progress** Every operation of the channel is wait-free: it runs a bounded number of atomic read-modify-writes and loads of its own, and none of them loops because another thread got in first or waits for another thread. That covers [`Sender::send`](https://nuclei.rs/api/nuclei/sync/oneshot/struct.Sender.html#method.send), [`Sender::is_closed`](https://nuclei.rs/api/nuclei/sync/oneshot/struct.Sender.html#method.is_closed), [`Sender::poll_closed`](https://nuclei.rs/api/nuclei/sync/oneshot/struct.Sender.html#method.poll_closed), every poll of the [`Receiver`](https://nuclei.rs/api/nuclei/sync/oneshot/struct.Receiver.html), [`Receiver::try_recv`](https://nuclei.rs/api/nuclei/sync/oneshot/struct.Receiver.html#method.try_recv), [`Receiver::close`](https://nuclei.rs/api/nuclei/sync/oneshot/struct.Receiver.html#method.close), [`Receiver::is_empty`](https://nuclei.rs/api/nuclei/sync/oneshot/struct.Receiver.html#method.is_empty), [`Receiver::is_terminated`](https://nuclei.rs/api/nuclei/sync/oneshot/struct.Receiver.html#method.is_terminated) and the drop of either half. Three things are not counted. A [`Waker`](https://doc.rust-lang.org/1.99.1/core/task/wake/struct.Waker.html) the channel calls is the executor’s, and so is what it does; the destructor of the value runs in the call that drops it; and [`Receiver::blocking_recv`](https://nuclei.rs/api/nuclei/sync/oneshot/struct.Receiver.html#method.blocking_recv) parks the calling thread until the value arrives, which is what it is for. **How the halves agree on the value** The value lives in one cell, `UnsafeCell>`, and the state word has three bits: `VALUE_SENT`, `RX_CLOSED` and `TX_DROPPED`. Every bit is set once, with one `fetch_or`, so the word has one modification order that both halves read their outcome from. The cell has exactly one owner at a time: 1. Before the sender’s `fetch_or`, the sender owns the cell and the receiver never reads it: the receiver reads it only after it saw `VALUE_SENT` in a word it loaded with `Acquire`, or in the word its own `fetch_or` returned. 2. `send` writes the value, then does one `fetch_or(VALUE_SENT | TX_DROPPED)` and looks at the word that came back. - `RX_CLOSED` was clear: the receiver’s `fetch_or(RX_CLOSED)`, if it ever happens, comes later in the order, so the receiver’s own result shows `VALUE_SENT`. The send succeeded and the cell is the receiver’s. - `RX_CLOSED` was set: the receiver’s `fetch_or` came first and its result showed no `VALUE_SENT`, so the receiver wrote down that its channel closed empty (`RxClose::Empty`) and never reads the cell, whatever bits show up later. The sender reads its value back out and returns it. 3. The receiver’s side reads the cell exactly once, in the first of: a poll or `try_recv` that sees `VALUE_SENT` (it takes the value out and forgets the channel), or `Receiver::drop` (it drops the value if `VALUE_SENT` was set when it closed). A receiver that closed empty skips all of these. So a value is read by the sender (a failed send), by the receiver’s take (a received value), or by the receiver’s drop (an unreceived value), never by two of them, and never leaked while both halves honour the protocol: the cell needs no drop glue of its own. **Wakeups** The receiver’s task and the sender’s task each have an `AtomicWaker`. A poll registers its waker and then looks at the state word again, and a state change is followed by a wake of the other side’s waker, so a change is either seen by the re-check or woken: see the waker’s module for the handshake. ### Modules - [error](https://nuclei.rs/api/nuclei/sync/oneshot/error/index.html): Error types of the one-shot channel. ### Structs - [Receiver](https://nuclei.rs/api/nuclei/sync/oneshot/struct.Receiver.html): Receives a value from the associated [`Sender`](https://nuclei.rs/api/nuclei/sync/oneshot/struct.Sender.html). - [Sender](https://nuclei.rs/api/nuclei/sync/oneshot/struct.Sender.html): Sends a value to the associated [`Receiver`](https://nuclei.rs/api/nuclei/sync/oneshot/struct.Receiver.html). ### Functions - [channel](https://nuclei.rs/api/nuclei/sync/oneshot/fn.channel.html): Creates a one-shot channel for sending a single value between tasks. ### struct `nuclei::sync::oneshot::Receiver` https://nuclei.rs/api/nuclei/sync/oneshot/struct.Receiver.html ```rust pub struct Receiver { /* private fields */ } ``` Receives a value from the associated [`Sender`](https://nuclei.rs/api/nuclei/sync/oneshot/struct.Sender.html). A [`Sender`](https://nuclei.rs/api/nuclei/sync/oneshot/struct.Sender.html) and a [`Receiver`](https://nuclei.rs/api/nuclei/sync/oneshot/struct.Receiver.html) are created together by [`channel`](https://nuclei.rs/api/nuclei/sync/oneshot/fn.channel.html). The receiver is itself a [`Future`](https://doc.rust-lang.org/1.99.1/core/future/future/trait.Future.html): await it to get a `Result`. There is no `recv` method. Polling a receiver never fails spuriously: a value sent before a poll starts is returned by that poll. **Cancel safety** Awaiting a `&mut Receiver` is cancel safe. If it is a branch of a select and another branch completes first, no value was received on this channel. **Panics** Polling a receiver again after it completed (it returned `Ready`, or [`try_recv`](https://nuclei.rs/api/nuclei/sync/oneshot/struct.Receiver.html#method.try_recv) returned a value or [`TryRecvError::Closed`](https://nuclei.rs/api/nuclei/sync/oneshot/error/enum.TryRecvError.html#variant.Closed)) panics with `called after complete`. Check [`is_terminated`](https://nuclei.rs/api/nuclei/sync/oneshot/struct.Receiver.html#method.is_terminated) first. ```rust use nuclei::sync::oneshot; use std::future::Future; use std::pin::Pin; use std::task::{Context, Poll, Waker}; let (tx, mut rx) = oneshot::channel(); let mut cx = Context::from_waker(Waker::noop()); assert_eq!(Pin::new(&mut rx).poll(&mut cx), Poll::Pending); tx.send(7).expect("the receiver is still there"); assert_eq!(Pin::new(&mut rx).poll(&mut cx), Poll::Ready(Ok(7))); assert!(rx.is_terminated()); ``` #### Implementations `impl Receiver` ```rust pub fn close(&mut self) ``` Prevents the associated [`Sender`](https://nuclei.rs/api/nuclei/sync/oneshot/struct.Sender.html) from sending a value. Any `send` that happens after `close` returns fails. A value sent *before* `close` can still be taken with [`try_recv`](https://nuclei.rs/api/nuclei/sync/oneshot/struct.Receiver.html#method.try_recv) (or by polling). This makes a graceful shutdown possible: close, then drain. `close` does nothing if the value was already received or the channel is already closed. Wait-free. ```rust use nuclei::sync::oneshot; let (tx, mut rx) = oneshot::channel(); tx.send("sent before").expect("the receiver is still there"); rx.close(); assert_eq!(rx.try_recv(), Ok("sent before")); let (tx, mut rx) = oneshot::channel(); rx.close(); assert!(tx.is_closed()); assert_eq!(tx.send("too late"), Err("too late")); ``` ```rust pub fn is_terminated(&self) -> bool ``` Whether this receiver already completed: it returned its value or an error, so it must not be polled again. ```rust use nuclei::sync::oneshot; let (tx, mut rx) = oneshot::channel(); assert!(!rx.is_terminated()); tx.send(0).expect("the receiver is still there"); assert!(!rx.is_terminated(), "a value that was sent but not read"); assert_eq!(rx.try_recv(), Ok(0)); assert!(rx.is_terminated()); ``` ```rust pub fn is_empty(&self) -> bool ``` Whether the channel holds no value. `true` before a send, after the sender was dropped, and after the receiver completed. It is not a promise that polling is safe: use [`is_terminated`](https://nuclei.rs/api/nuclei/sync/oneshot/struct.Receiver.html#method.is_terminated) for that. ```rust use nuclei::sync::oneshot; let (tx, rx) = oneshot::channel(); assert!(rx.is_empty()); tx.send(0).expect("the receiver is still there"); assert!(!rx.is_empty()); ``` ```rust pub fn try_recv(&mut self) -> Result ``` Attempts to receive a value without waiting. The current task is *not* registered for a later wake. Unlike a poll, it cannot fail spuriously: any send or close that happened before the call is reported. Wait-free. - `Ok(value)` when a value is waiting. - `Err(TryRecvError::Empty)` when none was sent yet. - `Err(TryRecvError::Closed)` when the sender was dropped without sending, the channel was closed empty, or the value was received already. ```rust use nuclei::sync::oneshot::{self, error::TryRecvError}; let (tx, mut rx) = oneshot::channel(); assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); tx.send("hello").expect("the receiver is still there"); assert_eq!(rx.try_recv(), Ok("hello")); assert_eq!(rx.try_recv(), Err(TryRecvError::Closed)); ``` ```rust pub fn blocking_recv(self) -> Result ``` Receives the value on this thread, parking the thread until it arrives. For use outside asynchronous code. On a nuclei shard (inside one of its tasks) it does not park the thread: it runs a nested `block_on`, so the shard keeps running its other tasks meanwhile. Inside another runtime’s task it blocks that task’s executor thread, so do not. It is not wait-free: waiting for the sender is what it does. **Panics** Panics if the receiver already completed; see [`Receiver`](https://nuclei.rs/api/nuclei/sync/oneshot/struct.Receiver.html). On `wasm32`, where no other thread can send, it also panics when the value is not there already: the call could never end. ```rust use nuclei::sync::oneshot; let (tx, rx) = oneshot::channel::(); let sender = std::thread::spawn(move || tx.send(10)); assert_eq!(rx.blocking_recv(), Ok(10)); sender.join().expect("sender thread").expect("the receiver was waiting"); ``` #### Trait Implementations - `impl Debug for Receiver` - `impl Drop for Receiver` - `impl Future for Receiver` #### Auto Trait Implementations - `impl !RefUnwindSafe for Receiver` - `impl !UnwindSafe for Receiver` - `impl Freeze for Receiver` - `impl Send for Receiver where T: Send` - `impl Sync for Receiver where T: Send` - `impl Unpin for Receiver` - `impl UnsafeUnpin for Receiver` ### struct `nuclei::sync::oneshot::Sender` https://nuclei.rs/api/nuclei/sync/oneshot/struct.Sender.html ```rust pub struct Sender { /* private fields */ } ``` Sends a value to the associated [`Receiver`](https://nuclei.rs/api/nuclei/sync/oneshot/struct.Receiver.html). A [`Sender`](https://nuclei.rs/api/nuclei/sync/oneshot/struct.Sender.html) and a [`Receiver`](https://nuclei.rs/api/nuclei/sync/oneshot/struct.Receiver.html) are created together by [`channel`](https://nuclei.rs/api/nuclei/sync/oneshot/fn.channel.html). Every operation is wait-free; see the [module docs](https://nuclei.rs/api/nuclei/sync/oneshot/index.html). ```rust use nuclei::sync::oneshot; let (tx, rx) = oneshot::channel(); tx.send(3).expect("the receiver is still there"); assert_eq!(rx.blocking_recv(), Ok(3)); ``` To use a `Sender` from a destructor, put it in an [`Option`](https://doc.rust-lang.org/1.99.1/core/option/enum.Option.html) and call [`Option::take`](https://doc.rust-lang.org/1.99.1/core/option/enum.Option.html#method.take). #### Implementations `impl Sender` ```rust pub fn send(self, value: T) -> Result<(), T> ``` Attempts to send a value on this channel, returning it back if it could not be sent. This method consumes `self`, since only one value may ever be sent on a `oneshot` channel. It never waits, so it can be used in both synchronous and asynchronous code. A successful send means the other end had not hung up when the value was published; an unsuccessful one means the [`Receiver`](https://nuclei.rs/api/nuclei/sync/oneshot/struct.Receiver.html) was already closed or dropped, and the value comes back in the `Err`. `Ok` does *not* promise the value will be received: the receiver can hang up right after this returns. Wait-free: one write and one atomic read-modify-write, plus the wake of the receiver’s task. ```rust use nuclei::sync::oneshot; let (tx, rx) = oneshot::channel(); drop(rx); assert_eq!(tx.send(3), Err(3)); ``` ```rust pub async fn closed(&mut self) ``` Waits for the associated [`Receiver`](https://nuclei.rs/api/nuclei/sync/oneshot/struct.Receiver.html) to close. A receiver closes by [`Receiver::close`](https://nuclei.rs/api/nuclei/sync/oneshot/struct.Receiver.html#method.close) or by being dropped. This is useful with a select to abort a computation whose result nobody wants any more. ```rust use nuclei::sync::oneshot; use std::future::Future; use std::pin::pin; use std::task::{Context, Poll, Waker}; let (mut tx, rx) = oneshot::channel::<()>(); let mut cx = Context::from_waker(Waker::noop()); { let mut closed = pin!(tx.closed()); assert_eq!(closed.as_mut().poll(&mut cx), Poll::Pending); drop(rx); assert_eq!(closed.as_mut().poll(&mut cx), Poll::Ready(())); } ``` ```rust pub fn is_closed(&self) -> bool ``` Whether the associated [`Receiver`](https://nuclei.rs/api/nuclei/sync/oneshot/struct.Receiver.html) has closed or been dropped. When this is `true`, a call to [`send`](https://nuclei.rs/api/nuclei/sync/oneshot/struct.Sender.html#method.send) always fails. ```rust use nuclei::sync::oneshot; let (tx, rx) = oneshot::channel::(); assert!(!tx.is_closed()); drop(rx); assert!(tx.is_closed()); ``` ```rust pub fn poll_closed(&mut self, cx: &mut Context<'_>) -> Poll<()> ``` Checks whether the channel is closed and, if it is not, arranges for the waker of `cx` to be woken when it closes. Only the waker of the most recent call is kept. Returns [`Poll::Pending`](https://doc.rust-lang.org/1.99.1/core/task/poll/enum.Poll.html#variant.Pending) while the channel is open and [`Poll::Ready`](https://doc.rust-lang.org/1.99.1/core/task/poll/enum.Poll.html#variant.Ready) once the receiver closed. Wait-free. #### Trait Implementations - `impl Debug for Sender` - `impl Drop for Sender` #### Auto Trait Implementations - `impl !RefUnwindSafe for Sender` - `impl !UnwindSafe for Sender` - `impl Freeze for Sender` - `impl Send for Sender where T: Send` - `impl Sync for Sender where T: Send` - `impl Unpin for Sender` - `impl UnsafeUnpin for Sender` ### fn `nuclei::sync::oneshot::channel` https://nuclei.rs/api/nuclei/sync/oneshot/fn.channel.html ```rust pub fn channel() -> (Sender, Receiver) ``` Creates a one-shot channel for sending a single value between tasks. The [`Sender`](https://nuclei.rs/api/nuclei/sync/oneshot/struct.Sender.html) sends the value; the [`Receiver`](https://nuclei.rs/api/nuclei/sync/oneshot/struct.Receiver.html) awaits it. ```rust use nuclei::sync::oneshot; let (tx, mut rx) = oneshot::channel(); assert!(rx.try_recv().is_err()); tx.send("hello").expect("the receiver is still there"); assert_eq!(rx.try_recv(), Ok("hello")); ``` ## Module `nuclei::sync::oneshot::error` https://nuclei.rs/api/nuclei/sync/oneshot/error/index.html Error types of the one-shot channel. ### Structs - [RecvError](https://nuclei.rs/api/nuclei/sync/oneshot/error/struct.RecvError.html): Error returned by the `Future` implementation of [`Receiver`](https://nuclei.rs/api/nuclei/sync/oneshot/struct.Receiver.html). ### Enums - [TryRecvError](https://nuclei.rs/api/nuclei/sync/oneshot/error/enum.TryRecvError.html): Error returned by [`Receiver::try_recv`](https://nuclei.rs/api/nuclei/sync/oneshot/struct.Receiver.html#method.try_recv). ### struct `nuclei::sync::oneshot::error::RecvError` https://nuclei.rs/api/nuclei/sync/oneshot/error/struct.RecvError.html ```rust pub struct RecvError(/* private fields */); ``` Error returned by the `Future` implementation of [`Receiver`](https://nuclei.rs/api/nuclei/sync/oneshot/struct.Receiver.html). The receiver gets it when the sender is dropped without sending, or when the receiver was closed with nothing sent. #### Trait Implementations - `impl Clone for RecvError` - `impl Debug for RecvError` - `impl Display for RecvError` - `impl Eq for RecvError` - `impl Error for RecvError` - `impl PartialEq for RecvError` - `impl StructuralPartialEq for RecvError` #### Auto Trait Implementations - `impl Freeze for RecvError` - `impl RefUnwindSafe for RecvError` - `impl Send for RecvError` - `impl Sync for RecvError` - `impl Unpin for RecvError` - `impl UnsafeUnpin for RecvError` - `impl UnwindSafe for RecvError` ### enum `nuclei::sync::oneshot::error::TryRecvError` https://nuclei.rs/api/nuclei/sync/oneshot/error/enum.TryRecvError.html ```rust pub enum TryRecvError { Empty, Closed, } ``` Error returned by [`Receiver::try_recv`](https://nuclei.rs/api/nuclei/sync/oneshot/struct.Receiver.html#method.try_recv). #### Variants ```rust Empty ``` The send half of the channel has not yet sent a value. ```rust Closed ``` The send half of the channel was dropped without sending a value, or the value has already been received. #### Trait Implementations - `impl Clone for TryRecvError` - `impl Debug for TryRecvError` - `impl Display for TryRecvError` - `impl Eq for TryRecvError` - `impl Error for TryRecvError` - `impl PartialEq for TryRecvError` - `impl StructuralPartialEq for TryRecvError` #### Auto Trait Implementations - `impl Freeze for TryRecvError` - `impl RefUnwindSafe for TryRecvError` - `impl Send for TryRecvError` - `impl Sync for TryRecvError` - `impl Unpin for TryRecvError` - `impl UnsafeUnpin for TryRecvError` - `impl UnwindSafe for TryRecvError` ## Module `nuclei::sync::watch` https://nuclei.rs/api/nuclei/sync/watch/index.html A multi-producer, multi-consumer channel that retains only the *last* sent value. [`channel`](https://nuclei.rs/api/nuclei/sync/watch/fn.channel.html) returns a [`Sender`](https://nuclei.rs/api/nuclei/sync/watch/struct.Sender.html) and a [`Receiver`](https://nuclei.rs/api/nuclei/sync/watch/struct.Receiver.html) around an initial value. Each [`Receiver`](https://nuclei.rs/api/nuclei/sync/watch/struct.Receiver.html) tracks the last value *seen* by its own caller. The API is the established async watch-channel API; nothing here needs a runtime. - [`Receiver::borrow_and_update`](https://nuclei.rs/api/nuclei/sync/watch/struct.Receiver.html#method.borrow_and_update) returns the current value and marks it seen. [`Receiver::borrow`](https://nuclei.rs/api/nuclei/sync/watch/struct.Receiver.html#method.borrow) returns it without marking it seen. - [`Receiver::changed`](https://nuclei.rs/api/nuclei/sync/watch/struct.Receiver.html#method.changed) completes when a value the receiver has not seen is in the channel, and marks it seen. At creation the initial value is seen, and a receiver made by [`Sender::subscribe`](https://nuclei.rs/api/nuclei/sync/watch/struct.Sender.html#method.subscribe) sees the value that was current at that moment as seen. - [`Receiver::has_changed`](https://nuclei.rs/api/nuclei/sync/watch/struct.Receiver.html#method.has_changed) is the synchronous check; it errors if and only if the channel is closed, while `changed` errors only when the channel is closed *and* the current value is seen. - [`Sender::is_closed`](https://nuclei.rs/api/nuclei/sync/watch/struct.Sender.html#method.is_closed) and [`Sender::closed`](https://nuclei.rs/api/nuclei/sync/watch/struct.Sender.html#method.closed) tell the producer that every [`Receiver`](https://nuclei.rs/api/nuclei/sync/watch/struct.Receiver.html) is gone. The value is dropped when every sender and every receiver is gone. ```rust use nuclei::sync::watch; let (tx, mut rx) = watch::channel("hello"); assert_eq!(*rx.borrow_and_update(), "hello"); assert!(!rx.has_changed().unwrap()); tx.send("world").unwrap(); assert!(rx.has_changed().unwrap()); assert_eq!(*rx.borrow_and_update(), "world"); ``` **The value lives in an `Atom`** Where a lock-based channel guards the value with a read-write lock, this one keeps it in an [`Atom`](https://nuclei.rs/api/nuclei/sync/struct.Atom.html). A send publishes a new allocation with one swap; a borrow is one protected load and never blocks a sender, and a sender never blocks a borrow. Two consequences follow, and both differ from the lock-based API: - The channel needs `T: Send + Sync + 'static`: values are shared by reference between threads and reclaimed later. - A [`Ref`](https://nuclei.rs/api/nuclei/sync/watch/struct.Ref.html) does not hold a lock but a reclamation guard. A value that was replaced stays allocated until every `Ref` that can see it is dropped, so keep a `Ref` short. It is `!Send`: it must be dropped on the thread that took it, and the compiler therefore refuses to hold one across an await in a task that may move threads. - The old value cannot be handed back by value while readers may still look at it, so [`Sender::send_replace`](https://nuclei.rs/api/nuclei/sync/watch/struct.Sender.html#method.send_replace) returns a *clone* (`T: Clone`), and the two in-place modifiers, [`Sender::send_modify`](https://nuclei.rs/api/nuclei/sync/watch/struct.Sender.html#method.send_modify) and [`Sender::send_if_modified`](https://nuclei.rs/api/nuclei/sync/watch/struct.Sender.html#method.send_if_modified), work on a clone too: they copy the value, let the closure change the copy and publish it with a compare-and-swap, retrying on a racing sender. Their closures are `FnMut` and may run more than once. A closure that panics, or that returns `false` from `send_if_modified`, publishes nothing, and the channel keeps the value it had. **Progress** - Wait-free (a bounded number of the caller’s own steps whatever other threads do): [`Receiver::borrow`](https://nuclei.rs/api/nuclei/sync/watch/struct.Receiver.html#method.borrow), [`Receiver::borrow_and_update`](https://nuclei.rs/api/nuclei/sync/watch/struct.Receiver.html#method.borrow_and_update), [`Receiver::has_changed`](https://nuclei.rs/api/nuclei/sync/watch/struct.Receiver.html#method.has_changed), [`Receiver::is_closed`](https://nuclei.rs/api/nuclei/sync/watch/struct.Receiver.html#method.is_closed), [`Receiver::mark_changed`](https://nuclei.rs/api/nuclei/sync/watch/struct.Receiver.html#method.mark_changed), [`Receiver::mark_unchanged`](https://nuclei.rs/api/nuclei/sync/watch/struct.Receiver.html#method.mark_unchanged), [`Sender::borrow`](https://nuclei.rs/api/nuclei/sync/watch/struct.Sender.html#method.borrow), [`Sender::is_closed`](https://nuclei.rs/api/nuclei/sync/watch/struct.Sender.html#method.is_closed), [`Sender::subscribe`](https://nuclei.rs/api/nuclei/sync/watch/struct.Sender.html#method.subscribe), [`Sender::receiver_count`](https://nuclei.rs/api/nuclei/sync/watch/struct.Sender.html#method.receiver_count), [`Sender::sender_count`](https://nuclei.rs/api/nuclei/sync/watch/struct.Sender.html#method.sender_count), both `same_channel` checks, the clones, and dropping a [`Ref`](https://nuclei.rs/api/nuclei/sync/watch/struct.Ref.html). A borrow is an `Atom` load, which is wait-free. - The *publication* of [`Sender::send`](https://nuclei.rs/api/nuclei/sync/watch/struct.Sender.html#method.send) and [`Sender::send_replace`](https://nuclei.rs/api/nuclei/sync/watch/struct.Sender.html#method.send_replace) (the swap and the version bump) is wait-free, but each ends by waking the waiting receivers through [`Notify::notify_waiters`](https://nuclei.rs/api/nuclei/sync/struct.Notify.html), which is lock-free: it takes the queue’s drain role with a compare-and-swap, or leaves a mark for the thread that holds it, and a pass may serve waiters other threads queue meanwhile. So `send` and `send_replace` are lock-free, not wait-free. So is dropping the last sender or the last receiver, for the same wake. - [`Sender::send_modify`](https://nuclei.rs/api/nuclei/sync/watch/struct.Sender.html#method.send_modify) and [`Sender::send_if_modified`](https://nuclei.rs/api/nuclei/sync/watch/struct.Sender.html#method.send_if_modified) are lock-free: they retry the compare-and-swap whenever another sender published first, so a call can be delayed without bound by other senders’ progress, and each retry runs the closure again. - Polling [`Receiver::changed`](https://nuclei.rs/api/nuclei/sync/watch/struct.Receiver.html#method.changed), [`Receiver::wait_for`](https://nuclei.rs/api/nuclei/sync/watch/struct.Receiver.html#method.wait_for) and [`Sender::closed`](https://nuclei.rs/api/nuclei/sync/watch/struct.Sender.html#method.closed) is lock-free: a poll may queue a waiter, which is a lock-free queue operation. ### Modules - [error](https://nuclei.rs/api/nuclei/sync/watch/error/index.html): Error types of the watch channel. ### Structs - [Receiver](https://nuclei.rs/api/nuclei/sync/watch/struct.Receiver.html): Receives values from the associated [`Sender`](https://nuclei.rs/api/nuclei/sync/watch/struct.Sender.html)s. - [Ref](https://nuclei.rs/api/nuclei/sync/watch/struct.Ref.html): A reference to the value inside the channel. - [Sender](https://nuclei.rs/api/nuclei/sync/watch/struct.Sender.html): Sends values to the associated [`Receiver`](https://nuclei.rs/api/nuclei/sync/watch/struct.Receiver.html)s. ### Functions - [channel](https://nuclei.rs/api/nuclei/sync/watch/fn.channel.html): Creates a new watch channel around `init`, returning the send and receive handles. ### struct `nuclei::sync::watch::Receiver` https://nuclei.rs/api/nuclei/sync/watch/struct.Receiver.html ```rust pub struct Receiver { /* private fields */ } ``` Receives values from the associated [`Sender`](https://nuclei.rs/api/nuclei/sync/watch/struct.Sender.html)s. Created by [`channel`](https://nuclei.rs/api/nuclei/sync/watch/fn.channel.html) or [`Sender::subscribe`](https://nuclei.rs/api/nuclei/sync/watch/struct.Sender.html#method.subscribe); clone it for more consumers, each with its own record of what it has seen. Requires `T: Send + Sync + 'static`, see the [module docs](https://nuclei.rs/api/nuclei/sync/watch/index.html). #### Implementations `impl Receiver` ```rust pub fn borrow(&self) -> Ref<'_, T> ``` Returns a reference to the most recently sent value. Does not mark the value seen, so a later [`changed`](https://nuclei.rs/api/nuclei/sync/watch/struct.Receiver.html#method.changed) can return at once even though you have read it. If you wait for changes in a loop, prefer [`borrow_and_update`](https://nuclei.rs/api/nuclei/sync/watch/struct.Receiver.html#method.borrow_and_update). Wait-free, and it never blocks a sender. A borrow keeps the value it points to alive; keep it short and drop it before awaiting. ```rust use nuclei::sync::watch; let (_tx, rx) = watch::channel("hello"); assert_eq!(*rx.borrow(), "hello"); ``` ```rust pub fn borrow_and_update(&mut self) -> Ref<'_, T> ``` Returns a reference to the most recently sent value and marks it seen. Later calls to [`changed`](https://nuclei.rs/api/nuclei/sync/watch/struct.Receiver.html#method.changed) do not return until a value newer than this one is sent. Wait-free; see [`borrow`](https://nuclei.rs/api/nuclei/sync/watch/struct.Receiver.html#method.borrow) for the advice on holding the reference. ```rust use nuclei::sync::watch; let (tx, mut rx) = watch::channel("hello"); tx.send("goodbye").unwrap(); assert_eq!(*rx.borrow_and_update(), "goodbye"); assert!(!rx.has_changed().unwrap()); ``` ```rust pub fn has_changed(&self) -> Result ``` Checks whether the channel holds a value this receiver has not seen. The value is not marked seen. It does not compare values: the same value sent twice counts as a change. **Errors** Returns a [`RecvError`](https://nuclei.rs/api/nuclei/sync/watch/error/struct.RecvError.html) if and only if the channel is closed. ```rust use nuclei::sync::watch; let (tx, mut rx) = watch::channel("hello"); tx.send("goodbye").unwrap(); assert!(rx.has_changed().unwrap()); assert_eq!(*rx.borrow_and_update(), "goodbye"); assert!(!rx.has_changed().unwrap()); drop(tx); assert!(rx.has_changed().is_err()); ``` ```rust pub fn is_closed(&self) -> bool ``` Whether the channel is closed: every [`Sender`](https://nuclei.rs/api/nuclei/sync/watch/struct.Sender.html) has been dropped. ```rust use nuclei::sync::watch; let (tx, rx) = watch::channel(()); assert!(!rx.is_closed()); drop(tx); assert!(rx.is_closed()); ``` ```rust pub fn mark_changed(&mut self) ``` Marks the current value as not seen. Afterwards [`has_changed`](https://nuclei.rs/api/nuclei/sync/watch/struct.Receiver.html#method.has_changed) is `true` and [`changed`](https://nuclei.rs/api/nuclei/sync/watch/struct.Receiver.html#method.changed) returns at once, whether or not a new value is sent. Useful to trigger a first notification after subscribing. ```rust pub fn mark_unchanged(&mut self) ``` Marks the current value as seen, without reading it. ```rust pub async fn changed(&mut self) -> Result<(), RecvError> ``` Waits for a change notification, then marks the current value as seen. If the current value has not been seen yet, this marks it seen and returns at once. Otherwise it waits until a sender sends a new value or the last sender is dropped. **Errors** Returns a [`RecvError`](https://nuclei.rs/api/nuclei/sync/watch/error/struct.RecvError.html) if the channel is closed *and* the current value is seen. **Cancel safety** Cancel safe: if the future is dropped before it completes, no value was marked seen by it. ```rust use nuclei::sync::watch; use std::future::Future; use std::pin::pin; use std::task::{Context, Poll, Waker}; let (tx, mut rx) = watch::channel("hello"); let mut cx = Context::from_waker(Waker::noop()); let mut changed = pin!(rx.changed()); assert!(changed.as_mut().poll(&mut cx).is_pending()); tx.send("goodbye").unwrap(); assert!(matches!(changed.as_mut().poll(&mut cx), Poll::Ready(Ok(())))); ``` ```rust pub async fn wait_for( &mut self, f: impl FnMut(&T) -> bool, ) -> Result, RecvError> ``` Waits for a value that satisfies `f`. Calls `f` on the current value first, even if it is already seen, and then on the newest value whenever something is sent. When `f` returns `true`, returns a reference to that value and marks it seen. The channel keeps only the latest value, so a burst of sends can skip values: `f` always sees the newest. **Errors** Returns a [`RecvError`](https://nuclei.rs/api/nuclei/sync/watch/error/struct.RecvError.html) if the channel is closed. Then `f` has been called on the last value and returned `false` for it. **Cancel safety** Cancel safe: the last value `f` returned `true` for is never marked seen by a dropped call. **Panics** If and only if `f` panics. Nothing the receiver shares is poisoned. ```rust use nuclei::sync::watch; use std::future::Future; use std::pin::pin; use std::task::{Context, Poll, Waker}; let (tx, mut rx) = watch::channel(0); let mut cx = Context::from_waker(Waker::noop()); let mut wait = pin!(rx.wait_for(|v| *v == 2)); assert!(wait.as_mut().poll(&mut cx).is_pending()); tx.send(1).unwrap(); assert!(wait.as_mut().poll(&mut cx).is_pending()); tx.send(2).unwrap(); match wait.as_mut().poll(&mut cx) { Poll::Ready(Ok(value)) => assert_eq!(*value, 2), _ => panic!("the value 2 was sent"), } ``` ```rust pub fn same_channel(&self, other: &Self) -> bool ``` Whether the two receivers belong to the same channel. ```rust use nuclei::sync::watch; let (_tx, rx) = watch::channel(true); let rx2 = rx.clone(); assert!(rx.same_channel(&rx2)); let (_tx3, rx3) = watch::channel(true); assert!(!rx3.same_channel(&rx2)); ``` #### Trait Implementations - `impl Clone for Receiver` - `impl Debug for Receiver` - `impl Drop for Receiver` #### Auto Trait Implementations - `impl !RefUnwindSafe for Receiver` - `impl !UnwindSafe for Receiver` - `impl Freeze for Receiver` - `impl Send for Receiver` - `impl Sync for Receiver` - `impl Unpin for Receiver` - `impl UnsafeUnpin for Receiver` ### struct `nuclei::sync::watch::Ref` https://nuclei.rs/api/nuclei/sync/watch/struct.Ref.html ```rust pub struct Ref<'a, T: Send + Sync + 'static> { /* private fields */ } ``` A reference to the value inside the channel. Unlike a lock guard, a `Ref` never blocks a sender. It keeps the value it points to, and every value replaced since, allocated until it is dropped, so keep it short. It must be dropped on the thread that took it: it is not `Send`. #### Implementations `impl Ref<'_, T>` ```rust pub fn has_changed(&self) -> bool ``` Whether the borrowed value is considered *changed* since it was last marked seen. Unlike [`Receiver::has_changed`](https://nuclei.rs/api/nuclei/sync/watch/struct.Receiver.html#method.has_changed), this does not fail when the channel is closed. For a borrow taken from the [`Sender`](https://nuclei.rs/api/nuclei/sync/watch/struct.Sender.html) it is always `false`. ```rust use nuclei::sync::watch; let (tx, mut rx) = watch::channel("hello"); tx.send("goodbye").unwrap(); assert!(!tx.borrow().has_changed()); drop(tx); assert!(rx.borrow().has_changed()); assert!(rx.borrow_and_update().has_changed()); assert!(!rx.borrow().has_changed()); ``` #### Trait Implementations - `impl Debug for Ref<'_, T>` - `impl Deref for Ref<'_, T>` - `impl Sync for Ref<'_, T>` #### Auto Trait Implementations - `impl<'a, T> !Send for Ref<'a, T>` - `impl<'a, T> Freeze for Ref<'a, T>` - `impl<'a, T> RefUnwindSafe for Ref<'a, T> where T: RefUnwindSafe` - `impl<'a, T> Unpin for Ref<'a, T>` - `impl<'a, T> UnsafeUnpin for Ref<'a, T>` - `impl<'a, T> UnwindSafe for Ref<'a, T> where T: RefUnwindSafe` ### struct `nuclei::sync::watch::Sender` https://nuclei.rs/api/nuclei/sync/watch/struct.Sender.html ```rust pub struct Sender { /* private fields */ } ``` Sends values to the associated [`Receiver`](https://nuclei.rs/api/nuclei/sync/watch/struct.Receiver.html)s. Created by [`channel`](https://nuclei.rs/api/nuclei/sync/watch/fn.channel.html). Clone it for more producers. The channel closes for the receivers when the last sender is dropped. Requires `T: Send + Sync + 'static`, see the [module docs](https://nuclei.rs/api/nuclei/sync/watch/index.html). #### Implementations `impl Sender` ```rust pub fn new(init: T) -> Self ``` Creates the sending half of a channel with no receiver yet. Sending fails until [`subscribe`](https://nuclei.rs/api/nuclei/sync/watch/struct.Sender.html#method.subscribe) creates one. ```rust use nuclei::sync::watch::Sender; let sender = Sender::new(0u8); assert!(sender.send(3).is_err()); let _rx = sender.subscribe(); assert!(sender.send(4).is_ok()); ``` ```rust pub fn send(&self, value: T) -> Result<(), SendError> ``` Sends a new value, notifying all receivers. Fails if every receiver is gone; the value comes back in the error and is not kept for receivers that [`subscribe`](https://nuclei.rs/api/nuclei/sync/watch/struct.Sender.html#method.subscribe) later. To always make a value available, even with no receiver, use [`send_replace`](https://nuclei.rs/api/nuclei/sync/watch/struct.Sender.html#method.send_replace), [`send_modify`](https://nuclei.rs/api/nuclei/sync/watch/struct.Sender.html#method.send_modify) or [`send_if_modified`](https://nuclei.rs/api/nuclei/sync/watch/struct.Sender.html#method.send_if_modified). The publication is wait-free; the wake of the receivers makes the whole call lock-free (see the [module docs](https://nuclei.rs/api/nuclei/sync/watch/index.html)). ```rust use nuclei::sync::watch; let (tx, rx) = watch::channel(1); tx.send(2).unwrap(); assert_eq!(*rx.borrow(), 2); drop(rx); assert_eq!(tx.send(3).unwrap_err().0, 3); ``` ```rust pub fn send_modify(&self, modify: F) where F: FnMut(&mut T), T: Clone ``` Modifies the watched value **unconditionally**, notifying all receivers. Also works with no receiver. `modify` runs on a clone of the current value, and the clone is published by a compare-and-swap; if another sender published first, `modify` runs again on the new value, so it is `FnMut`. Prefer [`send_if_modified`](https://nuclei.rs/api/nuclei/sync/watch/struct.Sender.html#method.send_if_modified) when the value is only sometimes changed. Lock-free: it retries against other senders. **Panics** Panics if `modify` (or the clone) panics. Nothing is published then and no receiver is notified: the channel keeps the value it had. ```rust use nuclei::sync::watch; #[derive(Clone)] struct State { counter: usize, } let (tx, rx) = watch::channel(State { counter: 0 }); tx.send_modify(|state| state.counter += 1); assert_eq!(rx.borrow().counter, 1); ``` ```rust pub fn send_if_modified(&self, modify: F) -> bool where F: FnMut(&mut T) -> bool, T: Clone ``` Modifies the watched value **conditionally**, notifying all receivers only if it was modified. `modify` runs on a clone of the current value and returns `true` if it changed it. Only then is the clone published, by a compare-and-swap that starts over on the new value when another sender published first (so `modify` is `FnMut` and may run more than once). When it returns `false` nothing is published, whatever it did to its copy: unlike a lock-based channel there is no silent modification. Returns `true` if a new value was published and `false` if `modify` returned `false`. Lock-free: it retries against other senders. **Panics** Panics if `modify` (or the clone) panics. Nothing is published then. ```rust use nuclei::sync::watch; let (tx, mut rx) = watch::channel(1u32); let inc_if_odd = |n: &mut u32| { if *n % 2 == 1 { *n += 1; return true; } false }; assert!(tx.send_if_modified(inc_if_odd)); assert_eq!(*rx.borrow_and_update(), 2); assert!(!tx.send_if_modified(inc_if_odd)); assert!(!rx.has_changed().unwrap()); ``` ```rust pub fn send_replace(&self, value: T) -> T where T: Clone ``` Sends a new value, notifying all receivers, and returns a clone of the value it replaced. Also works with no receiver. The old value is returned as a clone because receivers may still be reading it; see the [module docs](https://nuclei.rs/api/nuclei/sync/watch/index.html). The publication is wait-free; the wake of the receivers makes the whole call lock-free. ```rust use nuclei::sync::watch; let (tx, _rx) = watch::channel(1); assert_eq!(tx.send_replace(2), 1); assert_eq!(tx.send_replace(3), 2); ``` ```rust pub fn borrow(&self) -> Ref<'_, T> ``` Returns a reference to the most recently sent value. A borrow from the sender is never marked changed. See [`Receiver::borrow`](https://nuclei.rs/api/nuclei/sync/watch/struct.Receiver.html#method.borrow) for the advice on holding the reference. ```rust use nuclei::sync::watch; let (tx, _) = watch::channel("hello"); assert_eq!(*tx.borrow(), "hello"); ``` ```rust pub fn is_closed(&self) -> bool ``` Whether the channel is closed for sending: every [`Receiver`](https://nuclei.rs/api/nuclei/sync/watch/struct.Receiver.html) has been dropped. [`subscribe`](https://nuclei.rs/api/nuclei/sync/watch/struct.Sender.html#method.subscribe) reopens it. ```rust use nuclei::sync::watch; let (tx, rx) = watch::channel(()); assert!(!tx.is_closed()); drop(rx); assert!(tx.is_closed()); ``` ```rust pub async fn closed(&self) ``` Completes when every receiver has been dropped. Lets the producer stop work nobody wants. If the channel closes briefly (the last receiver is dropped and [`subscribe`](https://nuclei.rs/api/nuclei/sync/watch/struct.Sender.html#method.subscribe) is called again), this may or may not notice. **Cancel safety** Cancel safe. ```rust use nuclei::sync::watch; use std::future::Future; use std::pin::pin; use std::task::{Context, Poll, Waker}; let (tx, rx) = watch::channel("hello"); let mut cx = Context::from_waker(Waker::noop()); let mut closed = pin!(tx.closed()); assert_eq!(closed.as_mut().poll(&mut cx), Poll::Pending); drop(rx); assert_eq!(closed.as_mut().poll(&mut cx), Poll::Ready(())); ``` ```rust pub fn subscribe(&self) -> Receiver ``` Creates a new [`Receiver`](https://nuclei.rs/api/nuclei/sync/watch/struct.Receiver.html) connected to this sender. The value that is current now counts as seen by the new receiver. It works with no other receiver, which reopens the channel. ```rust use nuclei::sync::watch; let (tx, _rx) = watch::channel(0u64); tx.send(5).unwrap(); let rx = tx.subscribe(); assert_eq!(*rx.borrow(), 5); assert!(!rx.has_changed().unwrap()); ``` ```rust pub fn receiver_count(&self) -> usize ``` How many receivers exist now. ```rust use nuclei::sync::watch; let (tx, rx) = watch::channel("hello"); assert_eq!(tx.receiver_count(), 1); let _rx2 = rx.clone(); assert_eq!(tx.receiver_count(), 2); ``` ```rust pub fn sender_count(&self) -> usize ``` How many senders exist now. ```rust use nuclei::sync::watch; let (tx, _rx) = watch::channel("hello"); assert_eq!(tx.sender_count(), 1); let tx2 = tx.clone(); assert_eq!(tx2.sender_count(), 2); ``` ```rust pub fn same_channel(&self, other: &Self) -> bool ``` Whether the two senders belong to the same channel. ```rust use nuclei::sync::watch; let (tx, _rx) = watch::channel(true); let tx2 = tx.clone(); assert!(tx.same_channel(&tx2)); let (tx3, _rx3) = watch::channel(true); assert!(!tx3.same_channel(&tx2)); ``` #### Trait Implementations - `impl Clone for Sender` - `impl Debug for Sender` - `impl Default for Sender` - `impl Drop for Sender` #### Auto Trait Implementations - `impl !RefUnwindSafe for Sender` - `impl !UnwindSafe for Sender` - `impl Freeze for Sender` - `impl Send for Sender` - `impl Sync for Sender` - `impl Unpin for Sender` - `impl UnsafeUnpin for Sender` ### fn `nuclei::sync::watch::channel` https://nuclei.rs/api/nuclei/sync/watch/fn.channel.html ```rust pub fn channel(init: T) -> (Sender, Receiver) ``` Creates a new watch channel around `init`, returning the send and receive handles. All values sent by the [`Sender`](https://nuclei.rs/api/nuclei/sync/watch/struct.Sender.html) become visible to the [`Receiver`](https://nuclei.rs/api/nuclei/sync/watch/struct.Receiver.html) handles; only the last value sent is kept, and the ones before it are dropped. The initial value counts as seen by the first receiver. ```rust use nuclei::sync::watch; let (tx, rx) = watch::channel(0u32); tx.send(1).unwrap(); assert_eq!(*rx.borrow(), 1); ``` ## Module `nuclei::sync::watch::error` https://nuclei.rs/api/nuclei/sync/watch/error/index.html Error types of the watch channel. ### Structs - [RecvError](https://nuclei.rs/api/nuclei/sync/watch/error/struct.RecvError.html): Error produced when receiving a change notification: every sender is gone. - [SendError](https://nuclei.rs/api/nuclei/sync/watch/error/struct.SendError.html): Error produced when sending a value fails: every receiver is gone. ### struct `nuclei::sync::watch::error::RecvError` https://nuclei.rs/api/nuclei/sync/watch/error/struct.RecvError.html ```rust pub struct RecvError(/* private fields */); ``` Error produced when receiving a change notification: every sender is gone. #### Trait Implementations - `impl Clone for RecvError` - `impl Debug for RecvError` - `impl Display for RecvError` - `impl Error for RecvError` #### Auto Trait Implementations - `impl Freeze for RecvError` - `impl RefUnwindSafe for RecvError` - `impl Send for RecvError` - `impl Sync for RecvError` - `impl Unpin for RecvError` - `impl UnsafeUnpin for RecvError` - `impl UnwindSafe for RecvError` ### struct `nuclei::sync::watch::error::SendError` https://nuclei.rs/api/nuclei/sync/watch/error/struct.SendError.html ```rust pub struct SendError(pub T); ``` Error produced when sending a value fails: every receiver is gone. The value is handed back in the error. #### Tuple Fields `0: T` #### Trait Implementations - `impl Clone for SendError` - `impl Copy for SendError` - `impl Debug for SendError` - `impl Display for SendError` - `impl Eq for SendError` - `impl Error for SendError` - `impl PartialEq for SendError` - `impl StructuralPartialEq for SendError` #### Auto Trait Implementations - `impl Freeze for SendError where T: Freeze` - `impl RefUnwindSafe for SendError where T: RefUnwindSafe` - `impl Send for SendError where T: Send` - `impl Sync for SendError where T: Sync` - `impl Unpin for SendError where T: Unpin` - `impl UnsafeUnpin for SendError where T: UnsafeUnpin` - `impl UnwindSafe for SendError where T: UnwindSafe` ## Module `nuclei::task` https://nuclei.rs/api/nuclei/task/index.html Tasks: spawning, their handles and ids, cancellation from anywhere, and yielding. Tasks: spawning (named, or on a worker the caller names, or neither), their handles and ids, cancellation from anywhere, and yielding to the other tasks of the shard. ### Re-exports - `pub use crate::runtime::spawn;` - `pub use crate::runtime::spawn_blocking;` - `pub use crate::runtime::spawn_local;` ### Modules - [coop](https://nuclei.rs/api/nuclei/task/coop/index.html): Cooperative scheduling: the budget of operations each poll of a task may complete before it yields to the other tasks of its shard. IO that completes spends one, and so do the receives, acquires and locks of [`sync`](https://nuclei.rs/api/nuclei/sync/index.html) that complete without queueing (see its module docs). ### Structs - [AbortHandle](https://nuclei.rs/api/nuclei/task/struct.AbortHandle.html): Cancels a task from anywhere: made by [`Task::abort_handle`](https://nuclei.rs/api/nuclei/runtime/struct.Task.html#method.abort_handle), cloned and sent freely, and it outlives the [`Task`](https://nuclei.rs/api/nuclei/runtime/struct.Task.html). It keeps the task’s memory, not its future: an aborted task’s future is dropped where the task runs. - [AccessError](https://nuclei.rs/api/nuclei/task/struct.AccessError.html): The key was read where no scope set it. - [Builder](https://nuclei.rs/api/nuclei/task/struct.Builder.html): Spawns tasks with options: a name, kept with the task’s id while the task lives and shown to the runtime’s task hooks ([`TaskMeta::name`](https://nuclei.rs/api/nuclei/runtime/struct.TaskMeta.html#method.name)), and the worker to place it on. Every spawn answers an error where the free functions panic. - [FallibleTask](https://nuclei.rs/api/nuclei/task/struct.FallibleTask.html): A spawned task whose output is `None` when the task ended without one. - [Id](https://nuclei.rs/api/nuclei/task/struct.Id.html): A task’s id: unique among the tasks of the process, never reused. - [Join](https://nuclei.rs/api/nuclei/task/struct.Join.html): The future of [`Task::join`](https://nuclei.rs/api/nuclei/runtime/struct.Task.html#method.join): the task’s output, or why there is none. - [JoinError](https://nuclei.rs/api/nuclei/task/struct.JoinError.html): Why a task gave no output: it was cancelled (by its handle, an [`AbortHandle`](https://nuclei.rs/api/nuclei/task/struct.AbortHandle.html), or its runtime shutting down), or its future panicked. - [JoinSet](https://nuclei.rs/api/nuclei/task/struct.JoinSet.html): A set of spawned tasks, joined in the order they finish. - [LocalKey](https://nuclei.rs/api/nuclei/task/struct.LocalKey.html): A task-local key, declared with [`task_local!`](https://nuclei.rs/api/nuclei/macro.task_local.html). - [Task](https://nuclei.rs/api/nuclei/task/struct.Task.html): A spawned task. - [TaskLocalFuture](https://nuclei.rs/api/nuclei/task/struct.TaskLocalFuture.html): The future of [`LocalKey::scope`](https://nuclei.rs/api/nuclei/task/struct.LocalKey.html#method.scope). ### Functions - [id](https://nuclei.rs/api/nuclei/task/fn.id.html): The id of the task this code runs in. - [try_id](https://nuclei.rs/api/nuclei/task/fn.try_id.html): The id of the task this code runs in, `None` outside a task (in `block_on`’s own future, or on a blocking-pool thread). - [yield_now](https://nuclei.rs/api/nuclei/task/fn.yield_now.html): Gives the other tasks of this shard a turn: the task goes to the back of its shard’s run queue and runs again after the tasks queued before it. In `block_on`’s own future it lets the shard run its queue once. ### struct `nuclei::task::AbortHandle` https://nuclei.rs/api/nuclei/task/struct.AbortHandle.html ```rust pub struct AbortHandle { /* private fields */ } ``` Cancels a task from anywhere: made by [`Task::abort_handle`](https://nuclei.rs/api/nuclei/runtime/struct.Task.html#method.abort_handle), cloned and sent freely, and it outlives the [`Task`](https://nuclei.rs/api/nuclei/runtime/struct.Task.html). It keeps the task’s memory, not its future: an aborted task’s future is dropped where the task runs. #### Implementations `impl AbortHandle` ```rust pub fn abort(&self) ``` Cancels the task unless it completed; see [`Task::abort`](https://nuclei.rs/api/nuclei/runtime/struct.Task.html#method.abort). ```rust pub fn is_finished(&self) -> bool ``` Whether the task completed or was cancelled. ```rust pub fn id(&self) -> Id ``` The task’s id. #### Trait Implementations - `impl Clone for AbortHandle` - `impl Debug for AbortHandle` #### Auto Trait Implementations - `impl Freeze for AbortHandle` - `impl RefUnwindSafe for AbortHandle` - `impl Send for AbortHandle` - `impl Sync for AbortHandle` - `impl Unpin for AbortHandle` - `impl UnsafeUnpin for AbortHandle` - `impl UnwindSafe for AbortHandle` ### struct `nuclei::task::AccessError` https://nuclei.rs/api/nuclei/task/struct.AccessError.html ```rust pub struct AccessError { /* private fields */ } ``` The key was read where no scope set it. #### Trait Implementations - `impl Clone for AccessError` - `impl Copy for AccessError` - `impl Debug for AccessError` - `impl Display for AccessError` - `impl Eq for AccessError` - `impl Error for AccessError` - `impl PartialEq for AccessError` - `impl StructuralPartialEq for AccessError` #### Auto Trait Implementations - `impl Freeze for AccessError` - `impl RefUnwindSafe for AccessError` - `impl Send for AccessError` - `impl Sync for AccessError` - `impl Unpin for AccessError` - `impl UnsafeUnpin for AccessError` - `impl UnwindSafe for AccessError` ### struct `nuclei::task::Builder` https://nuclei.rs/api/nuclei/task/struct.Builder.html ```rust pub struct Builder<'a> { /* private fields */ } ``` Spawns tasks with options: a name, kept with the task’s id while the task lives and shown to the runtime’s task hooks ([`TaskMeta::name`](https://nuclei.rs/api/nuclei/runtime/struct.TaskMeta.html#method.name)), and the worker to place it on. Every spawn answers an error where the free functions panic. ```rust let task = nuclei::task::Builder::new().name("fetch").spawn(async { 7 })?; assert_eq!(task.await, 7); ``` #### Implementations `impl<'a> Builder<'a>` ```rust pub fn new() -> Self ``` A builder with no option set. ```rust pub fn name(self, name: &'a str) -> Self ``` Names the task. ```rust pub fn worker(self, worker: usize) -> Self ``` Places the task on worker `worker` of its runtime, where it stays, as [`RuntimeHandle::spawn_on_worker`](https://nuclei.rs/api/nuclei/runtime/struct.RuntimeHandle.html#method.spawn_on_worker) does. A [`spawn_local`](https://nuclei.rs/api/nuclei/task/struct.Builder.html#method.spawn_local) then needs to run on that worker, and a [`spawn_blocking`](https://nuclei.rs/api/nuclei/task/struct.Builder.html#method.spawn_blocking) is refused: the blocking pool runs no worker. ```rust pub fn spawn(self, future: F) -> Result> where F: Future + Send + 'static, F::Output: Send + 'static ``` Spawns as [`spawn`](https://nuclei.rs/api/nuclei/runtime/fn.spawn.html) does, on the named worker if one is set. **Errors** When the default runtime or this thread’s shard cannot start, and `InvalidInput` when the named worker does not exist or takes no new task. ```rust pub fn spawn_local(self, future: F) -> Result> where F: Future + 'static, F::Output: 'static ``` Spawns as [`spawn_local`](https://nuclei.rs/api/nuclei/runtime/fn.spawn_local.html) does. **Errors** When this thread’s shard cannot start, and `InvalidInput` when a worker is named that this thread does not run: a future that is not `Send` cannot go to another thread. ```rust pub fn spawn_blocking(self, f: F) -> Result> where F: FnOnce() -> T + Send + 'static, T: Send + 'static ``` Runs `f` on the blocking pool as [`spawn_blocking`](https://nuclei.rs/api/nuclei/runtime/fn.spawn_blocking.html) does. **Errors** When the default runtime cannot start, and `InvalidInput` when a worker is named. ```rust pub fn spawn_on( self, future: F, handle: &RuntimeHandle, ) -> Result> where F: Future + Send + 'static, F::Output: Send + 'static ``` Spawns on the runtime `handle` refers to, as [`RuntimeHandle::spawn`](https://nuclei.rs/api/nuclei/runtime/struct.RuntimeHandle.html#method.spawn) does, on the named worker if one is set. **Errors** When this thread’s shard cannot start (the runtime has no worker taking tasks), and `InvalidInput` when the named worker does not exist or takes no new task. #### Trait Implementations - `impl<'a> Clone for Builder<'a>` - `impl<'a> Copy for Builder<'a>` - `impl<'a> Debug for Builder<'a>` - `impl<'a> Default for Builder<'a>` #### Auto Trait Implementations - `impl<'a> Freeze for Builder<'a>` - `impl<'a> RefUnwindSafe for Builder<'a>` - `impl<'a> Send for Builder<'a>` - `impl<'a> Sync for Builder<'a>` - `impl<'a> Unpin for Builder<'a>` - `impl<'a> UnsafeUnpin for Builder<'a>` - `impl<'a> UnwindSafe for Builder<'a>` ### struct `nuclei::task::FallibleTask` https://nuclei.rs/api/nuclei/task/struct.FallibleTask.html ```rust pub struct FallibleTask { /* private fields */ } ``` A spawned task whose output is `None` when the task ended without one. Made by [`Task::fallible`](https://nuclei.rs/api/nuclei/runtime/struct.Task.html#method.fallible): awaiting it returns `Some(output)`, or `None` where awaiting the [`Task`](https://nuclei.rs/api/nuclei/runtime/struct.Task.html) would panic. #### Implementations `impl FallibleTask` ```rust pub fn detach(self) ``` Lets the task run to its end without a handle; see [`Task::detach`](https://nuclei.rs/api/nuclei/runtime/struct.Task.html#method.detach). ```rust pub async fn cancel(self) -> Option ``` Cancels the task; see [`Task::cancel`](https://nuclei.rs/api/nuclei/runtime/struct.Task.html#method.cancel). ```rust pub fn is_finished(&self) -> bool ``` Whether the task completed or was cancelled. ```rust pub fn id(&self) -> Id ``` The task’s id. #### Trait Implementations - `impl Debug for FallibleTask` - `impl Future for FallibleTask` #### Auto Trait Implementations - `impl Freeze for FallibleTask` - `impl RefUnwindSafe for FallibleTask` - `impl Send for FallibleTask where T: Send` - `impl Sync for FallibleTask` - `impl Unpin for FallibleTask` - `impl UnsafeUnpin for FallibleTask` - `impl UnwindSafe for FallibleTask` ### struct `nuclei::task::Id` https://nuclei.rs/api/nuclei/task/struct.Id.html ```rust pub struct Id(/* private fields */); ``` A task’s id: unique among the tasks of the process, never reused. #### Trait Implementations - `impl Clone for Id` - `impl Copy for Id` - `impl Debug for Id` - `impl Display for Id` - `impl Eq for Id` - `impl Hash for Id` - `impl Ord for Id` - `impl PartialEq for Id` - `impl PartialOrd for Id` - `impl StructuralPartialEq for Id` #### Auto Trait Implementations - `impl Freeze for Id` - `impl RefUnwindSafe for Id` - `impl Send for Id` - `impl Sync for Id` - `impl Unpin for Id` - `impl UnsafeUnpin for Id` - `impl UnwindSafe for Id` ### struct `nuclei::task::Join` https://nuclei.rs/api/nuclei/task/struct.Join.html ```rust pub struct Join { /* private fields */ } ``` The future of [`Task::join`](https://nuclei.rs/api/nuclei/runtime/struct.Task.html#method.join): the task’s output, or why there is none. #### Implementations `impl Join` ```rust pub fn detach(self) ``` Lets the task run to its end without a handle; see [`Task::detach`](https://nuclei.rs/api/nuclei/runtime/struct.Task.html#method.detach). ```rust pub fn id(&self) -> Id ``` The task’s id. #### Trait Implementations - `impl Debug for Join` - `impl Future for Join` #### Auto Trait Implementations - `impl Freeze for Join` - `impl RefUnwindSafe for Join` - `impl Send for Join where T: Send` - `impl Sync for Join` - `impl Unpin for Join` - `impl UnsafeUnpin for Join` - `impl UnwindSafe for Join` ### struct `nuclei::task::JoinError` https://nuclei.rs/api/nuclei/task/struct.JoinError.html ```rust pub struct JoinError { /* private fields */ } ``` Why a task gave no output: it was cancelled (by its handle, an [`AbortHandle`](https://nuclei.rs/api/nuclei/task/struct.AbortHandle.html), or its runtime shutting down), or its future panicked. #### Implementations `impl JoinError` ```rust pub fn is_cancelled(&self) -> bool ``` The task was cancelled. ```rust pub fn is_panic(&self) -> bool ``` The task’s future panicked. ```rust pub fn into_panic(self) -> Box ``` The payload of the panic. **Panics** When the task was cancelled, not panicked; [`try_into_panic`](https://nuclei.rs/api/nuclei/task/struct.JoinError.html#method.try_into_panic) answers it instead. ```rust pub fn try_into_panic(self) -> Result, JoinError> ``` The payload of the panic, or the error itself when the task was cancelled. ```rust pub fn id(&self) -> Id ``` The id of the task. #### Trait Implementations - `impl Debug for JoinError` - `impl Display for JoinError` - `impl Error for JoinError` - `impl From for Error` #### Auto Trait Implementations - `impl !RefUnwindSafe for JoinError` - `impl !Sync for JoinError` - `impl !UnwindSafe for JoinError` - `impl Freeze for JoinError` - `impl Send for JoinError` - `impl Unpin for JoinError` - `impl UnsafeUnpin for JoinError` ### struct `nuclei::task::JoinSet` https://nuclei.rs/api/nuclei/task/struct.JoinSet.html ```rust pub struct JoinSet { /* private fields */ } ``` A set of spawned tasks, joined in the order they finish. Dropping the set cancels every task still in it, as dropping their [`Task`](https://nuclei.rs/api/nuclei/runtime/struct.Task.html) handles would; [`detach_all`](https://nuclei.rs/api/nuclei/task/struct.JoinSet.html#method.detach_all) lets them run on. ```rust let mut set = nuclei::task::JoinSet::new(); for i in 0..4u64 { set.spawn(async move { i * 10 }); } let mut sum = 0; while let Some(out) = set.join_next().await { sum += out.unwrap(); } assert_eq!(sum, 60); ``` #### Implementations `impl JoinSet` ```rust pub fn new() -> Self ``` An empty set. ```rust pub fn len(&self) -> usize ``` The tasks in the set, finished and not joined ones included. ```rust pub fn is_empty(&self) -> bool ``` Whether the set holds no task. ```rust pub fn insert(&mut self, task: Task) -> AbortHandle ``` Takes `task` into the set and answers a handle that cancels it. ```rust pub fn spawn(&mut self, future: F) -> AbortHandle where F: Future + Send + 'static, T: Send + 'static ``` Spawns `future` as [`spawn`](https://nuclei.rs/api/nuclei/runtime/fn.spawn.html) does, into the set. ```rust pub fn spawn_local(&mut self, future: F) -> AbortHandle where F: Future + 'static, T: 'static ``` Spawns `future` as [`spawn_local`](https://nuclei.rs/api/nuclei/runtime/fn.spawn_local.html) does, into the set. ```rust pub fn spawn_blocking(&mut self, f: F) -> AbortHandle where F: FnOnce() -> T + Send + 'static, T: Send + 'static ``` Runs `f` on the blocking pool, into the set. ```rust pub fn spawn_on(&mut self, future: F, handle: &RuntimeHandle) -> AbortHandle where F: Future + Send + 'static, T: Send + 'static ``` Spawns `future` on the runtime `handle` refers to, into the set. ```rust pub async fn join_next(&mut self) -> Option> ``` The output of the next task to finish, `None` when the set is empty. A task that was cancelled or panicked gives its [`JoinError`](https://nuclei.rs/api/nuclei/task/struct.JoinError.html). ```rust pub async fn join_next_with_id(&mut self) -> Option> ``` [`join_next`](https://nuclei.rs/api/nuclei/task/struct.JoinSet.html#method.join_next), with the id of the task. ```rust pub fn try_join_next(&mut self) -> Option> ``` The output of a task that has finished, without waiting: `None` when none has (the set may still hold tasks). ```rust pub fn poll_join_next( &mut self, cx: &mut Context<'_>, ) -> Poll>> ``` Polls for the next finished task. ```rust pub async fn join_all(self) -> Vec ``` Every task’s output, in finishing order. **Panics** When a task panicked (its panic is resumed) or was cancelled. ```rust pub fn abort_all(&mut self) ``` Cancels every task in the set; they stay in it, and `join_next` gives each one’s cancellation (or its output, if it finished first). ```rust pub fn detach_all(&mut self) ``` Takes every task out of the set and lets each run to its end. The slots go with them, so a detached task’s later wake meets none. ```rust pub async fn shutdown(&mut self) ``` Cancels every task and waits until each one is out of the set. #### Trait Implementations - `impl Debug for JoinSet` - `impl Default for JoinSet` - `impl Extend for JoinSet where F: Future + Send + 'static, T: Send + 'static` - `impl FromIterator for JoinSet where F: Future + Send + 'static, T: Send + 'static` #### Auto Trait Implementations - `impl !RefUnwindSafe for JoinSet` - `impl !UnwindSafe for JoinSet` - `impl Freeze for JoinSet` - `impl Send for JoinSet where T: Send` - `impl Sync for JoinSet` - `impl Unpin for JoinSet` - `impl UnsafeUnpin for JoinSet` ### struct `nuclei::task::LocalKey` https://nuclei.rs/api/nuclei/task/struct.LocalKey.html ```rust pub struct LocalKey { /* private fields */ } ``` A task-local key, declared with [`task_local!`](https://nuclei.rs/api/nuclei/macro.task_local.html). #### Implementations `impl LocalKey` ```rust pub fn scope( &'static self, value: T, future: F, ) -> TaskLocalFuture ``` A future that runs `future` with the key set to `value` in each of its polls, and drops `future` (when it is dropped early) with the value still set. ```rust pub fn sync_scope R, R>(&'static self, value: T, f: F) -> R ``` Runs `f` with the key set to `value`, then unsets it. ```rust pub fn with R, R>(&'static self, f: F) -> R ``` Runs `f` on the key’s value. **Panics** Where no scope set the key; [`try_with`](https://nuclei.rs/api/nuclei/task/struct.LocalKey.html#method.try_with) answers an [`AccessError`](https://nuclei.rs/api/nuclei/task/struct.AccessError.html) instead. ```rust pub fn try_with R, R>( &'static self, f: F, ) -> Result ``` Runs `f` on the key’s value, or answers an [`AccessError`](https://nuclei.rs/api/nuclei/task/struct.AccessError.html) where no scope set it. ```rust pub fn get(&'static self) -> T where T: Clone ``` A clone of the key’s value. **Panics** Where no scope set the key. #### Trait Implementations - `impl Debug for LocalKey` #### Auto Trait Implementations - `impl Freeze for LocalKey` - `impl RefUnwindSafe for LocalKey` - `impl Send for LocalKey` - `impl Sync for LocalKey` - `impl Unpin for LocalKey` - `impl UnsafeUnpin for LocalKey` - `impl UnwindSafe for LocalKey` ### struct `nuclei::task::Task` https://nuclei.rs/api/nuclei/task/struct.Task.html ```rust pub struct Task { /* private fields */ } ``` A spawned task. Awaiting it gives the task’s output. Dropping it cancels the task: its future is dropped without being polled again. [`detach`](https://nuclei.rs/api/nuclei/runtime/struct.Task.html#method.detach) lets the task run to its end without a handle. If the task’s future panics, awaiting the handle resumes the panic. **Panics** Awaiting a task that was cancelled before it completed (through an [`AbortHandle`](https://nuclei.rs/api/nuclei/task/struct.AbortHandle.html), or by its runtime’s shutdown) panics; [`join`](https://nuclei.rs/api/nuclei/runtime/struct.Task.html#method.join) answers a [`JoinError`](https://nuclei.rs/api/nuclei/task/struct.JoinError.html) instead, and [`fallible`](https://nuclei.rs/api/nuclei/runtime/struct.Task.html#method.fallible) gives a handle that returns `None`. #### Implementations `impl Task` ```rust pub fn detach(self) ``` Lets the task run to its end without a handle; its output is dropped. ```rust pub async fn cancel(self) -> Option ``` Cancels the task and waits for its future to be dropped. Returns the output if the task had already completed. ```rust pub fn fallible(self) -> FallibleTask ``` A handle that returns `None` where this one panics: when the task was cancelled, or its runtime dropped it before it completed. ```rust pub fn is_finished(&self) -> bool ``` Whether the task completed or was cancelled. Awaiting a finished task returns at once. ```rust pub fn id(&self) -> Id ``` The task’s id. ```rust pub fn abort(&self) ``` Cancels the task without waiting: its future is dropped where it runs, and awaiting the handle then finds no output (unless the task had completed). [`join`](https://nuclei.rs/api/nuclei/runtime/struct.Task.html#method.join) reports it as a cancelled [`JoinError`](https://nuclei.rs/api/nuclei/task/struct.JoinError.html). ```rust pub fn abort_handle(&self) -> AbortHandle ``` A handle that cancels the task from anywhere, without the [`Task`](https://nuclei.rs/api/nuclei/runtime/struct.Task.html): it can be cloned and sent to another thread, and outlives the handle. ```rust pub fn join(self) -> Join ``` A future that gives the task’s output, or a [`JoinError`](https://nuclei.rs/api/nuclei/task/struct.JoinError.html) saying why there is none: the task was cancelled (its runtime dropped it too), or its future panicked, with the payload. #### Trait Implementations - `impl Debug for Task` - `impl Drop for Task` - `impl Future for Task` - `impl RefUnwindSafe for Task` - `impl Send for Task` - `impl Sync for Task` - `impl Unpin for Task` - `impl UnwindSafe for Task` #### Auto Trait Implementations - `impl Freeze for Task` - `impl UnsafeUnpin for Task` ### struct `nuclei::task::TaskLocalFuture` https://nuclei.rs/api/nuclei/task/struct.TaskLocalFuture.html ```rust pub struct TaskLocalFuture { /* private fields */ } ``` The future of [`LocalKey::scope`](https://nuclei.rs/api/nuclei/task/struct.LocalKey.html#method.scope). #### Trait Implementations - `impl Debug for TaskLocalFuture` - `impl Drop for TaskLocalFuture` - `impl Future for TaskLocalFuture` #### Auto Trait Implementations - `impl !Unpin for TaskLocalFuture` - `impl !UnsafeUnpin for TaskLocalFuture` - `impl Freeze for TaskLocalFuture where T: Freeze, F: Freeze` - `impl RefUnwindSafe for TaskLocalFuture where T: RefUnwindSafe, F: RefUnwindSafe` - `impl Send for TaskLocalFuture where T: Send, F: Send` - `impl Sync for TaskLocalFuture where T: Sync, F: Sync` - `impl UnwindSafe for TaskLocalFuture where T: UnwindSafe, F: UnwindSafe` ### fn `nuclei::task::id` https://nuclei.rs/api/nuclei/task/fn.id.html ```rust pub fn id() -> Id ``` The id of the task this code runs in. **Panics** Outside a task: in `block_on`’s own future, or on a blocking-pool thread. [`try_id`](https://nuclei.rs/api/nuclei/task/fn.try_id.html) answers `None` there instead. ### fn `nuclei::task::try_id` https://nuclei.rs/api/nuclei/task/fn.try_id.html ```rust pub fn try_id() -> Option ``` The id of the task this code runs in, `None` outside a task (in `block_on`’s own future, or on a blocking-pool thread). ### fn `nuclei::task::yield_now` https://nuclei.rs/api/nuclei/task/fn.yield_now.html ```rust pub async fn yield_now() ``` Gives the other tasks of this shard a turn: the task goes to the back of its shard’s run queue and runs again after the tasks queued before it. In `block_on`’s own future it lets the shard run its queue once. ## Module `nuclei::task::coop` https://nuclei.rs/api/nuclei/task/coop/index.html Cooperative scheduling: the budget of operations each poll of a task may complete before it yields to the other tasks of its shard. IO that completes spends one, and so do the receives, acquires and locks of [`sync`](https://nuclei.rs/api/nuclei/sync/index.html) that complete without queueing (see its module docs). ### Structs - [Cooperative](https://nuclei.rs/api/nuclei/task/coop/struct.Cooperative.html): The future of [`cooperative`](https://nuclei.rs/api/nuclei/task/coop/fn.cooperative.html). - [Unconstrained](https://nuclei.rs/api/nuclei/task/coop/struct.Unconstrained.html): The future of [`unconstrained`](https://nuclei.rs/api/nuclei/task/coop/fn.unconstrained.html). ### Constants - [BUDGET](https://nuclei.rs/api/nuclei/task/coop/constant.BUDGET.html): Operations one poll of a task may complete before it yields. ### Functions - [consume_budget](https://nuclei.rs/api/nuclei/task/coop/fn.consume_budget.html): Spends one operation of the budget, yielding first when it is spent: a loop of work that awaits nothing else can call it to stay fair. - [cooperative](https://nuclei.rs/api/nuclei/task/coop/fn.cooperative.html): Runs `future` under the budget: each of its polls spends one operation, and it yields instead of being polled when the budget is spent. - [has_budget_remaining](https://nuclei.rs/api/nuclei/task/coop/fn.has_budget_remaining.html): Whether the current poll has budget left (always `true` outside a poll and in an [`unconstrained`](https://nuclei.rs/api/nuclei/task/coop/fn.unconstrained.html) one). - [unconstrained](https://nuclei.rs/api/nuclei/task/coop/fn.unconstrained.html): Runs `future` with no budget: none of its operations spends any, and it never yields for the budget’s sake. ### struct `nuclei::task::coop::Cooperative` https://nuclei.rs/api/nuclei/task/coop/struct.Cooperative.html ```rust pub struct Cooperative { /* private fields */ } ``` The future of [`cooperative`](https://nuclei.rs/api/nuclei/task/coop/fn.cooperative.html). #### Trait Implementations - `impl Debug for Cooperative` - `impl Future for Cooperative` #### Auto Trait Implementations - `impl Freeze for Cooperative where F: Freeze` - `impl RefUnwindSafe for Cooperative where F: RefUnwindSafe` - `impl Send for Cooperative where F: Send` - `impl Sync for Cooperative where F: Sync` - `impl Unpin for Cooperative where F: Unpin` - `impl UnsafeUnpin for Cooperative where F: UnsafeUnpin` - `impl UnwindSafe for Cooperative where F: UnwindSafe` ### struct `nuclei::task::coop::Unconstrained` https://nuclei.rs/api/nuclei/task/coop/struct.Unconstrained.html ```rust pub struct Unconstrained { /* private fields */ } ``` The future of [`unconstrained`](https://nuclei.rs/api/nuclei/task/coop/fn.unconstrained.html). #### Trait Implementations - `impl Debug for Unconstrained` - `impl Future for Unconstrained` #### Auto Trait Implementations - `impl Freeze for Unconstrained where F: Freeze` - `impl RefUnwindSafe for Unconstrained where F: RefUnwindSafe` - `impl Send for Unconstrained where F: Send` - `impl Sync for Unconstrained where F: Sync` - `impl Unpin for Unconstrained where F: Unpin` - `impl UnsafeUnpin for Unconstrained where F: UnsafeUnpin` - `impl UnwindSafe for Unconstrained where F: UnwindSafe` ### const `nuclei::task::coop::BUDGET` https://nuclei.rs/api/nuclei/task/coop/constant.BUDGET.html ```rust pub const BUDGET: u8 = 128; ``` Operations one poll of a task may complete before it yields. ### fn `nuclei::task::coop::consume_budget` https://nuclei.rs/api/nuclei/task/coop/fn.consume_budget.html ```rust pub async fn consume_budget() ``` Spends one operation of the budget, yielding first when it is spent: a loop of work that awaits nothing else can call it to stay fair. ### fn `nuclei::task::coop::cooperative` https://nuclei.rs/api/nuclei/task/coop/fn.cooperative.html ```rust pub fn cooperative(future: F) -> Cooperative ``` Runs `future` under the budget: each of its polls spends one operation, and it yields instead of being polled when the budget is spent. ### fn `nuclei::task::coop::has_budget_remaining` https://nuclei.rs/api/nuclei/task/coop/fn.has_budget_remaining.html ```rust pub fn has_budget_remaining() -> bool ``` Whether the current poll has budget left (always `true` outside a poll and in an [`unconstrained`](https://nuclei.rs/api/nuclei/task/coop/fn.unconstrained.html) one). ### fn `nuclei::task::coop::unconstrained` https://nuclei.rs/api/nuclei/task/coop/fn.unconstrained.html ```rust pub fn unconstrained(future: F) -> Unconstrained ``` Runs `future` with no budget: none of its operations spends any, and it never yields for the budget’s sake. ## Module `nuclei::time` https://nuclei.rs/api/nuclei/time/index.html Time: sleeping, timeouts and intervals on the shard’s timer wheel. Time: sleeping, timeouts and intervals, on the timer wheel of the shard that polls them, and the runtime’s clock they read. The clock is [`Instant`](https://nuclei.rs/api/nuclei/time/struct.Instant.html). It runs with the system’s monotonic clock until [`pause`](https://nuclei.rs/api/nuclei/time/fn.pause.html) stops it (or a runtime built with [`start_paused`](https://nuclei.rs/api/nuclei/runtime/struct.Builder.html#method.start_paused) starts stopped); a paused clock moves only by [`advance`](https://nuclei.rs/api/nuclei/time/fn.advance.html), or by itself when every shard of its runtime is idle with a timer armed: it then jumps to the earliest timer, so code that sleeps runs at once in tests. Timers fire on the wheel’s millisecond: a timer waits at least its duration, rounded up to the next millisecond, and a shard busy with a task fires it once that task yields. [`sleep_precise`](https://nuclei.rs/api/nuclei/time/fn.sleep_precise.html) waits to the microsecond instead, off the millisecond wheel: its deadline ends the shard’s wait through the backend’s high-resolution timer, and a paused clock moves to it exactly; `sleep` and `timeout` on the wheel pay nothing for it. Arming and cancelling a timer on its shard costs no allocation once the shard’s wheel has grown to the most timers alive at once; a timer polled on a thread that is not a shard (another runtime’s) is fired for it by a shard of the current runtime, or of the default one. ### Modules - [error](https://nuclei.rs/api/nuclei/time/error/index.html): The error of a timeout. ### Structs - [Instant](https://nuclei.rs/api/nuclei/time/struct.Instant.html): A point in time on the clock of the runtime the code runs in. - [Interval](https://nuclei.rs/api/nuclei/time/struct.Interval.html): Ticks at a fixed period. Made by [`interval`](https://nuclei.rs/api/nuclei/time/fn.interval.html) and [`interval_at`](https://nuclei.rs/api/nuclei/time/fn.interval_at.html). - [Sleep](https://nuclei.rs/api/nuclei/time/struct.Sleep.html): A future that completes at its deadline. Made by [`sleep`](https://nuclei.rs/api/nuclei/time/fn.sleep.html) and [`sleep_until`](https://nuclei.rs/api/nuclei/time/fn.sleep_until.html). - [SleepPrecise](https://nuclei.rs/api/nuclei/time/struct.SleepPrecise.html): A future that completes at its deadline, to the microsecond. Made by [`sleep_precise`](https://nuclei.rs/api/nuclei/time/fn.sleep_precise.html) and [`sleep_until_precise`](https://nuclei.rs/api/nuclei/time/fn.sleep_until_precise.html). - [Timeout](https://nuclei.rs/api/nuclei/time/struct.Timeout.html): A future with a deadline. Made by [`timeout`](https://nuclei.rs/api/nuclei/time/fn.timeout.html) and [`timeout_at`](https://nuclei.rs/api/nuclei/time/fn.timeout_at.html). ### Enums - [MissedTickBehavior](https://nuclei.rs/api/nuclei/time/enum.MissedTickBehavior.html): What an interval does with ticks it missed because it was polled late. ### Functions - [advance](https://nuclei.rs/api/nuclei/time/fn.advance.html): Moves the clock of the runtime this code runs in forward by `duration`, paused or running, then lets the timers that came due fire before it returns. - [interval](https://nuclei.rs/api/nuclei/time/fn.interval.html): Ticks every `period`, the first tick at once. - [interval_at](https://nuclei.rs/api/nuclei/time/fn.interval_at.html): Ticks every `period`, the first tick at `start`. - [pause](https://nuclei.rs/api/nuclei/time/fn.pause.html): Stops the clock of the runtime this code runs in (or of the default runtime): [`Instant::now`](https://nuclei.rs/api/nuclei/time/struct.Instant.html#method.now) stands still, and timers fire only as the clock is moved, by [`advance`](https://nuclei.rs/api/nuclei/time/fn.advance.html) or by itself whenever every shard of the runtime is idle with a timer armed (it jumps to the earliest one). A paused clock stays paused. - [resume](https://nuclei.rs/api/nuclei/time/fn.resume.html): Starts a paused clock again from the time it stands at; a running clock goes on as it is. - [sleep](https://nuclei.rs/api/nuclei/time/fn.sleep.html): Waits until `duration` has passed. - [sleep_precise](https://nuclei.rs/api/nuclei/time/fn.sleep_precise.html): Waits until `duration` has passed, to the microsecond. - [sleep_until](https://nuclei.rs/api/nuclei/time/fn.sleep_until.html): Waits until `deadline`. - [sleep_until_precise](https://nuclei.rs/api/nuclei/time/fn.sleep_until_precise.html): Waits until `deadline`, to the microsecond (see [`sleep_precise`](https://nuclei.rs/api/nuclei/time/fn.sleep_precise.html)). - [timeout](https://nuclei.rs/api/nuclei/time/fn.timeout.html): Runs `future` for at most `duration`: its output, or [`Elapsed`](https://nuclei.rs/api/nuclei/time/error/struct.Elapsed.html) if the time ran out first. The future is polled before the clock is looked at, so one that is ready at once always wins. - [timeout_at](https://nuclei.rs/api/nuclei/time/fn.timeout_at.html): Runs `future` until `deadline` at most; see [`timeout`](https://nuclei.rs/api/nuclei/time/fn.timeout.html). ### struct `nuclei::time::Instant` https://nuclei.rs/api/nuclei/time/struct.Instant.html ```rust pub struct Instant(/* private fields */); ``` A point in time on the clock of the runtime the code runs in. It is std’s [`Instant`](https://doc.rust-lang.org/1.99.1/std/time/struct.Instant.html) as long as the runtime’s clock runs as the system’s; [`pause`](https://nuclei.rs/api/nuclei/time/fn.pause.html) stops it and [`advance`](https://nuclei.rs/api/nuclei/time/fn.advance.html) moves it, and every timer follows it. The two convert both ways ([`from_std`](https://nuclei.rs/api/nuclei/time/struct.Instant.html#method.from_std), [`into_std`](https://nuclei.rs/api/nuclei/time/struct.Instant.html#method.into_std)). #### Implementations `impl Instant` ```rust pub fn now() -> Self ``` The time now on the runtime’s clock. ```rust pub fn from_std(std: Instant) -> Self ``` The instant `std` names. ```rust pub fn into_std(self) -> Instant ``` This instant as std’s. ```rust pub fn duration_since(&self, earlier: Self) -> Duration ``` The time from `earlier` to this instant, zero if `earlier` is later. ```rust pub fn checked_duration_since(&self, earlier: Self) -> Option ``` The time from `earlier` to this instant, `None` if `earlier` is later. ```rust pub fn saturating_duration_since(&self, earlier: Self) -> Duration ``` The time from `earlier` to this instant, zero if `earlier` is later. ```rust pub fn elapsed(&self) -> Duration ``` The time on the runtime’s clock since this instant. ```rust pub fn checked_add(&self, duration: Duration) -> Option ``` This instant moved forward by `duration`, `None` past the clock’s range. ```rust pub fn checked_sub(&self, duration: Duration) -> Option ``` This instant moved back by `duration`, `None` before the clock’s range. #### Trait Implementations - `impl Add for Instant` - `impl AddAssign for Instant` - `impl Clone for Instant` - `impl Copy for Instant` - `impl Debug for Instant` - `impl Eq for Instant` - `impl From for Instant` - `impl From for Instant` - `impl Hash for Instant` - `impl Ord for Instant` - `impl PartialEq for Instant` - `impl PartialOrd for Instant` - `impl StructuralPartialEq for Instant` - `impl Sub for Instant` - `impl Sub for Instant` - `impl SubAssign for Instant` #### Auto Trait Implementations - `impl Freeze for Instant` - `impl RefUnwindSafe for Instant` - `impl Send for Instant` - `impl Sync for Instant` - `impl Unpin for Instant` - `impl UnsafeUnpin for Instant` - `impl UnwindSafe for Instant` ### struct `nuclei::time::Interval` https://nuclei.rs/api/nuclei/time/struct.Interval.html ```rust pub struct Interval { /* private fields */ } ``` Ticks at a fixed period. Made by [`interval`](https://nuclei.rs/api/nuclei/time/fn.interval.html) and [`interval_at`](https://nuclei.rs/api/nuclei/time/fn.interval_at.html). #### Implementations `impl Interval` ```rust pub async fn tick(&mut self) -> Instant ``` Waits for the next tick and returns the instant it was due at. ```rust pub fn poll_tick(&mut self, cx: &mut Context<'_>) -> Poll ``` Polls for the next tick; see [`tick`](https://nuclei.rs/api/nuclei/time/struct.Interval.html#method.tick). ```rust pub fn reset(&mut self) ``` Restarts the schedule: the next tick is one period from now. ```rust pub fn period(&self) -> Duration ``` The period. ```rust pub fn missed_tick_behavior(&self) -> MissedTickBehavior ``` What happens to missed ticks. ```rust pub fn set_missed_tick_behavior(&mut self, behavior: MissedTickBehavior) ``` Sets what happens to missed ticks. #### Trait Implementations - `impl Debug for Interval` #### Auto Trait Implementations - `impl !RefUnwindSafe for Interval` - `impl !UnwindSafe for Interval` - `impl Freeze for Interval` - `impl Send for Interval` - `impl Sync for Interval` - `impl Unpin for Interval` - `impl UnsafeUnpin for Interval` ### struct `nuclei::time::Sleep` https://nuclei.rs/api/nuclei/time/struct.Sleep.html ```rust pub struct Sleep { /* private fields */ } ``` A future that completes at its deadline. Made by [`sleep`](https://nuclei.rs/api/nuclei/time/fn.sleep.html) and [`sleep_until`](https://nuclei.rs/api/nuclei/time/fn.sleep_until.html). Polled on one of nuclei’s shards, it arms a timer in that shard’s wheel; polled anywhere else (another runtime’s thread), it asks a shard of the current runtime (or the default one) to fire it. Dropping it cancels the timer. #### Implementations `impl Sleep` ```rust pub fn deadline(&self) -> Instant ``` The deadline. ```rust pub fn is_elapsed(&self) -> bool ``` Whether the deadline has passed. ```rust pub fn reset(self: Pin<&mut Self>, deadline: impl Into) ``` Moves the deadline; the sleep is pending again until it. #### Trait Implementations - `impl Debug for Sleep` - `impl Future for Sleep` #### Auto Trait Implementations - `impl !RefUnwindSafe for Sleep` - `impl !UnwindSafe for Sleep` - `impl Freeze for Sleep` - `impl Send for Sleep` - `impl Sync for Sleep` - `impl Unpin for Sleep` - `impl UnsafeUnpin for Sleep` ### struct `nuclei::time::SleepPrecise` https://nuclei.rs/api/nuclei/time/struct.SleepPrecise.html ```rust pub struct SleepPrecise { /* private fields */ } ``` A future that completes at its deadline, to the microsecond. Made by [`sleep_precise`](https://nuclei.rs/api/nuclei/time/fn.sleep_precise.html) and [`sleep_until_precise`](https://nuclei.rs/api/nuclei/time/fn.sleep_until_precise.html). Polled on one of nuclei’s shards, it arms a timer in that shard’s microsecond wheel; polled anywhere else (another runtime’s thread), it asks a shard of the current runtime (or the default one) to fire it. Dropping it cancels the timer. #### Implementations `impl SleepPrecise` ```rust pub fn deadline(&self) -> Instant ``` The deadline. ```rust pub fn is_elapsed(&self) -> bool ``` Whether the deadline has passed. ```rust pub fn reset(self: Pin<&mut Self>, deadline: impl Into) ``` Moves the deadline; the sleep is pending again until it. #### Trait Implementations - `impl Debug for SleepPrecise` - `impl Future for SleepPrecise` #### Auto Trait Implementations - `impl !RefUnwindSafe for SleepPrecise` - `impl !UnwindSafe for SleepPrecise` - `impl Freeze for SleepPrecise` - `impl Send for SleepPrecise` - `impl Sync for SleepPrecise` - `impl Unpin for SleepPrecise` - `impl UnsafeUnpin for SleepPrecise` ### struct `nuclei::time::Timeout` https://nuclei.rs/api/nuclei/time/struct.Timeout.html ```rust pub struct Timeout { /* private fields */ } ``` A future with a deadline. Made by [`timeout`](https://nuclei.rs/api/nuclei/time/fn.timeout.html) and [`timeout_at`](https://nuclei.rs/api/nuclei/time/fn.timeout_at.html). #### Implementations `impl Timeout` ```rust pub fn get_ref(&self) -> &F ``` The future inside. ```rust pub fn get_mut(&mut self) -> &mut F ``` The future inside. ```rust pub fn into_inner(self) -> F ``` The future inside, without its deadline. #### Trait Implementations - `impl Debug for Timeout` - `impl Future for Timeout` #### Auto Trait Implementations - `impl !RefUnwindSafe for Timeout` - `impl !UnwindSafe for Timeout` - `impl Freeze for Timeout where F: Freeze` - `impl Send for Timeout where F: Send` - `impl Sync for Timeout where F: Sync` - `impl Unpin for Timeout where F: Unpin` - `impl UnsafeUnpin for Timeout where F: UnsafeUnpin` ### enum `nuclei::time::MissedTickBehavior` https://nuclei.rs/api/nuclei/time/enum.MissedTickBehavior.html ```rust pub enum MissedTickBehavior { Burst, Delay, Skip, } ``` What an interval does with ticks it missed because it was polled late. #### Variants ```rust Burst ``` Every missed tick fires as soon as it can, one after the other, until the interval is back on its schedule. ```rust Delay ``` The next tick comes one period after the late one: the schedule moves. ```rust Skip ``` Missed ticks are skipped: the next tick is the next one on the original schedule after now. #### Trait Implementations - `impl Clone for MissedTickBehavior` - `impl Copy for MissedTickBehavior` - `impl Debug for MissedTickBehavior` - `impl Default for MissedTickBehavior` - `impl Eq for MissedTickBehavior` - `impl Hash for MissedTickBehavior` - `impl PartialEq for MissedTickBehavior` - `impl StructuralPartialEq for MissedTickBehavior` #### Auto Trait Implementations - `impl Freeze for MissedTickBehavior` - `impl RefUnwindSafe for MissedTickBehavior` - `impl Send for MissedTickBehavior` - `impl Sync for MissedTickBehavior` - `impl Unpin for MissedTickBehavior` - `impl UnsafeUnpin for MissedTickBehavior` - `impl UnwindSafe for MissedTickBehavior` ### fn `nuclei::time::advance` https://nuclei.rs/api/nuclei/time/fn.advance.html ```rust pub async fn advance(duration: Duration) ``` Moves the clock of the runtime this code runs in forward by `duration`, paused or running, then lets the timers that came due fire before it returns. ```rust use std::time::Duration; use nuclei::time::{self, Instant}; time::pause(); let start = Instant::now(); time::advance(Duration::from_millis(250)).await; assert_eq!(start.elapsed(), Duration::from_millis(250)); ``` ### fn `nuclei::time::interval` https://nuclei.rs/api/nuclei/time/fn.interval.html ```rust pub fn interval(period: Duration) -> Interval ``` Ticks every `period`, the first tick at once. **Panics** If `period` is zero. ### fn `nuclei::time::interval_at` https://nuclei.rs/api/nuclei/time/fn.interval_at.html ```rust pub fn interval_at(start: impl Into, period: Duration) -> Interval ``` Ticks every `period`, the first tick at `start`. **Panics** If `period` is zero. ### fn `nuclei::time::pause` https://nuclei.rs/api/nuclei/time/fn.pause.html ```rust pub fn pause() ``` Stops the clock of the runtime this code runs in (or of the default runtime): [`Instant::now`](https://nuclei.rs/api/nuclei/time/struct.Instant.html#method.now) stands still, and timers fire only as the clock is moved, by [`advance`](https://nuclei.rs/api/nuclei/time/fn.advance.html) or by itself whenever every shard of the runtime is idle with a timer armed (it jumps to the earliest one). A paused clock stays paused. ```rust use std::time::Duration; use nuclei::time::{self, Instant}; time::pause(); let start = Instant::now(); // Nothing else runs: the clock jumps to the sleep's end at once. time::sleep(Duration::from_secs(3600)).await; assert_eq!(Instant::now() - start, Duration::from_secs(3600)); ``` ### fn `nuclei::time::resume` https://nuclei.rs/api/nuclei/time/fn.resume.html ```rust pub fn resume() ``` Starts a paused clock again from the time it stands at; a running clock goes on as it is. ### fn `nuclei::time::sleep` https://nuclei.rs/api/nuclei/time/fn.sleep.html Also exported as `nuclei::sleep`. ```rust pub fn sleep(duration: Duration) -> Sleep ``` Waits until `duration` has passed. The wait is at least `duration`, rounded up to the timer wheel’s millisecond; a busy shard may let it run later by the time its current task takes to yield. [`sleep_precise`](https://nuclei.rs/api/nuclei/time/fn.sleep_precise.html) waits to the microsecond instead. ### fn `nuclei::time::sleep_precise` https://nuclei.rs/api/nuclei/time/fn.sleep_precise.html ```rust pub fn sleep_precise(duration: Duration) -> SleepPrecise ``` Waits until `duration` has passed, to the microsecond. The wait is at least `duration`, rounded up to the microsecond, and ends as soon after that as the system’s timer wakes the shard; a busy shard may let it run later by the time its current task takes to yield. Use it where the millisecond of [`sleep`](https://nuclei.rs/api/nuclei/time/fn.sleep.html) is too coarse: a pacer, a retry spaced in microseconds, a deadline a protocol counts in microseconds. Each precise deadline that is the shard’s earliest costs the shard a timer of its own in the kernel (one system call to arm it on epoll), so a coarse sleep stays the cheaper choice where a millisecond is fine. ```rust use std::time::Duration; use nuclei::time::{self, Instant}; time::pause(); let start = Instant::now(); time::sleep_precise(Duration::from_micros(250)).await; // A paused clock moves to the deadline itself: not a millisecond later. assert_eq!(start.elapsed(), Duration::from_micros(250)); ``` ### fn `nuclei::time::sleep_until` https://nuclei.rs/api/nuclei/time/fn.sleep_until.html ```rust pub fn sleep_until(deadline: impl Into) -> Sleep ``` Waits until `deadline`. ### fn `nuclei::time::sleep_until_precise` https://nuclei.rs/api/nuclei/time/fn.sleep_until_precise.html ```rust pub fn sleep_until_precise(deadline: impl Into) -> SleepPrecise ``` Waits until `deadline`, to the microsecond (see [`sleep_precise`](https://nuclei.rs/api/nuclei/time/fn.sleep_precise.html)). ### fn `nuclei::time::timeout` https://nuclei.rs/api/nuclei/time/fn.timeout.html Also exported as `nuclei::timeout`. ```rust pub fn timeout(duration: Duration, future: F) -> Timeout ``` Runs `future` for at most `duration`: its output, or [`Elapsed`](https://nuclei.rs/api/nuclei/time/error/struct.Elapsed.html) if the time ran out first. The future is polled before the clock is looked at, so one that is ready at once always wins. ### fn `nuclei::time::timeout_at` https://nuclei.rs/api/nuclei/time/fn.timeout_at.html ```rust pub fn timeout_at( deadline: impl Into, future: F, ) -> Timeout ``` Runs `future` until `deadline` at most; see [`timeout`](https://nuclei.rs/api/nuclei/time/fn.timeout.html). ## Module `nuclei::time::error` https://nuclei.rs/api/nuclei/time/error/index.html The error of a timeout. ### Structs - [Elapsed](https://nuclei.rs/api/nuclei/time/error/struct.Elapsed.html): A [`timeout`](https://nuclei.rs/api/nuclei/time/fn.timeout.html) ran out before its future completed. ### struct `nuclei::time::error::Elapsed` https://nuclei.rs/api/nuclei/time/error/struct.Elapsed.html ```rust pub struct Elapsed(/* private fields */); ``` A [`timeout`](https://nuclei.rs/api/nuclei/time/fn.timeout.html) ran out before its future completed. #### Trait Implementations - `impl Clone for Elapsed` - `impl Copy for Elapsed` - `impl Debug for Elapsed` - `impl Display for Elapsed` - `impl Eq for Elapsed` - `impl Error for Elapsed` - `impl From for Error` - `impl Hash for Elapsed` - `impl PartialEq for Elapsed` - `impl StructuralPartialEq for Elapsed` #### Auto Trait Implementations - `impl Freeze for Elapsed` - `impl RefUnwindSafe for Elapsed` - `impl Send for Elapsed` - `impl Sync for Elapsed` - `impl Unpin for Elapsed` - `impl UnsafeUnpin for Elapsed` - `impl UnwindSafe for Elapsed` ## Items on other platforms Public only on the platforms named, so not in the reference above, which is built for Linux: - mod `nuclei::signal::windows` (Windows) - struct `nuclei::signal::windows::CtrlEvent` (Windows): The deliveries of one console control event, as a stream: each item stands for one event or more since the item before. - method `nuclei::signal::windows::CtrlEvent::recv` (Windows): Waits for the next event. Always `Some`: the stream never ends. - method `nuclei::signal::windows::CtrlEvent::poll_recv` (Windows): Ready with `Some` once the event came since the last item. - fn `nuclei::signal::windows::ctrl_break` (Windows): Listens to Ctrl-Break (`CTRL_BREAK_EVENT`). - fn `nuclei::signal::windows::ctrl_c` (Windows): Listens to Ctrl-C (`CTRL_C_EVENT`). - fn `nuclei::signal::windows::ctrl_close` (Windows): Listens to the console's closing (`CTRL_CLOSE_EVENT`). - fn `nuclei::signal::windows::ctrl_logoff` (Windows): Listens to the user's logging off (`CTRL_LOGOFF_EVENT`; services only). - fn `nuclei::signal::windows::ctrl_shutdown` (Windows): Listens to the system's shutting down (`CTRL_SHUTDOWN_EVENT`; services only). # Changelog ## 0.5.3 ### Fixed - **A shard taken from a blocked runner is never dropped with its tasks.** The monitor holds a worker's shard only weakly, and got a reference of its own only after its take had succeeded; a runner whose poll ended in between found the shard taken and let go of the last reference, so the shard was dropped with the tasks still queued on it, and each one's handle then found no output (on macOS, about one run in two thousand of the cadence test whose twelve tasks block their runners at once). The monitor now holds the shard before it claims the runner's slot, and lets go of it when the take does not happen (`proofs/tla/handoff/TakeRef.tla`). - **A worker that backs out of its park wakes the monitor.** With every worker parked the monitor sleeps until a worker's park ends; a worker that said it parks, found work at its last look and ran on rang nobody, so a monitor that took that moment for every worker parked could sleep while the worker ran, and a poll of it that blocked then waited for its end instead of a handoff (found in the protocol and its model, not seen in a run). The back-out now rings a monitor that sleeps, as a park's end does (`proofs/tla/handoff/Asleep.tla`). - **The monitor's ticks on macOS are as short as they say.** The monitor reads each worker's word every quarter of the handoff threshold with a timed park, which macOS coalesces with other timers: on a CI runner a 2.5 ms park took 18 ms at the median and up to 119 ms, so a blocked poll waited 70 ms or more for its handoff instead of 10 ms, and in the cadence test the first handoff came up to 800 ms after the runtime started. The monitor now waits on a kqueue there, its ring a user event and its tick a timer marked critical, which is not coalesced (as a shard's precise sleep's is): 2.5 ms take 3.8 ms at the median and 8.6 ms at most. - **A shard on io_uring no longer sleeps through a wake behind a full submission queue.** Entries past the queue's room wait in the shard, the read of its wake's eventfd first in line, and a wait handed the kernel only what the queue held. A shard that queued more operations than its ring has entries between two waits (130 receives on a ring of 64), then waited with no timer due, slept with the wake's read outside the kernel: until one of its operations completed, and with idle peers never, no wake ended the wait, neither another thread's nor that of a timer the shard fired on its way to the wait, whose `block_on` future then never ran again. CI's Ubuntu 6.8 job hung 5.5 hours so in `rt::shard::ring::tests_cap`, and a loaded host hangs that test about once in 300 runs, with the ring's table of fixed files and without. A wait that may sleep now hands the kernel every entry first, and only looks where the kernel takes not all of them (`proofs/tla/park`, the `no_submit_first` mutation). The cap tests bound their sends with a deadline, and a watchdog ends the test process with a message after 30 seconds, since a lost wake stops the shard's timers too. ### Changed - **`File::open` opens on the calling thread when it can answer at once** (Linux). A regular file on a local file system whose path the kernel's caches resolve at once (`openat2` with `RESOLVE_CACHED`, Linux 5.12) is opened on the task's own thread, non-blocking, with no job of the blocking pool. What the path names is looked at first through an `O_PATH` descriptor, so no FIFO, device or file of a network or user-space file system is opened there; those, every open the kernel's caches cannot answer, and every kernel without the call go to the blocking pool as before, and its answer, an error included, is the one the caller gets. - **A ring registers its table of fixed files at its first source's attach**, not at its start, so a shard that never attaches a socket or a file (a `block_on` of timers and channels) makes no registration call. - **The bounded channel's `send` and `recv` are single-state futures.** `Sender::send` waits for a slot and pushes the value in one future, and the receiver looks at its queue inline; a send that finds a slot free and a receive that finds a message take no state of nested waits. The signatures are the same futures as before (`fn send(&self, value) -> impl Future + '_`), not `Unpin`, and a send dropped while it waits lets go of its place and of a slot it was handed, as before. - **The stream and completion paths run fewer instructions per operation.** A stream read takes the bytes read ahead first, with one look at the first piece, keeps that piece out of the queue and consumes a piece it takes part of inline; a stream's direct read is decided in one place; the kernel counts what a read leaves out of line only the first time; `read` and `recvmsg` load only the registers they take; an arrival's hand-out and delivery and a chunk's take-in are inlined into the ring's completion loop, which enters its unwinding guard once per batch of completions and wakes the lone reader an arrival leaves inline; a read side's completion is applied at once when the side is free, as a write side's is; a step that left one waker alone settles inline; the run loop's look at the inbox and its spin are inlined in every codegen unit; a going shard asks its sources as their owner, with no heavy fence, so a runtime that drops with many streams open makes no `membarrier` call per stream (on epoll, 256 connections took about 250 calls and now take 1). - **A stream's owner polls and sends on its own shard under its biased hold**, inlined, and its send looks at one bit each write-side release publishes rather than at the whole write side (`proofs/tla/sendsnow`), while owned writes still go out whole. On a worker the handoff watch follows (the default), a task's poll and send take them in a bracket into the shard (below). - **A worker the handoff watch follows takes its shard's own paths from a task's code.** A call into the runtime from a task's code on such a worker (a wake, a spawn, a stream's poll and send as its owner) saw that it needed a bracket into its shard and went the general way with a bracket around it (a stream's side through its lock, a wake through a second look for its shard); it now takes the bracket and, in it, the path a worker with no watch takes. The bracket is the protocol a poll's end already used: the slot's word marked, the claim looked at, and the word the call found put back as it ends, so a poll that blocks after a call is still taken (`proofs/tla/handoff`: a call with no mark, `M_no_call_mark`, breaks `Exclusive`, and one that leaves its mark, `M_call_stays_marked`, breaks `Rescued`). A watched worker's run of a task keeps no guard to come back by (each part of the run that runs the task's code catches a panic or aborts on one), and a thread looks at one word per call where it looked at two. With the default watch on io_uring, default release build, user instructions per operation: a 64-byte TCP round trip 4321 before, 3792 now (3375 with the watch off, 3391 before); a 64 KiB chunk of a bulk stream 1414, 1217 (1060 off); a spawn and its join 899, 791 (632 off); a oneshot round 1127, 1018 (859 off); a bounded channel round 651, 611 (530 off); a sleep 1019, 942 (834 off). With the watch off each row costs what it did or less, but a few by a handful of instructions: a datagram round trip on io_uring (3 and 4 more, of 3677 and 4150), a sleep on epoll (3 more, of 831), `block_on` under fat LTO (2 more, of 244), and the file read, whose count moves by ten from run to run. The ops gate counts the TCP row with the watch on too (`tcp_watched` in `ci/op_count`). - **A connection costs less to open and close.** A source's attach allocates nothing beside the source itself, nor does a dropped handle's close when the handle's object fits in a word (a socket's descriptor does), a new source is written field by field into its allocation, and a stream a listener accepts inherits the listener's `TCP_INQ` with no `setsockopt` of its own (256 connections on epoll made 513 calls and now make 259). CI's budgets in `ci/op_budget.txt` were lowered to match these and the changes above. - **The API reference is built with `io-stats`**, on the site and on docs.rs, so the IO counts and latencies of `stats` are listed. ## 0.5.2 ### Fixed - **A read on io_uring gets a stream's end that came with its last bytes.** Linux's multishot receive stops trying once the socket's count of what is left says none, a count that leaves out a Unix stream's every end and a TCP reset, and waits for a wake. Bytes and the end that came between its first try and the arming of its poll woke nobody, so the receive took the bytes and waited for good with the end in the socket, and so did the read (three times in CI's full Linux suites, in the Unix reset fault test). The ring's thread now looks at the socket once, at the receive's first arrival after the arming, and stops a receive whose end is queued; the next receive takes it (`proofs/tla/ring/RingEnd.tla`). - **A Unix connect to a full backlog no longer holds a thread of the blocking pool.** Linux answers it `EAGAIN`, and the connect went to a blocking connect of a new socket on the pool, which a dropped future never stopped, and which lost the options set on the caller's socket. It now connects again on its own socket after a pause on a timer (1 ms, doubled up to 64 ms), until the listener takes it, as std's blocking connect waits; a drop frees everything (`proofs/tla/connect`). - **A runtime's drop whose bound runs out no longer drops a linger it was running.** The drop runs what dropped handles left for at most the linger time, and a linger it had started then was dropped with its run, closing the stream with the bytes behind never sent. It now goes on on a thread of its own, to its own deadline, as the ones the run never took do (`proofs/tla/going/Linger.tla`). - **A registration a stopping shard never made no longer fails the source's IO.** A worker whose shard had stopped still registered sources its thread polled, and one asked to register a source for a thread that runs no shard could stop first; either failed the registration, so the source's next operation returned "the shard stopped before the registration", and a dropped stream's drain (a runtime dropping with bytes behind) took that for its end and gave the bytes up (on macOS, about one run in seven of the drop test). A stopped shard now registers nothing: the source stays unregistered, and is registered where its tasks are polled next, as `proofs/tla/attach` has it. - **A stream dropped after its runtime's drop delivered its bytes closes.** A thread's own shard that leaves (its outermost `block_on` returned, the runtime's drop among them) evicts its sources and waits for each eviction; one a thread holding a side performs, as a dropped stream's linger does, showed the source unregistered before it posted the ring's detach, so the shard could look at its mailbox in between and leave, and the detach waited there until the thread's next `block_on`, with the ring's file and the lease that keeps the stream open. Every byte reached the peer, which then waited for the end that never came (on io_uring, one to six runs in four hundred of the drop test). The end of a registration now shows only once what its shard must undo is in that shard's mailbox (`proofs/tla/going/Going.tla`). - **A dropped TCP stream whose linger ran out resets its connection.** The bytes still behind were given up and the stream closed with a FIN, so the peer read a cut stream as a whole one; it now reads `ConnectionReset` (`proofs/tla/close`). - **IO of a shard handed over repeatedly no longer waits for 61 task runs.** When a task blocks its thread past the handoff threshold the shard goes to another thread, and the count of runs before the next look at the driver went with it. If the first task of every new runner blocked as well, the shard was handed on before any runner reached the driver, and an operation a task had queued (a socket receive pushed into the ring's submission queue) reached the kernel only after 61 runs, about 0.9 s with 15 ms blockers. The runner that takes a shard over now drives its IO once, without waiting, before it runs any task. - **IO is driven at least every 1 ms of task running, not only every 61 runs.** A single runner whose tasks each ran just under the handoff threshold looked at the driver once per 61 runs (61 x 9 ms is half a second). The run loop now reads a coarse monotonic clock of its own, `Quartz` (a vDSO read on Linux, a few nanoseconds, never a system call), once every 16 task runs and looks at the driver when the last look is older than 1 ms. It costs one masked branch per run and needs no extra thread. The clock steps by no more than the bound on every platform: the coarse clock where its tick is 1 ms or shorter (a 1000 Hz kernel), else `CLOCK_MONOTONIC`; `CLOCK_UPTIME_RAW` on macOS; the performance counter on Windows, whose tick count would step by 15.6 ms. - **The handoff acts at its threshold on Windows.** The watch ticks every quarter of the threshold, but a timed park on Windows ends at the system timer's tick (15.6 ms), so `handoff_after(10 ms)` handed a shard over only after about 62 ms. The watch now waits on a high-resolution waitable timer and an event there, and its ticks end on time; elsewhere it parks as before. - **A ring shrunk under memory pressure no longer deadlocks a request behind its own reply's receive.** Its receive group now fits within half its completion queue (a ring whose queue cannot hold one buffer runs without a group), and long-lived receives and accepts no longer count against the admission cap, so no finite operation waits behind idle connections. Before, a ring made with 128 entries or fewer and the default 256-buffer group had a cap of 1: the multishot receive armed for an HTTP client's reply held it, and the request's send waited for the receive to end. - **A file cut by `set_len` no longer hands out bytes read ahead past its new end.** A cut, a range call (`allocate`) and a copy into the file move its generation on, so a cursor read made after them reads the file as it is. ### Changed - **Each operation's instructions are counted, and CI holds them.** The IO, task and timer paths were reworked one operation at a time: a stream's direct read and write inline into their callers, a step that leaves nothing is made and settled with one store and one look, a task run starts with one addition, timers keep their deadlines in nanoseconds and fire without a removal, and a Unix datagram socket's ring poll stays armed across waits. `ci/op_counts.sh` counts the user instructions per operation of 19 operations, on io_uring and on epoll, under cachegrind, and CI fails when one rises above its budget in `ci/op_budget.txt`. - **The owned calls are generic over their buffer.** A caller handing a `Vec` in, and binding the buffer it gets back, compiles as before. Two forms that leaned on the old `Vec` parameter no longer infer a type: an argument the compiler had to infer from it (`Default::default()`, `.into()`, `Vec::new().into()`), which now needs its type written (`Vec::::new()`); and naming the address type of `UdpSocket::send_to_owned` or `UnixDatagram::send_to_owned` explicitly, which now takes the buffer type too (`send_to_owned::`). - **Sizes are validated where they take effect**, and a value outside what the runtime can work with is refused as `InvalidInput` naming the setting, its value and the allowed range (the first runtime build for the io_uring settings, `Builder::build` for the builder's). Values that were accepted before and are refused now: - `queue_len` below 64: the floor a ring is shrunk to under memory pressure. - `recv_buffers` that is not 0 or a power of two, or not below twice `queue_len`: the group would take more than half the completion queue. The profiles (`interrupt_driven` and the others) now give a `queue_len` under 256 that many buffers, rounded up to a power of two, where they gave 256, which left a cap of 1 for a `queue_len` from 64 to 128. - `recv_buffer_size` below 512 or above 1 GiB while `recv_buffers` is not 0. - `Builder::thread_stack_size` below 128 KiB: a worker starting, a timer and a TCP connect take 77 KiB in a debug build and 64 KiB in a release one. - `Builder::max_nesting(0)`: no `block_on` could run. - `Builder::max_blocking_threads(0)`, which was raised to 1 silently. - `Builder::handoff_after(Some(d))` with `d` under 1 ms: the watch measures in milliseconds. - **The runtime's clock read is inlined** (`time::Instant::now` and the read timers and timeouts make), so whether it is inlined no longer depends on how a build splits the crate into codegen units: a `timeout` whose future is ready takes about 4% fewer instructions than in 0.5.1 with fat LTO and one codegen unit. ### Added - **The attribute macros take a builder.** `#[nuclei::main]`, `#[nuclei::test]` and `#[nuclei::bench]` take `builder = "path"`: the runtime is built from the `nuclei::Builder` that function returns, with `threads` and `start_paused` applied on top when given (nuclei-macros 0.5.1). - **Owned calls take any buffer type.** `read_owned`, `write_owned`, `write_zero_copy`, the datagram owned calls and the file owned calls take any `IoBuf` (writes) or `IoBufMut` (reads) and give the same type back; a caller passing a `Vec` gets a `Vec` back as before (the runtime holds the buffer in a vector's size, and boxes any other type once). `Released` is `Released>`. A caller's own type implements the two unsafe traits. - **`AlignedBuf`**, a buffer of a fixed capacity at an address of a chosen alignment, made by a safe constructor: the buffer for a file opened for direct IO. Its memory is the caller's, not charged to the IO buffer cap. - **Owned vectored IO**: `write_vectored_owned` writes every buffer of an `IoVecBuf` (`Vec`, `[B; N]`) in order as one write, with no other write of the handle between them, and `read_vectored_owned` fills the rooms of an `IoVecBufMut`'s buffers in order, on TCP and Unix streams, pipes and files. Each kernel call takes every buffer at once: `writev`/`readv` or a `sendmsg`/`recvmsg` of several buffers on epoll and kqueue, `IORING_OP_WRITEV`/`READV` or `SENDMSG`/`RECVMSG` on io_uring, a `WSASend`/`WSARecv` of several `WSABUF`s on I/O completion ports, `pwritev`/`preadv` for files; a call the kernel takes part of goes on from the byte it stopped at. Where the system has no vectored call of the kind, the buffers go one call each, in order: a buffered file on Windows reads and writes so, and a Windows handle that is not a socket writes so and reads into its first room (a short read). - **Positional file IO on a shared handle**: `read_at`, `write_at`, `read_exact_at`, `write_all_at`, `read_at_owned`, `write_at_owned` and `read_many_at` (many reads in one call, at most 64 out at once, together on the shard's ring), ordered after the writes accepted at the cursor before them. - **More file calls**: `allocate` (`Allocate::{Extend, KeepSize, PunchHole, ZeroRange}`, on the ring as `IORING_OP_FALLOCATE`; a mode the system has not answers `Unsupported`), `sync_range` (`IORING_OP_SYNC_FILE_RANGE` on Linux, a data sync elsewhere), `fs::sync_dir` with the rename-then-sync recipe, `copy_range_to` (`copy_file_range` in bounded chunks, read and write where the kernel cannot), and advisory `lock_file`, `try_lock_file` and `unlock_file` (the blocking lock on the pool, never left held by a dropped future). `sync_all` and `sync_data` are operations of the ring, and a failed sync makes every later one of the handle fail. A file opened for direct IO is read and written with exactly the caller's lengths and offsets. - **`read_at` and `write_at` on `Handle` are the async calls**, and shadow std's `FileExt::read_at` and `write_at` reached through `Deref`, which block the worker; std's stay reachable as `(*file).read_at(..)`. The lock calls take names of their own, so std's `File::lock`, `try_lock` and `unlock` through `Deref` are unchanged. - **TLA+ models** of a file's positional calls, syncs, direct IO and descriptor leases (`proofs/tla/lent/LentFile.tla`), of a file lock's cancellation (`proofs/tla/flock`) and of many reads in one call (`proofs/tla/many`), each with mutations that break their rules, and a Lean proof that a vectored read fills its buffers' rooms in order (`proofs/lean/Nuclei/Fill.lean`). - **`shut` and `abort` on streams.** `TcpStream::shut(how)` and `UnixStream::shut(how)` make std's shutdown once the bytes written behind reached the kernel (`Write`, `Both`), and the reading half's through the ring's `SHUTDOWN` where the calling thread runs a ring; reads after it answer as std's on each system (macOS and Windows drop what was read ahead). It is not named `shutdown`, so `stream.shutdown(how)` still reaches std's through `Deref`. `TcpStream::abort()` sets `SO_LINGER` to zero, drops the bytes behind and closes now: the peer reads a reset (`proofs/tla/close`). - **IO settings on the builder**: `write_behind_linger` (how long a dropped handle's bytes may take, 60 s by default, more than zero), `zero_copy_threshold` (the least a `write_zero_copy` must have left for a zero-copy send, 1 MiB by default) and `send_file_chunk` (the most one call of a `send_file` sends, 1 MiB by default, from 1 to `0x7ffff000` bytes). Each is read once, as the runtime builds. - **TCP options**: `TcpKeepalive { time, interval, retries }` with `set_keepalive_timing` and `keepalive_timing` on `TcpSocket` and `TcpStream`; `TcpSocket::set_incoming_cpu`, `set_user_timeout`, `set_only_v6`, `set_fastopen` and `set_defer_accept`, and `TcpStream::set_quickack` and `set_user_timeout`, each with its getter. An option the system does not have answers `Unsupported`. - **`UdpSocketBuilder`**, a UDP socket set up before it binds (`SO_REUSEADDR`, `SO_REUSEPORT`, buffer sizes, `IP_TOS`, `IPV6_TCLASS`, `IPV6_V6ONLY`, `SO_BINDTODEVICE`), and `UdpSocket::poll_recv_from` and `poll_send_to`. - **What std's calls through `Deref` do**, on `Handle`: `shutdown`, `set_nonblocking(false)`, `take_error`, `Read` and `Write` go around the bytes read ahead and written behind, or block the shard; `UdpSocket::connect` is a constructor where `socket.connect(addr)` is std's. - **`sync::local`**: `mpsc`, `oneshot`, `Semaphore` and `Mutex` for the tasks of one shard, with the names, signatures and errors of their `nuclei::sync` twins. They are `!Send`, no path runs an atomic instruction or a fence, and full sends, acquires and locks are served in arrival order. - **`sync::mesh`**: a full mesh of bounded channels between a fixed number of parties, one channel for every ordered pair, with backpressure per pair and a `Party::recv` that is fair across senders. - **`time::sleep_precise` and `sleep_until_precise`**: waits to the microsecond, where the millisecond of `sleep` is too coarse. A precise deadline that is its shard's earliest arms a kernel timer of its own. - **The cooperative budget covers channels and locks**: a receive, acquire or lock of `nuclei::sync` that completes without queueing spends one unit of the task's budget, as completed IO does, so a task on a channel that is always ready yields to the other tasks of its shard. - **Each worker's IO in `stats`, behind the `io-stats` feature** (off by default): counts with `Builder::count_io` and `ShardStats::io` (`IoCounts`: reads, writes, the bytes of each, accepts), and the IO latencies `Builder::record_latencies` records in `ShardStats::io_latencies` (`IoLatencies`). The feature costs every IO call a few instructions, counted and timed or not; without it no IO path carries that code, and those items do not exist. The poll-time histograms need no feature. - **A TLA+ model of the cadence** (`proofs/tla/cadence`): the wait of a queued operation is bounded whatever mix of quick, slow and long tasks runs; removing the new runner's first drive or the time bound each breaks it. - **A TLA+ model of the admission cap** (`proofs/tla/admission`): a finite operation never waits in room while none is in the kernel, and arrivals plus finite completions fit the queue; counting long-lived operations breaks the first, an uncut group the second. An accept's connections and the last completion of a multishot operation have no room kept: past the queue the kernel holds them (`IORING_FEAT_NODROP`), as before. - **Tests** (`tests/cadence.rs`, `rt::quartz`, `rt::shard::ring::tests_cap`, `config::tests`, `tests/config_sizes.rs`, `tests/config_refused.rs`) for these fixes and for the clock, and benchmarks of the cost of a task run and of IO on a shard. ## 0.5.1 ### Fixed - **A kernel that refuses provided buffer rings no longer stops a runtime from starting.** Ubuntu's 6.8 kernels from 6.8.0-136 on (24.04's own, and 22.04's HWE kernel) refuse every valid buffer ring registration with `EINVAL`: a backport inverted the check of its reserved words ([Launchpad bug 2162843](https://bugs.launchpad.net/ubuntu/+source/linux/+bug/2162843)). A runtime there failed to start with `io_uring recv_buffers and recv_buffer_size: Invalid argument`. The backend choice now builds the ring a shard runs (the ring, its table of fixed files, the buffer ring for multishot receives while `recv_buffers` is not 0, and its enabling), so a kernel that refuses a feature a shard needs makes `auto` pick the poller. A backend named as io_uring on such a kernel fails naming the refused feature, and a shard of an `auto` runtime whose ring is refused anyway runs the poller. With `recv_buffers: 0` io_uring stays in use there. - **A kernel's refusal and a configuration mistake are told apart.** The kernel's `EINVAL` from a buffer ring or a fixed file table registration is now an `Unsupported` error naming what it refused, and only nuclei's own checks of `recv_buffers` and `recv_buffer_size` are reported as the configuration's mistake. A shard whose receive group fails for any reason other than memory is no longer started without it, unseen. ### Added - **A CI job on Ubuntu 24.04's own kernel** (6.8 generic) beside the mainline ones, which all register buffer rings: the suite runs with the backend left to `auto`, which must choose epoll and name the refusal, and with epoll named. ## Unreleased: 0.5.0 Nuclei is now a runtime of its own: thread-per-core shards that each run their tasks and drive their own IO, timers and buffers. The guide at covers every part below with a program that compiles and runs. ### Added - **Runtime.** `Runtime`, `Builder` and `RuntimeHandle`; `spawn`, `spawn_local`, `spawn_blocking` and `block_on` on the process default runtime, which starts on first use with no configuration. `block_on` nests, in a task too, and keeps its shard's other tasks and IO going. `RuntimeHandle::current` and `try_current`, `enter` with its `EnterGuard`, `RuntimeId`, `worker_index`, `shutdown_timeout` and `shutdown_background`. Builder settings for the workers, their threads and stacks, the blocking pool, the IO buffer cap, `event_interval`, `global_queue_interval`, `max_io_events_per_tick`, `disable_lifo_slot`, `rng_seed`, `unhandled_panic`, `start_paused` and the backend, and hooks on threads and tasks. A runtime may start more workers up to a maximum and drain them again. - **Shard handoff.** A worker whose task stays in one poll past `Builder::handoff_after` (10 ms by default; `None` turns it off) hands its shard to another thread on the same core: the shard's other tasks, timers and IO in flight go on, the blocked task carries on once its poll returns, a nested `block_on` and the tasks `spawn_local` keeps on that thread finish on it, and a shutdown does not wait for it. A poll pays two plain stores and a load. `ShardStats` counts `handoffs` and the `longest_poll`. With the handoff on, an io_uring worker's ring takes submissions from any thread. - **Tasks.** `Task` with `detach`, `cancel`, `abort`, `abort_handle`, `join` (a `JoinError` says why a task gave no output) and `fallible`; `JoinSet`; task ids; `task::Builder`; `task_local!`; `yield_now`; the cooperative budget in `task::coop`. - **Macros.** `select!`, `join!` and `try_join!`; `#[nuclei::main]`, `#[nuclei::test]` and `#[nuclei::bench]`, from the new `nuclei-macros`, with the `threads`, `start_paused` and `crate` options. - **`nuclei::net`.** `TcpListener`, `TcpStream`, `UdpSocket`, `UnixListener`, `UnixStream` and `UnixDatagram`. Addresses are anything `ToSocketAddrs` takes, and names are looked up on the blocking pool (`lookup_host` alone). `TcpSocket` and `UnixSocket` set a socket up before it listens or connects: buffer sizes, address and port reuse, keepalive, no-delay, linger, the type of service, and the network interface on Linux. Stream halves (`split`, `into_split`, `reunite`); Unix abstract names (`bind_addr`, `connect_addr`), `peer_cred` and `UnixDatagram::unbound`; `poll_accept`, `poll_peek`, `peek_sender`, `recv_buf` and `recv_buf_from`; readiness waits (`readable`, `writable`, `ready` and their `poll_` forms) and the `try_` calls, answered from the handle's read-ahead and write-behind; `try_io` and `async_io` for calls of one's own on a socket (Unix); `net::unix::pipe` for anonymous pipes and FIFOs. - **`nuclei::io`.** `AsyncReadExt`, `AsyncWriteExt`, `AsyncBufReadExt` and `AsyncSeekExt`, `ReadBuf`, `copy`, `copy_buf` and `copy_bidirectional`, `BufReader`, `BufWriter` and `BufStream`, `duplex` and `simplex`, `split`, `empty`, `repeat` and `sink`, `stdin`, `stdout` and `stderr`, `Interest` and `Ready`; `io::unix::AsyncFd` drives a descriptor of one's own by readiness. - **`nuclei::fs`.** `File`, `OpenOptions`, `DirBuilder`, `read_dir` streamed a page at a time, and the calls by path (`read`, `write`, `copy`, `rename`, `metadata`, links and the rest). - **`nuclei::time`.** `sleep`, `sleep_until`, `timeout`, `timeout_at`, `interval`, `interval_at` and `Instant`; a clock that `pause`, `resume` and `advance` control, which jumps to the next timer when every shard is idle. - **`nuclei::sync`.** Mutexes, reader-writer locks with upgradable reads, reentrant locks keyed by `Owner`, semaphores, `Notify`, `Barrier`, `Event`, `Latch`, `OnceCell`, `SetOnce`, `Lazy`, `CancellationToken`, and mpsc, oneshot, broadcast (with weak senders) and watch channels. They need only futures and wakers, so they work under any executor. - **`nuclei::process`.** Child processes, their exits and their pipes; `kill_on_drop`, `kill`, `start_kill`, `try_wait`, `wait_with_output`, `spawn_with`, `as_std` and `into_std`. - **`nuclei::signal`.** Unix signals and Windows console events as streams, and `ctrl_c`. - **`nuclei::stats()`.** A snapshot of every shard's tasks, polls, IO in flight, buffers, timers and errors by kind, and of the blocking pool's threads. - **Backends.** An I/O completion port backend on Windows; multishot receives on io_uring, from a provided buffer pool per shard; `read_owned` and `write_owned`, which lend the driver the caller's buffer, on TCP and Unix streams and on files. - The `recycle` feature: node memory from a per-thread cache instead of the global allocator. - `proofs/`: TLA+ models of the concurrent protocols and Lean proofs of the arithmetic they rest on. ### Changed - The executor is nuclei's own; `init`, `init_with_config`, `spawn_more_threads`, `stop_thread`, `stop_current_thread` and `GlobalExecutorConfig` remain, on the shards. - On Linux io_uring comes first, probed safely (a seccomp filter that kills the caller included), and epoll serves where io_uring cannot be used. `NUCLEI_BACKEND` and `Builder::backend` pick one. - The epoll, kqueue and io_uring drivers are rewritten as proactive drivers of the shards: only the driver touches a descriptor, and every operation completes for the task that asked. - TCP and UDP `bind` are async and take any `ToSocketAddrs`, a name included. - `TcpListener::accept` gives `(Handle, SocketAddr)` on every backend. - `Handle` takes an `IoObject`: on Unix anything that implements `AsFd` (it was `AsRawFd`), on Windows TCP and UDP sockets, files and a child's pipes. - The io_uring ring is nuclei's own, on `libc` only, and needs Linux 6.1 or later. `IoUringConfiguration::default()` is interrupt-driven. - Edition 2024; the minimum Rust version is 1.99. ### Removed - The `async-exec` feature and the feature that ran the executor on another crate's runtime, and with them every dependency but `libc`, the `kovan` crates, `futures-io` and `futures-core`. - `nuclei-attributes`, replaced by `nuclei-macros`. - `HandleOpRegisterer`, `AsyncOp` and `Proactor::ring_params`. ### Migrating from 0.4 1. Ask for `nuclei = "0.5"` and Rust 1.99 or later, and drop the `async-exec` feature and any feature that named another runtime. 2. Name the socket types from `nuclei::net`: `TcpListener` is `Handle`, so code that spells the handle out still compiles. 3. Await `bind` on TCP and UDP: `Handle::::bind(addr)?` becomes `TcpListener::bind(addr).await?`. Unix `bind` stays synchronous. 4. Take the read and write helpers from `nuclei::io` (`AsyncReadExt`, `AsyncWriteExt`, ...); the handles implement the `futures-io` traits, so other crates' helpers keep working too. 5. Open files with `nuclei::fs` (`File::open(path).await`, `OpenOptions`), or keep `Handle::::open`. 6. Use `#[nuclei::main]` and `#[nuclei::test]` from the crate itself; remove the `nuclei-attributes` dependency. 7. Code that used `HandleOpRegisterer`, `AsyncOp` or `Proactor::ring_params` calls the handle's own methods instead; the ring's settings are `IoUringConfiguration`.