Skip to content

Instantly share code, notes, and snippets.

@lovely-error
Last active October 31, 2025 12:51
Show Gist options
  • Select an option

  • Save lovely-error/2bd81ca03aa7954d17b7f871226826f2 to your computer and use it in GitHub Desktop.

Select an option

Save lovely-error/2bd81ca03aa7954d17b7f871226826f2 to your computer and use it in GitHub Desktop.
almost sane coroutine interface in rust
#![feature(coroutines)]
#![feature(coroutine_trait)]
#![feature(decl_macro)]
// ideal iface
// struct ConFun<R, Y>(fn (*mut (), R) -> Option<(ConFun<R, Y>, Y)>);
// struct StartFun<R, Y>(fn (*mut ()) -> Option<(ConFun<R, Y>, *mut ())>);
trait Coroutine2<R>: core::ops::Coroutine<R> {
fn start(&mut self) -> core::ops::CoroutineState<Self::Yield, Self::Return>;
fn resume(&mut self, _:R) -> core::ops::CoroutineState<Self::Yield, Self::Return>;
}
impl <R, T:core::ops::Coroutine<R>> Coroutine2<R> for T {
#[inline]
fn start(&mut self) -> core::ops::CoroutineState<Self::Yield, Self::Return> {
let pined = unsafe { core::pin::Pin::new_unchecked(self) };
let null = core::mem::MaybeUninit::<R>::uninit();
Self::resume(pined, unsafe { null.assume_init() })
}
fn resume(&mut self, resume_val:R) -> core::ops::CoroutineState<Self::Yield, Self::Return> {
let pined = unsafe { core::pin::Pin::new_unchecked(self) };
Self::resume(pined, resume_val)
}
}
macro cowait($val:ident) {
{
let mut resume_arg = core::mem::MaybeUninit::uninit();
loop {
let pinned = core::pin::Pin::new(&mut $val);
let outcome = core::ops::Coroutine::resume(
pinned,
unsafe { resume_arg.assume_init_read() }
);
match outcome {
core::ops::CoroutineState::Yielded(susp_val) => {
let resume_val = yield susp_val;
resume_arg.write(resume_val);
}
core::ops::CoroutineState::Complete(result) => {
break result;
}
}
}
}
}
fn coro_head_drop<T>(arg:T) {
if core::mem::needs_drop::<T>() {
core::mem::forget(arg);
}
}
fn test1(arg:u32) -> impl Coroutine2<u32, Return=u32, Yield=u32> {
#[coroutine] move |x| {
coro_head_drop(x);
yield (arg + 1)
}
}
fn test2() -> impl Coroutine2<u32, Return=u32, Yield=u32> {
#[coroutine] static |x| {
coro_head_drop(x);
let mut coro = test1(42);
let result = cowait!(coro);
return result
}
}
fn main() {
let mut k = test2();
let res = k.start();
let susp_arg = if let core::ops::CoroutineState::Yielded(smth) = res {
assert!(smth == 43);
smth
} else {
panic!("unexpected");
};
let res = k.resume(susp_arg + 1);
if let core::ops::CoroutineState::Complete(smth) = res {
assert!(smth == 44);
println!("as expected!");
} else {
panic!("unexpected");
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment