I made this simplest possible block executor, but it requires unsafe and I wasn't able to remove this.
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.
}
}
}
}
Is there a way to remove the unsafe keyword? The goal is to use no more dependencies on my code.
You can implement the Wake trait manually and use pin macro to avoid unsafe code
#![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);
}