1 #![expect(unsafe_op_in_unsafe_fn, reason = "old code, not worth updating yet")]
2 
3 use std::collections::HashMap;
4 use std::mem::MaybeUninit;
5 use test_programs::preview1::{STDERR_FD, STDIN_FD, STDOUT_FD, assert_errno};
6 
7 const TIMEOUT: u64 = 200_000_000u64; // 200 milliseconds, required to satisfy slow execution in CI
8 const CLOCK_ID: wasip1::Userdata = 0x0123_45678;
9 const STDIN_ID: wasip1::Userdata = 0x8765_43210;
10 
poll_oneoff_impl( r#in: &[wasip1::Subscription], ) -> Result<Vec<wasip1::Event>, wasip1::Errno>11 unsafe fn poll_oneoff_impl(
12     r#in: &[wasip1::Subscription],
13 ) -> Result<Vec<wasip1::Event>, wasip1::Errno> {
14     let mut out: Vec<wasip1::Event> = Vec::new();
15     out.resize_with(r#in.len(), || {
16         MaybeUninit::<wasip1::Event>::zeroed().assume_init()
17     });
18     let size = wasip1::poll_oneoff(r#in.as_ptr(), out.as_mut_ptr(), r#in.len())?;
19     out.truncate(size);
20     Ok(out)
21 }
22 
test_stdin_read()23 unsafe fn test_stdin_read() {
24     let clock = wasip1::SubscriptionClock {
25         id: wasip1::CLOCKID_MONOTONIC,
26         timeout: TIMEOUT,
27         precision: 0,
28         flags: 0,
29     };
30     let fd_readwrite = wasip1::SubscriptionFdReadwrite {
31         file_descriptor: STDIN_FD,
32     };
33     // Either stdin can be ready for reading, or this poll can timeout.
34     let r#in = [
35         wasip1::Subscription {
36             userdata: CLOCK_ID,
37             u: wasip1::SubscriptionU {
38                 tag: wasip1::EVENTTYPE_CLOCK.raw(),
39                 u: wasip1::SubscriptionUU { clock },
40             },
41         },
42         wasip1::Subscription {
43             userdata: STDIN_ID,
44             u: wasip1::SubscriptionU {
45                 tag: wasip1::EVENTTYPE_FD_READ.raw(),
46                 u: wasip1::SubscriptionUU {
47                     fd_read: fd_readwrite,
48                 },
49             },
50         },
51     ];
52     let out = poll_oneoff_impl(&r#in).unwrap();
53     // The result should be either a timeout, or that stdin is ready for reading.
54     // Both are valid behaviors that depend on the test environment.
55     assert!(out.len() >= 1, "stdin read should return at least 1 event");
56     for event in out {
57         if event.type_ == wasip1::EVENTTYPE_CLOCK {
58             assert_errno!(event.error, wasip1::ERRNO_SUCCESS);
59             assert_eq!(
60                 event.userdata, CLOCK_ID,
61                 "the event.userdata should contain CLOCK_ID",
62             );
63         } else if event.type_ == wasip1::EVENTTYPE_FD_READ {
64             assert_errno!(event.error, wasip1::ERRNO_SUCCESS);
65             assert_eq!(
66                 event.userdata, STDIN_ID,
67                 "the event.userdata should contain STDIN_ID",
68             );
69         } else {
70             panic!("unexpected event type {}", event.type_.raw());
71         }
72     }
73 }
74 
writable_subs(h: &HashMap<u64, wasip1::Fd>) -> Vec<wasip1::Subscription>75 fn writable_subs(h: &HashMap<u64, wasip1::Fd>) -> Vec<wasip1::Subscription> {
76     h.iter()
77         .map(|(ud, fd)| wasip1::Subscription {
78             userdata: *ud,
79             u: wasip1::SubscriptionU {
80                 tag: wasip1::EVENTTYPE_FD_WRITE.raw(),
81                 u: wasip1::SubscriptionUU {
82                     fd_write: wasip1::SubscriptionFdReadwrite {
83                         file_descriptor: *fd,
84                     },
85                 },
86             },
87         })
88         .collect()
89 }
90 
test_stdout_stderr_write()91 unsafe fn test_stdout_stderr_write() {
92     let mut writable: HashMap<u64, wasip1::Fd> =
93         [(1, STDOUT_FD), (2, STDERR_FD)].into_iter().collect();
94 
95     let clock = wasip1::Subscription {
96         userdata: CLOCK_ID,
97         u: wasip1::SubscriptionU {
98             tag: wasip1::EVENTTYPE_CLOCK.raw(),
99             u: wasip1::SubscriptionUU {
100                 clock: wasip1::SubscriptionClock {
101                     id: wasip1::CLOCKID_MONOTONIC,
102                     timeout: TIMEOUT,
103                     precision: 0,
104                     flags: 0,
105                 },
106             },
107         },
108     };
109     let mut timed_out = false;
110     while !writable.is_empty() {
111         if timed_out {
112             panic!("timed out with the following pending subs: {writable:?}")
113         }
114         let mut subs = writable_subs(&writable);
115         subs.push(clock);
116         let out = poll_oneoff_impl(&subs).unwrap();
117         for event in out {
118             match event.userdata {
119                 CLOCK_ID => timed_out = true,
120                 ud => {
121                     if let Some(_) = writable.remove(&ud) {
122                         assert_eq!(event.type_, wasip1::EVENTTYPE_FD_WRITE);
123                         assert_errno!(event.error, wasip1::ERRNO_SUCCESS);
124                     } else {
125                         panic!("Unknown userdata {ud}, pending sub: {writable:?}")
126                     }
127                 }
128             }
129         }
130     }
131 }
132 
test_poll_oneoff()133 unsafe fn test_poll_oneoff() {
134     // NB we assume that stdin/stdout/stderr are valid and open
135     // for the duration of the test case
136     test_stdin_read();
137     test_stdout_stderr_write();
138 }
main()139 fn main() {
140     // Run the tests.
141     unsafe { test_poll_oneoff() }
142 }
143