makepad/libs/relax/compiler/tests/live/async_body/v1.rs
Admin b22a714840 makepad run: the Rust JIT (libs/relax) and makepad-remote
The JIT that runs makepad apps from source: lexer, front end, type checker,
lazy borrow checker (Gandalf; `--check-first` opts in), codegen, session and
warm/cold caches keyed by compiler stamp, provided crates bound late,
startup images, live patching. User-facing name is `makepad run` (binary
`makepad`, MAKEPAD_RUN_* env, ~/.makepad-run); libs/relax stays the internal
library name. `makepad check` reports rustc-style diagnostics with rustc
error codes and checks a whole workspace (`--workspace`). Runs on macOS,
Linux, Windows and Android. makepad-remote: one tool schema for apps and the
WM (app/1): grabs, captures, traces, frame profiles and tweaks.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-13 12:26:21 +02:00

63 lines
2.1 KiB
Rust

// G2 / 3.8: async fn bodies. Each run completes the future the previous run left suspended at its
// await (across the edit), then runs a fresh one and leaves a new one suspended.
// v1: body-only edit after the await (same state layout, same awaits): the suspended future
// resumes in the NEW poll code, and fresh futures run the new body.
// v2: a local held across the await is added (the state layout changes): a raw future the user
// holds cannot be cancelled by the runtime, so it must finish on the OLD (v1) code; fresh
// futures run the new body. Never the new poll on the old state.
use std::cell::RefCell;
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
fn noop_raw() -> RawWaker {
fn clone(_: *const ()) -> RawWaker { noop_raw() }
fn noop(_: *const ()) {}
static VT: RawWakerVTable = RawWakerVTable::new(clone, noop, noop, noop);
RawWaker::new(std::ptr::null(), &VT)
}
fn poll_once(f: &mut Pin<Box<dyn Future<Output = u64>>>) -> Option<u64> {
let waker = unsafe { Waker::from_raw(noop_raw()) };
let mut cx = Context::from_waker(&waker);
match f.as_mut().poll(&mut cx) {
Poll::Ready(v) => Some(v),
Poll::Pending => None,
}
}
struct Yield(bool);
impl Future for Yield {
type Output = ();
fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<()> {
if self.0 { Poll::Ready(()) } else { self.0 = true; Poll::Pending }
}
}
async fn step(x: u64) -> u64 {
Yield(false).await;
x * 10 + 2
}
thread_local! {
static PENDING: RefCell<Option<Pin<Box<dyn Future<Output = u64>>>>> = RefCell::new(None);
}
fn finish(mut f: Pin<Box<dyn Future<Output = u64>>>) -> u64 {
loop {
if let Some(v) = poll_once(&mut f) {
return v;
}
}
}
#[test]
fn run() {
if let Some(f) = PENDING.with(|p| p.borrow_mut().take()) {
println!("out resumed {}", finish(f));
}
println!("out fresh {}", finish(Box::pin(step(4))));
let mut f: Pin<Box<dyn Future<Output = u64>>> = Box::pin(step(7));
assert!(poll_once(&mut f).is_none());
PENDING.with(|p| *p.borrow_mut() = Some(f));
}