pub struct BorrowMutex<const MAX_BORROWERS: usize, T: ?Sized> { /* private fields */ }Expand description
Async Mutex which does not require wrapping the target structure.
A &mut T can be lended to the mutex at any given time.
This lets any other side borrow the &mut T. The mutable ref is borrow-able
only while the lender awaits, and the lending side can await until someone
wants to borrow. The semantics enforce at most one side has a mutable reference
at any given time.
This lets us share any mutable object between distinct async contexts
without Arc<Mutex> over the object in question and without relying
on any kind of internal mutability. It’s mostly aimed at single-threaded
executors where internal mutability is unnecessary complication.
Still, the BorrowMutex is Send+Sync and can be safely used from
any number of threads.
Implementations§
Source§impl<const M: usize, T: ?Sized> BorrowMutex<M, T>
impl<const M: usize, T: ?Sized> BorrowMutex<M, T>
Sourcepub const MAX_BORROWERS: usize = M
pub const MAX_BORROWERS: usize = M
Note: must be a power of 2, and must be >= 2
Sourcepub const fn new() -> Self
pub const fn new() -> Self
Create a new empty BorrowMutex.
Sourcepub fn try_borrow<'g, 'm: 'g>(&'m self) -> BorrowGuardUnarmed<'g, T> ⓘ
pub fn try_borrow<'g, 'm: 'g>(&'m self) -> BorrowGuardUnarmed<'g, T> ⓘ
Obtain a mutable reference. The returned BorrowGuardUnarmed is
a future that resolves after BorrowMutex::lend() is called.
Specifically, it resolves to Result<BorrowGuardArmed, Error>.
The error can be:
- the max number of concurrent borrowers was reached -
MAX_BORROWERS. - the mutex was terminated via
BorrowMutex::terminate()call.
The borrowers are lended to in FIFO order but they get put to the waiting queue only on their first poll.
A borrow guard which was lended to must be dropped to allow further borrows to happen.
Sourcepub fn wait_to_lend<'g, 'm: 'g>(&'m self) -> LendWaiter<'g, T> ⓘ
pub fn wait_to_lend<'g, 'm: 'g>(&'m self) -> LendWaiter<'g, T> ⓘ
Wait until BorrowMutex::try_borrow() is called.
BorrowMutex::lend() can be called immediately after.
§Note
This can be called concurrently from multiple async contexts but only one wait-er is guaranteed to be awoken.
Sourcepub fn lend<'g, 'm: 'g>(&'m self, value: &'g mut T) -> Option<LendGuard<'g, T>>
pub fn lend<'g, 'm: 'g>(&'m self, value: &'g mut T) -> Option<LendGuard<'g, T>>
Lend a mutable reference to the first waiting borrower (FIFO order).
The usual pattern is to select! on BorrowMutex::wait_to_lend(),
then lend() and await.
The await returns after the borrower drops.
This can be also called when there are no borrowers at the time,
and the returned LendGuard will effectively wait until the first
borrower appears.
This can fail and return None when either:
- someone else is currently lending
- someone else is currently terminating the mutex
On successful lend, a LendGuard future is returned which:
- can be immediately dropped, which makes the whole operation invisible to the borrower - it will keep waiting for another lender
- or, can be polled, and then has to be polled until completion
The first poll will awake the borrower. Dropping the LendGuard before
it resolves (which implies - before the borrowing side drops its guard)
will abort the process.
Do not forget the LendGuard with core::mem::forget() or similar,
as it may cause Undefined Behavior.
Sourcepub async fn terminate(&self) -> Option<()>
pub async fn terminate(&self) -> Option<()>
Make any borrows requests (pending or to-be-made) return
Error::Terminated.
The mutex remains terminated until another BorrowMutex::lend()
is called.
This can also fail and return None when either:
- someone else is currently lending
- someone else is currently terminating the mutex
§Note
This is an async function as the existing borrowers need to be awoken one by one to drop their guard, which then allows this function to proceed. This only applies to existing borrowers - Any borrows made after the function was polled at least once will immediately return an error on the first poll.