feat: add basic wasm support

pull/757/head
dignifiedquire 4 years ago
parent 2cd2ba3530
commit e4df1405c1

@ -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

@ -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"

@ -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)]

@ -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.
///

@ -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;
}

@ -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(())
})
});
}
}

@ -218,7 +218,7 @@ impl<T: BufRead> BufRead for Take<T> {
}
}
#[cfg(test)]
#[cfg(all(test, not(target_os = "unknown")))]
mod tests {
use crate::io;
use crate::prelude::*;

@ -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.
///

@ -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;

@ -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;

@ -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> {
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::Metadata> {
fs::symlink_metadata(self).await
}
@ -632,6 +634,7 @@ impl Path {
/// #
/// # Ok(()) }) }
/// ```
#[cfg(not(target_os = "unknown"))]
pub async fn canonicalize(&self) -> io::Result<PathBuf> {
fs::canonicalize(self).await
}
@ -654,6 +657,7 @@ impl Path {
/// #
/// # Ok(()) }) }
/// ```
#[cfg(not(target_os = "unknown"))]
pub async fn read_link(&self) -> io::Result<PathBuf> {
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::ReadDir> {
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

@ -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.
///

@ -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)]

@ -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`.

@ -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

@ -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;

@ -25,9 +25,20 @@ use crate::task::Builder;
/// })
/// }
/// ```
#[cfg(not(target_os = "unknown"))]
pub fn block_on<F, T>(future: F) -> T
where
F: Future<Output = T>,
{
Builder::new().blocking(future)
}
/// Spawns a task and waits for it to finish.
#[cfg(target_os = "unknown")]
pub fn block_on<F, T>(future: F)
where
F: Future<Output = T> + 'static,
T: 'static,
{
Builder::new().local(future).unwrap();
}

@ -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<F, T>(self, future: F) -> io::Result<JoinHandle<T>>
where
F: Future<Output = T> + Send + 'static,
@ -61,6 +61,7 @@ impl Builder {
}
/// Spawns a task locally with the configured settings.
#[cfg(not(target_os = "unknown"))]
pub fn local<F, T>(self, future: F) -> io::Result<JoinHandle<T>>
where
F: Future<Output = T> + '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<F, T>(self, future: F) -> io::Result<JoinHandle<T>>
where
F: Future<Output = T> + '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<F, T>(self, future: F) -> T
where
F: Future<Output = T>,
@ -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),
});

@ -13,13 +13,18 @@ use crate::task::{Context, Poll, Task};
/// [spawned]: fn.spawn.html
#[derive(Debug)]
pub struct JoinHandle<T> {
handle: Option<async_task::JoinHandle<T, ()>>,
handle: Option<InnerHandle<T>>,
task: Task,
}
#[cfg(not(target_os = "unknown"))]
type InnerHandle<T> = async_task::JoinHandle<T, ()>;
#[cfg(target_arch = "wasm32")]
type InnerHandle<T> = futures_channel::oneshot::Receiver<T>;
impl<T> JoinHandle<T> {
/// Creates a new `JoinHandle`.
pub(crate) fn new(inner: async_task::JoinHandle<T, ()>, task: Task) -> JoinHandle<T> {
pub(crate) fn new(inner: InnerHandle<T>, task: Task) -> JoinHandle<T> {
JoinHandle {
handle: Some(inner),
task,
@ -46,11 +51,20 @@ impl<T> JoinHandle<T> {
}
/// Cancel this task.
#[cfg(not(target_os = "unknown"))]
pub async fn cancel(mut self) -> Option<T> {
let handle = self.handle.take().unwrap();
handle.cancel();
handle.await
}
/// Cancel this task.
#[cfg(target_arch = "wasm32")]
pub async fn cancel(mut self) -> Option<T> {
let mut handle = self.handle.take().unwrap();
handle.close();
handle.await.ok()
}
}
impl<T> Future for JoinHandle<T> {

@ -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;
}

@ -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<Self::Output> {
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)]

@ -1,3 +1,5 @@
#![cfg(not(target_os = "unknown"))]
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
use async_std::net::ToSocketAddrs;

@ -1,3 +1,5 @@
#![cfg(not(target_os = "unknown"))]
use async_std::task;
#[test]

@ -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<u8> = Vec::new();
let mut writer = BufWriter::<Vec<u8>>::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::<u8>::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()));

@ -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::<DropCounter>(50);
let child = task::spawn({
let child = spawn({
let r = r.clone();
async move {
for _ in 0..steps {

@ -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<JoinHandle<()>> = 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 {

@ -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 {

@ -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();
}

@ -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<AtomicUsize>);
@ -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<bool>);
@ -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;

@ -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::<i32>(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::<i32>(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: Stream>(s: S) -> Explode<S> {
}
#[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]);
}

@ -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();

@ -1,3 +1,5 @@
#![cfg(not(target_os = "unknown"))]
use async_std::io;
use async_std::net::{TcpListener, TcpStream};
use async_std::prelude::*;

@ -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)

@ -1,3 +1,5 @@
#![cfg(not(target_os = "unknown"))]
use async_std::io;
use async_std::net::UdpSocket;
use async_std::task;

@ -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};

@ -1,3 +1,5 @@
#![cfg(not(target_os = "unknown"))]
use async_std::{fs, io, net::ToSocketAddrs, task};
#[test]

@ -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
Loading…
Cancel
Save