pub fn with_branded_token_async<'a, F, R>(f: F) -> impl Future<Output = R> + 'a where
    for<'brand> F: IntoBrandedFuture<'brand, Output = R> + 'a, 
Available on crate feature unstable only.
Expand description

Call the provided closure with a brand new BrandedToken, which can only be used during the execution of the returned Future.

This pattern is an asynchronous extension of GhostCell. See with_branded_token for the synchronous version.

Example

Passing impl FnOnce(BrandedToken<'_>) -> impl Future (a free async fn):

use async_scoped::TokioScope;
use futures::executor::block_on;
use rayon::prelude::*;
use std::pin::Pin;
use tokenlock::{with_branded_token_async, BrandedTokenLock, BrandedToken};

struct Node<'arena, 'brand> {
    next: BrandedTokenLock<'brand, Option<&'arena Node<'arena, 'brand>>>,
}

with_branded_token_async(task).await;

async fn task(mut token: BrandedToken<'_>) {
    let mut token = token;
    let arena = [
        Node { next: BrandedTokenLock::wrap(None) },
        Node { next: BrandedTokenLock::wrap(None) },
    ];

    // Link the nodes together
    arena[0].next.replace(&mut token, Some(&arena[1]));
    arena[1].next.replace(&mut token, Some(&arena[0]));

    // Unlike `Cell`, this doesn't prevent shared read-only access
    TokioScope::scope_and_block(|s| {
        for node in arena.iter() {
            let token = token.borrow();
            s.spawn(async move {
                println!("{:p} is linked to {:p}", node, node.next.get(&*token).unwrap());
            });
        }
    });
}

Passing (T, impl FnOnce(T, BrandedToken<'_>) -> impl Future):

let mut value = 0;
with_branded_token_async((&mut value, task)).await;
assert_eq!(value, 42);

async fn task(borrowed_value: &mut i32, _token: BrandedToken<'_>) {
    *borrowed_value = 42;
}

Closures don’t work currently:

with_branded_token_async(|token: BrandedToken<'_>| async move {
    let _ = token;
}).await;