Игрушечные Future комбинаторы на async/await

Все мы знакомы с Future комбинаторами и их запутанным кодом. Я могу только представить, как новички реагируют на исходники FutureExt::then :

trait FutureExt
{
    fn then<...>(self, f) -> Then<...>
    {
        Then::new(self, f)
    }
}

impl Then
{
    fn poll(self, waker) -> Poll<...> {
        self.as_mut().chain().poll(waker, |output, f| f(output))
    }
}

impl Chain
{
    fn poll(self, waker, f) -> Poll<...>
    {
        let mut f = Some(f);

        // Safe to call `get_unchecked_mut` because we won't move the futures.
        let this = unsafe { Pin::get_unchecked_mut(self) };

        loop {
            let (output, data) = match this {
                Chain::First(fut1, data) => {
                    match unsafe { Pin::new_unchecked(fut1) }.poll(waker) {
                        Poll::Pending => return Poll::Pending,
                        Poll::Ready(output) => (output, data.take().unwrap()),
                    }
                }
                Chain::Second(fut2) => {
                    return unsafe { Pin::new_unchecked(fut2) }.poll(waker);
                }
                Chain::Empty => unreachable!()
            };

            *this = Chain::Empty; // Drop fut1
            let fut2 = (f.take().unwrap())(output, data);
            *this = Chain::Second(fut2)
        }
    }
}

Я понимаю причины, по которым комбинаторы были так написаны. И все же кода в них слишком много, чтобы ухватить суть сходу.

Сравните с переписанным вариантом с использованием async/await синтаксиса:

pub async fn then<...>(future, f) -> ...
{
    let future_result = await!(future);
    let new_future = f(future_result);
    await!(new_future)
}

Я надеюсь мой проект даст вам понимание того, как устроены комбинаторы и как они могли бы быть написаны (цель проекта как fahrenheit для futures executor).

Вот ссылка на проект futures-async-combinators, жду пул реквестов!

3 лайка

где почитать про синтаксис <…> ?

Это не синтаксис, просто пропущены фрагменты кода

3 лайка