Latest Threat Research:SANDWORM_MODE: Shai-Hulud-Style npm Worm Hijacks CI Workflows and Poisons AI Toolchains.Details
Socket
Book a DemoInstallSign in
Socket

wit-bindgen

Package Overview
Dependencies
Maintainers
0
Versions
61
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

wit-bindgen - npm Package Compare versions

Comparing version
0.46.0
to
0.47.0
+30
src/rt/async_support/spawn_disabled.rs
use crate::rt::async_support::BoxFuture;
use std::task::{Context, Poll};
#[derive(Default)]
pub struct Tasks<'a> {
future: Option<BoxFuture<'a>>,
}
impl<'a> Tasks<'a> {
pub fn new(root: BoxFuture<'a>) -> Tasks<'a> {
Tasks { future: Some(root) }
}
pub fn poll_next(&mut self, cx: &mut Context<'_>) -> Poll<Option<()>> {
if let Some(future) = self.future.as_mut() {
if future.as_mut().poll(cx).is_ready() {
self.future = None;
}
}
if self.is_empty() {
Poll::Ready(None)
} else {
Poll::Pending
}
}
pub fn is_empty(&self) -> bool {
self.future.is_none()
}
}
// TODO: Switch to interior mutability (e.g. use Mutexes or thread-local
// RefCells) and remove this, since even in single-threaded mode `static mut`
// references can be a hazard due to recursive access.
#![allow(static_mut_refs)]
use crate::rt::async_support::BoxFuture;
use futures::stream::{FuturesUnordered, StreamExt};
use std::boxed::Box;
use std::future::Future;
use std::task::{Context, Poll};
use std::vec::Vec;
/// Any newly-deferred work queued by calls to the `spawn` function while
/// polling the current task.
static mut SPAWNED: Vec<BoxFuture> = Vec::new();
#[derive(Default)]
pub struct Tasks<'a> {
tasks: FuturesUnordered<BoxFuture<'a>>,
}
impl<'a> Tasks<'a> {
pub fn new(root: BoxFuture<'a>) -> Tasks<'a> {
Tasks {
tasks: [root].into_iter().collect(),
}
}
pub fn poll_next(&mut self, cx: &mut Context<'_>) -> Poll<Option<()>> {
unsafe {
let ret = self.tasks.poll_next_unpin(cx);
if !SPAWNED.is_empty() {
self.tasks.extend(SPAWNED.drain(..));
}
ret
}
}
pub fn is_empty(&self) -> bool {
self.tasks.is_empty()
}
}
/// Spawn the provided `future` to get executed concurrently with the
/// currently-running async computation.
///
/// This API is somewhat similar to `tokio::task::spawn` for example but has a
/// number of limitations to be aware of. If possible it's recommended to avoid
/// this, but it can be convenient if these limitations do not apply to you:
///
/// * Spawned tasks do not work when the version of the `wit-bindgen` crate
/// managing the export bindings is different from the version of this crate.
/// To work correctly the `spawn` function and export executor must be at
/// exactly the same version. Given the major-version-breaking nature of
/// `wit-bindgen` this is not always easy to rely on. This is tracked in
/// [#1305].
///
/// * Spawned tasks do not outlive the scope of the async computation they are
/// spawned within. For example with an async export function spawned tasks
/// will be polled within the context of that component-model async task. For
/// computations executing within a [`block_on`] call, however, the spawned
/// tasks will be executed within that scope. This notably means that for
/// [`block_on`] spawned tasks will prevent the [`block_on`] function from
/// returning, even if a value is available to return.
///
/// * There is no handle returned to the spawned task meaning that it cannot be
/// cancelled or monitored.
///
/// * The task spawned here is executed *concurrently*, not in *parallel*. This
/// means that while one future is being polled no other future can be polled
/// at the same time. This is similar to a single-thread executor in Tokio.
///
/// With these restrictions in mind this can be used to express
/// execution-after-returning in the component model. For example once an
/// exported async function has produced a value this can be used to continue to
/// execute some more code before the component model async task exits.
///
/// [`block_on`]: crate::block_on
/// [#1305]: https://github.com/bytecodealliance/wit-bindgen/issues/1305
pub fn spawn(future: impl Future<Output = ()> + 'static) {
unsafe { SPAWNED.push(Box::pin(future)) }
}
+1
-1
{
"git": {
"sha1": "4c0e9a4edb73efb7b41758562eb0055c0e99cf92"
"sha1": "65ee50585900d9de30d48e99d03ff3e3f97ae186"
},
"path_in_vcs": "crates/guest-rust"
}

@@ -7,11 +7,11 @@ # This file is automatically @generated by Cargo.

name = "anyhow"
version = "1.0.98"
version = "1.0.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
[[package]]
name = "bitflags"
version = "2.9.1"
version = "2.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394"

@@ -121,5 +121,5 @@ [[package]]

name = "hashbrown"
version = "0.15.4"
version = "0.15.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5"
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
dependencies = [

@@ -130,2 +130,8 @@ "foldhash",

[[package]]
name = "hashbrown"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d"
[[package]]
name = "heck"

@@ -144,9 +150,10 @@ version = "0.5.0"

name = "indexmap"
version = "2.9.0"
version = "2.11.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5"
dependencies = [
"equivalent",
"hashbrown",
"hashbrown 0.16.0",
"serde",
"serde_core",
]

@@ -168,19 +175,13 @@

name = "log"
version = "0.4.27"
version = "0.4.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
[[package]]
name = "memchr"
version = "2.7.5"
version = "2.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
[[package]]
name = "once_cell"
version = "1.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
[[package]]
name = "pin-project-lite"

@@ -199,5 +200,5 @@ version = "0.2.16"

name = "prettyplease"
version = "0.2.35"
version = "0.2.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "061c1221631e079b26479d25bbf2275bfe5917ae8419cd7e34f13bfc2aa7539a"
checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
dependencies = [

@@ -210,5 +211,5 @@ "proc-macro2",

name = "proc-macro2"
version = "1.0.95"
version = "1.0.101"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de"
dependencies = [

@@ -220,5 +221,5 @@ "unicode-ident",

name = "quote"
version = "1.0.40"
version = "1.0.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1"
dependencies = [

@@ -248,12 +249,21 @@ "proc-macro2",

name = "semver"
version = "1.0.26"
version = "1.0.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0"
checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2"
[[package]]
name = "serde"
version = "1.0.219"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
dependencies = [
"serde_core",
]
[[package]]
name = "serde_core"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
dependencies = [
"serde_derive",

@@ -264,5 +274,5 @@ ]

name = "serde_derive"
version = "1.0.219"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
dependencies = [

@@ -276,5 +286,5 @@ "proc-macro2",

name = "serde_json"
version = "1.0.140"
version = "1.0.145"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c"
dependencies = [

@@ -285,2 +295,3 @@ "itoa",

"serde",
"serde_core",
]

@@ -290,11 +301,11 @@

name = "slab"
version = "0.4.10"
version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d"
checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589"
[[package]]
name = "syn"
version = "2.0.104"
version = "2.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6"
dependencies = [

@@ -308,5 +319,5 @@ "proc-macro2",

name = "unicode-ident"
version = "1.0.18"
version = "1.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d"

@@ -321,5 +332,5 @@ [[package]]

name = "wasm-encoder"
version = "0.239.0"
version = "0.240.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5be00faa2b4950c76fe618c409d2c3ea5a3c9422013e079482d78544bb2d184c"
checksum = "06d642d8c5ecc083aafe9ceb32809276a304547a3a6eeecceb5d8152598bc71f"
dependencies = [

@@ -332,5 +343,5 @@ "leb128fmt",

name = "wasm-metadata"
version = "0.239.0"
version = "0.240.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20b3ec880a9ac69ccd92fbdbcf46ee833071cf09f82bb005b2327c7ae6025ae2"
checksum = "ee093e1e1ccffa005b9b778f7a10ccfd58e25a20eccad294a1a93168d076befb"
dependencies = [

@@ -345,8 +356,8 @@ "anyhow",

name = "wasmparser"
version = "0.239.0"
version = "0.240.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c9d90bb93e764f6beabf1d02028c70a2156a6583e63ac4218dd07ef733368b0"
checksum = "b722dcf61e0ea47440b53ff83ccb5df8efec57a69d150e4f24882e4eba7e24a4"
dependencies = [
"bitflags",
"hashbrown",
"hashbrown 0.15.5",
"indexmap",

@@ -358,7 +369,6 @@ "semver",

name = "wit-bindgen"
version = "0.46.0"
version = "0.47.0"
dependencies = [
"bitflags",
"futures",
"once_cell",
"rustc-std-workspace-alloc",

@@ -371,5 +381,5 @@ "rustc-std-workspace-core",

name = "wit-bindgen-core"
version = "0.46.0"
version = "0.47.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cabd629f94da277abc739c71353397046401518efb2c707669f805205f0b9890"
checksum = "cdf62e62178415a705bda25dc01c54ed65c0f956e4efd00ca89447a9a84f4881"
dependencies = [

@@ -383,5 +393,5 @@ "anyhow",

name = "wit-bindgen-rust"
version = "0.46.0"
version = "0.47.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a4232e841089fa5f3c4fc732a92e1c74e1a3958db3b12f1de5934da2027f1f4"
checksum = "c6d585319871ca18805056f69ddec7541770fc855820f9944029cb2b75ea108f"
dependencies = [

@@ -400,5 +410,5 @@ "anyhow",

name = "wit-bindgen-rust-macro"
version = "0.46.0"
version = "0.47.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e0d4698c2913d8d9c2b220d116409c3f51a7aa8d7765151b886918367179ee9"
checksum = "bde589435d322e88b8f708f70e313f60dfb7975ac4e7c623fef6f1e5685d90e8"
dependencies = [

@@ -416,5 +426,5 @@ "anyhow",

name = "wit-component"
version = "0.239.0"
version = "0.240.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88a866b19dba2c94d706ec58c92a4c62ab63e482b4c935d2a085ac94caecb136"
checksum = "7dc5474b078addc5fe8a72736de8da3acfb3ff324c2491133f8b59594afa1a20"
dependencies = [

@@ -436,5 +446,5 @@ "anyhow",

name = "wit-parser"
version = "0.239.0"
version = "0.240.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55c92c939d667b7bf0c6bf2d1f67196529758f99a2a45a3355cc56964fd5315d"
checksum = "9875ea3fa272f57cc1fc50f225a7b94021a7878c484b33792bccad0d93223439"
dependencies = [

@@ -441,0 +451,0 @@ "anyhow",

@@ -16,3 +16,3 @@ # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO

name = "wit-bindgen"
version = "0.46.0"
version = "0.47.0"
authors = ["Alex Crichton <alex@alexcrichton.com>"]

@@ -41,6 +41,8 @@ build = "build.rs"

"std",
"dep:futures",
"dep:once_cell",
"wit-bindgen-rust-macro/async",
]
async-spawn = [
"async",
"dep:futures",
]
bitflags = ["dep:bitflags"]

@@ -84,8 +86,4 @@ default = [

[dependencies.once_cell]
version = "1.19.0"
optional = true
[dependencies.wit-bindgen-rust-macro]
version = "0.46.0"
version = "0.47.0"
optional = true

@@ -12,2 +12,3 @@ //! Bindings generation support for Rust with the Component Model.

#![no_std]
#![cfg_attr(docsrs, feature(doc_cfg))]

@@ -877,7 +878,11 @@ #[cfg(not(feature = "rustc-dep-of-std"))]

#[cfg(feature = "async")]
#[allow(deprecated)]
pub use rt::async_support::backpressure_set;
#[cfg(feature = "async-spawn")]
pub use rt::async_support::spawn;
#[cfg(feature = "async")]
pub use rt::async_support::{
backpressure_dec, backpressure_inc, backpressure_set, block_on, spawn, yield_async,
yield_blocking, AbiBuffer, FutureRead, FutureReader, FutureWrite, FutureWriteCancel,
FutureWriteError, FutureWriter, StreamRead, StreamReader, StreamResult, StreamWrite,
StreamWriter,
backpressure_dec, backpressure_inc, block_on, yield_async, yield_blocking, AbiBuffer,
FutureRead, FutureReader, FutureWrite, FutureWriteCancel, FutureWriteError, FutureWriter,
StreamRead, StreamReader, StreamResult, StreamWrite, StreamWriter,
};
#![deny(missing_docs)]
// TODO: Switch to interior mutability (e.g. use Mutexes or thread-local
// RefCells) and remove this, since even in single-threaded mode `static mut`
// references can be a hazard due to recursive access.
#![allow(static_mut_refs)]

@@ -18,8 +14,3 @@ extern crate std;

use std::task::{Context, Poll, Wake, Waker};
use std::vec::Vec;
use futures::channel::oneshot;
use futures::future::FutureExt;
use futures::stream::{FuturesUnordered, StreamExt};
macro_rules! rtdebug {

@@ -54,9 +45,16 @@ ($($f:tt)*) => {

pub use futures;
type BoxFuture<'a> = Pin<Box<dyn Future<Output = ()> + 'a>>;
type BoxFuture = Pin<Box<dyn Future<Output = ()> + 'static>>;
#[cfg(feature = "async-spawn")]
mod spawn;
#[cfg(feature = "async-spawn")]
pub use spawn::spawn;
#[cfg(not(feature = "async-spawn"))]
mod spawn_disabled;
#[cfg(not(feature = "async-spawn"))]
use spawn_disabled as spawn;
/// Represents a task created by either a call to an async-lifted export or a
/// future run using `block_on` or `start_task`.
struct FutureState {
struct FutureState<'a> {
/// Remaining work to do (if any) before this task can be considered "done".

@@ -66,3 +64,3 @@ ///

/// and `waitables` is empty.
tasks: FuturesUnordered<BoxFuture>,
tasks: spawn::Tasks<'a>,

@@ -94,4 +92,4 @@ /// The waitable set containing waitables created by this task, if any.

impl FutureState {
fn new(future: BoxFuture) -> FutureState {
impl FutureState<'_> {
fn new(future: BoxFuture<'_>) -> FutureState<'_> {
let waker = Arc::new(FutureWaker::default());

@@ -101,3 +99,3 @@ FutureState {

waker,
tasks: [future].into_iter().collect(),
tasks: spawn::Tasks::new(future),
waitable_set: None,

@@ -184,10 +182,4 @@ waitables: BTreeMap::new(),

// Poll our future, handling `SPAWNED` around this.
let poll;
unsafe {
poll = me.tasks.poll_next_unpin(&mut context);
if !SPAWNED.is_empty() {
me.tasks.extend(SPAWNED.drain(..));
}
}
// Poll our future, seeing if it was able to make progress.
let poll = me.tasks.poll_next(&mut context);

@@ -199,13 +191,20 @@ match poll {

// The `FuturesUnordered` list is empty meaning that there's no
// more work left to do, so we're done.
// The task list is empty, but there might be remaining work
// in terms of waitables through the cabi interface. In this
// situation wait for all waitables to be resolved before
// signaling that our own task is done.
Poll::Ready(None) => {
assert!(!me.remaining_work());
assert!(me.tasks.is_empty());
break (CALLBACK_CODE_EXIT, true);
if me.remaining_work() {
let waitable = me.waitable_set.as_ref().unwrap().as_raw();
break (CALLBACK_CODE_WAIT | (waitable << 4), false);
} else {
break (CALLBACK_CODE_EXIT, true);
}
}
// Some future within `FuturesUnordered` is not ready yet. If
// our `waker` was signaled then that means this is a yield
// operation, otherwise it means we're blocking on something.
// Some future within `self.tasks` is not ready yet. If our
// `waker` was signaled then that means this is a yield
// operation, otherwise it means we're blocking on
// something.
Poll::Pending => {

@@ -239,3 +238,3 @@ assert!(!me.tasks.is_empty());

}
let self_raw = self as *mut FutureState;
let self_raw = self as *mut FutureState<'_>;
self.wasip3_task.ptr = self_raw.cast();

@@ -249,3 +248,3 @@ let prev = unsafe { cabi::wasip3_task_set(&mut self.wasip3_task) };

impl Drop for FutureState {
impl Drop for FutureState<'_> {
fn drop(&mut self) {

@@ -271,3 +270,3 @@ // If this state has active tasks then they need to be dropped which may

) -> *mut c_void {
let ptr = ptr.cast::<FutureState>();
let ptr = ptr.cast::<FutureState<'static>>();
assert!(!ptr.is_null());

@@ -282,3 +281,3 @@ (*ptr).add_waitable(waitable);

unsafe extern "C" fn waitable_unregister(ptr: *mut c_void, waitable: u32) -> *mut c_void {
let ptr = ptr.cast::<FutureState>();
let ptr = ptr.cast::<FutureState<'static>>();
assert!(!ptr.is_null());

@@ -305,6 +304,2 @@ (*ptr).remove_waitable(waitable);

/// Any newly-deferred work queued by calls to the `spawn` function while
/// polling the current task.
static mut SPAWNED: Vec<BoxFuture> = Vec::new();
const EVENT_NONE: u32 = 0;

@@ -401,3 +396,3 @@ const EVENT_SUBTASK: u32 = 1;

// usage.
let state = context_get().cast::<FutureState>();
let state = context_get().cast::<FutureState<'static>>();
assert!(!state.is_null());

@@ -424,11 +419,2 @@ unsafe {

/// Defer the specified future to be run after the current async-lifted export
/// task has returned a value.
///
/// The task will remain in a running state until all spawned futures have
/// completed.
pub fn spawn(future: impl Future<Output = ()> + 'static) {
unsafe { SPAWNED.push(Box::pin(future)) }
}
/// Run the specified future to completion, returning the result.

@@ -439,9 +425,14 @@ ///

// TODO: refactor so `'static` bounds aren't necessary
pub fn block_on<T: 'static>(future: impl Future<Output = T> + 'static) -> T {
let (tx, mut rx) = oneshot::channel();
let state = &mut FutureState::new(Box::pin(future.map(move |v| drop(tx.send(v)))) as BoxFuture);
pub fn block_on<T: 'static>(future: impl Future<Output = T>) -> T {
let mut result = None;
let mut state = FutureState::new(Box::pin(async {
result = Some(future.await);
}));
let mut event = (EVENT_NONE, 0, 0);
loop {
match state.callback(event.0, event.1, event.2) {
(_, true) => break rx.try_recv().unwrap().unwrap(),
(_, true) => {
drop(state);
break result.unwrap();
}
(CALLBACK_CODE_YIELD, false) => event = state.waitable_set.as_ref().unwrap().poll(),

@@ -448,0 +439,0 @@ _ => event = state.waitable_set.as_ref().unwrap().wait(),

@@ -114,17 +114,14 @@ //! Runtime support for `future<T>` in the component model.

use {
crate::rt::async_support::waitable::{WaitableOp, WaitableOperation},
crate::rt::async_support::ReturnCode,
crate::rt::Cleanup,
std::{
alloc::Layout,
fmt,
future::{Future, IntoFuture},
marker,
pin::Pin,
ptr,
sync::atomic::{AtomicU32, Ordering::Relaxed},
task::{Context, Poll},
},
};
use crate::rt::async_support::waitable::{WaitableOp, WaitableOperation};
use crate::rt::async_support::ReturnCode;
use crate::rt::Cleanup;
use std::alloc::Layout;
use std::fmt;
use std::future::{Future, IntoFuture};
use std::marker;
use std::pin::Pin;
use std::ptr;
use std::sync::atomic::{AtomicU32, Ordering::Relaxed};
use std::sync::{Arc, Mutex};
use std::task::{Context, Poll, Wake, Waker};

@@ -273,3 +270,3 @@ /// Function table used for [`FutureWriter`] and [`FutureReader`]

FutureWrite {
op: WaitableOperation::new((self, value)),
op: WaitableOperation::new(FutureWriteOp(marker::PhantomData), (self, value)),
}

@@ -290,8 +287,7 @@ }

// If a value has not yet been written into this writer than that must
// be done so now. Perform a "clone" of `self` by moving our data into a
// subtask, but ensure that `should_write_default_value` is set to
// `false` to avoid infinite loops by accident. Once the task is spawned
// we're done and the subtask's destructor of the closed-over
// `FutureWriter` will be responsible for performing the
// `drop-writable` call below.
// be done so now. Perform a "clone" of `self` ensuring that
// `should_write_default_value` is set to `false` to avoid infinite
// loops by accident. The cloned `FutureWriter` will be responsible for
// performing the `drop-writable` call below once the write has
// completed.
//

@@ -308,6 +304,5 @@ // Note, though, that if `should_write_default_value` is `false` then a

};
crate::rt::async_support::spawn(async move {
let value = (clone.default)();
let _ = clone.write(value).await;
});
let value = (clone.default)();
let write = clone.write(value);
Arc::new(DeferredWrite::new(write)).wake();
} else {

@@ -322,2 +317,63 @@ unsafe {

/// Helper structure which behaves both as a future of sorts and an executor of
/// sorts.
///
/// This type is constructed in `Drop for FutureWriter<T>` to send out a
/// default value when no other has been written. This manages the
/// `FutureWrite` operation happening internally through a `Wake`
/// implementation. That means that this is a sort of cyclical future which,
/// when woken, will complete the write operation.
///
/// The purpose of this is to be a "lightweight" way of "spawn"-ing a future
/// write to happen in the background. Crucially, however, this doesn't require
/// the `async-spawn` feature and instead works with the `wasip3_task` C ABI
/// structures (which spawn doesn't support).
struct DeferredWrite<T: 'static> {
write: Mutex<FutureWrite<T>>,
}
// TODO
unsafe impl<T> Send for DeferredWrite<T> {}
unsafe impl<T> Sync for DeferredWrite<T> {}
impl<T> DeferredWrite<T> {
fn new(write: FutureWrite<T>) -> DeferredWrite<T> {
DeferredWrite {
write: Mutex::new(write),
}
}
}
impl<T> Wake for DeferredWrite<T> {
fn wake(self: Arc<Self>) {
// When a `wake` signal comes in that should happen in two locations:
//
// 1. When `DeferredWrite` is initially constructed.
// 2. When an event comes in indicating that the internal write has
// completed.
//
// The implementation here is the same in both cases. A clone of `self`
// is converted to a `Waker`, and this `Waker` notably owns the
// internal future itself. The internal write operation is then pushed
// forward (e.g. it's issued in (1) or checked up on in (2)).
//
// If `Pending` is returned then `waker` should have been stored away
// within the `wasip3_task` C ABI structure. Otherwise it should not
// have been stored away and `self` should be the sole reference which
// means everything will get cleaned up when this function returns.
let poll = {
let waker = Waker::from(self.clone());
let mut cx = Context::from_waker(&waker);
let mut write = self.write.lock().unwrap();
unsafe { Pin::new_unchecked(&mut *write).poll(&mut cx) }
};
if poll.is_ready() {
assert_eq!(Arc::strong_count(&self), 1);
} else {
assert!(Arc::strong_count(&self) > 1);
}
assert_eq!(Arc::weak_count(&self), 0);
}
}
/// Represents a write operation which may be cancelled prior to completion.

@@ -347,3 +403,3 @@ ///

fn start((writer, value): Self::Start) -> (u32, Self::InProgress) {
fn start(&self, (writer, value): Self::Start) -> (u32, Self::InProgress) {
// TODO: it should be safe to store the lower-destination in

@@ -370,3 +426,3 @@ // `WaitableOperation` using `Pin` memory and such, but that would

fn start_cancelled((writer, value): Self::Start) -> Self::Cancel {
fn start_cancelled(&self, (writer, value): Self::Start) -> Self::Cancel {
FutureWriteCancel::Cancelled(value, writer)

@@ -376,2 +432,3 @@ }

fn in_progress_update(
&self,
(mut writer, cleanup): Self::InProgress,

@@ -436,7 +493,7 @@ code: u32,

fn in_progress_waitable((writer, _): &Self::InProgress) -> u32 {
fn in_progress_waitable(&self, (writer, _): &Self::InProgress) -> u32 {
writer.handle
}
fn in_progress_cancel((writer, _): &Self::InProgress) -> u32 {
fn in_progress_cancel(&self, (writer, _): &Self::InProgress) -> u32 {
// SAFETY: we're managing `writer` and all the various operational bits,

@@ -449,3 +506,3 @@ // so this relies on `WaitableOperation` being safe.

fn result_into_cancel((result, writer): Self::Result) -> Self::Cancel {
fn result_into_cancel(&self, (result, writer): Self::Result) -> Self::Cancel {
match result {

@@ -594,3 +651,3 @@ // The value was actually sent, meaning we can't yield back the

FutureRead {
op: WaitableOperation::new(self),
op: WaitableOperation::new(FutureReadOp(marker::PhantomData), self),
}

@@ -636,3 +693,3 @@ }

fn start(reader: Self::Start) -> (u32, Self::InProgress) {
fn start(&self, reader: Self::Start) -> (u32, Self::InProgress) {
let (ptr, cleanup) = Cleanup::new(reader.vtable.layout);

@@ -647,3 +704,3 @@ // SAFETY: `ptr` is allocated with `vtable.layout` and should be

fn start_cancelled(state: Self::Start) -> Self::Cancel {
fn start_cancelled(&self, state: Self::Start) -> Self::Cancel {
Err(state)

@@ -653,2 +710,3 @@ }

fn in_progress_update(
&self,
(reader, cleanup): Self::InProgress,

@@ -684,7 +742,7 @@ code: u32,

fn in_progress_waitable((reader, _): &Self::InProgress) -> u32 {
fn in_progress_waitable(&self, (reader, _): &Self::InProgress) -> u32 {
reader.handle()
}
fn in_progress_cancel((reader, _): &Self::InProgress) -> u32 {
fn in_progress_cancel(&self, (reader, _): &Self::InProgress) -> u32 {
// SAFETY: we're managing `reader` and all the various operational bits,

@@ -697,3 +755,3 @@ // so this relies on `WaitableOperation` being safe.

fn result_into_cancel((value, reader): Self::Result) -> Self::Cancel {
fn result_into_cancel(&self, (value, reader): Self::Result) -> Self::Cancel {
match value {

@@ -700,0 +758,0 @@ // The value was actually read, so thread that through here.

@@ -146,3 +146,3 @@ //! For a high-level overview of how this module is implemented see the

StreamWrite {
op: WaitableOperation::new((self, values)),
op: WaitableOperation::new(StreamWriteOp(marker::PhantomData), (self, values)),
}

@@ -247,3 +247,3 @@ }

fn start((writer, buf): Self::Start) -> (u32, Self::InProgress) {
fn start(&self, (writer, buf): Self::Start) -> (u32, Self::InProgress) {
if writer.done {

@@ -264,3 +264,3 @@ return (DROPPED, (writer, buf));

fn start_cancelled((_writer, buf): Self::Start) -> Self::Cancel {
fn start_cancelled(&self, (_writer, buf): Self::Start) -> Self::Cancel {
(StreamResult::Cancelled, buf)

@@ -270,2 +270,3 @@ }

fn in_progress_update(
&self,
(writer, mut buf): Self::InProgress,

@@ -291,7 +292,7 @@ code: u32,

fn in_progress_waitable((writer, _): &Self::InProgress) -> u32 {
fn in_progress_waitable(&self, (writer, _): &Self::InProgress) -> u32 {
writer.handle
}
fn in_progress_cancel((writer, _): &Self::InProgress) -> u32 {
fn in_progress_cancel(&self, (writer, _): &Self::InProgress) -> u32 {
// SAFETY: we're managing `writer` and all the various operational bits,

@@ -304,3 +305,3 @@ // so this relies on `WaitableOperation` being safe.

fn result_into_cancel(result: Self::Result) -> Self::Cancel {
fn result_into_cancel(&self, result: Self::Result) -> Self::Cancel {
result

@@ -400,3 +401,3 @@ }

StreamRead {
op: WaitableOperation::new((self, buf)),
op: WaitableOperation::new(StreamReadOp(marker::PhantomData), (self, buf)),
}

@@ -469,3 +470,3 @@ }

fn start((reader, mut buf): Self::Start) -> (u32, Self::InProgress) {
fn start(&self, (reader, mut buf): Self::Start) -> (u32, Self::InProgress) {
if reader.done {

@@ -503,3 +504,3 @@ return (DROPPED, (reader, buf, None));

fn start_cancelled((_, buf): Self::Start) -> Self::Cancel {
fn start_cancelled(&self, (_, buf): Self::Start) -> Self::Cancel {
(StreamResult::Cancelled, buf)

@@ -509,2 +510,3 @@ }

fn in_progress_update(
&self,
(reader, mut buf, cleanup): Self::InProgress,

@@ -566,7 +568,7 @@ code: u32,

fn in_progress_waitable((reader, ..): &Self::InProgress) -> u32 {
fn in_progress_waitable(&self, (reader, ..): &Self::InProgress) -> u32 {
reader.handle()
}
fn in_progress_cancel((reader, ..): &Self::InProgress) -> u32 {
fn in_progress_cancel(&self, (reader, ..): &Self::InProgress) -> u32 {
// SAFETY: we're managing `reader` and all the various operational bits,

@@ -579,3 +581,3 @@ // so this relies on `WaitableOperation` being safe.

fn result_into_cancel(result: Self::Result) -> Self::Cancel {
fn result_into_cancel(&self, result: Self::Result) -> Self::Cancel {
result

@@ -582,0 +584,0 @@ }

@@ -32,10 +32,2 @@ //! Bindings used to manage subtasks, or invocations of imported functions.

pub unsafe trait Subtask {
/// The in-memory layout of both parameters and results allocated with
/// parameters coming first.
const ABI_LAYOUT: Layout;
/// The offset, in bytes, from the start of `ABI_LAYOUT` to where the
/// results will be stored.
const RESULTS_OFFSET: usize;
/// The parameters to this task.

@@ -52,4 +44,12 @@ type Params;

/// The in-memory layout of both parameters and results allocated with
/// parameters coming first.
fn abi_layout(&self) -> Layout;
/// The offset, in bytes, from the start of `ABI_LAYOUT` to where the
/// results will be stored.
fn results_offset(&self) -> usize;
/// The raw function import using `[async-lower]` and the canonical ABI.
unsafe fn call_import(params: Self::ParamsLower, results: *mut u8) -> u32;
unsafe fn call_import(&self, params: Self::ParamsLower, results: *mut u8) -> u32;

@@ -65,18 +65,18 @@ /// Bindings-generated version of lowering `params`.

/// ABI).
unsafe fn params_lower(params: Self::Params, dst: *mut u8) -> Self::ParamsLower;
unsafe fn params_lower(&self, params: Self::Params, dst: *mut u8) -> Self::ParamsLower;
/// Bindings-generated version of deallocating any lists stored within
/// `lower`.
unsafe fn params_dealloc_lists(lower: Self::ParamsLower);
unsafe fn params_dealloc_lists(&self, lower: Self::ParamsLower);
/// Bindings-generated version of deallocating not only owned lists within
/// `lower` but also deallocating any owned resources.
unsafe fn params_dealloc_lists_and_own(lower: Self::ParamsLower);
unsafe fn params_dealloc_lists_and_own(&self, lower: Self::ParamsLower);
/// Bindings-generated version of lifting the results stored at `src`.
unsafe fn results_lift(src: *mut u8) -> Self::Results;
unsafe fn results_lift(&self, src: *mut u8) -> Self::Results;
/// Helper function to actually perform this asynchronous call with
/// `params`.
fn call(params: Self::Params) -> impl Future<Output = Self::Results>
fn call(&self, params: Self::Params) -> impl Future<Output = Self::Results>
where

@@ -86,3 +86,5 @@ Self: Sized,

async {
match WaitableOperation::<SubtaskOps<Self>>::new(Start { params }).await {
match WaitableOperation::<SubtaskOps<Self>>::new(SubtaskOps(self), Start { params })
.await
{
Ok(results) => results,

@@ -98,3 +100,3 @@ Err(_) => unreachable!(

struct SubtaskOps<T>(marker::PhantomData<T>);
struct SubtaskOps<'a, T>(&'a T);

@@ -105,3 +107,3 @@ struct Start<T: Subtask> {

unsafe impl<T: Subtask> WaitableOp for SubtaskOps<T> {
unsafe impl<T: Subtask> WaitableOp for SubtaskOps<'_, T> {
type Start = Start<T>;

@@ -112,8 +114,8 @@ type InProgress = InProgress<T>;

fn start(state: Self::Start) -> (u32, Self::InProgress) {
fn start(&self, state: Self::Start) -> (u32, Self::InProgress) {
unsafe {
let (ptr_params, cleanup) = Cleanup::new(T::ABI_LAYOUT);
let ptr_results = ptr_params.add(T::RESULTS_OFFSET);
let params_lower = T::params_lower(state.params, ptr_params);
let packed = T::call_import(params_lower, ptr_results);
let (ptr_params, cleanup) = Cleanup::new(self.0.abi_layout());
let ptr_results = ptr_params.add(self.0.results_offset());
let params_lower = self.0.params_lower(state.params, ptr_params);
let packed = self.0.call_import(params_lower, ptr_results);
let code = packed & 0xf;

@@ -136,3 +138,3 @@ let subtask = NonZeroU32::new(packed >> 4).map(|handle| SubtaskHandle { handle });

fn start_cancelled(_state: Self::Start) -> Self::Cancel {
fn start_cancelled(&self, _state: Self::Start) -> Self::Cancel {
Err(())

@@ -142,2 +144,3 @@ }

fn in_progress_update(
&self,
mut state: Self::InProgress,

@@ -157,3 +160,3 @@ code: u32,

STATUS_STARTED => {
state.flag_started();
state.flag_started(self.0);
Err(state)

@@ -166,3 +169,3 @@ }

if !state.started {
state.flag_started();
state.flag_started(self.0);
}

@@ -175,3 +178,3 @@

// itself.
unsafe { Ok(Ok(T::results_lift(state.ptr_results()))) }
unsafe { Ok(Ok(self.0.results_lift(state.ptr_results(self.0)))) }
}

@@ -191,3 +194,3 @@

unsafe {
T::params_dealloc_lists_and_own(state.params_lower);
self.0.params_dealloc_lists_and_own(state.params_lower);
}

@@ -213,3 +216,3 @@ Ok(Err(()))

if !state.started {
state.flag_started();
state.flag_started(self.0);
}

@@ -223,3 +226,3 @@ Ok(Err(()))

fn in_progress_waitable(state: &Self::InProgress) -> u32 {
fn in_progress_waitable(&self, state: &Self::InProgress) -> u32 {
// This shouldn't get called in the one case this isn't present: when

@@ -231,7 +234,7 @@ // `STATUS_RETURNED` is returned and no waitable is created. That's the

fn in_progress_cancel(state: &Self::InProgress) -> u32 {
unsafe { cancel(Self::in_progress_waitable(state)) }
fn in_progress_cancel(&self, state: &Self::InProgress) -> u32 {
unsafe { cancel(self.in_progress_waitable(state)) }
}
fn result_into_cancel(result: Self::Result) -> Self::Cancel {
fn result_into_cancel(&self, result: Self::Result) -> Self::Cancel {
result

@@ -263,3 +266,3 @@ }

impl<T: Subtask> InProgress<T> {
fn flag_started(&mut self) {
fn flag_started(&mut self, op: &T) {
assert!(!self.started);

@@ -272,7 +275,7 @@ self.started = true;

unsafe {
T::params_dealloc_lists(self.params_lower);
op.params_dealloc_lists(self.params_lower);
}
}
fn ptr_results(&self) -> *mut u8 {
fn ptr_results(&self, op: &T) -> *mut u8 {
// SAFETY: the `T` trait has unsafely promised us that the offset is

@@ -285,3 +288,3 @@ // in-bounds of the allocation layout.

.unwrap_or(ptr::null_mut())
.add(T::RESULTS_OFFSET)
.add(op.results_offset())
}

@@ -288,0 +291,0 @@ }

@@ -20,2 +20,3 @@ //! Generic support for "any waitable" and performing asynchronous operations on

pub struct WaitableOperation<S: WaitableOp> {
op: S,
state: WaitableOperationState<S>,

@@ -87,3 +88,3 @@ /// Storage for the final result of this asynchronous operation, if it's

/// along with the `InProgress` state.
fn start(state: Self::Start) -> (u32, Self::InProgress);
fn start(&self, state: Self::Start) -> (u32, Self::InProgress);

@@ -99,2 +100,3 @@ /// Optionally complete the async operation.

fn in_progress_update(
&self,
state: Self::InProgress,

@@ -106,7 +108,7 @@ code: u32,

/// operation is cancelled before it's started.
fn start_cancelled(state: Self::Start) -> Self::Cancel;
fn start_cancelled(&self, state: Self::Start) -> Self::Cancel;
/// Acquires the component-model `waitable` index that the `InProgress`
/// state is waiting on.
fn in_progress_waitable(state: &Self::InProgress) -> u32;
fn in_progress_waitable(&self, state: &Self::InProgress) -> u32;

@@ -122,3 +124,3 @@ /// Initiates a request for cancellation of this operation. Returns the

/// component model ABI, for example.
fn in_progress_cancel(state: &Self::InProgress) -> u32;
fn in_progress_cancel(&self, state: &Self::InProgress) -> u32;

@@ -128,3 +130,3 @@ /// Converts a "completion result" into a "cancel result". This is necessary

/// first acquired and then transitioned to a cancel request.
fn result_into_cancel(result: Self::Result) -> Self::Cancel;
fn result_into_cancel(&self, result: Self::Result) -> Self::Cancel;
}

@@ -143,4 +145,5 @@

/// Creates a new operation in the initial state.
pub fn new(state: S::Start) -> WaitableOperation<S> {
pub fn new(op: S, state: S::Start) -> WaitableOperation<S> {
WaitableOperation {
op,
state: WaitableOperationState::Start(state),

@@ -157,3 +160,7 @@ completion_status: CompletionStatus {

self: Pin<&mut Self>,
) -> (&mut WaitableOperationState<S>, Pin<&mut CompletionStatus>) {
) -> (
&S,
&mut WaitableOperationState<S>,
Pin<&mut CompletionStatus>,
) {
// SAFETY: this is the one method used to project from `Pin<&mut Self>`

@@ -166,3 +173,7 @@ // to the fields, and the contract we're deciding on is that

let me = self.get_unchecked_mut();
(&mut me.state, Pin::new_unchecked(&mut me.completion_status))
(
&me.op,
&mut me.state,
Pin::new_unchecked(&mut me.completion_status),
)
}

@@ -176,3 +187,3 @@ }

pub fn register_waker(self: Pin<&mut Self>, waitable: u32, cx: &mut Context) {
let (_, mut completion_status) = self.pin_project();
let (_, _, mut completion_status) = self.pin_project();
debug_assert!(completion_status.as_mut().code_mut().is_none());

@@ -249,3 +260,3 @@ *completion_status.as_mut().waker_mut() = Some(cx.waker().clone());

if !prev.is_null() {
let ptr: *mut CompletionStatus = self.pin_project().1.get_unchecked_mut();
let ptr: *mut CompletionStatus = self.pin_project().2.get_unchecked_mut();
assert_eq!(ptr, prev.cast());

@@ -264,3 +275,3 @@ }

let (state, completion_status) = self.as_mut().pin_project();
let (op, state, completion_status) = self.as_mut().pin_project();

@@ -275,3 +286,3 @@ // First up, determine the completion status, if any, that's available.

};
let (code, s) = S::start(s);
let (code, s) = op.start(s);
*state = InProgress(s);

@@ -310,3 +321,3 @@ Some(code)

let (state, _completion_status) = self.as_mut().pin_project();
let (op, state, _completion_status) = self.as_mut().pin_project();

@@ -324,3 +335,3 @@ // If a status code is provided, then extract the in-progress state and

};
match S::in_progress_update(in_progress, code) {
match op.in_progress_update(in_progress, code) {
Ok(result) => return Poll::Ready(result),

@@ -341,3 +352,3 @@ Err(in_progress) => *state = InProgress(in_progress),

if let Some(cx) = cx {
let handle = S::in_progress_waitable(in_progress);
let handle = op.in_progress_waitable(in_progress);
self.register_waker(handle, cx);

@@ -362,3 +373,3 @@ }

let (state, mut completion_status) = self.as_mut().pin_project();
let (op, state, mut completion_status) = self.as_mut().pin_project();
let in_progress = match state {

@@ -371,3 +382,3 @@ // This operation was never actually started, so there's no need to

};
return S::start_cancelled(s);
return op.start_cancelled(s);
}

@@ -406,3 +417,5 @@

// operation is now inert, and we can immediately return.
Poll::Ready(result) => return S::result_into_cancel(result),
Poll::Ready(result) => {
return self.as_mut().pin_project().0.result_into_cancel(result)
}

@@ -423,3 +436,3 @@ // The operation, despite receiving an update via a code,

None => {
let waitable = S::in_progress_waitable(in_progress);
let waitable = op.in_progress_waitable(in_progress);
self.as_mut().unregister_waker(waitable);

@@ -442,8 +455,8 @@ }

// proceed asynchronously that we could rely on it being invoked.
let (InProgress(in_progress), _) = self.as_mut().pin_project() else {
let (op, InProgress(in_progress), _) = self.as_mut().pin_project() else {
unreachable!()
};
let code = S::in_progress_cancel(in_progress);
match self.poll_complete_with_code(None, Some(code)) {
Poll::Ready(result) => S::result_into_cancel(result),
let code = op.in_progress_cancel(in_progress);
match self.as_mut().poll_complete_with_code(None, Some(code)) {
Poll::Ready(result) => self.as_mut().pin_project().0.result_into_cancel(result),
Poll::Pending => unreachable!(),

@@ -468,3 +481,3 @@ }

let (state, _) = pin.as_mut().pin_project();
let (_, state, _) = pin.as_mut().pin_project();

@@ -471,0 +484,0 @@ // If this operation has already completed then skip cancellation,

@@ -5,7 +5,7 @@ // This file is generated by ./ci/rebuild-libwit-bindgen-cabi.sh

extern void *cabi_realloc_wit_bindgen_0_46_0(void *ptr, size_t old_size, size_t align, size_t new_size);
extern void *cabi_realloc_wit_bindgen_0_47_0(void *ptr, size_t old_size, size_t align, size_t new_size);
__attribute__((__weak__, __export_name__("cabi_realloc")))
void *cabi_realloc(void *ptr, size_t old_size, size_t align, size_t new_size) {
return cabi_realloc_wit_bindgen_0_46_0(ptr, old_size, align, new_size);
return cabi_realloc_wit_bindgen_0_47_0(ptr, old_size, align, new_size);
}
// This file is generated by ./ci/rebuild-libwit-bindgen-cabi.sh
#[unsafe(no_mangle)]
pub unsafe extern "C" fn cabi_realloc_wit_bindgen_0_46_0(
pub unsafe extern "C" fn cabi_realloc_wit_bindgen_0_47_0(
old_ptr: *mut u8,

@@ -6,0 +6,0 @@ old_len: usize,

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet