mirror of
https://github.com/mii443/wasmer.git
synced 2025-12-12 05:18:43 +00:00
Move WasmerEnv into its own mod, implement it for stdlib types
This commit is contained in:
@@ -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> {}
|
||||
|
||||
Reference in New Issue
Block a user