diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e9fcdcc6..8f519e53 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -58,6 +58,14 @@ jobs: with: command: check args: --features unstable --all --bins --examples --tests + + - name: check wasm + uses: actions-rs/cargo@v1 + with: + command: check + target: wasm32-unknown-unknown + override: true + args: --features unstable --all --bins --tests - name: check bench uses: actions-rs/cargo@v1 diff --git a/Cargo.toml b/Cargo.toml index dffdc5cd..e74a2ed0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,14 +63,25 @@ once_cell = { version = "1.3.1", optional = true } pin-project-lite = { version = "0.1.4", optional = true } pin-utils = { version = "0.1.0-alpha.4", optional = true } slab = { version = "0.4.2", optional = true } + +[target.'cfg(not(target_os = "unknown"))'.dependencies] smol = { path = "../smol", optional = true } +[target.'cfg(target_arch = "wasm32")'.dependencies] +wasm-timer = "0.2.4" +wasm-bindgen-futures = "0.4.10" +futures-channel = "0.3.4" + +[target.'cfg(target_arch = "wasm32")'.dev-dependencies] +wasm-bindgen-test = "0.3.10" + [dev-dependencies] femme = "1.3.0" rand = "0.7.3" surf = "1.0.3" tempdir = "0.3.7" futures = "0.3.4" +rand_xorshift = "0.2.0" [[test]] name = "stream" diff --git a/src/future/future/delay.rs b/src/future/future/delay.rs index e1944702..b6c30bcc 100644 --- a/src/future/future/delay.rs +++ b/src/future/future/delay.rs @@ -3,9 +3,9 @@ use std::pin::Pin; use std::time::Duration; use pin_project_lite::pin_project; -use smol::Timer; use crate::task::{Context, Poll}; +use crate::utils::Timer; pin_project! { #[doc(hidden)] diff --git a/src/future/timeout.rs b/src/future/timeout.rs index ec547f89..4a9d93c7 100644 --- a/src/future/timeout.rs +++ b/src/future/timeout.rs @@ -5,9 +5,9 @@ use std::pin::Pin; use std::time::Duration; use pin_project_lite::pin_project; -use smol::Timer; use crate::task::{Context, Poll}; +use crate::utils::Timer; /// Awaits a future or times out after a duration of time. /// diff --git a/src/io/mod.rs b/src/io/mod.rs index dd97567b..f5dd9e2c 100644 --- a/src/io/mod.rs +++ b/src/io/mod.rs @@ -307,22 +307,33 @@ cfg_std! { cfg_default! { // For use in the print macros. #[doc(hidden)] + #[cfg(not(target_os = "unknown"))] pub use stdio::{_eprint, _print}; + #[cfg(not(target_os = "unknown"))] pub use stderr::{stderr, Stderr}; + #[cfg(not(target_os = "unknown"))] pub use stdin::{stdin, Stdin}; + #[cfg(not(target_os = "unknown"))] pub use stdout::{stdout, Stdout}; pub use timeout::timeout; mod timeout; + #[cfg(not(target_os = "unknown"))] mod stderr; + #[cfg(not(target_os = "unknown"))] mod stdin; + #[cfg(not(target_os = "unknown"))] mod stdio; + #[cfg(not(target_os = "unknown"))] mod stdout; } cfg_unstable_default! { + #[cfg(not(target_os = "unknown"))] pub use stderr::StderrLock; + #[cfg(not(target_os = "unknown"))] pub use stdin::StdinLock; + #[cfg(not(target_os = "unknown"))] pub use stdout::StdoutLock; } diff --git a/src/io/read/mod.rs b/src/io/read/mod.rs index 8aade189..0d429209 100644 --- a/src/io/read/mod.rs +++ b/src/io/read/mod.rs @@ -17,9 +17,9 @@ use std::mem; use crate::io::IoSliceMut; -pub use take::Take; pub use bytes::Bytes; pub use chain::Chain; +pub use take::Take; extension_trait! { use std::pin::Pin; @@ -483,7 +483,7 @@ mod tests { use crate::prelude::*; #[test] - fn test_read_by_ref() -> io::Result<()> { + fn test_read_by_ref() { crate::task::block_on(async { let mut f = io::Cursor::new(vec![0u8, 1, 2, 3, 4, 5, 6, 7, 8]); let mut buffer = Vec::new(); @@ -493,14 +493,13 @@ mod tests { let reference = f.by_ref(); // read at most 5 bytes - assert_eq!(reference.take(5).read_to_end(&mut buffer).await?, 5); + assert_eq!(reference.take(5).read_to_end(&mut buffer).await.unwrap(), 5); assert_eq!(&buffer, &[0, 1, 2, 3, 4]) } // drop our &mut reference so we can use f again // original file still usable, read the rest - assert_eq!(f.read_to_end(&mut other_buffer).await?, 4); + assert_eq!(f.read_to_end(&mut other_buffer).await.unwrap(), 4); assert_eq!(&other_buffer, &[5, 6, 7, 8]); - Ok(()) - }) + }); } } diff --git a/src/io/read/take.rs b/src/io/read/take.rs index 09b02c2f..ba9a9e31 100644 --- a/src/io/read/take.rs +++ b/src/io/read/take.rs @@ -218,7 +218,7 @@ impl BufRead for Take { } } -#[cfg(test)] +#[cfg(all(test, not(target_os = "unknown")))] mod tests { use crate::io; use crate::prelude::*; diff --git a/src/io/timeout.rs b/src/io/timeout.rs index c19d25dd..ce33fea1 100644 --- a/src/io/timeout.rs +++ b/src/io/timeout.rs @@ -4,9 +4,9 @@ use std::task::{Context, Poll}; use std::time::Duration; use pin_project_lite::pin_project; -use smol::Timer; use crate::io; +use crate::utils::Timer; /// Awaits an I/O future or times out after a duration of time. /// diff --git a/src/lib.rs b/src/lib.rs index 7e0e98d3..408a7ab1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -267,14 +267,17 @@ cfg_std! { } cfg_default! { + #[cfg(not(target_os = "unknown"))] pub mod fs; pub mod path; pub mod net; + #[cfg(not(target_os = "unknown"))] pub(crate) mod rt; } cfg_unstable! { pub mod pin; + #[cfg(not(target_os = "unknown"))] pub mod process; mod unit; diff --git a/src/net/mod.rs b/src/net/mod.rs index fe83d3b1..18140735 100644 --- a/src/net/mod.rs +++ b/src/net/mod.rs @@ -61,10 +61,16 @@ pub use std::net::Shutdown; pub use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; pub use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6}; +#[cfg(not(target_os = "unknown"))] pub use addr::ToSocketAddrs; +#[cfg(not(target_os = "unknown"))] pub use tcp::{Incoming, TcpListener, TcpStream}; +#[cfg(not(target_os = "unknown"))] pub use udp::UdpSocket; +#[cfg(not(target_os = "unknown"))] mod addr; +#[cfg(not(target_os = "unknown"))] mod tcp; +#[cfg(not(target_os = "unknown"))] mod udp; diff --git a/src/path/path.rs b/src/path/path.rs index dfe9426a..185bfaff 100644 --- a/src/path/path.rs +++ b/src/path/path.rs @@ -4,9 +4,9 @@ use std::ffi::{OsStr, OsString}; use std::rc::Rc; use std::sync::Arc; -use crate::fs; -use crate::io; use crate::path::{Ancestors, Components, Display, Iter, PathBuf, StripPrefixError}; +#[cfg(not(target_os = "unknown"))] +use crate::{fs, io}; /// A slice of a path. /// @@ -584,6 +584,7 @@ impl Path { /// # /// # Ok(()) }) } /// ``` + #[cfg(not(target_os = "unknown"))] pub async fn metadata(&self) -> io::Result { fs::metadata(self).await } @@ -607,6 +608,7 @@ impl Path { /// # /// # Ok(()) }) } /// ``` + #[cfg(not(target_os = "unknown"))] pub async fn symlink_metadata(&self) -> io::Result { fs::symlink_metadata(self).await } @@ -632,6 +634,7 @@ impl Path { /// # /// # Ok(()) }) } /// ``` + #[cfg(not(target_os = "unknown"))] pub async fn canonicalize(&self) -> io::Result { fs::canonicalize(self).await } @@ -654,6 +657,7 @@ impl Path { /// # /// # Ok(()) }) } /// ``` + #[cfg(not(target_os = "unknown"))] pub async fn read_link(&self) -> io::Result { fs::read_link(self).await } @@ -688,6 +692,7 @@ impl Path { /// # /// # Ok(()) }) } /// ``` + #[cfg(not(target_os = "unknown"))] pub async fn read_dir(&self) -> io::Result { fs::read_dir(self).await } @@ -717,6 +722,7 @@ impl Path { /// check errors, call [fs::metadata]. /// /// [fs::metadata]: ../fs/fn.metadata.html + #[cfg(not(target_os = "unknown"))] pub async fn exists(&self) -> bool { fs::metadata(self).await.is_ok() } @@ -749,6 +755,7 @@ impl Path { /// /// [fs::metadata]: ../fs/fn.metadata.html /// [fs::Metadata::is_file]: ../fs/struct.Metadata.html#method.is_file + #[cfg(not(target_os = "unknown"))] pub async fn is_file(&self) -> bool { fs::metadata(self) .await @@ -785,6 +792,7 @@ impl Path { /// /// [fs::metadata]: ../fs/fn.metadata.html /// [fs::Metadata::is_dir]: ../fs/struct.Metadata.html#method.is_dir + #[cfg(not(target_os = "unknown"))] pub async fn is_dir(&self) -> bool { fs::metadata(self) .await diff --git a/src/stream/interval.rs b/src/stream/interval.rs index fe249fb2..4e5c92b0 100644 --- a/src/stream/interval.rs +++ b/src/stream/interval.rs @@ -4,7 +4,7 @@ use std::task::{Context, Poll}; use std::time::Duration; use crate::stream::Stream; -use smol::Timer; +use crate::utils::Timer; /// Creates a new stream that yields at a set interval. /// diff --git a/src/stream/stream/delay.rs b/src/stream/stream/delay.rs index 754bef80..0ba42b05 100644 --- a/src/stream/stream/delay.rs +++ b/src/stream/stream/delay.rs @@ -3,10 +3,10 @@ use core::pin::Pin; use core::time::Duration; use pin_project_lite::pin_project; -use smol::Timer; use crate::stream::Stream; use crate::task::{Context, Poll}; +use crate::utils::Timer; pin_project! { #[doc(hidden)] diff --git a/src/stream/stream/throttle.rs b/src/stream/stream/throttle.rs index 4d4cc878..2f9333a7 100644 --- a/src/stream/stream/throttle.rs +++ b/src/stream/stream/throttle.rs @@ -3,10 +3,10 @@ use std::pin::Pin; use std::time::Duration; use pin_project_lite::pin_project; -use smol::Timer; use crate::stream::Stream; use crate::task::{Context, Poll}; +use crate::utils::Timer; pin_project! { /// A stream that only yields one element once every `duration`. diff --git a/src/stream/stream/timeout.rs b/src/stream/stream/timeout.rs index f49aed31..28e52aeb 100644 --- a/src/stream/stream/timeout.rs +++ b/src/stream/stream/timeout.rs @@ -5,10 +5,10 @@ use std::pin::Pin; use std::time::Duration; use pin_project_lite::pin_project; -use smol::Timer; use crate::stream::Stream; use crate::task::{Context, Poll}; +use crate::utils::Timer; pin_project! { /// A stream with timeout time set diff --git a/src/sync/barrier.rs b/src/sync/barrier.rs index 2822d546..86e9a2d9 100644 --- a/src/sync/barrier.rs +++ b/src/sync/barrier.rs @@ -202,7 +202,7 @@ impl BarrierWaitResult { } } -#[cfg(test)] +#[cfg(all(test, not(target_os = "unknown")))] mod test { use futures::channel::mpsc::unbounded; use futures::sink::SinkExt; diff --git a/src/task/block_on.rs b/src/task/block_on.rs index 92a11879..fa66f915 100644 --- a/src/task/block_on.rs +++ b/src/task/block_on.rs @@ -25,9 +25,20 @@ use crate::task::Builder; /// }) /// } /// ``` +#[cfg(not(target_os = "unknown"))] pub fn block_on(future: F) -> T where F: Future, { Builder::new().blocking(future) } + +/// Spawns a task and waits for it to finish. +#[cfg(target_os = "unknown")] +pub fn block_on(future: F) +where + F: Future + 'static, + T: 'static, +{ + Builder::new().local(future).unwrap(); +} diff --git a/src/task/builder.rs b/src/task/builder.rs index f1bf791a..f48b6b4c 100644 --- a/src/task/builder.rs +++ b/src/task/builder.rs @@ -3,7 +3,6 @@ use std::pin::Pin; use std::sync::Arc; use std::task::{Context, Poll}; -use kv_log_macro::trace; use pin_project_lite::pin_project; use crate::io; @@ -38,15 +37,16 @@ impl Builder { // Create a new task handle. let task = Task::new(name); + #[cfg(not(target_os = "unknown"))] once_cell::sync::Lazy::force(&crate::rt::RUNTIME); let tag = TaskLocalsWrapper::new(task.clone()); - // FIXME: do not require all futures to be boxed. SupportTaskLocals { tag, future } } /// Spawns a task with the configured settings. + #[cfg(not(target_os = "unknown"))] pub fn spawn(self, future: F) -> io::Result> where F: Future + Send + 'static, @@ -61,6 +61,7 @@ impl Builder { } /// Spawns a task locally with the configured settings. + #[cfg(not(target_os = "unknown"))] pub fn local(self, future: F) -> io::Result> where F: Future + 'static, @@ -74,7 +75,29 @@ impl Builder { Ok(JoinHandle::new(smol_task, task)) } + /// Spawns a task locally with the configured settings. + #[cfg(target_arch = "wasm32")] + pub fn local(self, future: F) -> io::Result> + where + F: Future + 'static, + T: 'static, + { + use futures_channel::oneshot::channel; + let (sender, receiver) = channel(); + + let wrapped = self.build(async move { + let res = future.await; + let _ = sender.send(res); + }); + + let task = wrapped.tag.task().clone(); + wasm_bindgen_futures::spawn_local(wrapped); + + Ok(JoinHandle::new(receiver, task)) + } + /// Spawns a task with the configured settings, blocking on its execution. + #[cfg(not(target_os = "unknown"))] pub fn blocking(self, future: F) -> T where F: Future, @@ -82,7 +105,7 @@ impl Builder { let wrapped = self.build(future); // Log this `block_on` operation. - trace!("block_on", { + kv_log_macro::trace!("block_on", { task_id: wrapped.tag.id().0, parent_task_id: TaskLocalsWrapper::get_current(|t| t.id().0).unwrap_or(0), }); diff --git a/src/task/join_handle.rs b/src/task/join_handle.rs index 3a632711..110b827e 100644 --- a/src/task/join_handle.rs +++ b/src/task/join_handle.rs @@ -13,13 +13,18 @@ use crate::task::{Context, Poll, Task}; /// [spawned]: fn.spawn.html #[derive(Debug)] pub struct JoinHandle { - handle: Option>, + handle: Option>, task: Task, } +#[cfg(not(target_os = "unknown"))] +type InnerHandle = async_task::JoinHandle; +#[cfg(target_arch = "wasm32")] +type InnerHandle = futures_channel::oneshot::Receiver; + impl JoinHandle { /// Creates a new `JoinHandle`. - pub(crate) fn new(inner: async_task::JoinHandle, task: Task) -> JoinHandle { + pub(crate) fn new(inner: InnerHandle, task: Task) -> JoinHandle { JoinHandle { handle: Some(inner), task, @@ -46,11 +51,20 @@ impl JoinHandle { } /// Cancel this task. + #[cfg(not(target_os = "unknown"))] pub async fn cancel(mut self) -> Option { let handle = self.handle.take().unwrap(); handle.cancel(); handle.await } + + /// Cancel this task. + #[cfg(target_arch = "wasm32")] + pub async fn cancel(mut self) -> Option { + let mut handle = self.handle.take().unwrap(); + handle.close(); + handle.await.ok() + } } impl Future for JoinHandle { diff --git a/src/task/mod.rs b/src/task/mod.rs index f5bc8641..6a142ffc 100644 --- a/src/task/mod.rs +++ b/src/task/mod.rs @@ -138,6 +138,7 @@ cfg_default! { pub use task_id::TaskId; pub use join_handle::JoinHandle; pub use sleep::sleep; + #[cfg(not(target_os = "unknown"))] pub use spawn::spawn; pub use spawn_local::spawn_local; pub use task_local::{AccessError, LocalKey}; @@ -150,7 +151,9 @@ cfg_default! { mod current; mod join_handle; mod sleep; + #[cfg(not(target_os = "unknown"))] mod spawn; + #[cfg(not(target_os = "unknown"))] mod spawn_blocking; mod spawn_local; mod task; @@ -158,8 +161,10 @@ cfg_default! { mod task_local; mod task_locals_wrapper; + #[cfg(not(target_os = "unknown"))] #[cfg(any(feature = "unstable", test))] pub use spawn_blocking::spawn_blocking; + #[cfg(not(target_os = "unknown"))] #[cfg(not(any(feature = "unstable", test)))] pub(crate) use spawn_blocking::spawn_blocking; } diff --git a/src/utils.rs b/src/utils.rs index 33e66044..2ae5488e 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -59,6 +59,37 @@ pub(crate) trait Context { fn context(self, message: impl Fn() -> String) -> Self; } +#[cfg(not(target_os = "unknown"))] +pub(crate) type Timer = smol::Timer; + +#[cfg(target_arch = "wasm32")] +#[derive(Debug)] +pub(crate) struct Timer(wasm_timer::Delay); + +#[cfg(target_arch = "wasm32")] +impl Timer { + pub(crate) fn after(dur: std::time::Duration) -> Self { + Timer(wasm_timer::Delay::new(dur)) + } +} + +#[cfg(target_arch = "wasm32")] +use std::pin::Pin; +#[cfg(target_arch = "wasm32")] +use std::task::Poll; + +#[cfg(target_arch = "wasm32")] +impl std::future::Future for Timer { + type Output = (); + + fn poll(mut self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll { + match Pin::new(&mut self.0).poll(cx) { + Poll::Pending => Poll::Pending, + Poll::Ready(_) => Poll::Ready(()), + } + } +} + /// Defers evaluation of a block of code until the end of the scope. #[cfg(feature = "default")] #[doc(hidden)] diff --git a/tests/addr.rs b/tests/addr.rs index aada557c..fcd5aa1f 100644 --- a/tests/addr.rs +++ b/tests/addr.rs @@ -1,3 +1,5 @@ +#![cfg(not(target_os = "unknown"))] + use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; use async_std::net::ToSocketAddrs; diff --git a/tests/block_on.rs b/tests/block_on.rs index c422d063..28902b01 100644 --- a/tests/block_on.rs +++ b/tests/block_on.rs @@ -1,3 +1,5 @@ +#![cfg(not(target_os = "unknown"))] + use async_std::task; #[test] diff --git a/tests/buf_writer.rs b/tests/buf_writer.rs index 5df90e08..442cf8a4 100644 --- a/tests/buf_writer.rs +++ b/tests/buf_writer.rs @@ -2,15 +2,19 @@ use async_std::io::{self, BufWriter, SeekFrom}; use async_std::prelude::*; use async_std::task; +#[cfg(target_arch = "wasm32")] +wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); + #[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_buffered_writer() { #![allow(clippy::cognitive_complexity)] task::block_on(async { - let inner = Vec::new(); - let mut writer = BufWriter::with_capacity(2, inner); + let inner: Vec = Vec::new(); + let mut writer = BufWriter::>::with_capacity(2, inner); writer.write(&[0, 1]).await.unwrap(); - assert_eq!(writer.buffer(), []); + assert!(writer.buffer().is_empty()); assert_eq!(*writer.get_ref(), [0, 1]); writer.write(&[2]).await.unwrap(); @@ -22,7 +26,7 @@ fn test_buffered_writer() { assert_eq!(*writer.get_ref(), [0, 1]); writer.flush().await.unwrap(); - assert_eq!(writer.buffer(), []); + assert!(writer.buffer().is_empty()); assert_eq!(*writer.get_ref(), [0, 1, 2, 3]); writer.write(&[4]).await.unwrap(); @@ -35,31 +39,33 @@ fn test_buffered_writer() { assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5]); writer.write(&[7, 8]).await.unwrap(); - assert_eq!(writer.buffer(), []); + assert!(writer.buffer().is_empty()); assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8]); writer.write(&[9, 10, 11]).await.unwrap(); - assert_eq!(writer.buffer(), []); + assert!(writer.buffer().is_empty()); assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); writer.flush().await.unwrap(); - assert_eq!(writer.buffer(), []); + assert!(writer.buffer().is_empty()); assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); }) } #[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_buffered_writer_inner_into_inner_flushes() { task::block_on(async { - let mut w = BufWriter::with_capacity(3, Vec::new()); + let mut w = BufWriter::with_capacity(3, Vec::::new()); w.write(&[0, 1]).await.unwrap(); - assert_eq!(*w.get_ref(), []); + assert!(w.get_ref().is_empty()); let w = w.into_inner().await.unwrap(); assert_eq!(w, [0, 1]); }) } #[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_buffered_writer_seek() { task::block_on(async { let mut w = BufWriter::with_capacity(3, io::Cursor::new(Vec::new())); diff --git a/tests/channel.rs b/tests/channel.rs index f3029060..a218ea2a 100644 --- a/tests/channel.rs +++ b/tests/channel.rs @@ -6,13 +6,22 @@ use std::time::Duration; use async_std::sync::channel; use async_std::task; -use rand::{thread_rng, Rng}; +use rand::{Rng, SeedableRng}; + +#[cfg(not(target_os = "unknown"))] +use async_std::task::spawn; +#[cfg(target_os = "unknown")] +use async_std::task::spawn_local as spawn; + +#[cfg(target_arch = "wasm32")] +wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); fn ms(ms: u64) -> Duration { Duration::from_millis(ms) } #[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn smoke() { task::block_on(async { let (s, r) = channel(1); @@ -35,6 +44,7 @@ fn smoke() { } #[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn capacity() { for i in 1..10 { let (s, r) = channel::<()>(i); @@ -44,6 +54,7 @@ fn capacity() { } #[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn len_empty_full() { #![allow(clippy::cognitive_complexity)] task::block_on(async { @@ -86,11 +97,12 @@ fn len_empty_full() { } #[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn recv() { task::block_on(async { let (s, r) = channel(100); - task::spawn(async move { + spawn(async move { assert_eq!(r.recv().await.unwrap(), 7); task::sleep(ms(1000)).await; assert_eq!(r.recv().await.unwrap(), 8); @@ -107,11 +119,12 @@ fn recv() { } #[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn send() { task::block_on(async { let (s, r) = channel(1); - task::spawn(async move { + spawn(async move { s.send(7).await; task::sleep(ms(1000)).await; s.send(8).await; @@ -129,6 +142,7 @@ fn send() { } #[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn recv_after_disconnect() { task::block_on(async { let (s, r) = channel(100); @@ -147,6 +161,7 @@ fn recv_after_disconnect() { } #[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn len() { const COUNT: usize = 25_000; const CAP: usize = 1000; @@ -184,7 +199,7 @@ fn len() { assert_eq!(s.len(), 0); assert_eq!(r.len(), 0); - let child = task::spawn({ + let child = spawn({ let r = r.clone(); async move { for i in 0..COUNT { @@ -209,11 +224,12 @@ fn len() { } #[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn disconnect_wakes_receiver() { task::block_on(async { let (s, r) = channel::<()>(1); - let child = task::spawn(async move { + let child = spawn(async move { assert!(r.recv().await.is_err()); }); @@ -225,13 +241,14 @@ fn disconnect_wakes_receiver() { } #[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn spsc() { const COUNT: usize = 100_000; task::block_on(async { let (s, r) = channel(3); - let child = task::spawn(async move { + let child = spawn(async move { for i in 0..COUNT { assert_eq!(r.recv().await.unwrap(), i); } @@ -248,6 +265,7 @@ fn spsc() { } #[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn mpmc() { const COUNT: usize = 25_000; const TASKS: usize = 4; @@ -262,7 +280,7 @@ fn mpmc() { for _ in 0..TASKS { let r = r.clone(); let v = v.clone(); - tasks.push(task::spawn(async move { + tasks.push(spawn(async move { for _ in 0..COUNT { let n = r.recv().await.unwrap(); v[n].fetch_add(1, Ordering::SeqCst); @@ -272,7 +290,7 @@ fn mpmc() { for _ in 0..TASKS { let s = s.clone(); - tasks.push(task::spawn(async move { + tasks.push(spawn(async move { for i in 0..COUNT { s.send(i).await; } @@ -290,6 +308,7 @@ fn mpmc() { } #[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn oneshot() { const COUNT: usize = 10_000; @@ -297,8 +316,8 @@ fn oneshot() { for _ in 0..COUNT { let (s, r) = channel(1); - let c1 = task::spawn(async move { r.recv().await.unwrap() }); - let c2 = task::spawn(async move { s.send(0).await }); + let c1 = spawn(async move { r.recv().await.unwrap() }); + let c2 = spawn(async move { s.send(0).await }); c1.await; c2.await; @@ -307,6 +326,7 @@ fn oneshot() { } #[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn drops() { const RUNS: usize = 100; @@ -321,17 +341,16 @@ fn drops() { } } - let mut rng = thread_rng(); - for _ in 0..RUNS { - task::block_on(async { + let mut rng = rand_xorshift::XorShiftRng::seed_from_u64(0); + task::block_on(async move { let steps = rng.gen_range(0, 10_000); let additional = rng.gen_range(0, 50); DROPS.store(0, Ordering::SeqCst); let (s, r) = channel::(50); - let child = task::spawn({ + let child = spawn({ let r = r.clone(); async move { for _ in 0..steps { diff --git a/tests/condvar.rs b/tests/condvar.rs index c4d680fc..7b05b286 100644 --- a/tests/condvar.rs +++ b/tests/condvar.rs @@ -5,13 +5,22 @@ use std::time::Duration; use async_std::sync::{Condvar, Mutex}; use async_std::task::{self, JoinHandle}; +#[cfg(not(target_os = "unknown"))] +use async_std::task::spawn; +#[cfg(target_os = "unknown")] +use async_std::task::spawn_local as spawn; + +#[cfg(target_arch = "wasm32")] +wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); + #[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn wait_timeout_with_lock() { task::block_on(async { let pair = Arc::new((Mutex::new(false), Condvar::new())); let pair2 = pair.clone(); - task::spawn(async move { + spawn(async move { let (m, c) = &*pair2; let _g = m.lock().await; task::sleep(Duration::from_millis(20)).await; @@ -27,6 +36,7 @@ fn wait_timeout_with_lock() { } #[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn wait_timeout_without_lock() { task::block_on(async { let m = Mutex::new(false); @@ -40,6 +50,7 @@ fn wait_timeout_without_lock() { } #[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn wait_timeout_until_timed_out() { task::block_on(async { let m = Mutex::new(false); @@ -55,6 +66,7 @@ fn wait_timeout_until_timed_out() { } #[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn notify_all() { task::block_on(async { let mut tasks: Vec> = Vec::new(); @@ -62,7 +74,7 @@ fn notify_all() { for _ in 0..10 { let pair = pair.clone(); - tasks.push(task::spawn(async move { + tasks.push(spawn(async move { let (m, c) = &*pair; let mut count = m.lock().await; while *count == 0 { diff --git a/tests/io_timeout.rs b/tests/io_timeout.rs index 85a17ab7..fa30a68a 100644 --- a/tests/io_timeout.rs +++ b/tests/io_timeout.rs @@ -5,6 +5,7 @@ use async_std::task; #[test] #[should_panic(expected = "timed out")] +#[cfg(not(target_os = "unknown"))] fn io_timeout_timedout() { task::block_on(async { io::timeout(Duration::from_secs(1), async { diff --git a/tests/mutex.rs b/tests/mutex.rs index ebdd7520..76f42e28 100644 --- a/tests/mutex.rs +++ b/tests/mutex.rs @@ -5,7 +5,16 @@ use async_std::sync::Mutex; use async_std::task; use futures::channel::mpsc; +#[cfg(not(target_os = "unknown"))] +use async_std::task::spawn; +#[cfg(target_os = "unknown")] +use async_std::task::spawn_local as spawn; + +#[cfg(target_arch = "wasm32")] +wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); + #[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn smoke() { task::block_on(async { let m = Mutex::new(()); @@ -15,18 +24,21 @@ fn smoke() { } #[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn try_lock() { let m = Mutex::new(()); *m.try_lock().unwrap() = (); } #[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn into_inner() { let m = Mutex::new(10); assert_eq!(m.into_inner(), 10); } #[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn get_mut() { let mut m = Mutex::new(10); *m.get_mut() = 20; @@ -34,21 +46,21 @@ fn get_mut() { } #[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn contention() { task::block_on(async { let (tx, mut rx) = mpsc::unbounded(); let tx = Arc::new(tx); let mutex = Arc::new(Mutex::new(0)); - let num_tasks = 10; //000; + let num_tasks = 10000; let mut handles = Vec::new(); for _ in 0..num_tasks { let tx = tx.clone(); let mutex = mutex.clone(); - dbg!("spawn"); - handles.push(task::spawn(async move { + handles.push(spawn(async move { let mut lock = mutex.lock().await; *lock += 1; tx.unbounded_send(()).unwrap(); @@ -56,8 +68,7 @@ fn contention() { })); } - for i in 0..num_tasks { - dbg!(i); + for _ in 0..num_tasks { rx.next().await.unwrap(); } diff --git a/tests/rwlock.rs b/tests/rwlock.rs index 370dcb9f..1d33a456 100644 --- a/tests/rwlock.rs +++ b/tests/rwlock.rs @@ -10,6 +10,14 @@ use async_std::sync::RwLock; use async_std::task; use futures::channel::mpsc; +#[cfg(not(target_os = "unknown"))] +use async_std::task::spawn; +#[cfg(target_os = "unknown")] +use async_std::task::spawn_local as spawn; + +#[cfg(target_arch = "wasm32")] +wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); + /// Generates a random number in `0..n`. pub fn random(n: u32) -> u32 { thread_local! { @@ -35,6 +43,7 @@ pub fn random(n: u32) -> u32 { } #[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn smoke() { task::block_on(async { let lock = RwLock::new(()); @@ -46,6 +55,7 @@ fn smoke() { } #[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn try_write() { task::block_on(async { let lock = RwLock::new(0isize); @@ -56,12 +66,14 @@ fn try_write() { } #[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn into_inner() { let lock = RwLock::new(10); assert_eq!(lock.into_inner(), 10); } #[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn into_inner_and_drop() { struct Counter(Arc); @@ -84,6 +96,7 @@ fn into_inner_and_drop() { } #[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn get_mut() { let mut lock = RwLock::new(10); *lock.get_mut() = 20; @@ -91,6 +104,7 @@ fn get_mut() { } #[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn contention() { const N: u32 = 10; const M: usize = 1000; @@ -104,7 +118,7 @@ fn contention() { let tx = tx.clone(); let rw = rw.clone(); - task::spawn(async move { + spawn(async move { for _ in 0..M { if random(N) == 0 { drop(rw.write().await); @@ -116,7 +130,7 @@ fn contention() { }); } - task::block_on(async { + task::block_on(async move { for _ in 0..N { rx.next().await.unwrap(); } @@ -124,6 +138,7 @@ fn contention() { } #[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn writer_and_readers() { #[derive(Default)] struct Yield(Cell); @@ -146,7 +161,7 @@ fn writer_and_readers() { let (tx, mut rx) = mpsc::unbounded(); // Spawn a writer task. - task::spawn({ + spawn({ let lock = lock.clone(); async move { let mut lock = lock.write().await; @@ -164,13 +179,13 @@ fn writer_and_readers() { let mut readers = Vec::new(); for _ in 0..5 { let lock = lock.clone(); - readers.push(task::spawn(async move { + readers.push(spawn(async move { let lock = lock.read().await; assert!(*lock >= 0); })); } - task::block_on(async { + task::block_on(async move { // Wait for readers to pass their asserts. for r in readers { r.await; diff --git a/tests/stream.rs b/tests/stream.rs index 42a6191f..3576cb90 100644 --- a/tests/stream.rs +++ b/tests/stream.rs @@ -8,14 +8,23 @@ use async_std::stream; use async_std::sync::channel; use async_std::task; +#[cfg(target_arch = "wasm32")] +wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); + +#[cfg(not(target_os = "unknown"))] +use async_std::task::spawn; +#[cfg(target_os = "unknown")] +use async_std::task::spawn_local as spawn; + #[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] /// Checks that streams are merged fully even if one of the components /// experiences delay. fn merging_delayed_streams_work() { let (sender, receiver) = channel::(10); let mut s = receiver.merge(stream::empty()); - let t = task::spawn(async move { + let t = spawn(async move { let mut xs = Vec::new(); while let Some(x) = s.next().await { xs.push(x); @@ -34,7 +43,7 @@ fn merging_delayed_streams_work() { let (sender, receiver) = channel::(10); let mut s = stream::empty().merge(receiver); - let t = task::spawn(async move { + let t = spawn(async move { let mut xs = Vec::new(); while let Some(x) = s.next().await { xs.push(x); @@ -85,16 +94,17 @@ fn explode(s: S) -> Explode { } #[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn merge_works_with_unfused_streams() { let s1 = explode(stream::once(92)); let s2 = explode(stream::once(92)); let mut s = s1.merge(s2); - let xs = task::block_on(async move { + + task::block_on(async move { let mut xs = Vec::new(); while let Some(x) = s.next().await { xs.push(x) } - xs + assert_eq!(xs, vec![92, 92]); }); - assert_eq!(xs, vec![92, 92]); } diff --git a/tests/task_local.rs b/tests/task_local.rs index 813185c8..b5345fec 100644 --- a/tests/task_local.rs +++ b/tests/task_local.rs @@ -3,7 +3,16 @@ use std::sync::atomic::{AtomicBool, Ordering}; use async_std::task; use async_std::task_local; +#[cfg(not(target_os = "unknown"))] +use async_std::task::spawn; +#[cfg(target_os = "unknown")] +use async_std::task::spawn_local as spawn; + +#[cfg(target_arch = "wasm32")] +wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); + #[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn drop_local() { static DROP_LOCAL: AtomicBool = AtomicBool::new(false); @@ -20,7 +29,7 @@ fn drop_local() { } // Spawn a task that just touches its task-local. - let handle = task::spawn(async { + let handle = spawn(async { LOCAL.with(|_| ()); }); let task = handle.task().clone(); diff --git a/tests/tcp.rs b/tests/tcp.rs index d92cff0d..f21737e8 100644 --- a/tests/tcp.rs +++ b/tests/tcp.rs @@ -1,3 +1,5 @@ +#![cfg(not(target_os = "unknown"))] + use async_std::io; use async_std::net::{TcpListener, TcpStream}; use async_std::prelude::*; diff --git a/tests/timeout.rs b/tests/timeout.rs index c9694f83..8ad358a4 100644 --- a/tests/timeout.rs +++ b/tests/timeout.rs @@ -3,7 +3,11 @@ use std::time::Duration; use async_std::future::timeout; use async_std::task; +#[cfg(target_arch = "wasm32")] +wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); + #[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn timeout_future_many() { task::block_on(async { let futures = (0..100) diff --git a/tests/udp.rs b/tests/udp.rs index 319dc74a..15404f87 100644 --- a/tests/udp.rs +++ b/tests/udp.rs @@ -1,3 +1,5 @@ +#![cfg(not(target_os = "unknown"))] + use async_std::io; use async_std::net::UdpSocket; use async_std::task; diff --git a/tests/uds.rs b/tests/uds.rs index 3ab4d6ba..038ac0ee 100644 --- a/tests/uds.rs +++ b/tests/uds.rs @@ -1,4 +1,4 @@ -#![cfg(unix)] +#![cfg(all(unix, not(target_os = "unknown")))] use async_std::io; use async_std::os::unix::net::{UnixDatagram, UnixListener, UnixStream}; diff --git a/tests/verbose_errors.rs b/tests/verbose_errors.rs index 17d42611..2876183e 100644 --- a/tests/verbose_errors.rs +++ b/tests/verbose_errors.rs @@ -1,3 +1,5 @@ +#![cfg(not(target_os = "unknown"))] + use async_std::{fs, io, net::ToSocketAddrs, task}; #[test] diff --git a/wasm-test.sh b/wasm-test.sh new file mode 100755 index 00000000..3d8be9fd --- /dev/null +++ b/wasm-test.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +wasm-pack test --chrome --headless -- --features unstable --test buf_writer +wasm-pack test --chrome --headless -- --features unstable --test channel +wasm-pack test --chrome --headless -- --features unstable --test condvar +wasm-pack test --chrome --headless -- --features unstable --test mutex +wasm-pack test --chrome --headless -- --features unstable --test rwlock +wasm-pack test --chrome --headless -- --features unstable --test stream +wasm-pack test --chrome --headless -- --features unstable --test task_local +wasm-pack test --chrome --headless -- --features unstable --test timeout