15764da5fSJoel Dice mod bindings {
25764da5fSJoel Dice     wit_bindgen::generate!({
35764da5fSJoel Dice         path: "../misc/component-async-tests/wit",
45764da5fSJoel Dice         world: "readiness-guest",
55764da5fSJoel Dice     });
65764da5fSJoel Dice }
75764da5fSJoel Dice 
85764da5fSJoel Dice use {
95764da5fSJoel Dice     std::{mem, ptr},
105764da5fSJoel Dice     test_programs::async_::{
115764da5fSJoel Dice         BLOCKED, CALLBACK_CODE_EXIT, CALLBACK_CODE_WAIT, DROPPED, EVENT_NONE, EVENT_STREAM_READ,
125764da5fSJoel Dice         EVENT_STREAM_WRITE, context_get, context_set, waitable_join, waitable_set_drop,
135764da5fSJoel Dice         waitable_set_new,
145764da5fSJoel Dice     },
155764da5fSJoel Dice };
165764da5fSJoel Dice 
175764da5fSJoel Dice #[cfg(target_arch = "wasm32")]
185764da5fSJoel Dice #[link(wasm_import_module = "[export]local:local/readiness")]
195764da5fSJoel Dice unsafe extern "C" {
20*020727d0SAlex Crichton     #[link_name = "[task-return]start"]
task_return_start(_: u32, _: *const u8, _: usize)215764da5fSJoel Dice     fn task_return_start(_: u32, _: *const u8, _: usize);
225764da5fSJoel Dice }
235764da5fSJoel Dice #[cfg(not(target_arch = "wasm32"))]
task_return_start(_: u32, _: *const u8, _: usize)245764da5fSJoel Dice unsafe extern "C" fn task_return_start(_: u32, _: *const u8, _: usize) {
255764da5fSJoel Dice     unreachable!()
265764da5fSJoel Dice }
275764da5fSJoel Dice 
285764da5fSJoel Dice #[cfg(target_arch = "wasm32")]
295764da5fSJoel Dice #[link(wasm_import_module = "[export]local:local/readiness")]
305764da5fSJoel Dice unsafe extern "C" {
31*020727d0SAlex Crichton     #[link_name = "[stream-new-0]start"]
stream_new() -> u64325764da5fSJoel Dice     fn stream_new() -> u64;
335764da5fSJoel Dice }
345764da5fSJoel Dice #[cfg(not(target_arch = "wasm32"))]
stream_new() -> u64355764da5fSJoel Dice unsafe extern "C" fn stream_new() -> u64 {
365764da5fSJoel Dice     unreachable!()
375764da5fSJoel Dice }
385764da5fSJoel Dice 
395764da5fSJoel Dice #[cfg(target_arch = "wasm32")]
405764da5fSJoel Dice #[link(wasm_import_module = "[export]local:local/readiness")]
415764da5fSJoel Dice unsafe extern "C" {
42*020727d0SAlex Crichton     #[link_name = "[async-lower][stream-write-0]start"]
stream_write(_: u32, _: *const u8, _: usize) -> u32435764da5fSJoel Dice     fn stream_write(_: u32, _: *const u8, _: usize) -> u32;
445764da5fSJoel Dice }
455764da5fSJoel Dice #[cfg(not(target_arch = "wasm32"))]
stream_write(_: u32, _: *const u8, _: usize) -> u32465764da5fSJoel Dice unsafe extern "C" fn stream_write(_: u32, _: *const u8, _: usize) -> u32 {
475764da5fSJoel Dice     unreachable!()
485764da5fSJoel Dice }
495764da5fSJoel Dice 
505764da5fSJoel Dice #[cfg(target_arch = "wasm32")]
515764da5fSJoel Dice #[link(wasm_import_module = "[export]local:local/readiness")]
525764da5fSJoel Dice unsafe extern "C" {
53*020727d0SAlex Crichton     #[link_name = "[async-lower][stream-read-0]start"]
stream_read(_: u32, _: *mut u8, _: usize) -> u32545764da5fSJoel Dice     fn stream_read(_: u32, _: *mut u8, _: usize) -> u32;
555764da5fSJoel Dice }
565764da5fSJoel Dice #[cfg(not(target_arch = "wasm32"))]
stream_read(_: u32, _: *mut u8, _: usize) -> u32575764da5fSJoel Dice unsafe extern "C" fn stream_read(_: u32, _: *mut u8, _: usize) -> u32 {
585764da5fSJoel Dice     unreachable!()
595764da5fSJoel Dice }
605764da5fSJoel Dice 
615764da5fSJoel Dice #[cfg(target_arch = "wasm32")]
625764da5fSJoel Dice #[link(wasm_import_module = "[export]local:local/readiness")]
635764da5fSJoel Dice unsafe extern "C" {
64*020727d0SAlex Crichton     #[link_name = "[stream-drop-readable-0]start"]
stream_drop_readable(_: u32)655764da5fSJoel Dice     fn stream_drop_readable(_: u32);
665764da5fSJoel Dice }
675764da5fSJoel Dice #[cfg(not(target_arch = "wasm32"))]
stream_drop_readable(_: u32)685764da5fSJoel Dice unsafe extern "C" fn stream_drop_readable(_: u32) {
695764da5fSJoel Dice     unreachable!()
705764da5fSJoel Dice }
715764da5fSJoel Dice 
725764da5fSJoel Dice #[cfg(target_arch = "wasm32")]
735764da5fSJoel Dice #[link(wasm_import_module = "[export]local:local/readiness")]
745764da5fSJoel Dice unsafe extern "C" {
75*020727d0SAlex Crichton     #[link_name = "[stream-drop-writable-0]start"]
stream_drop_writable(_: u32)765764da5fSJoel Dice     fn stream_drop_writable(_: u32);
775764da5fSJoel Dice }
785764da5fSJoel Dice #[cfg(not(target_arch = "wasm32"))]
stream_drop_writable(_: u32)795764da5fSJoel Dice unsafe extern "C" fn stream_drop_writable(_: u32) {
805764da5fSJoel Dice     unreachable!()
815764da5fSJoel Dice }
825764da5fSJoel Dice 
835764da5fSJoel Dice static BYTES_TO_WRITE: &[u8] = &[1, 3, 5, 7, 11];
845764da5fSJoel Dice 
855764da5fSJoel Dice enum State {
865764da5fSJoel Dice     S0 {
875764da5fSJoel Dice         rx: u32,
885764da5fSJoel Dice         expected: Vec<u8>,
895764da5fSJoel Dice     },
905764da5fSJoel Dice     S1 {
915764da5fSJoel Dice         set: u32,
925764da5fSJoel Dice         tx: Option<u32>,
935764da5fSJoel Dice         rx: Option<u32>,
945764da5fSJoel Dice         expected: Vec<u8>,
955764da5fSJoel Dice     },
965764da5fSJoel Dice }
975764da5fSJoel Dice 
98*020727d0SAlex Crichton #[unsafe(export_name = "[async-lift]local:local/readiness#start")]
export_start(rx: u32, expected: u32, expected_len: u32) -> u32995764da5fSJoel Dice unsafe extern "C" fn export_start(rx: u32, expected: u32, expected_len: u32) -> u32 {
1005764da5fSJoel Dice     let expected_len = usize::try_from(expected_len).unwrap();
1015764da5fSJoel Dice 
1025764da5fSJoel Dice     unsafe {
1035764da5fSJoel Dice         context_set(
1045764da5fSJoel Dice             u32::try_from(Box::into_raw(Box::new(State::S0 {
1055764da5fSJoel Dice                 rx,
1065764da5fSJoel Dice                 expected: Vec::from_raw_parts(
1075764da5fSJoel Dice                     expected as usize as *mut u8,
1085764da5fSJoel Dice                     expected_len,
1095764da5fSJoel Dice                     expected_len,
1105764da5fSJoel Dice                 ),
1115764da5fSJoel Dice             })) as usize)
1125764da5fSJoel Dice             .unwrap(),
1135764da5fSJoel Dice         );
1145764da5fSJoel Dice 
1155764da5fSJoel Dice         callback_start(EVENT_NONE, 0, 0)
1165764da5fSJoel Dice     }
1175764da5fSJoel Dice }
1185764da5fSJoel Dice 
119*020727d0SAlex Crichton #[unsafe(export_name = "[callback][async-lift]local:local/readiness#start")]
callback_start(event0: u32, event1: u32, event2: u32) -> u321205764da5fSJoel Dice unsafe extern "C" fn callback_start(event0: u32, event1: u32, event2: u32) -> u32 {
1215764da5fSJoel Dice     unsafe {
1225764da5fSJoel Dice         let state = &mut *(usize::try_from(context_get()).unwrap() as *mut State);
1235764da5fSJoel Dice         match state {
1245764da5fSJoel Dice             State::S0 { rx, expected } => {
1255764da5fSJoel Dice                 assert_eq!(event0, EVENT_NONE);
1265764da5fSJoel Dice 
1275764da5fSJoel Dice                 // Do a zero-length read to wait until the writer is ready.
1285764da5fSJoel Dice                 //
1295764da5fSJoel Dice                 // Here we assume specific behavior from the writer, namely:
1305764da5fSJoel Dice                 //
1315764da5fSJoel Dice                 // - It is not immediately ready to send us anything.
1325764da5fSJoel Dice                 //
1335764da5fSJoel Dice                 // - When it _is_ ready, it will send us all the bytes it told us to
1345764da5fSJoel Dice                 // expect at once.
1355764da5fSJoel Dice                 let status = stream_read(*rx, ptr::null_mut(), 0);
1365764da5fSJoel Dice                 assert_eq!(status, BLOCKED);
1375764da5fSJoel Dice 
1385764da5fSJoel Dice                 let set = waitable_set_new();
1395764da5fSJoel Dice 
1405764da5fSJoel Dice                 waitable_join(*rx, set);
1415764da5fSJoel Dice 
1425764da5fSJoel Dice                 let tx = {
1435764da5fSJoel Dice                     let pair = stream_new();
1445764da5fSJoel Dice                     let tx = u32::try_from(pair >> 32).unwrap();
1455764da5fSJoel Dice                     let rx = u32::try_from(pair & 0xFFFFFFFF_u64).unwrap();
1465764da5fSJoel Dice 
1475764da5fSJoel Dice                     // Do a zero-length write to wait until the reader is ready.
1485764da5fSJoel Dice                     //
1495764da5fSJoel Dice                     // Here we assume specific behavior from the reader, namely:
1505764da5fSJoel Dice                     //
1515764da5fSJoel Dice                     // - It is not immediately ready to receive anything (indeed, it
1525764da5fSJoel Dice                     // can't possibly be ready given that we haven't returned the
1535764da5fSJoel Dice                     // read handle to it yet).
1545764da5fSJoel Dice                     //
1555764da5fSJoel Dice                     // - When it _is_ ready, it will accept all the bytes we told it
1565764da5fSJoel Dice                     // to expect at once.
1575764da5fSJoel Dice                     let status = stream_write(tx, ptr::null(), 0);
1585764da5fSJoel Dice                     assert_eq!(status, BLOCKED);
1595764da5fSJoel Dice 
1605764da5fSJoel Dice                     waitable_join(tx, set);
1615764da5fSJoel Dice 
1625764da5fSJoel Dice                     task_return_start(rx, BYTES_TO_WRITE.as_ptr(), BYTES_TO_WRITE.len());
1635764da5fSJoel Dice 
1645764da5fSJoel Dice                     tx
1655764da5fSJoel Dice                 };
1665764da5fSJoel Dice 
1675764da5fSJoel Dice                 *state = State::S1 {
1685764da5fSJoel Dice                     set,
1695764da5fSJoel Dice                     tx: Some(tx),
1705764da5fSJoel Dice                     rx: Some(*rx),
1715764da5fSJoel Dice                     expected: mem::take(expected),
1725764da5fSJoel Dice                 };
1735764da5fSJoel Dice 
1745764da5fSJoel Dice                 CALLBACK_CODE_WAIT | (set << 4)
1755764da5fSJoel Dice             }
1765764da5fSJoel Dice 
1775764da5fSJoel Dice             State::S1 {
1785764da5fSJoel Dice                 set,
1795764da5fSJoel Dice                 tx,
1805764da5fSJoel Dice                 rx,
1815764da5fSJoel Dice                 expected,
1825764da5fSJoel Dice             } => {
1835764da5fSJoel Dice                 if event0 == EVENT_STREAM_READ {
1845764da5fSJoel Dice                     let rx = rx.take().unwrap();
1855764da5fSJoel Dice                     assert_eq!(event1, rx);
1865764da5fSJoel Dice                     assert_eq!(event2, 0);
1875764da5fSJoel Dice 
1885764da5fSJoel Dice                     // The writer is ready now, so this read should not block.
1895764da5fSJoel Dice                     //
19036a5339dSjuejinyuxitu                     // As noted above, we rely on the writer sending us all the
1915764da5fSJoel Dice                     // expected bytes at once.
1925764da5fSJoel Dice                     let received = &mut vec![0_u8; expected.len()];
1935764da5fSJoel Dice                     let status = stream_read(rx, received.as_mut_ptr(), received.len());
1945764da5fSJoel Dice                     assert_eq!(
1955764da5fSJoel Dice                         status,
1965764da5fSJoel Dice                         DROPPED | u32::try_from(received.len() << 4).unwrap()
1975764da5fSJoel Dice                     );
1985764da5fSJoel Dice                     assert_eq!(received, expected);
1995764da5fSJoel Dice 
2005764da5fSJoel Dice                     waitable_join(rx, 0);
2015764da5fSJoel Dice                     stream_drop_readable(rx);
2025764da5fSJoel Dice 
2035764da5fSJoel Dice                     if tx.is_none() {
2045764da5fSJoel Dice                         waitable_set_drop(*set);
2055764da5fSJoel Dice 
2065764da5fSJoel Dice                         CALLBACK_CODE_EXIT
2075764da5fSJoel Dice                     } else {
2085764da5fSJoel Dice                         CALLBACK_CODE_WAIT | (*set << 4)
2095764da5fSJoel Dice                     }
2105764da5fSJoel Dice                 } else if event0 == EVENT_STREAM_WRITE {
2115764da5fSJoel Dice                     let tx = tx.take().unwrap();
2125764da5fSJoel Dice                     assert_eq!(event1, tx);
2135764da5fSJoel Dice                     assert_eq!(event2, 0);
2145764da5fSJoel Dice 
2155764da5fSJoel Dice                     // The reader is ready now, so this write should not block.
2165764da5fSJoel Dice                     //
21736a5339dSjuejinyuxitu                     // As noted above, we rely on the reader accepting all the
2185764da5fSJoel Dice                     // expected bytes at once.
2195764da5fSJoel Dice                     let status = stream_write(tx, BYTES_TO_WRITE.as_ptr(), BYTES_TO_WRITE.len());
2205764da5fSJoel Dice                     assert_eq!(
2215764da5fSJoel Dice                         status,
2225764da5fSJoel Dice                         DROPPED | u32::try_from(BYTES_TO_WRITE.len() << 4).unwrap()
2235764da5fSJoel Dice                     );
2245764da5fSJoel Dice 
2255764da5fSJoel Dice                     waitable_join(tx, 0);
2265764da5fSJoel Dice                     stream_drop_writable(tx);
2275764da5fSJoel Dice 
2285764da5fSJoel Dice                     if rx.is_none() {
2295764da5fSJoel Dice                         waitable_set_drop(*set);
2305764da5fSJoel Dice 
2315764da5fSJoel Dice                         CALLBACK_CODE_EXIT
2325764da5fSJoel Dice                     } else {
2335764da5fSJoel Dice                         CALLBACK_CODE_WAIT | (*set << 4)
2345764da5fSJoel Dice                     }
2355764da5fSJoel Dice                 } else {
2365764da5fSJoel Dice                     unreachable!()
2375764da5fSJoel Dice                 }
2385764da5fSJoel Dice             }
2395764da5fSJoel Dice         }
2405764da5fSJoel Dice     }
2415764da5fSJoel Dice }
2425764da5fSJoel Dice 
2435764da5fSJoel Dice // Unused function; required since this file is built as a `bin`:
main()2445764da5fSJoel Dice fn main() {}
245