A quick-and-dirty attempt to get scoped tasks in Rust.

Overview

scoped_tasks_prototype

A quick-and-dirty attempt to get scoped tasks in Rust.

This library tries to provide an interface similar to scoped threads, accessible from tasks. See Tyler Mandry's article for why this is non-trivial. This crate explores the "Restricting Borrowing" option described in that post.

To be specific, this crate creates three concepts:

  • A Bank, where your task is stored.
  • Vaults, located inside the Bank.
  • Loans which point to contents of the Vaults.

When you want to run scoped tasks, you call the scope function:

scope(|bank| async move {
    // code that will spawn tasks
})

This function accepts a callback which returns a promise (alas, no async closures yet); that callback will be given a Bank, which represents the underlying memory the promise is stored in.

Inside the callback, you can use the vault! macro to pin values to that underlying storage (it's literally a slightly modified version of the standard pin! macro):

let a = vault!(vec![1, 2, 3]);
let x = vault!(0);

Finally, you can use that vault and the bank to get loans. Loans are 'static values storing a reference to a vault, and a shared reference to the bank. The bank can't possibly be dropped until all loans are dropped, even if the parent task is dropped, which means that a loan is always safe to deref:

let a = a.loan(&bank);
let mut x = x.loan_mut(&bank);
tokio::spawn(async move {
    let a = a.deref();
    let x = x.deref_mut();
    *x += a[0] + a[2];
})

Taken together, this means it's possible with some overhead to run scoped tasks with a syntax similar to scoped threads:

async fn foobar() {
    scope(|bank| async move {
        let a = vault!(vec![1, 2, 3]);
        let x = vault!(0);

        let t1 = {
            let a = a.loan(&bank);
            tokio::spawn(async move {
                let a = a.deref();
                // We can borrow `a` here.
                println!("hello from the first scoped task: {:?}", a);
            })
        };

        let t2 = {
            let a = a.loan(&bank);
            let mut x = x.loan_mut(&bank);
            tokio::spawn(async move {
                let a = a.deref();
                let x = x.deref_mut();

                println!("hello from the second scoped task");
                // We can even mutably borrow `x` here,
                // because no other tasks are using it.
                *x += a[0] + a[2];
            })
        };

        t1.await.unwrap();
        t2.await.unwrap();
    })
    .await;
}

How safe is this?

:shrug_emoji:

This is very much at the proof-of-concept stage.

So far I've only tried to run examples in the repo, including the threads example with MIRI, which reported no error. It does not immediately blow up my computer, which is honestly better than I expected.

If people are interested, I would strongly encourage them to poke at this at the seams and see if any parts of the crate are unsound. I have virtually no experience whatsoever with unsafe, so I'm curious if I missed something.

More importantly, I'm hoping this serves as inspiration to the writers of async runtimes for including similar concepts in their crates. Scoped tasks aren't impossible, there's just a lot of design space we need to explore before they can really become convenient to use. This is just one very early attempt.

You might also like...
Quick, lightweight find and replace cli tool.

quick-replace A fast, lightweight find and replace tool Usage quick-replace [OPTIONS] FROM TO path/to/file.txt Options Flag Description -h Displ

A simple and efficient terminal UI implementation with ratatui.rs for getting quick insights from csv files right on the terminal
A simple and efficient terminal UI implementation with ratatui.rs for getting quick insights from csv files right on the terminal

CSV-GREP csv-grep is an intuitive TUI application writting with ratatui.rs for reading, viewing and quickly analysing csv files right on the terminal.

Attempt to summarize text from `stdin`, using a large language model (locally and offline), to `stdout`

summarize-cli Attempt to summarize text from stdin, using a large language model (locally and offline), to stdout. cargo build --release target/releas

A modern high-performance open source file analysis library for automating localization tasks

🧛 Filecount Filecount is a modern high-performance open source file analysis library for automating localization tasks. It enables you to add file an

A library providing helpers for various StarkNet fees related tasks.
A library providing helpers for various StarkNet fees related tasks.

🐺 How Much ? 🦀 Table of Contents About Getting Started Prerequisites Installation Usage Estimate fees on network Authors & contributors Security Lic

A program that provides LLMs with the ability to complete complex tasks using plugins.

SmartGPT SmartGPT is an experimental program meant to provide LLMs (particularly GPT-3.5 and GPT-4) with the ability to complete complex tasks without

Advent of Code 2021, also an attempt to practice a bit of Rust.

Advent of Code 2021 Advent of Code 2021 (my first one!), also an attempt to practice a bit of Rust. Running (Assuming that the respective inputs are i

Best-effort attempt at rewriting Reticulum in Rust.

reticulum-rs WIP rewrite of Reticulum in Rust explicitly targeted at the ESP32 (no tokio, avoids memory-inefficient data structures. etc). Not ready f

Attempt to make a git profile switcher to switch profiles.

Git Profile Switcher █▀▀ █ ▀█▀   █▀ █░█░█ █ ▀█▀ █▀▀ █░█ █▀▀ █▀█ █▄█ █ ░█░   ▄█ ▀▄▀▄▀ █ ░█░ █▄▄ █▀█

Owner
Olivier FAURE
Developer, Tinker 2 rating
Olivier FAURE
Quick & Dirty cli to process mysql dumps

mysql2databend Quick & Dirtyl CLI to process mysql dumps and clean them so they can be ingested in Databend using a regular MySQL client. Features: re

Scoop.it Inc 9 Oct 2, 2022
Semi-persistent, scoped test directories

Semi-persistent, scoped test directories This crate aims to make it easier to use temporary directories in tests, primarily by calling the testdir!()

Floris Bruynooghe 4 Nov 19, 2022
A simple solution for scoped styles in Leptos

Styled: Easy Styling for Leptos Components If you're looking for an easy way to apply scoped styles to your Leptos components, Styled is the Leptos ma

Eran Boodnero 8 Mar 5, 2023
Check a folder for dirty git repositories, forgotten branches and commits

dg - find dirty git repos Ever forgot to push a commit or lost your work because you assumed it was pushed to Github but it wasn't? dg finds local git

Dotan J. Nahum 11 Mar 19, 2023
Horus is an open source tool for running forensic and administrative tasks at the kernel level using eBPF, a low-overhead in-kernel virtual machine, and the Rust programming language.

Horus Horus is an open-source tool for running forensic and administrative tasks at the kernel level using eBPF, a low-overhead in-kernel virtual mach

null 4 Dec 15, 2022
A blazingly fast Insertion Sort and Quick Sort visualizer built with Rust and WASM.

sortysort A blazingly fast Insertion Sort and Quick Sort visualizer built with Rust and WASM. Try it in your browser from here Testing locally cargo r

null 3 Jan 28, 2022
Create tasks and save notes offline from your terminal

Create tasks and save notes offline from your terminal

null 9 Dec 18, 2022
Stall tracking for Python's GIL and Trio tasks

Perpetuo perpetuo, verb: To cause to continue uninterruptedly, to proceed with continually Perpetuo is a stall tracker for Python. Specifically, it ca

Nathaniel J. Smith 10 Apr 29, 2023
An feature packed Google Tasks CLI written purely in Rust

rChore A feature packed unofficial Google Tasks CLI to boost your producitvity, written purely in Rust. ?? What is rChore? rChore is an unofficial Goo

Hemanth Krishna 41 Dec 24, 2022
A truly zero-dependency crate providing quick, easy, reliable, and scalable access to the name "jordin"

jordin Finally! A truly zero-dependency crate providing quick, easy, reliable, and scalable access to the name "jordin". Additionally, this one-of-a-k

jordin 2 Aug 4, 2022