Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/wasi/src/p3/mod.rs
1692 views
1
//! Experimental, unstable and incomplete implementation of wasip3 version of WASI.
2
//!
3
//! This module is under heavy development.
4
//! It is not compliant with semver and is not ready
5
//! for production use.
6
//!
7
//! Bug and security fixes limited to wasip3 will not be given patch releases.
8
//!
9
//! Documentation of this module may be incorrect or out-of-sync with the implementation.
10
11
pub mod bindings;
12
pub mod cli;
13
pub mod clocks;
14
pub mod filesystem;
15
pub mod random;
16
pub mod sockets;
17
18
use crate::WasiView;
19
use crate::p3::bindings::LinkOptions;
20
use anyhow::Context as _;
21
use core::marker::PhantomData;
22
use core::pin::Pin;
23
use core::task::{Context, Poll};
24
use tokio::sync::oneshot;
25
use wasmtime::StoreContextMut;
26
use wasmtime::component::{
27
Accessor, Destination, FutureProducer, Linker, StreamProducer, StreamResult, VecBuffer,
28
};
29
30
// Default buffer capacity to use for reads of byte-sized values.
31
const DEFAULT_BUFFER_CAPACITY: usize = 8192;
32
33
struct StreamEmptyProducer<T>(PhantomData<fn(T) -> T>);
34
35
impl<T> Default for StreamEmptyProducer<T> {
36
fn default() -> Self {
37
Self(PhantomData)
38
}
39
}
40
41
impl<T: Send + Sync + 'static, D> StreamProducer<D> for StreamEmptyProducer<T> {
42
type Item = T;
43
type Buffer = Option<Self::Item>;
44
45
fn poll_produce<'a>(
46
self: Pin<&mut Self>,
47
_: &mut Context<'_>,
48
_: StoreContextMut<'a, D>,
49
_: Destination<'a, Self::Item, Self::Buffer>,
50
_: bool,
51
) -> Poll<wasmtime::Result<StreamResult>> {
52
Poll::Ready(Ok(StreamResult::Dropped))
53
}
54
}
55
56
struct FutureReadyProducer<T>(T);
57
58
impl<T, D> FutureProducer<D> for FutureReadyProducer<T>
59
where
60
T: Send + 'static,
61
{
62
type Item = T;
63
64
async fn produce(self, _: &Accessor<D>) -> wasmtime::Result<T> {
65
Ok(self.0)
66
}
67
}
68
69
struct FutureOneshotProducer<T>(oneshot::Receiver<T>);
70
71
impl<T, D> FutureProducer<D> for FutureOneshotProducer<T>
72
where
73
T: Send + 'static,
74
{
75
type Item = T;
76
77
async fn produce(self, _: &Accessor<D>) -> wasmtime::Result<T> {
78
self.0.await.context("oneshot sender dropped")
79
}
80
}
81
82
/// Helper structure to convert an iterator of `Result<T, E>` into a `stream<T>`
83
/// plus a `future<result<_, T>>` in WIT.
84
///
85
/// This will drain the iterator on calls to `poll_produce` and place as many
86
/// items as the input buffer has capacity for into the result. This will avoid
87
/// doing anything if the async read is cancelled.
88
///
89
/// Note that this does not actually do anything async, it's assuming that the
90
/// internal `iter` is either fast or intended to block.
91
struct FallibleIteratorProducer<I, E> {
92
iter: I,
93
result: Option<oneshot::Sender<Result<(), E>>>,
94
}
95
96
impl<I, T, E, D> StreamProducer<D> for FallibleIteratorProducer<I, E>
97
where
98
I: Iterator<Item = Result<T, E>> + Send + Unpin + 'static,
99
T: Send + Sync + 'static,
100
E: Send + 'static,
101
{
102
type Item = T;
103
type Buffer = VecBuffer<T>;
104
105
fn poll_produce<'a>(
106
mut self: Pin<&mut Self>,
107
_: &mut Context<'_>,
108
mut store: StoreContextMut<'a, D>,
109
mut dst: Destination<'a, Self::Item, Self::Buffer>,
110
// Explicitly ignore `_finish` because this implementation never
111
// returns `Poll::Pending` anyway meaning that it never "blocks" in the
112
// async sense.
113
_finish: bool,
114
) -> Poll<wasmtime::Result<StreamResult>> {
115
// Take up to `count` items as requested by the guest, or pick some
116
// reasonable-ish number for the host.
117
let count = dst.remaining(&mut store).unwrap_or(32);
118
119
// Handle 0-length reads which test for readiness as saying "we're
120
// always ready" since, in theory, this is.
121
if count == 0 {
122
return Poll::Ready(Ok(StreamResult::Completed));
123
}
124
125
// Drain `self.iter`. Successful results go into `buf`. Any errors make
126
// their way to the `oneshot` result inside this structure. Otherwise
127
// this only gets dropped if `None` is seen or an error. Also this'll
128
// terminate once `buf` grows too large.
129
let mut buf = Vec::new();
130
let result = loop {
131
match self.iter.next() {
132
Some(Ok(item)) => buf.push(item),
133
Some(Err(e)) => {
134
self.close(Err(e));
135
break StreamResult::Dropped;
136
}
137
138
None => {
139
self.close(Ok(()));
140
break StreamResult::Dropped;
141
}
142
}
143
if buf.len() >= count {
144
break StreamResult::Completed;
145
}
146
};
147
148
dst.set_buffer(buf.into());
149
return Poll::Ready(Ok(result));
150
}
151
}
152
153
impl<I, E> FallibleIteratorProducer<I, E> {
154
fn new(iter: I, result: oneshot::Sender<Result<(), E>>) -> Self {
155
Self {
156
iter,
157
result: Some(result),
158
}
159
}
160
161
fn close(&mut self, result: Result<(), E>) {
162
// Ignore send failures because it means the other end wasn't interested
163
// in the final error, if any.
164
let _ = self.result.take().unwrap().send(result);
165
}
166
}
167
168
impl<I, E> Drop for FallibleIteratorProducer<I, E> {
169
fn drop(&mut self) {
170
if self.result.is_some() {
171
self.close(Ok(()));
172
}
173
}
174
}
175
176
/// Add all WASI interfaces from this module into the `linker` provided.
177
///
178
/// This function will add all interfaces implemented by this module to the
179
/// [`Linker`], which corresponds to the `wasi:cli/imports` world supported by
180
/// this module.
181
///
182
/// # Example
183
///
184
/// ```
185
/// use wasmtime::{Engine, Result, Store, Config};
186
/// use wasmtime::component::{Linker, ResourceTable};
187
/// use wasmtime_wasi::{WasiCtx, WasiCtxView, WasiView};
188
///
189
/// fn main() -> Result<()> {
190
/// let mut config = Config::new();
191
/// config.async_support(true);
192
/// config.wasm_component_model_async(true);
193
/// let engine = Engine::new(&config)?;
194
///
195
/// let mut linker = Linker::<MyState>::new(&engine);
196
/// wasmtime_wasi::p3::add_to_linker(&mut linker)?;
197
/// // ... add any further functionality to `linker` if desired ...
198
///
199
/// let mut store = Store::new(
200
/// &engine,
201
/// MyState::default(),
202
/// );
203
///
204
/// // ... use `linker` to instantiate within `store` ...
205
///
206
/// Ok(())
207
/// }
208
///
209
/// #[derive(Default)]
210
/// struct MyState {
211
/// ctx: WasiCtx,
212
/// table: ResourceTable,
213
/// }
214
///
215
/// impl WasiView for MyState {
216
/// fn ctx(&mut self) -> WasiCtxView<'_> {
217
/// WasiCtxView{
218
/// ctx: &mut self.ctx,
219
/// table: &mut self.table,
220
/// }
221
/// }
222
/// }
223
/// ```
224
pub fn add_to_linker<T>(linker: &mut Linker<T>) -> wasmtime::Result<()>
225
where
226
T: WasiView + 'static,
227
{
228
let options = LinkOptions::default();
229
add_to_linker_with_options(linker, &options)
230
}
231
232
/// Similar to [`add_to_linker`], but with the ability to enable unstable features.
233
pub fn add_to_linker_with_options<T>(
234
linker: &mut Linker<T>,
235
options: &LinkOptions,
236
) -> wasmtime::Result<()>
237
where
238
T: WasiView + 'static,
239
{
240
cli::add_to_linker_with_options(linker, &options.into())?;
241
clocks::add_to_linker(linker)?;
242
filesystem::add_to_linker(linker)?;
243
random::add_to_linker(linker)?;
244
sockets::add_to_linker(linker)?;
245
Ok(())
246
}
247
248