Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ json = ["dep:serde", "dep:serde_json"]
anyhow.workspace = true
async-task.workspace = true
bytes.workspace = true
cfg-if.workspace = true
futures-lite.workspace = true
http-body-util.workspace = true
http-body.workspace = true
Expand Down Expand Up @@ -71,6 +72,7 @@ anyhow = "1"
async-task = "4.7"
axum = { version = "0.8.6", default-features = false }
bytes = "1.10.1"
cfg-if = "1"
cargo_metadata = "0.22"
clap = { version = "4.5.26", features = ["derive"] }
futures-core = "0.3.19"
Expand Down
3 changes: 3 additions & 0 deletions src/http.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
//! HTTP networking support
//!
pub use crate::sys::http::*;
5 changes: 1 addition & 4 deletions src/io/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,15 @@ mod cursor;
mod empty;
mod read;
mod seek;
mod stdio;
mod streams;
mod write;

pub use crate::runtime::AsyncPollable;
pub use crate::sys::io::*;
pub use copy::*;
pub use cursor::*;
pub use empty::*;
pub use read::*;
pub use seek::*;
pub use stdio::*;
pub use streams::*;
pub use write::*;

/// The error type for I/O operations.
Expand Down
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@
//! These are unique capabilities provided by WASI 0.2, and because this library
//! is specific to that are exposed from here.

#[allow(unreachable_pub)]
mod sys;

pub mod future;
#[macro_use]
pub mod http;
Expand Down
3 changes: 3 additions & 0 deletions src/net.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
//! Async network abstractions.

pub use crate::sys::net::*;
3 changes: 3 additions & 0 deletions src/rand.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
//! Random number generation.

pub use crate::sys::rand::*;
10 changes: 10 additions & 0 deletions src/runtime.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
//! Async event loop support.
//!
//! The way to use this is to call [`block_on()`]. Inside the future, [`Reactor::current`]
//! will give an instance of the [`Reactor`] running the event loop, which can be
//! to [`AsyncPollable::wait_for`] instances of
//! [`wasip2::Pollable`](https://docs.rs/wasi/latest/wasi/io/poll/struct.Pollable.html).
//! This will automatically wait for the futures to resolve, and call the
//! necessary wakers to work.

pub use crate::sys::runtime::*;
40 changes: 40 additions & 0 deletions src/sys/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//! Platform-specific backends.
//!
//! Each supported target provides an implementation under `src/sys/`, selected
//! here by a single `cfg-if`. The crate-root modules (`crate::time`,
//! `crate::io`, ...) are target-agnostic facades, free of `#[cfg]`, written
//! against the `crate::sys::*` items the selected backend provides. There is no
//! shared `trait`: backends are duck-typed in the `std::sys` style, and the
//! `const _` assertions below check the shapes the facades depend on.
//!
//! Backend modules: `time`, `io`, `net`, `http`, `rand`, `runtime`. The reified
//! pollable types (`AsyncPollable`, `WaitFor`) are p2-only and intentionally
//! left out of the common contract; once a second backend lands they become a
//! localized escape hatch rather than facade `#[cfg]`s.

cfg_if::cfg_if! {
if #[cfg(all(target_os = "wasi", target_env = "p2"))] {
mod p2;
use p2 as backend;
} else {
compile_error!("unsupported target: wstd only compiles on `wasm32-wasip2`");
}
}

pub use backend::*;

// Check the selected backend provides the shapes the facades rely on, so drift
// fails here instead of deep inside a facade.
const _: fn() = || {
fn assert_async_read<T: crate::io::AsyncRead>() {}
fn assert_async_write<T: crate::io::AsyncWrite>() {}
fn assert_sleep_future<T: core::future::Future<Output = ()>>() {}

assert_async_read::<crate::sys::io::AsyncInputStream>();
assert_async_write::<crate::sys::io::AsyncOutputStream>();
assert_sleep_future::<crate::sys::time::Sleep>();

let _: fn() -> crate::sys::time::MonotonicInstant = crate::sys::time::now;
let _: fn(crate::sys::time::MonotonicInstant) -> crate::sys::time::Sleep =
crate::sys::time::sleep_until;
};
7 changes: 2 additions & 5 deletions src/http/body.rs → src/sys/p2/http/body.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
use crate::http::{
Error, HeaderMap,
error::Context as _,
fields::{header_map_from_wasi, header_map_to_wasi},
};
use super::fields::{header_map_from_wasi, header_map_to_wasi};
use crate::http::{Error, HeaderMap, error::Context as _};
use crate::io::{AsyncInputStream, AsyncOutputStream};
use crate::runtime::{AsyncPollable, Reactor, WaitFor};

Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
3 changes: 2 additions & 1 deletion src/http/response.rs → src/sys/p2/http/response.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use http::StatusCode;
use wasip2::http::types::IncomingResponse;

use super::fields::header_map_from_wasi;
use crate::http::HeaderMap;
use crate::http::body::{Body, BodyHint};
use crate::http::error::Error;
use crate::http::fields::{HeaderMap, header_map_from_wasi};

pub use http::response::{Builder, Response};

Expand Down
File renamed without changes.
File renamed without changes.
5 changes: 5 additions & 0 deletions src/sys/p2/io/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
mod stdio;
mod streams;

pub use stdio::*;
pub use streams::*;
2 changes: 1 addition & 1 deletion src/io/stdio.rs → src/sys/p2/io/stdio.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::{AsyncInputStream, AsyncOutputStream, AsyncRead, AsyncWrite, Result};
use crate::io::{AsyncInputStream, AsyncOutputStream, AsyncRead, AsyncWrite, Result};
use std::cell::LazyCell;
use wasip2::cli::terminal_input::TerminalInput;
use wasip2::cli::terminal_output::TerminalOutput;
Expand Down
4 changes: 2 additions & 2 deletions src/io/streams.rs → src/sys/p2/io/streams.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::{AsyncPollable, AsyncRead, AsyncWrite};
use crate::runtime::WaitFor;
use crate::io::{AsyncRead, AsyncWrite};
use crate::runtime::{AsyncPollable, WaitFor};
use std::future::{Future, poll_fn};
use std::pin::Pin;
use std::sync::{Mutex, OnceLock};
Expand Down
8 changes: 8 additions & 0 deletions src/sys/p2/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
//! The wasip2 (`wasm32-wasip2`) backend.

pub mod http;
pub mod io;
pub mod net;
pub mod rand;
pub mod runtime;
pub mod time;
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion src/runtime/mod.rs → src/sys/p2/runtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
//! necessary wakers to work.

#![deny(missing_debug_implementations, nonstandard_style)]
#![warn(missing_docs, unreachable_pub)]
#![warn(missing_docs)]

mod block_on;
mod reactor;
Expand Down
File renamed without changes.
78 changes: 78 additions & 0 deletions src/sys/p2/time/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
//! Monotonic and system clocks for the wasip2 backend.
//!
//! This is the platform half of the [`crate::time`] facade. The facade owns the
//! portable `Duration`/`Instant`/`Timer` types and all of their arithmetic;
//! this module provides only the primitives that genuinely depend on the WASI
//! 0.2 clocks. See [`crate::sys`] for the full backend contract.

use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
use wasip2::clocks::{monotonic_clock, wall_clock};

use crate::runtime::{Reactor, WaitFor};

/// A measurement of the monotonic clock, in nanoseconds.
///
/// The facade's `Instant` wraps this. Keeping it a plain integer lets the
/// facade own all time arithmetic without coupling to the backend.
pub type MonotonicInstant = monotonic_clock::Instant;

/// A span of monotonic-clock time, in nanoseconds.
pub type MonotonicDuration = monotonic_clock::Duration;

/// Return the current monotonic-clock instant.
pub fn now() -> MonotonicInstant {
monotonic_clock::now()
}

/// A measurement of the system clock, useful for talking to external entities
/// like the file system or other processes. May be converted losslessly to a
/// more useful `std::time::SystemTime` to provide more methods.
#[derive(Debug, Clone, Copy)]
#[allow(dead_code)]
pub struct SystemTime(wall_clock::Datetime);

impl SystemTime {
pub fn now() -> Self {
Self(wall_clock::now())
}
}

impl From<SystemTime> for std::time::SystemTime {
fn from(st: SystemTime) -> Self {
std::time::SystemTime::UNIX_EPOCH
+ std::time::Duration::from_secs(st.0.seconds)
+ std::time::Duration::from_nanos(st.0.nanoseconds.into())
}
}

/// A future that resolves once the monotonic clock reaches a deadline.
///
/// Created by [`sleep_until`]. This is the backend `Sleep` type named by the
/// facade's `Timer`/`Wait`; on p2 it is a thin wrapper over a reactor-scheduled
/// `monotonic-clock` pollable.
#[must_use = "futures do nothing unless polled or .awaited"]
#[derive(Debug)]
pub struct Sleep {
wait_for: WaitFor,
}

impl Future for Sleep {
type Output = ();

fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
Pin::new(&mut self.wait_for).poll(cx)
}
}

/// Create a [`Sleep`] future that resolves when the monotonic clock reaches
/// `deadline`.
///
/// Must be called from within [`crate::runtime::block_on`].
pub fn sleep_until(deadline: MonotonicInstant) -> Sleep {
let pollable = Reactor::current().schedule(monotonic_clock::subscribe_instant(deadline));
Sleep {
wait_for: pollable.wait_for(),
}
}
Loading
Loading