futures-rs

repository·main·Indexed 26 days ago

https://github.com/rust-lang/futures-rs

Foundational building blocks for asynchronous programming in Rust. It provides essential traits such as Future and Stream, control flow utilities like join! and select!, and communication primitives including oneshot and mpsc channels. The library includes core traits in futures-core, channel implementations in futures-channel, and execution utilities in futures-executor, with support for #[no_std] environments.

Tokens
14.7K
Snippets
41
Records
130
Agent score
91%

What's inside futures-rs

  1. Use futures-rs in a `#[no_std]` environment

    main

    By default, futures-rs includes the standard library (std). If you are working in a bare metal or #[no_std] environment, you must disable default features to use the reduced API surface.

    [dependencies]
    futures = { version = "0.3", default-features = false }
  2. Use LocalPool for single-threaded task execution

    main

    A LocalPool is a single-threaded task pool used to multiplex multiple tasks onto a single thread. It is ideal for I/O-bound futures that perform minimal work between I/O actions. Because it is single-threaded, it supports spawning non-Send futures using spawn_local_obj via a LocalSpawner handle.

    use futures::executor::LocalPool;
    
    let mut pool = LocalPool::new();
    // ... spawn tasks ...
    pool.run();
  3. Core asynchronous abstractions in futures-rs

    main

    The futures crate provides the fundamental building blocks for asynchronous programming in Rust:

    • Futures: Single eventual values produced by asynchronous computations (similar to Promises in JavaScript).
    • Streams: A series of values produced asynchronously over time.
    • Sinks: Support for asynchronous writing of data.
    • Executors: Responsible for running asynchronous tasks.
    • Asynchronous I/O: Abstractions for reading and writing data asynchronously.
    • Cross-task communication: Channels for sending data between tasks.
  4. Use `futures-util` combinators for Futures and Streams

    main

    futures-util provides essential extension traits and combinators for working with asynchronous primitives.

    • Futures: Use FutureExt and TryFutureExt to access combinators that transform or manage Futures.
    • Streams: Use StreamExt and TryStreamExt to manipulate Streams (sequences of values).
    • Sinks: Use SinkExt to manage Sinks (consumers of values).

    Note: Most combinators are marked #[must_use], meaning they do nothing unless you .await them or poll them.

  5. Create a ThreadPool using default configuration

    main

    Use ThreadPool::new() to create a general-purpose thread pool that multiplexes tasks onto a fixed number of worker threads. The number of threads defaults to the number of available CPU cores. This type is available only when the thread-pool feature is enabled.

    Note: ThreadPool is a clonable handle; cloning it creates a new reference to the same pool, not a new pool.

    use futures::executor::ThreadPool;
    
    let pool = ThreadPool::new().unwrap();
  6. Create a counting Waker with new_count_waker

    main

    In testing scenarios, you can use new_count_waker to create a Waker that tracks how many times it has been awoken. This function returns a tuple containing the Waker and an AwokenCount handle used to inspect the wake count.

    use futures_test::task::new_count_waker;
    
    let (waker, count) = new_count_waker();
    
    assert_eq!(count, 0);
    
    waker.wake_by_ref();
    waker.wake();
    
    assert_eq!(count, 2);
  7. Use the `#[futures_test::test]` attribute for async tests

    main

    The #[futures_test::test] attribute allows you to write asynchronous test functions directly. It automatically wraps the async function in futures_executor::block_on, running the generated future to completion. This is a convenient alternative to manually calling block_on inside a standard #[test] function.

    #[futures_test::test]
    async fn my_test() {
        let fut = async { true };
        assert!(fut.await);
    }
  8. Abort a future or stream using Abortable

    main

    The Abortable<T> wrapper allows you to remotely short-circuit a future or stream. You can control the abortion using an AbortHandle. When aborted, an Abortable future returns Err(Aborted), and an Abortable stream returns None (completes).

    # futures::executor::block_on(async {
    # use futures::future::{Abortable, AbortHandle, Aborted};
    
    // Usage with futures:
    let (abort_handle, abort_registration) = AbortHandle::new_pair();
    let future = Abortable::new(async { 2 }, abort_registration);
    abort_handle.abort();
    assert_eq!(future.await, Err(Aborted));
    
    # use futures::stream::{self, StreamExt};
    // Usage with streams:
    let (abort_handle, abort_registration) = AbortHandle::new_pair();
    let mut stream = Abortable::new(stream::iter(vec![1, 2, 3]), abort_registration);
    abort_handle.abort();
    assert_eq!(stream.next().await, None);
    # });
  9. Use PanicSpawner to test panic behavior in tasks

    main

    The PanicSpawner is a testing utility provided by futures-test that implements the Spawn trait but panics whenever a task is attempted to be spawned. This is useful for verifying that your code correctly handles or avoids spawning tasks in specific scenarios.

    use futures::task::SpawnExt;
    use futures_test::task::PanicSpawner;
    
    let spawn = PanicSpawner::new();
    spawn.spawn(async { })?; // This call will panic
    # Ok::<(), Box<dyn std::error::Error>>(())