Минимальный код для асинхронного блока block_on на Rust без зависимостей

Я сделал этот простейший исполнитель блоков, но он требует небезопасности, и я не смог его удалить.

use core::future::Future;
use core::pin::Pin;
use core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};

// Create a no-op waker
fn dummy_raw_waker() -> RawWaker {
    fn no_op_clone(_: *const ()) -> RawWaker {
        dummy_raw_waker()
    }

    fn no_op(_: *const ()) {}

    RawWaker::new(
        core::ptr::null(),
        &RawWakerVTable::new(no_op_clone, no_op, no_op, no_op),
    )
}

// no dependency blocking function for debugging only
pub fn debug_only_unsafe_block_on<F: Future>(mut future: F) -> F::Output {
    let waker = unsafe { Waker::from_raw(dummy_raw_waker()) };
    let mut context = Context::from_waker(&waker);

    // Pin the future on the stack
    let mut future = unsafe { Pin::new_unchecked(&mut future) };

    loop {
        match future.as_mut().poll(&mut context) {
            Poll::Ready(val) => return val,
            Poll::Pending => {
                // In a real system, you might yield to the executor or check other tasks,
                // but in this simple case, we just keep polling.
            }
        }
    }
}

Есть ли способ удалить ключевое слово unsafe? Цель состоит в том, чтобы больше не использовать зависимости в моем коде.

По сути, это настолько мало, насколько это возможно: docs.rs/pollster/latest/src/pollster/lib.rs.html

drewtato 02.09.2024 03:01
Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
0
1
51
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы можете реализовать черту Wake вручную и использовать макрос pin, чтобы избежать небезопасного кода.

#![deny(unsafe_code)]

use core::future::Future;
use core::task::{Context, Poll};
use std::pin::pin;
use std::sync::Arc;
use std::task::Wake;

struct NoOpWaker;

impl Wake for NoOpWaker {
    fn wake(self: Arc<Self>) {}
}

// no dependency blocking function for debugging only
pub fn debug_only_safe_block_on<F: Future>(mut future: F) -> F::Output {
    let waker = Arc::new(NoOpWaker).into();

    let mut context = Context::from_waker(&waker);

    let mut future = pin!(future);

    loop {
        match future.as_mut().poll(&mut context) {
            Poll::Ready(val) => return val,
            Poll::Pending => {
                // In a real system, you might yield to the executor or check other tasks,
                // but in this simple case, we just keep polling.
            }
        }
    }
}

async fn foo() -> i32 {
    1
}

fn main() {
    let data = debug_only_safe_block_on(foo());
    assert_eq!(1, data);
}

Другие вопросы по теме