waitmap - an async awaitable map

I’ve just released a new crate called waitmap. This is a concurrent hash map (built on top of dashmap) intended for use as a concurrency primitive with async/await. It extends the API of dashmap by having an additional wait method.

The wait future looks up an entry in the map and suspends this task if the entry was not present when wait was called. The task will be woken whenever a value is inserted under that key.

For example:

// task a
// This task will pause until a value is inserted under the key
// "Rosa Luxemburg"
if let Some(value) = map.wait("Rosa Luxemburg").await {
    // process `value`
}


// task b
// This task will insert a value under "Rosa Luxemburg", causing
// task a to wake up
map.insert(String::from("Rosa Luxemburg"), some_value);

This allows the map to act as a concurrency primitive in a program using async/await. It seems particularly beneficial for compute-heavy loads: pausing work on one task which depends on another task until that task is actually done. (For example, this map could be a primitive for constructing some sort of parallel memoization system.)

Cancelling waits

However, a task waiting on an entry will wait forever if nothing is ever filled under that key. Therefore, waitmap also has an API called cancel, which allows the user to wake any tasks waiting on a particular key, causing their futures to yield None (signalling that there is no value under that key). For example:

// task a
if let Some(value) = map.wait("Voltairine de Cleyre").await {
    // process `value`
}

// task b
// This causes task a to wake up and receive `None`, not entering
// the block to process this value
map.cancel("Voltairine de Cleyre");

Under the hood

Internally, a WaitMap stores as the value an enum of either the value or a set of wakers. When you start waiting on a value that has not been set, your task adds this waker under that value. Then, when the value is actually set, all of the wakers that have been stored there are awoken. Wakers are stored as a SmallVec with an optimization to store 1 waker inline, rather than in a separate allocation.

Maintenance

I enjoyed writing the first draft of this library, and I’ve unblocked my own work now, but I have very little interest in expanding, documenting, and maintaining this code. If anyone is looking for an open source library to take on, I would be excited to start accepting your PRs with the end goal of eventually passing off maintainership entirely!

In particular, the API is still not feature-compatible with the std hash map API or dashmap (for example, no entry API) and it has absolutely no documentation and only a very basic smoke test.