Async мутекс

Краен срок
19.01.2025 23:59
Точки
4

Срокът за предаване на решения е отминал

// Warning: the test uses the `futures` library.
// This is available only to the testing code (it is a dev-dependency),
// it is not available to the solution code.
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
use futures::{SinkExt, StreamExt};
use solution::*;
#[test]
fn test_futures_join() {
run_with_timeout(1000, || async {
let resource = Arc::new(MyMutex::new(vec![]));
let (mut sender_3to1, mut recv_3to1) = futures::channel::mpsc::channel(1);
let fut1 = {
// A future that locks the resource, then holds the lock across an
// await point (awaiting the next message from the channel).
//
// With an async-aware mutex this is not a problem - while `fut1` is blocked,
// `fut2` and `fut3` can still run. So eventually `fut3` will send the message
// and unblock `fut1`.
let resource = Arc::clone(&resource);
async move {
let mut lock = resource.lock().await;
let () = recv_3to1.next().await.unwrap();
lock.push("one".to_string());
}
};
let fut2 = {
let resource = Arc::clone(&resource);
async move {
let mut lock = resource.lock().await;
lock.push("two".to_string());
}
};
let fut3 = {
let resource = Arc::clone(&resource);
async move {
sender_3to1.send(()).await.unwrap();
let mut lock = resource.lock().await;
lock.push("three".to_string());
}
};
// `join` polls the futures in order.
//
// Also `join` provides a single `Waker`, which just wakes the `Join3` future,
// which every time polls each of the inner futures in order.
// So using any waker will "wake" all three futures.
futures::future::join3(fut1, fut2, fut3).await;
assert_eq!(&*resource.lock().await, &["one", "two", "three"]);
});
}
#[test]
fn test_futures_unordered() {
run_with_timeout(1000, || async {
let resource = Arc::new(MyMutex::new(vec![]));
let (mut sender_3to1, mut recv_3to1) = futures::channel::mpsc::channel(1);
let fut1 = pin_box({
let resource = Arc::clone(&resource);
async move {
let mut lock = resource.lock().await;
let () = recv_3to1.next().await.unwrap();
lock.push("one".to_string());
}
});
let fut2 = pin_box({
let resource = Arc::clone(&resource);
async move {
let mut lock = resource.lock().await;
lock.push("two".to_string());
}
});
let fut3 = pin_box({
let resource = Arc::clone(&resource);
async move {
sender_3to1.send(()).await.unwrap();
let mut lock = resource.lock().await;
lock.push("three".to_string());
}
});
// Same example, but uses `FuturesUnordered` instead of `join`.
//
// `FuturesUnordered` doesn't guarantee any ordering.
// Also it is more optimized for a large number of futures and will provide a separate
// `Waker` for each of the inner futures.
// So we can test that the correct wakers are being used.
let mut unordered = futures::stream::FuturesUnordered::from_iter([fut1, fut2, fut3]);
while let Some(_) = unordered.next().await {}
let mut final_resource = resource.lock().await.clone();
final_resource.sort();
assert_eq!(final_resource, &["one", "three", "two"]);
});
}
fn run_with_timeout<F, R>(timeout_millis: u64, test_fn: F)
where
F: FnOnce() -> R + Send + std::panic::UnwindSafe + 'static,
R: Future<Output = ()> + 'static,
{
use futures::task::LocalSpawn;
use std::panic::catch_unwind;
use std::sync::mpsc;
let (sender, receiver) = mpsc::sync_channel(1);
std::thread::spawn(move || {
let result = catch_unwind(move || {
let mut runtime = futures::executor::LocalPool::new();
let test_future = Box::new(test_fn());
runtime.spawner().spawn_local_obj(test_future.into()).unwrap();
runtime.run();
});
let _ = sender.send(result);
});
let timeout = std::time::Duration::from_millis(timeout_millis);
match receiver.recv_timeout(timeout) {
Ok(Ok(())) => {}
Ok(Err(any)) => panic!("test panicked: {}", any.downcast::<&str>().unwrap()),
Err(mpsc::RecvTimeoutError::Timeout) => panic!("test timed out"),
Err(mpsc::RecvTimeoutError::Disconnected) => unreachable!(),
}
}
fn pin_box<F>(fut: F) -> Pin<Box<dyn Future<Output = ()>>>
where
F: Future<Output = ()> + 'static,
{
Box::into_pin(Box::new(fut) as Box<dyn Future<Output = ()>>)
}

Имплементирайте async-aware мутекс.

Това изисква скок в дълбокото, защото ще трябва да се имплементира един Future на ръка. Но от друга страна е добро упражнение, ако човек иска да добие интуиция как работят future-ите в езика.

За по-лесно, ще искаме въпросния мутекс да не е thread safe, т.е. да може да се използва само от single threaded runtime.

use std::cell::RefCell;
use std::future::Future;
use std::ops::{Deref, DerefMut};
use std::pin::Pin;
use std::task::{Context, Poll};

/// Неблокиращ мутекс, предназначен да се използва от асинхронен код.
pub struct MyMutex<T> {
    value: RefCell<T>,
    /* todo: other fields */
}

impl<T> MyMutex<T> {
    pub fn new(value: T) -> Self {
        todo!()
    }

    // Забележете, че `lock` не е маркирана като `async fn`, защото си имплементираме future-а
    // на ръка (тук компилатора няма как да ни помогне).
    //
    // Бихме могли да я декларираме `fn lock() -> impl Future<Output = MyMytexGuard<'_, T>>`,
    // ако искаме да не правим структурата публична, но пак ще трябва да си напишем и върнем
    // наша структура.
    pub fn lock(&self) -> MyMutexLockFuture<'_, T> {
        todo!()
    }

    fn unlock(&self) {
        todo!()
    }
}

pub struct MyMutexLockFuture<'a, T> {
    /* todo: fields */
}

impl<'a, T> Future for MyMutexLockFuture<'a, T> {
    type Output = MyMutexGuard<'a, T>;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        todo!()
    }
}

pub struct MyMutexGuard<'a, T> {
    /* todo: fields */
}

impl<'a, T> Deref for MyMutexGuard<'a, T> {
    type Target = T;
    fn deref(&self) -> &Self::Target {
        todo!()
    }
}

impl<'a, T> DerefMut for MyMutexGuard<'a, T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        todo!()
    }
}

impl<'a, T> Drop for MyMutexGuard<'a, T> {
    fn drop(&mut self) {
        // hint: извикайте MyMytex::unlock
        todo!()
    }
}

Зашо използваме RefCell за value? Защото ни дава всичката необходима функционалност. За да имплементираме мутекса е нужно да можем от &MyMutex<T> да вземем &mut T, за което е нужен някакъв вид internal mutability.
Бихме могли да използваме std::sync::Mutex, но няма да го използваме пълноценно. Или дори UnsafeCell, но това изисква unsafe код и просто ще преимплементираме RefCell (но би имало смисъл, ако правим thread safe вариант).

Изискването за мутекса е когато две задачи (task-а) се опитат да го заключат едновременно, т.е. да извикат my_mutex.lock().await, едната задача ще получи MyMutexGuard и ще продължи изпълнението си, докато другата ще бъде "блокирана" и ще трябва да изчака, докато мутекса не се освободи.
За да се получи това, при poll-ването на future-а, върнат от my_mutex.lock(), във втората задача трябва да се върне Poll::Pending, което означава, че задачата за момента не може да продължи работата си. Съответно async runtime-а повече няма да schedule-ва тази задача, но е свободен да изпълнява други задачи. Когато обаче мутекса се освободи, runtime-а трябва да бъде уведомен, че втората задача вече може да направи прогрес. За целта предварително трябва да се вземе Waker обекта за съответната задача, който може да бъде получен от Context параметъра на poll, и да се запази до момента, в който задачата трябва да бъде събудена.

Целия тест можете да намерите на https://github.com/fmi/rust-homework/blob/master/2024/challenge_03/tests/test_full.rs.
Внимание - теста използва futures библиотеката, но тя е достъпна само за тестовете, но не и за решението (добавена е като dev-dependency). В решението не можете да използвате външни библиотеки - но не са ви и нужни.

Решения

Никола
  • Коректно
  • 2 успешни тест(а)
  • 0 неуспешни тест(а)
Никола

use std::cell::{RefCell, RefMut};
use std::collections::VecDeque;
use std::future::Future;
use std::ops::{Deref, DerefMut};
use std::pin::Pin;
use std::task::{Context, Poll, Waker};
pub struct MyMutex<T> {
value: RefCell<T>,
waiters: RefCell<VecDeque<Waker>>,
}
impl<T> MyMutex<T> {
pub fn new(value: T) -> Self {
MyMutex {
value: RefCell::new(value),
waiters: RefCell::new(VecDeque::new()),
}
}
pub fn lock(&self) -> MyMutexLockFuture<'_, T> {
MyMutexLockFuture { mutex: Some(self) }
}
fn unlock(&self) {
if let Some(waiter) = self.waiters.borrow_mut().pop_front() {
waiter.wake();
}
}
}
pub struct MyMutexLockFuture<'a, T> {
mutex: Option<&'a MyMutex<T>>,
}
impl<'a, T> Future for MyMutexLockFuture<'a, T> {
type Output = MyMutexGuard<'a, T>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let mutex = self.mutex.clone().expect("polling a finished MyMutexLockFuture");
match mutex.value.try_borrow_mut() {
Ok(borrow) => {
self.mutex = None;
Poll::Ready(MyMutexGuard { borrow, mutex })
}
Err(_) => {
mutex.waiters.borrow_mut().push_back(cx.waker().clone());
Poll::Pending
}
}
}
}
pub struct MyMutexGuard<'a, T> {
borrow: RefMut<'a, T>,
mutex: &'a MyMutex<T>,
}
impl<'a, T> Deref for MyMutexGuard<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&*self.borrow
}
}
impl<'a, T> DerefMut for MyMutexGuard<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut *self.borrow
}
}
impl<'a, T> Drop for MyMutexGuard<'a, T> {
fn drop(&mut self) {
self.mutex.unlock();
}
}
Updating crates.io index
     Locking 18 packages to latest compatible versions
   Compiling proc-macro2 v1.0.93
   Compiling unicode-ident v1.0.14
   Compiling autocfg v1.4.0
   Compiling slab v0.4.9
   Compiling futures-sink v0.3.31
   Compiling futures-core v0.3.31
   Compiling quote v1.0.38
   Compiling syn v2.0.96
   Compiling futures-channel v0.3.31
   Compiling pin-project-lite v0.2.16
   Compiling pin-utils v0.1.0
   Compiling futures-io v0.3.31
   Compiling futures-task v0.3.31
   Compiling memchr v2.7.4
   Compiling solution v0.1.0 (/tmp/d20250120-1137348-1rpvh7e/solution)
   Compiling futures-macro v0.3.31
   Compiling futures-util v0.3.31
   Compiling futures-executor v0.3.31
   Compiling futures v0.3.31
    Finished `test` profile [unoptimized + debuginfo] target(s) in 31.08s
     Running tests/solution_test.rs (target/debug/deps/solution_test-f2cda45de43a0fd3)

running 2 tests
test solution_test::test_futures_join ... ok
test solution_test::test_futures_unordered ... ok

test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Габриела Димитрова
  • Коректно
  • 2 успешни тест(а)
  • 0 неуспешни тест(а)
Габриела Димитрова

use std::cell::{RefCell, UnsafeCell};
use std::future::Future;
use std::ops::{Deref, DerefMut};
use std::pin::Pin;
use std::task::{Context, Poll, Waker};
pub struct MyMutex<T> {
inner: RefCell<Inner<T>>,
}
struct Inner<T> {
value: UnsafeCell<T>,
locked: bool,
wakers: Vec<Waker>, // tasks to wake up when the lock is released
}
impl<T> MyMutex<T> {
pub fn new(value: T) -> Self {
Self {
inner: RefCell::new(Inner {
value: UnsafeCell::new(value),
locked: false,
wakers: Vec::new(),
}),
}
}
// `lock` is not marked as `async fn` since we are implementing our own future
pub fn lock(&self) -> MyMutexLockFuture<'_, T> {
print!("LOCK\n");
MyMutexLockFuture { mutex: self }
}
pub fn unlock(&self) {
print!("UNLOCK\n");
let mut inner = self.inner.borrow_mut();
inner.locked = false;
for waker in inner.wakers.drain(..) {
print!("Task woken\n");
waker.wake();
}
}
}
pub struct MyMutexLockFuture<'a, T> {
mutex: &'a MyMutex<T>,
}
impl<'a, T> Future for MyMutexLockFuture<'a, T> {
type Output = MyMutexGuard<'a, T>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let mut inner = self.mutex.inner.borrow_mut();
if !inner.locked {
print!("Poll locking\n");
// lock is available; acquire it
inner.locked = true;
Poll::Ready(MyMutexGuard {
mutex: self.mutex,
})
} else {
print!("Poll unlocking\n");
inner.wakers.push(cx.waker().clone());
// drop the borrow before returning Poll::Pending
drop(inner);
//inner.locked = false;
Poll::Pending
}
}
}
impl<'a, T> Drop for MyMutexGuard<'a, T> {
fn drop(&mut self) {
print!("DROP INNER\n");
self.mutex.unlock();
}
}
pub struct MyMutexGuard<'a, T> {
mutex: &'a MyMutex<T>,
}
impl<'a, T> Deref for MyMutexGuard<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
// borrow the value from the RefCell and return a reference to it
unsafe { &*self.mutex.inner.borrow().value.get() }
}
}
impl<'a, T> DerefMut for MyMutexGuard<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
// access the protected data mutably through RefCell
unsafe { &mut *self.mutex.inner.borrow().value.get() }
}
}
Updating crates.io index
     Locking 18 packages to latest compatible versions
   Compiling proc-macro2 v1.0.93
   Compiling unicode-ident v1.0.14
   Compiling autocfg v1.4.0
   Compiling slab v0.4.9
   Compiling futures-sink v0.3.31
   Compiling futures-core v0.3.31
   Compiling futures-channel v0.3.31
   Compiling quote v1.0.38
   Compiling syn v2.0.96
   Compiling futures-task v0.3.31
   Compiling pin-project-lite v0.2.16
   Compiling memchr v2.7.4
   Compiling futures-io v0.3.31
   Compiling pin-utils v0.1.0
   Compiling solution v0.1.0 (/tmp/d20250120-1137348-15g0o8z/solution)
   Compiling futures-macro v0.3.31
   Compiling futures-util v0.3.31
   Compiling futures-executor v0.3.31
   Compiling futures v0.3.31
    Finished `test` profile [unoptimized + debuginfo] target(s) in 1m 03s
     Running tests/solution_test.rs (target/debug/deps/solution_test-f2cda45de43a0fd3)

running 2 tests
test solution_test::test_futures_join ... ok
test solution_test::test_futures_unordered ... ok

test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Стоян Генчев
  • Коректно
  • 2 успешни тест(а)
  • 0 неуспешни тест(а)
Стоян Генчев

use std::cell::{RefCell, RefMut};
use std::collections::VecDeque;
use std::future::Future;
use std::ops::{Deref, DerefMut};
use std::pin::Pin;
use std::task::{Context, Poll, Waker};
/// Неблокиращ мутекс, предназначен да се използва от асинхронен код.
pub struct MyMutex<T> {
value: RefCell<T>,
queue: RefCell<VecDeque<Waker>>,
locked: RefCell<bool>,
}
impl<T> MyMutex<T> {
pub fn new(value: T) -> Self {
MyMutex {
value: RefCell::new(value),
queue: RefCell::new(VecDeque::new()),
locked: RefCell::new(false),
}
}
// Забележете, че `lock` не е маркирана като `async fn`, защото си имплементираме future-а
// на ръка (тук компилатора няма как да ни помогне).
//
// Бихме могли да я декларираме `fn lock() -> impl Future<Output = MyMytexGuard<'_, T>>`,
// ако искаме да не правим структурата публична, но пак ще трябва да си напишем и върнем
// наша структура.
pub fn lock(&self) -> MyMutexLockFuture<'_, T> {
MyMutexLockFuture { mutex: self }
}
fn unlock(&self) {
let mut locked = self.locked.borrow_mut();
*locked = false;
let mut queue = self.queue.borrow_mut();
if let Some(waker) = queue.pop_front() {
waker.wake();
}
}
}
pub struct MyMutexLockFuture<'a, T> {
mutex: &'a MyMutex<T>,
}
impl<'a, T> Future for MyMutexLockFuture<'a, T> {
type Output = MyMutexGuard<'a, T>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let mut locked = self.mutex.locked.borrow_mut();
if !*locked {
*locked = true;
let mutex = self.mutex;
let value_borrowed_mut = self.mutex.value.borrow_mut();
Poll::Ready(MyMutexGuard {
mutex,
value_borrowed_mut
})
} else {
let mut queue = self.mutex.queue.borrow_mut();
queue.push_back(cx.waker().clone());
Poll::Pending
}
}
}
pub struct MyMutexGuard<'a, T> {
mutex: &'a MyMutex<T>,
value_borrowed_mut: RefMut<'a, T>,
}
impl<'a, T> Deref for MyMutexGuard<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&*self.value_borrowed_mut
}
}
impl<'a, T> DerefMut for MyMutexGuard<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut *self.value_borrowed_mut
}
}
impl<'a, T> Drop for MyMutexGuard<'a, T> {
fn drop(&mut self) {
self.mutex.unlock();
}
}
Updating crates.io index
     Locking 18 packages to latest compatible versions
   Compiling proc-macro2 v1.0.93
   Compiling unicode-ident v1.0.14
   Compiling autocfg v1.4.0
   Compiling slab v0.4.9
   Compiling quote v1.0.38
   Compiling futures-sink v0.3.31
   Compiling futures-core v0.3.31
   Compiling syn v2.0.96
   Compiling futures-channel v0.3.31
   Compiling pin-project-lite v0.2.16
   Compiling futures-task v0.3.31
   Compiling pin-utils v0.1.0
   Compiling futures-io v0.3.31
   Compiling memchr v2.7.4
   Compiling solution v0.1.0 (/tmp/d20250120-1137348-9hngn8/solution)
   Compiling futures-macro v0.3.31
   Compiling futures-util v0.3.31
   Compiling futures-executor v0.3.31
   Compiling futures v0.3.31
    Finished `test` profile [unoptimized + debuginfo] target(s) in 1m 15s
     Running tests/solution_test.rs (target/debug/deps/solution_test-f2cda45de43a0fd3)

running 2 tests
test solution_test::test_futures_join ... ok
test solution_test::test_futures_unordered ... ok

test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Йосиф Иванов
  • Коректно
  • 2 успешни тест(а)
  • 0 неуспешни тест(а)
Йосиф Иванов

use std::cell::{Ref, RefCell, RefMut};
use std::collections::VecDeque;
use std::future::Future;
use std::ops::{Deref, DerefMut};
use std::pin::Pin;
use std::task::{Context, Poll, Waker};
pub struct MyMutex<T> {
value: RefCell<T>,
locked: RefCell<bool>,
waiters: RefCell<VecDeque<Waker>>,
}
impl<T> MyMutex<T> {
pub fn new(value: T) -> Self {
Self {
value: RefCell::new(value),
locked: RefCell::new(false),
waiters: RefCell::new(VecDeque::new()),
}
}
pub fn lock(&self) -> MyMutexLockFuture<'_, T> {
MyMutexLockFuture { mutex: self }
}
fn unlock(&self) {
*self.locked.borrow_mut() = false;
if let Some(waker) = self.waiters.borrow_mut().pop_front() {
waker.wake();
}
}
}
pub struct MyMutexLockFuture<'a, T> {
mutex: &'a MyMutex<T>,
}
impl<'a, T> Future for MyMutexLockFuture<'a, T> {
type Output = MyMutexGuard<'a, T>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let mut locked = self.mutex.locked.borrow_mut();
if !*locked {
*locked = true;
Poll::Ready(MyMutexGuard {
mutex: self.mutex,
value: self.mutex.value.borrow_mut(),
})
} else {
self.mutex.waiters.borrow_mut().push_back(cx.waker().clone());
Poll::Pending
}
}
}
pub struct MyMutexGuard<'a, T> {
mutex: &'a MyMutex<T>,
value: RefMut<'a, T>,
}
impl<'a, T> Deref for MyMutexGuard<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.value
}
}
impl<'a, T> DerefMut for MyMutexGuard<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.value
}
}
impl<'a, T> Drop for MyMutexGuard<'a, T> {
fn drop(&mut self) {
self.mutex.unlock();
}
}
Updating crates.io index
     Locking 18 packages to latest compatible versions
   Compiling proc-macro2 v1.0.93
   Compiling unicode-ident v1.0.14
   Compiling autocfg v1.4.0
   Compiling slab v0.4.9
   Compiling futures-sink v0.3.31
   Compiling futures-core v0.3.31
   Compiling futures-channel v0.3.31
   Compiling quote v1.0.38
   Compiling syn v2.0.96
   Compiling memchr v2.7.4
   Compiling pin-utils v0.1.0
   Compiling futures-task v0.3.31
   Compiling pin-project-lite v0.2.16
   Compiling futures-io v0.3.31
   Compiling solution v0.1.0 (/tmp/d20250120-1137348-18zudfc/solution)
warning: unused import: `Ref`
 --> src/lib.rs:1:17
  |
1 | use std::cell::{Ref, RefCell, RefMut};
  |                 ^^^
  |
  = note: `#[warn(unused_imports)]` on by default

warning: `solution` (lib) generated 1 warning (run `cargo fix --lib -p solution` to apply 1 suggestion)
   Compiling futures-macro v0.3.31
   Compiling futures-util v0.3.31
   Compiling futures-executor v0.3.31
   Compiling futures v0.3.31
    Finished `test` profile [unoptimized + debuginfo] target(s) in 1m 18s
     Running tests/solution_test.rs (target/debug/deps/solution_test-f2cda45de43a0fd3)

running 2 tests
test solution_test::test_futures_join ... ok
test solution_test::test_futures_unordered ... ok

test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Карина Георгиева
  • Коректно
  • 2 успешни тест(а)
  • 0 неуспешни тест(а)
Карина Георгиева

use std::collections::VecDeque;
use std::cell::RefCell;
use std::future::Future;
use std::ops::{Deref, DerefMut};
use std::pin::Pin;
use std::task::{Context, Poll, Waker};
pub struct MyMutex<T> {
value: RefCell<T>,
locked: RefCell<bool>,
wakers: RefCell<VecDeque<Waker>>,
}
impl<T> MyMutex<T> {
pub fn new(value: T) -> Self {
MyMutex {
value: RefCell::new(value),
locked: RefCell::new(false),
wakers: RefCell::new(VecDeque::new()),
}
}
pub fn lock(&self) -> MyMutexLockFuture<'_, T> {
MyMutexLockFuture { mutex: self }
}
fn unlock(&self) {
*self.locked.borrow_mut() = false;
if let Some(waker) = self.wakers.borrow_mut().pop_front() {
waker.wake();
}
}
}
pub struct MyMutexLockFuture<'a, T> {
mutex: &'a MyMutex<T>,
}
impl<'a, T> Future for MyMutexLockFuture<'a, T> {
type Output = MyMutexGuard<'a, T>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let mut locked = self.mutex.locked.borrow_mut();
if !*locked {
*locked = true;
Poll::Ready(MyMutexGuard {
mutex: self.mutex,
value: Some(self.mutex.value.borrow_mut()),
})
} else {
self.mutex.wakers.borrow_mut().push_back(cx.waker().clone());
Poll::Pending
}
}
}
pub struct MyMutexGuard<'a, T> {
mutex: &'a MyMutex<T>,
value: Option<std::cell::RefMut<'a, T>>,
}
impl<'a, T> Deref for MyMutexGuard<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.value.as_ref().unwrap().deref()
}
}
impl<'a, T> DerefMut for MyMutexGuard<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.value.as_mut().unwrap().deref_mut()
}
}
impl<'a, T> Drop for MyMutexGuard<'a, T> {
fn drop(&mut self) {
self.mutex.unlock();
}
}
Updating crates.io index
     Locking 18 packages to latest compatible versions
   Compiling proc-macro2 v1.0.93
   Compiling unicode-ident v1.0.14
   Compiling autocfg v1.4.0
   Compiling slab v0.4.9
   Compiling futures-sink v0.3.31
   Compiling futures-core v0.3.31
   Compiling quote v1.0.38
   Compiling syn v2.0.96
   Compiling futures-channel v0.3.31
   Compiling futures-io v0.3.31
   Compiling pin-utils v0.1.0
   Compiling futures-task v0.3.31
   Compiling memchr v2.7.4
   Compiling pin-project-lite v0.2.16
   Compiling solution v0.1.0 (/tmp/d20250120-1137348-1cxveaz/solution)
   Compiling futures-macro v0.3.31
   Compiling futures-util v0.3.31
   Compiling futures-executor v0.3.31
   Compiling futures v0.3.31
    Finished `test` profile [unoptimized + debuginfo] target(s) in 55.95s
     Running tests/solution_test.rs (target/debug/deps/solution_test-f2cda45de43a0fd3)

running 2 tests
test solution_test::test_futures_join ... ok
test solution_test::test_futures_unordered ... ok

test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Ясен Ефремов
  • Коректно
  • 2 успешни тест(а)
  • 0 неуспешни тест(а)
Ясен Ефремов

use std::cell::RefCell;
use std::collections::HashMap;
use std::future::Future;
use std::mem;
use std::ops::{Deref, DerefMut};
use std::pin::Pin;
use std::task::{Context, Poll, Waker};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Mutex;
/// Неблокиращ мутекс, предназначен да се използва от асинхронен код.
pub struct MyMutex<T> {
value: RefCell<T>,
state: AtomicUsize,
waiters: Mutex<HashMap<usize, Waiter>>,
}
enum Waiter {
Waiting(Waker),
Woken,
}
impl Waiter {
fn register(&mut self, waker: &Waker) {
match self {
Self::Waiting(w) if waker.will_wake(w) => {}
_ => *self = Self::Waiting(waker.clone()),
}
}
fn wake(&mut self) {
match mem::replace(self, Self::Woken) {
Self::Waiting(waker) => waker.wake(),
Self::Woken => {}
}
}
}
const IS_LOCKED: usize = 1 << 0;
const HAS_WAITERS: usize = 1 << 1;
const WAIT_KEY_NONE: usize = usize::MAX;
impl<T> MyMutex<T> {
pub fn new(value: T) -> Self {
MyMutex {
value: RefCell::new(value),
state: AtomicUsize::new(0),
waiters: Mutex::new(HashMap::new())
}
}
pub fn try_lock(&self) -> Option<MyMutexGuard<'_, T>> {
let old_state = self.state.fetch_or(IS_LOCKED, Ordering::Acquire);
if (old_state & IS_LOCKED) == 0 {
Some(MyMutexGuard { mutex: self })
} else {
None
}
}
// Забележете, че `lock` не е маркирана като `async fn`, защото си имплементираме future-а
// на ръка (тук компилатора няма как да ни помогне).
//
// Бихме могли да я декларираме `fn lock() -> impl Future<Output = MyMytexGuard<'_, T>>`,
// ако искаме да не правим структурата публична, но пак ще трябва да си напишем и върнем
// наша структура.
pub fn lock(&self) -> MyMutexLockFuture<'_, T> {
MyMutexLockFuture { mutex: Some(self), wait_key: WAIT_KEY_NONE }
}
fn unlock(&self) {
let old_state = self.state.fetch_and(!IS_LOCKED, Ordering::AcqRel);
if (old_state & HAS_WAITERS) != 0 {
let mut waiters = self.waiters.lock().unwrap();
if let Some((_i, waiter)) = waiters.iter_mut().next() {
waiter.wake();
}
}
}
fn remove_waker(&self, wait_key: usize, wake_another: bool) {
if wait_key != WAIT_KEY_NONE {
let mut waiters = self.waiters.lock().unwrap();
match waiters.remove(&wait_key).unwrap() {
Waiter::Waiting(_) => {}
Waiter::Woken => {
if wake_another {
if let Some((_i, waiter)) = waiters.iter_mut().next() {
waiter.wake();
}
}
}
}
if waiters.is_empty() {
self.state.fetch_and(!HAS_WAITERS, Ordering::Relaxed);
}
}
}
}
pub struct MyMutexLockFuture<'a, T> {
mutex: Option<&'a MyMutex<T>>,
wait_key: usize,
}
impl<'a, T> Future for MyMutexLockFuture<'a, T> {
type Output = MyMutexGuard<'a, T>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let mutex = self.mutex.expect("polled MutexLockFuture after completion");
if let Some(lock) = mutex.try_lock() {
mutex.remove_waker(self.wait_key, false);
self.mutex = None;
return Poll::Ready(lock);
}
{
let mut waiters = mutex.waiters.lock().unwrap();
if self.wait_key == WAIT_KEY_NONE {
self.wait_key = waiters.len();
waiters.insert(self.wait_key, Waiter::Waiting(cx.waker().clone()));
if waiters.len() == 1 {
mutex.state.fetch_or(HAS_WAITERS, Ordering::Relaxed);
}
} else {
waiters.get_mut(&self.wait_key).unwrap().register(cx.waker());
}
}
if let Some(lock) = mutex.try_lock() {
mutex.remove_waker(self.wait_key, false);
self.mutex = None;
return Poll::Ready(lock);
}
Poll::Pending
}
}
pub struct MyMutexGuard<'a, T> {
mutex: &'a MyMutex<T>,
}
impl<'a, T> Deref for MyMutexGuard<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { &*self.mutex.value.as_ptr() }
}
}
impl<'a, T> DerefMut for MyMutexGuard<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
// self.mutex.value.get_mut()
unsafe { &mut *self.mutex.value.as_ptr() }
}
}
impl<'a, T> Drop for MyMutexGuard<'a, T> {
fn drop(&mut self) {
self.mutex.unlock();
}
}
Updating crates.io index
     Locking 18 packages to latest compatible versions
   Compiling proc-macro2 v1.0.93
   Compiling unicode-ident v1.0.14
   Compiling autocfg v1.4.0
   Compiling slab v0.4.9
   Compiling futures-sink v0.3.31
   Compiling futures-core v0.3.31
   Compiling futures-channel v0.3.31
   Compiling quote v1.0.38
   Compiling syn v2.0.96
   Compiling memchr v2.7.4
   Compiling pin-utils v0.1.0
   Compiling futures-task v0.3.31
   Compiling pin-project-lite v0.2.16
   Compiling futures-io v0.3.31
   Compiling solution v0.1.0 (/tmp/d20250120-1137348-yfs5cd/solution)
   Compiling futures-macro v0.3.31
   Compiling futures-util v0.3.31
   Compiling futures-executor v0.3.31
   Compiling futures v0.3.31
    Finished `test` profile [unoptimized + debuginfo] target(s) in 51.78s
     Running tests/solution_test.rs (target/debug/deps/solution_test-f2cda45de43a0fd3)

running 2 tests
test solution_test::test_futures_unordered ... ok
test solution_test::test_futures_join ... ok

test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Петър Велков
  • Коректно
  • 2 успешни тест(а)
  • 0 неуспешни тест(а)
Петър Велков

use std::cell::{Cell, RefCell, RefMut};
use std::future::Future;
use std::ops::{Deref, DerefMut};
use std::pin::Pin;
use std::task::{Context, Poll, Waker};
/// Неблокиращ мутекс, предназначен да се използва от асинхронен код.
pub struct MyMutex<T> {
value: RefCell<T>,
locked: Cell<bool>,
waiters: RefCell<Vec<Waker>>,
}
impl<T> MyMutex<T> {
pub fn new(value: T) -> Self {
Self {
value: RefCell::new(value),
locked: Cell::new(false),
waiters: RefCell::new(Vec::new()),
}
}
// Забележете, че `lock` не е маркирана като `async fn`, защото си имплементираме future-а
// на ръка (тук компилатора няма как да ни помогне).
//
// Бихме могли да я декларираме `fn lock() -> impl Future<Output = MyMytexGuard<'_, T>>`,
// ако искаме да не правим структурата публична, но пак ще трябва да си напишем и върнем
// наша структура.
pub fn lock(&self) -> MyMutexLockFuture<'_, T> {
MyMutexLockFuture { mutex: self }
}
fn unlock(&self) {
self.locked.set(false);
let mut waiters = self.waiters.borrow_mut();
for waker in waiters.drain(..) {
waker.wake();
}
}
}
pub struct MyMutexLockFuture<'a, T> {
mutex: &'a MyMutex<T>,
}
impl<'a, T> Future for MyMutexLockFuture<'a, T> {
type Output = MyMutexGuard<'a, T>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.get_mut();
if !this.mutex.locked.get() {
this.mutex.locked.set(true);
let data = this.mutex.value.borrow_mut();
Poll::Ready(MyMutexGuard {
mutex: this.mutex,
data,
})
} else {
let mut waiters = this.mutex.waiters.borrow_mut();
waiters.push(cx.waker().clone());
Poll::Pending
}
}
}
pub struct MyMutexGuard<'a, T> {
mutex: &'a MyMutex<T>,
data: RefMut<'a, T>,
}
impl<'a, T> Deref for MyMutexGuard<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&*self.data
}
}
impl<'a, T> DerefMut for MyMutexGuard<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut *self.data
}
}
impl<'a, T> Drop for MyMutexGuard<'a, T> {
fn drop(&mut self) {
self.mutex.unlock();
}
}
Updating crates.io index
     Locking 18 packages to latest compatible versions
   Compiling proc-macro2 v1.0.93
   Compiling unicode-ident v1.0.14
   Compiling autocfg v1.4.0
   Compiling slab v0.4.9
   Compiling futures-sink v0.3.31
   Compiling quote v1.0.38
   Compiling syn v2.0.96
   Compiling futures-core v0.3.31
   Compiling futures-channel v0.3.31
   Compiling pin-utils v0.1.0
   Compiling memchr v2.7.4
   Compiling pin-project-lite v0.2.16
   Compiling futures-task v0.3.31
   Compiling futures-io v0.3.31
   Compiling solution v0.1.0 (/tmp/d20250120-1137348-43pnni/solution)
   Compiling futures-macro v0.3.31
   Compiling futures-util v0.3.31
   Compiling futures-executor v0.3.31
   Compiling futures v0.3.31
    Finished `test` profile [unoptimized + debuginfo] target(s) in 36.73s
     Running tests/solution_test.rs (target/debug/deps/solution_test-f2cda45de43a0fd3)

running 2 tests
test solution_test::test_futures_join ... ok
test solution_test::test_futures_unordered ... ok

test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Василен Петков
  • Коректно
  • 2 успешни тест(а)
  • 0 неуспешни тест(а)
Василен Петков

use std::cell::RefCell;
use std::collections::VecDeque;
use std::future::Future;
use std::ops::{Deref, DerefMut};
use std::pin::Pin;
use std::task::{Context, Poll, Waker};
pub struct MyMutex<T> {
value: RefCell<T>,
locked: RefCell<bool>,
waiters: RefCell<VecDeque<Waker>>,
}
impl<T> MyMutex<T> {
pub fn new(value: T) -> Self {
Self {
value: RefCell::new(value),
locked: RefCell::new(false),
waiters: RefCell::new(VecDeque::new()),
}
}
pub fn lock(&self) -> MyMutexLockFuture<'_, T> {
MyMutexLockFuture { mutex: self }
}
fn unlock(&self) {
let mut locked = self.locked.borrow_mut();
*locked = false;
if let Some(waker) = self.waiters.borrow_mut().pop_front() {
waker.wake();
}
}
}
pub struct MyMutexLockFuture<'a, T> {
mutex: &'a MyMutex<T>,
}
impl<'a, T> Future for MyMutexLockFuture<'a, T> {
type Output = MyMutexGuard<'a, T>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let mut locked = self.mutex.locked.borrow_mut();
if !*locked {
*locked = true;
Poll::Ready(MyMutexGuard {
mutex: self.mutex,
value_ref: Some(self.mutex.value.borrow_mut()),
})
} else {
self.mutex.waiters.borrow_mut().push_back(cx.waker().clone());
Poll::Pending
}
}
}
pub struct MyMutexGuard<'a, T> {
mutex: &'a MyMutex<T>,
value_ref: Option<std::cell::RefMut<'a, T>>,
}
impl<'a, T> Deref for MyMutexGuard<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&*self.value_ref.as_ref().unwrap()
}
}
impl<'a, T> DerefMut for MyMutexGuard<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut *self.value_ref.as_mut().unwrap()
}
}
impl<'a, T> Drop for MyMutexGuard<'a, T> {
fn drop(&mut self) {
self.value_ref.take();
self.mutex.unlock();
}
}
Updating crates.io index
     Locking 18 packages to latest compatible versions
   Compiling proc-macro2 v1.0.93
   Compiling unicode-ident v1.0.14
   Compiling autocfg v1.4.0
   Compiling slab v0.4.9
   Compiling futures-core v0.3.31
   Compiling futures-sink v0.3.31
   Compiling futures-channel v0.3.31
   Compiling quote v1.0.38
   Compiling syn v2.0.96
   Compiling memchr v2.7.4
   Compiling pin-utils v0.1.0
   Compiling futures-io v0.3.31
   Compiling futures-task v0.3.31
   Compiling pin-project-lite v0.2.16
   Compiling solution v0.1.0 (/tmp/d20250120-1137348-12im4o1/solution)
   Compiling futures-macro v0.3.31
   Compiling futures-util v0.3.31
   Compiling futures-executor v0.3.31
   Compiling futures v0.3.31
    Finished `test` profile [unoptimized + debuginfo] target(s) in 31.28s
     Running tests/solution_test.rs (target/debug/deps/solution_test-f2cda45de43a0fd3)

running 2 tests
test solution_test::test_futures_join ... ok
test solution_test::test_futures_unordered ... ok

test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Ангел Пенчев
  • Некоректно
  • 0 успешни тест(а)
  • 0 неуспешни тест(а)
Ангел Пенчев

use std::cell::{Ref, RefCell, RefMut};
use std::collections::VecDeque;
use std::ops::{Deref, DerefMut};
use std::task::Waker;
pub struct MyMutex<T> {
value: RefCell<T>,
waker_queue: RefCell<VecDeque<Waker>>,
locked: RefCell<bool>,
}
impl<T> MyMutex<T> {
pub fn new(value: T) -> Self {
MyMutex {
value: RefCell::new(value),
waker_queue: RefCell::new(VecDeque::new()),
locked: RefCell::new(false),
}
}
pub fn lock(&self) -> MyMutexLockFuture<'_, T> {
MyMutexLockFuture {
mutex: self,
was_pooled: false,
}
}
fn unlock(&self) {
let mut locked = self.locked.borrow_mut();
*locked = false;
if let Some(waker) = self.waker_queue.borrow_mut().pop_front() {
waker.wake();
}
}
}
pub struct MyMutexLockFuture<'a, T> {
mutex: &'a MyMutex<T>,
was_pooled: bool,
}
pub struct MyMutexGuard<'a, T> {
mutex: &'a MyMutex<T>,
borrow: Option<Ref<'a, T>>,
borrow_mut: Option<RefMut<'a, T>>,
}
impl<'a, T> Deref for MyMutexGuard<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.borrow.as_ref().unwrap()
}
}
impl<'a, T> DerefMut for MyMutexGuard<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.borrow_mut.as_mut().unwrap()
}
}
impl<'a, T> Drop for MyMutexGuard<'a, T> {
fn drop(&mut self) {
self.mutex.unlock();
}
}
#[cfg(test)]
mod tests {
// Warning: the test uses the `futures` library.
// This is available only to the testing code (it is a dev-dependency),
// it is not available to the solution code.
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
use super::*;
use futures::{SinkExt, StreamExt};
#[test]
fn test_futures_join() {
run_with_timeout(1000, || async {
let resource = Arc::new(MyMutex::new(vec![]));
let (mut sender_3to1, mut recv_3to1) = futures::channel::mpsc::channel(1);
let fut1 = {
// A future that locks the resource, then holds the lock across an
// await point (awaiting the next message from the channel).
//
// With an async-aware mutex this is not a problem - while `fut1` is blocked,
// `fut2` and `fut3` can still run. So eventually `fut3` will send the message
// and unblock `fut1`.
let resource = Arc::clone(&resource);
async move {
let mut lock = resource.lock().await;
let () = recv_3to1.next().await.unwrap();
lock.push("one".to_string());
}
};
let fut2 = {
let resource = Arc::clone(&resource);
async move {
let mut lock = resource.lock().await;
lock.push("two".to_string());
}
};
let fut3 = {
let resource = Arc::clone(&resource);
async move {
sender_3to1.send(()).await.unwrap();
let mut lock = resource.lock().await;
lock.push("three".to_string());
}
};
// `join` polls the futures in order.
//
// Also `join` provides a single `Waker`, which just wakes the `Join3` future,
// which every time polls each of the inner futures in order.
// So using any waker will "wake" all three futures.
futures::future::join3(fut1, fut2, fut3).await;
assert_eq!(&*resource.lock().await, &["one", "two", "three"]);
});
}
#[test]
fn test_futures_unordered() {
run_with_timeout(1000, || async {
let resource = Arc::new(MyMutex::new(vec![]));
let (mut sender_3to1, mut recv_3to1) = futures::channel::mpsc::channel(1);
let fut1 = pin_box({
let resource = Arc::clone(&resource);
async move {
let mut lock = resource.lock().await;
let () = recv_3to1.next().await.unwrap();
lock.push("one".to_string());
}
});
let fut2 = pin_box({
let resource = Arc::clone(&resource);
async move {
let mut lock = resource.lock().await;
lock.push("two".to_string());
}
});
let fut3 = pin_box({
let resource = Arc::clone(&resource);
async move {
sender_3to1.send(()).await.unwrap();
let mut lock = resource.lock().await;
lock.push("three".to_string());
}
});
// Same example, but uses `FuturesUnordered` instead of `join`.
//
// `FuturesUnordered` doesn't guarantee any ordering.
// Also it is more optimized for a large number of futures and will provide a separate
// `Waker` for each of the inner futures.
// So we can test that the correct wakers are being used.
let mut unordered = futures::stream::FuturesUnordered::from_iter([fut1, fut2, fut3]);
while let Some(_) = unordered.next().await {}
let mut final_resource = resource.lock().await.clone();
final_resource.sort();
assert_eq!(final_resource, &["one", "three", "two"]);
});
}
fn run_with_timeout<F, R>(timeout_millis: u64, test_fn: F)
where
F: FnOnce() -> R + Send + std::panic::UnwindSafe + 'static,
R: Future<Output = ()> + 'static,
{
use futures::task::LocalSpawn;
use std::panic::catch_unwind;
use std::sync::mpsc;
let (sender, receiver) = mpsc::sync_channel(1);
std::thread::spawn(move || {
let result = catch_unwind(move || {
let mut runtime = futures::executor::LocalPool::new();
let test_future = Box::new(test_fn());
runtime
.spawner()
.spawn_local_obj(test_future.into())
.unwrap();
runtime.run();
});
let _ = sender.send(result);
});
let timeout = std::time::Duration::from_millis(timeout_millis);
match receiver.recv_timeout(timeout) {
Ok(Ok(())) => {}
Ok(Err(any)) => panic!("test panicked: {}", any.downcast::<&str>().unwrap()),
Err(mpsc::RecvTimeoutError::Timeout) => panic!("test timed out"),
Err(mpsc::RecvTimeoutError::Disconnected) => unreachable!(),
}
}
fn pin_box<F>(fut: F) -> Pin<Box<dyn Future<Output = ()>>>
where
F: Future<Output = ()> + 'static,
{
Box::into_pin(Box::new(fut) as Box<dyn Future<Output = ()>>)
}
}
// Сетих се за това 50 мин преди края ;-;
Updating crates.io index
     Locking 18 packages to latest compatible versions
   Compiling proc-macro2 v1.0.93
   Compiling unicode-ident v1.0.14
   Compiling autocfg v1.4.0
   Compiling slab v0.4.9
   Compiling futures-core v0.3.31
   Compiling quote v1.0.38
   Compiling syn v2.0.96
   Compiling futures-sink v0.3.31
   Compiling futures-channel v0.3.31
   Compiling pin-project-lite v0.2.16
   Compiling pin-utils v0.1.0
   Compiling futures-task v0.3.31
   Compiling futures-io v0.3.31
   Compiling memchr v2.7.4
   Compiling solution v0.1.0 (/tmp/d20250120-1137348-55tcli/solution)
warning: field `value` is never read
 --> src/lib.rs:7:5
  |
6 | pub struct MyMutex<T> {
  |            ------- field in this struct
7 |     value: RefCell<T>,
  |     ^^^^^
  |
  = note: `#[warn(dead_code)]` on by default

warning: fields `mutex` and `was_pooled` are never read
  --> src/lib.rs:39:5
   |
38 | pub struct MyMutexLockFuture<'a, T> {
   |            ----------------- fields in this struct
39 |     mutex: &'a MyMutex<T>,
   |     ^^^^^
40 |     was_pooled: bool,
   |     ^^^^^^^^^^

warning: `solution` (lib) generated 2 warnings
   Compiling futures-macro v0.3.31
   Compiling futures-util v0.3.31
   Compiling futures-executor v0.3.31
   Compiling futures v0.3.31
error[E0277]: `MyMutexLockFuture<'_, Vec<_>>` is not a future
  --> tests/solution_test.rs:28:48
   |
28 |                 let mut lock = resource.lock().await;
   |                                               -^^^^^
   |                                               ||
   |                                               |`MyMutexLockFuture<'_, Vec<_>>` is not a future
   |                                               help: remove the `.await`
   |
   = help: the trait `futures::Future` is not implemented for `MyMutexLockFuture<'_, Vec<_>>`
   = note: MyMutexLockFuture<'_, Vec<_>> must be a future or must implement `IntoFuture` to be awaited
   = note: required for `MyMutexLockFuture<'_, Vec<_>>` to implement `std::future::IntoFuture`

error[E0277]: `MyMutexLockFuture<'_, Vec<_>>` is not a future
  --> tests/solution_test.rs:37:48
   |
37 |                 let mut lock = resource.lock().await;
   |                                               -^^^^^
   |                                               ||
   |                                               |`MyMutexLockFuture<'_, Vec<_>>` is not a future
   |                                               help: remove the `.await`
   |
   = help: the trait `futures::Future` is not implemented for `MyMutexLockFuture<'_, Vec<_>>`
   = note: MyMutexLockFuture<'_, Vec<_>> must be a future or must implement `IntoFuture` to be awaited
   = note: required for `MyMutexLockFuture<'_, Vec<_>>` to implement `std::future::IntoFuture`

error[E0277]: `MyMutexLockFuture<'_, Vec<_>>` is not a future
  --> tests/solution_test.rs:46:48
   |
46 |                 let mut lock = resource.lock().await;
   |                                               -^^^^^
   |                                               ||
   |                                               |`MyMutexLockFuture<'_, Vec<_>>` is not a future
   |                                               help: remove the `.await`
   |
   = help: the trait `futures::Future` is not implemented for `MyMutexLockFuture<'_, Vec<_>>`
   = note: MyMutexLockFuture<'_, Vec<_>> must be a future or must implement `IntoFuture` to be awaited
   = note: required for `MyMutexLockFuture<'_, Vec<_>>` to implement `std::future::IntoFuture`

error[E0277]: `MyMutexLockFuture<'_, Vec<_>>` is not a future
  --> tests/solution_test.rs:58:38
   |
58 |         assert_eq!(&*resource.lock().await, &["one", "two", "three"]);
   |                                     -^^^^^
   |                                     ||
   |                                     |`MyMutexLockFuture<'_, Vec<_>>` is not a future
   |                                     help: remove the `.await`
   |
   = help: the trait `futures::Future` is not implemented for `MyMutexLockFuture<'_, Vec<_>>`
   = note: MyMutexLockFuture<'_, Vec<_>> must be a future or must implement `IntoFuture` to be awaited
   = note: required for `MyMutexLockFuture<'_, Vec<_>>` to implement `std::future::IntoFuture`

error[E0277]: `MyMutexLockFuture<'_, Vec<_>>` is not a future
  --> tests/solution_test.rs:71:48
   |
71 |                 let mut lock = resource.lock().await;
   |                                               -^^^^^
   |                                               ||
   |                                               |`MyMutexLockFuture<'_, Vec<_>>` is not a future
   |                                               help: remove the `.await`
   |
   = help: the trait `futures::Future` is not implemented for `MyMutexLockFuture<'_, Vec<_>>`
   = note: MyMutexLockFuture<'_, Vec<_>> must be a future or must implement `IntoFuture` to be awaited
   = note: required for `MyMutexLockFuture<'_, Vec<_>>` to implement `std::future::IntoFuture`

error[E0277]: `MyMutexLockFuture<'_, Vec<_>>` is not a future
  --> tests/solution_test.rs:80:48
   |
80 |                 let mut lock = resource.lock().await;
   |                                               -^^^^^
   |                                               ||
   |                                               |`MyMutexLockFuture<'_, Vec<_>>` is not a future
   |                                               help: remove the `.await`
   |
   = help: the trait `futures::Future` is not implemented for `MyMutexLockFuture<'_, Vec<_>>`
   = note: MyMutexLockFuture<'_, Vec<_>> must be a future or must implement `IntoFuture` to be awaited
   = note: required for `MyMutexLockFuture<'_, Vec<_>>` to implement `std::future::IntoFuture`

error[E0277]: `MyMutexLockFuture<'_, Vec<_>>` is not a future
  --> tests/solution_test.rs:89:48
   |
89 |                 let mut lock = resource.lock().await;
   |                                               -^^^^^
   |                                               ||
   |                                               |`MyMutexLockFuture<'_, Vec<_>>` is not a future
   |                                               help: remove the `.await`
   |
   = help: the trait `futures::Future` is not implemented for `MyMutexLockFuture<'_, Vec<_>>`
   = note: MyMutexLockFuture<'_, Vec<_>> must be a future or must implement `IntoFuture` to be awaited
   = note: required for `MyMutexLockFuture<'_, Vec<_>>` to implement `std::future::IntoFuture`

error[E0277]: `MyMutexLockFuture<'_, Vec<_>>` is not a future
   --> tests/solution_test.rs:103:50
    |
103 |         let mut final_resource = resource.lock().await.clone();
    |                                                 -^^^^^
    |                                                 ||
    |                                                 |`MyMutexLockFuture<'_, Vec<_>>` is not a future
    |                                                 help: remove the `.await`
    |
    = help: the trait `futures::Future` is not implemented for `MyMutexLockFuture<'_, Vec<_>>`
    = note: MyMutexLockFuture<'_, Vec<_>> must be a future or must implement `IntoFuture` to be awaited
    = note: required for `MyMutexLockFuture<'_, Vec<_>>` to implement `std::future::IntoFuture`

For more information about this error, try `rustc --explain E0277`.
error: could not compile `solution` (test "solution_test") due to 8 previous errors