wasi_tokio/
lib.rs

1#![cfg_attr(io_lifetimes_use_std, feature(io_safety))]
2
3mod dir;
4mod file;
5pub mod net;
6pub mod sched;
7pub mod stdio;
8
9use crate::sched::sched_ctx;
10pub use dir::Dir;
11pub use file::File;
12pub use net::*;
13use std::future::Future;
14use std::mem;
15use std::path::Path;
16use wasi_cap_std_sync::net::Socket;
17pub use wasi_cap_std_sync::{clocks_ctx, random_ctx};
18use wasi_common::{file::FileAccessMode, Error, Table, WasiCtx, WasiFile};
19
20pub struct WasiCtxBuilder {
21    ctx: WasiCtx,
22    built: bool,
23}
24
25impl WasiCtxBuilder {
26    pub fn new() -> Self {
27        WasiCtxBuilder {
28            ctx: WasiCtx::new(random_ctx(), clocks_ctx(), sched_ctx(), Table::new()),
29            built: false,
30        }
31    }
32    pub fn env(
33        &mut self,
34        var: &str,
35        value: &str,
36    ) -> Result<&mut Self, wasi_common::StringArrayError> {
37        self.ctx.push_env(var, value)?;
38        Ok(self)
39    }
40    pub fn envs(
41        &mut self,
42        env: &[(String, String)],
43    ) -> Result<&mut Self, wasi_common::StringArrayError> {
44        for (k, v) in env {
45            self.ctx.push_env(k, v)?;
46        }
47        Ok(self)
48    }
49    pub fn inherit_env(&mut self) -> Result<&mut Self, wasi_common::StringArrayError> {
50        for (key, value) in std::env::vars() {
51            self.ctx.push_env(&key, &value)?;
52        }
53        Ok(self)
54    }
55    pub fn arg(&mut self, arg: &str) -> Result<&mut Self, wasi_common::StringArrayError> {
56        self.ctx.push_arg(arg)?;
57        Ok(self)
58    }
59    pub fn args(&mut self, arg: &[String]) -> Result<&mut Self, wasi_common::StringArrayError> {
60        for a in arg {
61            self.ctx.push_arg(&a)?;
62        }
63        Ok(self)
64    }
65    pub fn inherit_args(&mut self) -> Result<&mut Self, wasi_common::StringArrayError> {
66        for arg in std::env::args() {
67            self.ctx.push_arg(&arg)?;
68        }
69        Ok(self)
70    }
71    pub fn stdin(&mut self, f: Box<dyn WasiFile>) -> &mut Self {
72        self.ctx.set_stdin(f);
73        self
74    }
75    pub fn stdout(&mut self, f: Box<dyn WasiFile>) -> &mut Self {
76        self.ctx.set_stdout(f);
77        self
78    }
79    pub fn stderr(&mut self, f: Box<dyn WasiFile>) -> &mut Self {
80        self.ctx.set_stderr(f);
81        self
82    }
83    pub fn inherit_stdin(&mut self) -> &mut Self {
84        self.stdin(Box::new(crate::stdio::stdin()))
85    }
86    pub fn inherit_stdout(&mut self) -> &mut Self {
87        self.stdout(Box::new(crate::stdio::stdout()))
88    }
89    pub fn inherit_stderr(&mut self) -> &mut Self {
90        self.stderr(Box::new(crate::stdio::stderr()))
91    }
92    pub fn inherit_stdio(&mut self) -> &mut Self {
93        self.inherit_stdin().inherit_stdout().inherit_stderr()
94    }
95    pub fn preopened_dir(
96        &mut self,
97        dir: cap_std::fs::Dir,
98        guest_path: impl AsRef<Path>,
99    ) -> Result<&mut Self, Error> {
100        let dir = Box::new(crate::dir::Dir::from_cap_std(dir));
101        self.ctx.push_preopened_dir(dir, guest_path)?;
102        Ok(self)
103    }
104    pub fn preopened_socket(
105        &mut self,
106        fd: u32,
107        socket: impl Into<Socket>,
108    ) -> Result<&mut Self, Error> {
109        let socket: Socket = socket.into();
110        let file: Box<dyn WasiFile> = socket.into();
111        self.ctx
112            .insert_file(fd, file, FileAccessMode::READ | FileAccessMode::WRITE);
113        Ok(self)
114    }
115
116    pub fn build(&mut self) -> WasiCtx {
117        assert!(!self.built);
118        let WasiCtxBuilder { ctx, .. } = mem::replace(self, Self::new());
119        self.built = true;
120        ctx
121    }
122}
123
124// Much of this crate is implemented in terms of `async` methods from the
125// wasi-cap-std-sync crate. These methods may be async in signature, however,
126// they are synchronous in implementation (always Poll::Ready on first poll)
127// and perform blocking syscalls.
128//
129// This function takes this blocking code and executes it using a dummy executor
130// to assert its immediate readiness. We tell tokio this is a blocking operation
131// with the block_in_place function.
132pub(crate) fn block_on_dummy_executor<'a, F, Fut, T>(f: F) -> Result<T, Error>
133where
134    F: FnOnce() -> Fut + Send + 'a,
135    Fut: Future<Output = Result<T, Error>>,
136    T: Send + 'static,
137{
138    tokio::task::block_in_place(move || {
139        wiggle::run_in_dummy_executor(f()).expect("wrapped operation should be synchronous")
140    })
141}