hermit-wasm 0.1.1

Running WASM modules inside a lightweight virtual machine
Documentation
use std::mem;

use wasmtime::component::ResourceTable;

/// A trait which provides access to internal WASI state.
///
/// This trait is the basis of implementation of all traits in this crate. All
/// traits are implemented like:
///
/// ```
/// # trait WasiView {}
/// # mod bindings { pub mod wasi { pub trait Host {} } }
/// impl<T: WasiView> bindings::wasi::Host for T {
///     // ...
/// }
/// ```
///
/// For a [`Store<T>`](wasmtime::Store) this trait will be implemented
/// for the `T`. This also corresponds to the `T` in
/// [`Linker<T>`](wasmtime::component::Linker).
///
/// # Example
///
/// ```
/// use wasmtime_wasi::{WasiCtx, ResourceTable, WasiView, WasiCtxBuilder};
///
/// struct MyState {
///     ctx: WasiCtx,
///     table: ResourceTable,
/// }
///
/// impl WasiView for MyState {
///     fn ctx(&mut self) -> &mut WasiCtx { &mut self.ctx }
///     fn table(&mut self) -> &mut ResourceTable { &mut self.table }
/// }
///
/// impl MyState {
///     fn new() -> MyState {
///         let mut wasi = WasiCtxBuilder::new();
///         wasi.arg("./foo.wasm");
///         wasi.arg("--help");
///         wasi.env("FOO", "bar");
///
///         MyState {
///             ctx: wasi.build(),
///             table: ResourceTable::new(),
///         }
///     }
/// }
/// ```
pub trait WasiView: Send {
	/// Yields mutable access to the internal resource management that this
	/// context contains.
	///
	/// Embedders can add custom resources to this table as well to give
	/// resources to wasm as well.
	fn table(&mut self) -> &mut ResourceTable;

	/// Yields mutable access to the configuration used for this context.
	///
	/// The returned type is created through [`WasiCtxBuilder`].
	fn ctx(&mut self) -> &mut WasiCtx;
}

impl<T: ?Sized + WasiView> WasiView for &mut T {
	fn table(&mut self) -> &mut ResourceTable {
		T::table(self)
	}
	fn ctx(&mut self) -> &mut WasiCtx {
		T::ctx(self)
	}
}

impl<T: ?Sized + WasiView> WasiView for Box<T> {
	fn table(&mut self) -> &mut ResourceTable {
		T::table(self)
	}
	fn ctx(&mut self) -> &mut WasiCtx {
		T::ctx(self)
	}
}

/// A small newtype wrapper which serves as the basis for implementations of
/// `Host` WASI traits in this crate.
///
/// This type is used as the basis for the implementation of all `Host` traits
/// generated by `bindgen!` for WASI interfaces. This is used automatically with
/// [`add_to_linker_sync`](crate::add_to_linker_sync) and
/// [`add_to_linker_async`](crate::add_to_linker_async).
///
/// This type is otherwise provided if you're calling the `add_to_linker`
/// functions generated by `bindgen!` from the [`bindings`
/// module](crate::bindings). In this situation you'll want to create a value of
/// this type in the closures added to a `Linker`.
#[repr(transparent)]
pub struct WasiImpl<T>(pub T);

impl<T: WasiView> WasiView for WasiImpl<T> {
	fn table(&mut self) -> &mut ResourceTable {
		T::table(&mut self.0)
	}
	fn ctx(&mut self) -> &mut WasiCtx {
		T::ctx(&mut self.0)
	}
}

/// Per-[`Store`] state which holds state necessary to implement WASI from this
/// crate.
///
/// This structure is created through [`WasiCtxBuilder`] and is stored within
/// the `T` of [`Store<T>`][`Store`]. Access to the structure is provided
/// through the [`WasiView`] trait as an implementation on `T`.
///
/// Note that this structure itself does not have any accessors, it's here for
/// internal use within the `wasmtime-wasi` crate's implementation of
/// bindgen-generated traits.
///
/// [`Store`]: wasmtime::Store
pub struct WasiCtx {
	/*pub(crate) random: Box<dyn RngCore + Send>,
	pub(crate) insecure_random: Box<dyn RngCore + Send>,
	pub(crate) insecure_random_seed: u128,
	pub(crate) wall_clock: Box<dyn HostWallClock + Send>,
	pub(crate) monotonic_clock: Box<dyn HostMonotonicClock + Send>,*/
	pub(crate) env: Vec<(String, String)>,
	pub(crate) args: Vec<String>,
	/*pub(crate) preopens: Vec<(Dir, String)>,
	pub(crate) stdin: Box<dyn StdinStream>,
	pub(crate) stdout: Box<dyn StdoutStream>,
	pub(crate) stderr: Box<dyn StdoutStream>,
	pub(crate) socket_addr_check: SocketAddrCheck,
	pub(crate) allowed_network_uses: AllowedNetworkUses,
	pub(crate) allow_blocking_current_thread: bool,*/
}

/// Builder-style structure used to create a [`WasiCtx`].
///
/// This type is used to create a [`WasiCtx`] that is considered per-[`Store`]
/// state. The [`build`][WasiCtxBuilder::build] method is used to finish the
/// building process and produce a finalized [`WasiCtx`].
///
/// # Examples
///
/// ```
/// use wasmtime_wasi::{WasiCtxBuilder, WasiCtx};
///
/// let mut wasi = WasiCtxBuilder::new();
/// wasi.arg("./foo.wasm");
/// wasi.arg("--help");
/// wasi.env("FOO", "bar");
///
/// let wasi: WasiCtx = wasi.build();
/// ```
///
/// [`Store`]: wasmtime::Store
pub struct WasiCtxBuilder {
	/*stdin: Box<dyn StdinStream>,
	stdout: Box<dyn StdoutStream>,
	stderr: Box<dyn StdoutStream>,*/
	env: Vec<(String, String)>,
	args: Vec<String>,
	/*preopens: Vec<(Dir, String)>,
	socket_addr_check: SocketAddrCheck,
	random: Box<dyn RngCore + Send>,
	insecure_random: Box<dyn RngCore + Send>,
	insecure_random_seed: u128,
	wall_clock: Box<dyn HostWallClock + Send>,
	monotonic_clock: Box<dyn HostMonotonicClock + Send>,
	allowed_network_uses: AllowedNetworkUses,
	allow_blocking_current_thread: bool,*/
	built: bool,
}

impl WasiCtxBuilder {
	/// Creates a builder for a new context with default parameters set.
	///
	/// The current defaults are:
	///
	/// * stdin is closed
	/// * stdout and stderr eat all input and it doesn't go anywhere
	/// * no env vars
	/// * no arguments
	/// * no preopens
	/// * clocks use the host implementation of wall/monotonic clocks
	/// * RNGs are all initialized with random state and suitable generator
	///   quality to satisfy the requirements of WASI APIs.
	/// * TCP/UDP are allowed but all addresses are denied by default.
	/// * `wasi:network/ip-name-lookup` is denied by default.
	///
	/// These defaults can all be updated via the various builder configuration
	/// methods below.
	pub fn new() -> Self {
		// For the insecure random API, use `SmallRng`, which is fast. It's
		// also insecure, but that's the deal here.
		/*let insecure_random = Box::new(
			cap_rand::rngs::SmallRng::from_rng(cap_rand::thread_rng(cap_rand::ambient_authority()))
				.unwrap(),
		);*/

		// For the insecure random seed, use a `u128` generated from
		// `thread_rng()`, so that it's not guessable from the insecure_random
		// API.
		/*let insecure_random_seed =
		cap_rand::thread_rng(cap_rand::ambient_authority()).gen::<u128>();*/
		Self {
			/*stdin: Box::new(pipe::ClosedInputStream),
			stdout: Box::new(pipe::SinkOutputStream),
			stderr: Box::new(pipe::SinkOutputStream),*/
			env: Vec::new(),
			args: Vec::new(),
			/*preopens: Vec::new(),
			socket_addr_check: SocketAddrCheck::default(),
			random: random::thread_rng(),
			insecure_random,
			insecure_random_seed,
			wall_clock: wall_clock(),
			monotonic_clock: monotonic_clock(),
			allowed_network_uses: AllowedNetworkUses::default(),
			allow_blocking_current_thread: false,*/
			built: false,
		}
	}

	/// Uses the configured context so far to construct the final [`WasiCtx`].
	///
	/// Note that each `WasiCtxBuilder` can only be used to "build" once, and
	/// calling this method twice will panic.
	///
	/// # Panics
	///
	/// Panics if this method is called twice. Each [`WasiCtxBuilder`] can be
	/// used to create only a single [`WasiCtx`]. Repeated usage of this method
	/// is not allowed and should use a second builder instead.
	pub fn build(&mut self) -> WasiCtx {
		assert!(!self.built);

		let Self {
			/*stdin,
			stdout,
			stderr,*/
			env,
			args,
			/*preopens,
			socket_addr_check,
			random,
			insecure_random,
			insecure_random_seed,
			wall_clock,
			monotonic_clock,
			allowed_network_uses,
			allow_blocking_current_thread,*/
			built: _,
		} = mem::replace(self, Self::new());
		self.built = true;

		WasiCtx {
			/*stdin,
			stdout,
			stderr,*/
			env,
			args,
			/*preopens,
			socket_addr_check,
			random,
			insecure_random,
			insecure_random_seed,
			wall_clock,
			monotonic_clock,
			allowed_network_uses,
			allow_blocking_current_thread,*/
		}
	}
}