Move WasmerEnv into its own mod, implement it for stdlib types

This commit is contained in:
Mark McCaskey
2020-11-17 15:30:21 -08:00
parent 619afb5b10
commit 38b296e36f
2 changed files with 204 additions and 164 deletions

View File

@@ -28,6 +28,7 @@
)
)]
mod env;
mod exports;
mod externals;
mod import_object;
@@ -51,6 +52,7 @@ pub mod internals {
pub use crate::externals::{WithEnv, WithoutEnv};
}
pub use crate::env::{HostEnvInitError, LazyInit, WasmerEnv};
pub use crate::exports::{ExportError, Exportable, Exports, ExportsIterator};
pub use crate::externals::{
Extern, FromToNativeWasmType, Function, Global, HostFunction, Memory, Table, WasmTypeList,
@@ -134,167 +136,3 @@ pub use wasmer_engine_native::{Native, NativeArtifact, NativeEngine};
/// Version number of this crate.
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
// --------------------------------------------------------------
// TODO: put this in a proper location, just prototyping for now:
// TODO: rename everything, all names are throw-away names
use thiserror::Error;
/// An error while initializing the user supplied host env with the `WasmerEnv` trait.
#[derive(Error, Debug)]
#[error("Host env initialization error: {0}")]
pub enum HostEnvInitError {
/// An error occurred when accessing an export
Export(ExportError),
}
impl From<ExportError> for HostEnvInitError {
fn from(other: ExportError) -> Self {
Self::Export(other)
}
}
/// Prototype trait for finishing envs.
/// # Examples
///
/// This trait can be derived like so:
///
/// ```
/// # use wasmer::{WasmerEnv, LazyInit, Memory, NativeFunc};
///
/// #[derive(WasmerEnv)]
/// pub struct MyEnvWithNoInstanceData {
/// non_instance_data: u8,
/// }
///
/// #[derive(WasmerEnv)]
/// pub struct MyEnvWithInstanceData {
/// non_instance_data: u8,
/// #[wasmer(export)]
/// memory: LazyInit<Memory>,
/// #[wasmer(export(name = "real_name"))]
/// func: LazyInit<NativeFunc<(i32, i32), i32>>,
/// }
///
/// ```
///
/// This trait can also be implemented manually:
/// ```
/// # use wasmer::{WasmerEnv, LazyInit, Memory, Instance, HostEnvInitError};
/// pub struct MyEnv {
/// memory: LazyInit<Memory>,
/// }
///
/// impl WasmerEnv for MyEnv {
/// fn finish(&mut self, instance: &Instance) -> Result<(), HostEnvInitError> {
/// let memory = instance.exports.get_memory("memory").unwrap();
/// self.memory.initialize(memory.clone());
/// Ok(())
/// }
/// }
/// ```
pub trait WasmerEnv {
/// The function that Wasmer will call on your type to let it finish
/// setting up the environment with data from the `Instance`.
///
/// This function is called after `Instance` is created but before it is
/// returned to the user via `Instance::new`.
fn finish(&mut self, instance: &Instance) -> Result<(), HostEnvInitError>;
}
impl<T: WasmerEnv> WasmerEnv for &'static mut T {
fn finish(&mut self, instance: &Instance) -> Result<(), HostEnvInitError> {
(*self).finish(instance)
}
}
// TODO: do we want to use mutex/atomics here? like old WASI solution
/// Lazily init an item
pub struct LazyInit<T: Sized> {
/// The data to be initialized
data: std::mem::MaybeUninit<T>,
/// Whether or not the data has been initialized
initialized: bool,
}
impl<T> LazyInit<T> {
/// Creates an unitialized value.
pub fn new() -> Self {
Self {
data: std::mem::MaybeUninit::uninit(),
initialized: false,
}
}
/// # Safety
/// - The data must be initialized first
pub unsafe fn get_unchecked(&self) -> &T {
&*self.data.as_ptr()
}
/// Get the inner data.
pub fn get_ref(&self) -> Option<&T> {
if !self.initialized {
None
} else {
Some(unsafe { self.get_unchecked() })
}
}
/// TOOD: review
pub fn initialize(&mut self, value: T) -> bool {
if self.initialized {
return false;
}
unsafe {
self.data.as_mut_ptr().write(value);
}
self.initialized = true;
true
}
}
impl<T: std::fmt::Debug> std::fmt::Debug for LazyInit<T> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.debug_struct("LazyInit")
.field("data", &self.get_ref())
.finish()
}
}
impl<T: Clone> Clone for LazyInit<T> {
fn clone(&self) -> Self {
if let Some(inner) = self.get_ref() {
Self {
data: std::mem::MaybeUninit::new(inner.clone()),
initialized: true,
}
} else {
Self {
data: std::mem::MaybeUninit::uninit(),
initialized: false,
}
}
}
}
impl<T> Drop for LazyInit<T> {
fn drop(&mut self) {
if self.initialized {
unsafe {
let ptr = self.data.as_mut_ptr();
std::ptr::drop_in_place(ptr);
};
}
}
}
impl<T> Default for LazyInit<T> {
fn default() -> Self {
Self::new()
}
}
unsafe impl<T: Send> Send for LazyInit<T> {}
// I thought we could opt out of sync..., look into this
// unsafe impl<T> !Sync for InitWithInstance<T> {}