mirror of
https://github.com/fluencelabs/marine.git
synced 2025-07-03 08:31:39 +00:00
move fce to fce_wit_interfaces
This commit is contained in:
28
Cargo.lock
generated
28
Cargo.lock
generated
@ -361,6 +361,20 @@ dependencies = [
|
|||||||
"synstructure",
|
"synstructure",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fce"
|
||||||
|
version = "0.2.0"
|
||||||
|
dependencies = [
|
||||||
|
"fce_wit_interfaces",
|
||||||
|
"multimap",
|
||||||
|
"parity-wasm",
|
||||||
|
"pwasm-utils",
|
||||||
|
"wasmer-interface-types",
|
||||||
|
"wasmer-runtime",
|
||||||
|
"wasmer-runtime-core",
|
||||||
|
"wasmer-wasi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fce_wit_interfaces"
|
name = "fce_wit_interfaces"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -369,6 +383,7 @@ dependencies = [
|
|||||||
"multimap",
|
"multimap",
|
||||||
"walrus",
|
"walrus",
|
||||||
"wasmer-interface-types",
|
"wasmer-interface-types",
|
||||||
|
"wasmer-runtime-core",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1209,16 +1224,3 @@ dependencies = [
|
|||||||
"failure",
|
"failure",
|
||||||
"fce_wit_interfaces",
|
"fce_wit_interfaces",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wit_fce"
|
|
||||||
version = "0.2.0"
|
|
||||||
dependencies = [
|
|
||||||
"multimap",
|
|
||||||
"parity-wasm",
|
|
||||||
"pwasm-utils",
|
|
||||||
"wasmer-interface-types",
|
|
||||||
"wasmer-runtime",
|
|
||||||
"wasmer-runtime-core",
|
|
||||||
"wasmer-wasi",
|
|
||||||
]
|
|
||||||
|
@ -10,6 +10,8 @@ path = "src/lib.rs"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
walrus = "0.17.0"
|
walrus = "0.17.0"
|
||||||
|
wasmer-core = { package = "wasmer-runtime-core", version = "0.17.0", features = ["dynamicfunc-fat-closures"] }
|
||||||
wasmer-wit = { package = "wasmer-interface-types", git = "https://github.com/fluencelabs/interface-types", branch = "master"}
|
wasmer-wit = { package = "wasmer-interface-types", git = "https://github.com/fluencelabs/interface-types", branch = "master"}
|
||||||
|
|
||||||
multimap = "0.8.1"
|
multimap = "0.8.1"
|
||||||
anyhow = "1.0.31"
|
anyhow = "1.0.31"
|
||||||
|
@ -23,39 +23,35 @@ use std::collections::HashMap;
|
|||||||
|
|
||||||
pub type CoreFunctionType = u32;
|
pub type CoreFunctionType = u32;
|
||||||
pub type AdapterFunctionType = u32;
|
pub type AdapterFunctionType = u32;
|
||||||
pub type ExportName = String;
|
pub type ExportName<'a> = &'a str;
|
||||||
pub type ImportName = String;
|
pub type ImportName<'a> = &'a str;
|
||||||
pub type ImportNamespace = String;
|
pub type ImportNamespace<'a> = &'a str;
|
||||||
|
pub type WITAstType = Type;
|
||||||
|
|
||||||
pub struct FCEWITInterfaces {
|
pub struct FCEWITInterfaces<'a> {
|
||||||
/// All the types.
|
/// All the types.
|
||||||
types: Vec<Type>,
|
types: Vec<WITAstType>,
|
||||||
|
|
||||||
/// All the imported functions.
|
/// All the imported functions.
|
||||||
imports: HashMap<CoreFunctionType, (ImportName, ImportNamespace)>,
|
imports: HashMap<CoreFunctionType, (ImportName<'a>, ImportNamespace<'a>)>,
|
||||||
|
|
||||||
/// All the adapters.
|
/// All the adapters.
|
||||||
adapters: HashMap<AdapterFunctionType, Vec<Instruction>>,
|
adapters: HashMap<AdapterFunctionType, Vec<Instruction>>,
|
||||||
|
|
||||||
/// All the exported functions.
|
/// All the exported functions.
|
||||||
exports: HashMap<CoreFunctionType, ExportName>,
|
exports: HashMap<CoreFunctionType, ExportName<'a>>,
|
||||||
|
|
||||||
/// All the implementations.
|
/// All the implementations.
|
||||||
adapter_type_to_core: MultiMap<AdapterFunctionType, CoreFunctionType>,
|
adapter_type_to_core: MultiMap<AdapterFunctionType, CoreFunctionType>,
|
||||||
core_type_to_adapter: MultiMap<CoreFunctionType, AdapterFunctionType>,
|
core_type_to_adapter: MultiMap<CoreFunctionType, AdapterFunctionType>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FCEWITInterfaces {
|
impl<'a> FCEWITInterfaces<'a> {
|
||||||
pub fn new(interfaces: Interfaces<'_>) -> Self {
|
pub fn new(interfaces: Interfaces<'a>) -> Self {
|
||||||
let imports = interfaces
|
let imports = interfaces
|
||||||
.imports
|
.imports
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|import| {
|
.map(|import| (import.function_type, (import.namespace, import.name)))
|
||||||
(
|
|
||||||
import.function_type,
|
|
||||||
(import.namespace.to_owned(), import.name.to_owned()),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect::<HashMap<_, _>>();
|
.collect::<HashMap<_, _>>();
|
||||||
|
|
||||||
let adapters = interfaces
|
let adapters = interfaces
|
||||||
@ -67,7 +63,7 @@ impl FCEWITInterfaces {
|
|||||||
let exports = interfaces
|
let exports = interfaces
|
||||||
.exports
|
.exports
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|export| (export.function_type, export.name.to_owned()))
|
.map(|export| (export.function_type, export.name))
|
||||||
.collect::<HashMap<_, _>>();
|
.collect::<HashMap<_, _>>();
|
||||||
|
|
||||||
let adapter_type_to_core = interfaces
|
let adapter_type_to_core = interfaces
|
||||||
@ -102,8 +98,8 @@ impl FCEWITInterfaces {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_by_idx(&self, idx: usize) -> Option<&Type> {
|
pub fn type_by_idx(&self, idx: u32) -> Option<&Type> {
|
||||||
self.types.get(idx)
|
self.types.get(idx as usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn types(&self) -> impl Iterator<Item = &Type> {
|
pub fn types(&self) -> impl Iterator<Item = &Type> {
|
||||||
@ -113,13 +109,13 @@ impl FCEWITInterfaces {
|
|||||||
pub fn import_by_type(
|
pub fn import_by_type(
|
||||||
&self,
|
&self,
|
||||||
import_type: CoreFunctionType,
|
import_type: CoreFunctionType,
|
||||||
) -> Option<&(ImportName, ImportNamespace)> {
|
) -> Option<&(ImportName<'a>, ImportNamespace<'a>)> {
|
||||||
self.imports.get(&import_type)
|
self.imports.get(&import_type)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn imports(
|
pub fn imports(
|
||||||
&self,
|
&self,
|
||||||
) -> impl Iterator<Item = (&CoreFunctionType, &(ImportName, ImportNamespace))> {
|
) -> impl Iterator<Item = (&CoreFunctionType, &(ImportName<'a>, ImportNamespace<'a>))> {
|
||||||
self.imports.iter()
|
self.imports.iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,22 +123,22 @@ impl FCEWITInterfaces {
|
|||||||
self.adapters.get(&adapter_type)
|
self.adapters.get(&adapter_type)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn export_by_type(&self, export_type: u32) -> Option<&ExportName> {
|
pub fn export_by_type(&self, export_type: u32) -> Option<&ExportName<'a>> {
|
||||||
self.exports.get(&export_type)
|
self.exports.get(&export_type)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn adapter_func_implementations(
|
pub fn exports(
|
||||||
|
&self,
|
||||||
|
) -> impl Iterator<Item = (&CoreFunctionType, &ExportName<'a>)> {
|
||||||
|
self.exports.iter()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn implementations(
|
||||||
&self,
|
&self,
|
||||||
) -> impl Iterator<Item = (&AdapterFunctionType, &CoreFunctionType)> {
|
) -> impl Iterator<Item = (&AdapterFunctionType, &CoreFunctionType)> {
|
||||||
self.adapter_type_to_core.iter()
|
self.adapter_type_to_core.iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn core_func_implementations(
|
|
||||||
&self,
|
|
||||||
) -> impl Iterator<Item = (&CoreFunctionType, &AdapterFunctionType)> {
|
|
||||||
self.core_type_to_adapter.iter()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn adapter_types_by_core_type(
|
pub fn adapter_types_by_core_type(
|
||||||
&self,
|
&self,
|
||||||
core_function_type: CoreFunctionType,
|
core_function_type: CoreFunctionType,
|
||||||
|
@ -20,40 +20,47 @@ use crate::fce_wit_interfaces::FCEWITInterfaces;
|
|||||||
|
|
||||||
use walrus::{IdsToIndices, ModuleConfig};
|
use walrus::{IdsToIndices, ModuleConfig};
|
||||||
use wasmer_wit::ast::Interfaces;
|
use wasmer_wit::ast::Interfaces;
|
||||||
|
use wasmer_core::Module as WasmerModule;
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
/// Extracts WIT section of provided Wasm binary and converts it to a string.
|
||||||
pub fn extract_text_wit(wasm_file_path: PathBuf) -> Result<String, WITParserError> {
|
pub fn extract_text_wit(wasm_file_path: PathBuf) -> Result<String, WITParserError> {
|
||||||
|
let wit_section_bytes = extract_wit_section_bytes(wasm_file_path)?;
|
||||||
extract_wit_with_fn(
|
extract_wit_with_fn(
|
||||||
wasm_file_path,
|
&wit_section_bytes,
|
||||||
|wit: Interfaces<'_>| -> Result<String, WITParserError> { Ok((&wit).to_string()) },
|
|wit: Interfaces<'_>| -> Result<String, WITParserError> { Ok((&wit).to_string()) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn extract_fce_wit(wasm_file_path: PathBuf) -> Result<FCEWITInterfaces, WITParserError> {
|
/// Extracts WIT section of provided Wasm binary and converts it to a FCEWITInterfaces.
|
||||||
|
pub fn extract_fce_wit(
|
||||||
|
wasmer_module: &WasmerModule,
|
||||||
|
) -> Result<FCEWITInterfaces<'_>, WITParserError> {
|
||||||
|
let wit_sections = wasmer_module
|
||||||
|
.custom_sections(WIT_SECTION_NAME)
|
||||||
|
.ok_or_else(|| WITParserError::NoWITSection)?;
|
||||||
|
|
||||||
|
if wit_sections.len() > 1 {
|
||||||
|
return Err(WITParserError::MultipleWITSections);
|
||||||
|
}
|
||||||
|
|
||||||
extract_wit_with_fn(
|
extract_wit_with_fn(
|
||||||
wasm_file_path,
|
&wit_sections[0],
|
||||||
|wit: Interfaces<'_>| -> Result<FCEWITInterfaces, WITParserError> {
|
|wit: Interfaces<'_>| -> Result<FCEWITInterfaces<'_>, WITParserError> {
|
||||||
Ok(FCEWITInterfaces::new(wit))
|
Ok(FCEWITInterfaces::new(wit))
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_wit_with_fn<F, FResultType>(
|
fn extract_wit_with_fn<'a, F, FResultType: 'a>(
|
||||||
wasm_file_path: PathBuf,
|
wit_section_bytes: &'a [u8],
|
||||||
func: F,
|
func: F,
|
||||||
) -> Result<FResultType, WITParserError>
|
) -> Result<FResultType, WITParserError>
|
||||||
where
|
where
|
||||||
F: FnOnce(Interfaces<'_>) -> Result<FResultType, WITParserError>,
|
F: FnOnce(Interfaces<'a>) -> Result<FResultType, WITParserError>,
|
||||||
{
|
{
|
||||||
let wit_section_bytes = extract_wit_section_bytes(wasm_file_path)?;
|
let raw_wit = match wasmer_wit::decoders::binary::parse::<()>(&wit_section_bytes) {
|
||||||
let raw_wit = extract_raw_interfaces(&wit_section_bytes)?;
|
|
||||||
|
|
||||||
func(raw_wit)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn extract_raw_interfaces(wit_section_bytes: &[u8]) -> Result<Interfaces<'_>, WITParserError> {
|
|
||||||
let wit = match wasmer_wit::decoders::binary::parse::<()>(&wit_section_bytes) {
|
|
||||||
Ok((remainder, wit)) if remainder.is_empty() => wit,
|
Ok((remainder, wit)) if remainder.is_empty() => wit,
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
return Err(WITParserError::WITRemainderNotEmpty);
|
return Err(WITParserError::WITRemainderNotEmpty);
|
||||||
@ -63,7 +70,7 @@ fn extract_raw_interfaces(wit_section_bytes: &[u8]) -> Result<Interfaces<'_>, WI
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(wit)
|
func(raw_wit)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_wit_section_bytes(wasm_file_path: PathBuf) -> Result<Vec<u8>, WITParserError> {
|
fn extract_wit_section_bytes(wasm_file_path: PathBuf) -> Result<Vec<u8>, WITParserError> {
|
@ -1,6 +1,6 @@
|
|||||||
mod custom;
|
mod custom;
|
||||||
mod errors;
|
mod errors;
|
||||||
mod extracter;
|
mod extractor;
|
||||||
mod embedder;
|
mod embedder;
|
||||||
|
|
||||||
pub use errors::WITParserError;
|
pub use errors::WITParserError;
|
||||||
@ -8,5 +8,5 @@ pub use errors::WITParserError;
|
|||||||
pub use embedder::EmbedderConfig;
|
pub use embedder::EmbedderConfig;
|
||||||
pub use embedder::embed_text_wit;
|
pub use embedder::embed_text_wit;
|
||||||
|
|
||||||
pub use extracter::extract_fce_wit;
|
pub use extractor::extract_fce_wit;
|
||||||
pub use extracter::extract_text_wit;
|
pub use extractor::extract_text_wit;
|
||||||
|
@ -1,15 +1,18 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wit_fce"
|
name = "fce"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
authors = ["Fluence Labs"]
|
authors = ["Fluence Labs"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
fce_wit_interfaces = { path = "../crates/fce_wit_interfaces" }
|
||||||
|
|
||||||
wasmer-runtime = "0.17.0"
|
wasmer-runtime = "0.17.0"
|
||||||
# dynamicfunc-fat-closures allows using state inside DynamicFunc
|
# dynamicfunc-fat-closures allows using state inside DynamicFunc
|
||||||
wasmer-core = { package = "wasmer-runtime-core", version = "0.17.0", features = ["dynamicfunc-fat-closures"] }
|
wasmer-core = { package = "wasmer-runtime-core", version = "0.17.0", features = ["dynamicfunc-fat-closures"] }
|
||||||
wasmer-wit = { package = "wasmer-interface-types", git = "http://github.com/fluencelabs/interface-types" }
|
wasmer-wit = { package = "wasmer-interface-types", git = "http://github.com/fluencelabs/interface-types" }
|
||||||
wasmer-wasi = "0.17.0"
|
wasmer-wasi = "0.17.0"
|
||||||
|
|
||||||
multimap = "0.8.1"
|
multimap = "0.8.1"
|
||||||
parity-wasm = "0.41.0"
|
parity-wasm = "0.41.0"
|
||||||
pwasm-utils = "0.12.0"
|
pwasm-utils = "0.12.0"
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use fce_wit_interfaces::WITParserError;
|
||||||
use wasmer_wit::errors::InstructionError;
|
use wasmer_wit::errors::InstructionError;
|
||||||
use wasmer_runtime::error::{
|
use wasmer_runtime::error::{
|
||||||
CallError, CompileError, CreationError, Error as WasmerError, ResolveError, RuntimeError,
|
CallError, CompileError, CreationError, Error as WasmerError, ResolveError, RuntimeError,
|
||||||
@ -47,17 +48,11 @@ pub enum FCEError {
|
|||||||
/// Returns when there is no module with such name.
|
/// Returns when there is no module with such name.
|
||||||
NoSuchModule,
|
NoSuchModule,
|
||||||
|
|
||||||
/// WIT section is absent.
|
/// WIT section parse error.
|
||||||
NoWITSection,
|
WITParseError(WITParserError),
|
||||||
|
|
||||||
/// Multiple WIT sections.
|
/// Incorrect WIT section.
|
||||||
MultipleWITSections,
|
IncorrectWIT(String),
|
||||||
|
|
||||||
/// WIT section remainder isn't empty.
|
|
||||||
WITRemainderNotEmpty,
|
|
||||||
|
|
||||||
/// An error occurred while parsing WIT section.
|
|
||||||
WITParseError,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Error for FCEError {}
|
impl Error for FCEError {}
|
||||||
@ -77,19 +72,8 @@ impl std::fmt::Display for FCEError {
|
|||||||
write!(f, "FCE doesn't have a function with such a name: {}", msg)
|
write!(f, "FCE doesn't have a function with such a name: {}", msg)
|
||||||
}
|
}
|
||||||
FCEError::NoSuchModule => write!(f, "FCE doesn't have a module with such a name"),
|
FCEError::NoSuchModule => write!(f, "FCE doesn't have a module with such a name"),
|
||||||
FCEError::NoWITSection => write!(
|
FCEError::WITParseError(err) => write!(f, "{}", err),
|
||||||
f,
|
FCEError::IncorrectWIT(err_msg) => write!(f, "{}", err_msg),
|
||||||
"Loaded module doesn't contain WIT section that is neccessary for instantiation"
|
|
||||||
),
|
|
||||||
FCEError::MultipleWITSections => write!(
|
|
||||||
f,
|
|
||||||
"Loaded module contains multiple WIT sections that is unsupported now"
|
|
||||||
),
|
|
||||||
FCEError::WITRemainderNotEmpty => write!(
|
|
||||||
f,
|
|
||||||
"WIT section remainder isn't empty - WIT section possibly corrupted"
|
|
||||||
),
|
|
||||||
FCEError::WITParseError => write!(f, "WIT section is corrupted"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -144,3 +128,9 @@ impl From<InstructionError> for FCEError {
|
|||||||
FCEError::WasmerInvokeError(format!("{}", err))
|
FCEError::WasmerInvokeError(format!("{}", err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<WITParserError> for FCEError {
|
||||||
|
fn from(err: WITParserError) -> Self {
|
||||||
|
FCEError::WITParseError(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -17,10 +17,10 @@
|
|||||||
use super::wit_prelude::*;
|
use super::wit_prelude::*;
|
||||||
use super::{IType, IValue, WValue};
|
use super::{IType, IValue, WValue};
|
||||||
|
|
||||||
use wasmer_wit::ast::Interfaces;
|
use fce_wit_interfaces::extract_fce_wit;
|
||||||
|
use fce_wit_interfaces::FCEWITInterfaces;
|
||||||
use wasmer_wit::interpreter::Interpreter;
|
use wasmer_wit::interpreter::Interpreter;
|
||||||
use wasmer_runtime::{compile, ImportObject};
|
use wasmer_runtime::{compile, ImportObject};
|
||||||
use wasmer_core::Module as WasmerModule;
|
|
||||||
use wasmer_core::Instance as WasmerInstance;
|
use wasmer_core::Instance as WasmerInstance;
|
||||||
use wasmer_core::import::Namespace;
|
use wasmer_core::import::Namespace;
|
||||||
|
|
||||||
@ -29,11 +29,14 @@ use std::convert::TryInto;
|
|||||||
use std::mem::MaybeUninit;
|
use std::mem::MaybeUninit;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
const WIT_SECTION_NAME: &str = "interface-types";
|
|
||||||
type WITInterpreter =
|
type WITInterpreter =
|
||||||
Interpreter<WITInstance, WITExport, WITFunction, WITMemory, WITMemoryView<'static>>;
|
Interpreter<WITInstance, WITExport, WITFunction, WITMemory, WITMemoryView<'static>>;
|
||||||
// TODO: introduce new trait instead of type
|
|
||||||
type WITModuleFunc = (WITInterpreter, Vec<IType>, Vec<IType>);
|
struct WITModuleFunc {
|
||||||
|
interpreter: WITInterpreter,
|
||||||
|
inputs: Vec<IType>,
|
||||||
|
outputs: Vec<IType>,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct FCEModule {
|
pub struct FCEModule {
|
||||||
// it is needed because of WITInstance contains dynamic functions
|
// it is needed because of WITInstance contains dynamic functions
|
||||||
@ -51,11 +54,11 @@ impl FCEModule {
|
|||||||
modules: &HashMap<String, Arc<FCEModule>>,
|
modules: &HashMap<String, Arc<FCEModule>>,
|
||||||
) -> Result<Self, FCEError> {
|
) -> Result<Self, FCEError> {
|
||||||
let wasmer_module = compile(&wasm_bytes)?;
|
let wasmer_module = compile(&wasm_bytes)?;
|
||||||
let wit = Self::extract_wit(&wasmer_module)?;
|
let wit = extract_fce_wit(&wasmer_module)?;
|
||||||
let wit_exports = Self::instantiate_wit_exports(&wit)?;
|
let wit_exports = Self::instantiate_wit_exports(&wit)?;
|
||||||
|
|
||||||
let mut wit_instance = Arc::new_uninit();
|
let mut wit_instance = Arc::new_uninit();
|
||||||
let mut import_object = Self::adjust_imports(&wit, wit_instance.clone())?;
|
let mut import_object = Self::adjust_wit_imports(&wit, wit_instance.clone())?;
|
||||||
import_object.extend(imports);
|
import_object.extend(imports);
|
||||||
|
|
||||||
let wasmer_instance = wasmer_module.instantiate(&import_object)?;
|
let wasmer_instance = wasmer_module.instantiate(&import_object)?;
|
||||||
@ -81,7 +84,7 @@ impl FCEModule {
|
|||||||
match self.exports_funcs.get(function_name) {
|
match self.exports_funcs.get(function_name) {
|
||||||
Some(func) => {
|
Some(func) => {
|
||||||
let result = func
|
let result = func
|
||||||
.0
|
.interpreter
|
||||||
.run(args, Arc::make_mut(&mut self.wit_instance))?
|
.run(args, Arc::make_mut(&mut self.wit_instance))?
|
||||||
.as_slice()
|
.as_slice()
|
||||||
.to_owned();
|
.to_owned();
|
||||||
@ -99,7 +102,7 @@ impl FCEModule {
|
|||||||
function_name: &str,
|
function_name: &str,
|
||||||
) -> Result<(&Vec<IType>, &Vec<IType>), FCEError> {
|
) -> Result<(&Vec<IType>, &Vec<IType>), FCEError> {
|
||||||
match self.exports_funcs.get(function_name) {
|
match self.exports_funcs.get(function_name) {
|
||||||
Some((_, inputs, outputs)) => Ok((inputs, outputs)),
|
Some(func) => Ok((&func.inputs, &func.outputs)),
|
||||||
None => Err(FCEError::NoSuchFunction(format!(
|
None => Err(FCEError::NoSuchFunction(format!(
|
||||||
"{} has't been found during its signature looking up",
|
"{} has't been found during its signature looking up",
|
||||||
function_name
|
function_name
|
||||||
@ -107,189 +110,146 @@ impl FCEModule {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_wit(wasmer_module: &WasmerModule) -> Result<Interfaces<'_>, FCEError> {
|
|
||||||
let wit_sections = wasmer_module
|
|
||||||
.custom_sections(WIT_SECTION_NAME)
|
|
||||||
.ok_or_else(|| FCEError::NoWITSection)?;
|
|
||||||
|
|
||||||
if wit_sections.len() > 1 {
|
|
||||||
return Err(FCEError::MultipleWITSections);
|
|
||||||
}
|
|
||||||
|
|
||||||
let (remainder, interfaces) = wasmer_wit::decoders::binary::parse::<()>(&wit_sections[0])
|
|
||||||
.map_err(|_e| FCEError::WITParseError)?;
|
|
||||||
if remainder.len() > 1 {
|
|
||||||
return Err(FCEError::WITRemainderNotEmpty);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(interfaces)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn instantiate_wit_exports(
|
fn instantiate_wit_exports(
|
||||||
wit: &Interfaces<'_>,
|
wit: &FCEWITInterfaces<'_>,
|
||||||
) -> Result<HashMap<String, WITModuleFunc>, FCEError> {
|
) -> Result<HashMap<String, WITModuleFunc>, FCEError> {
|
||||||
use super::IAstType;
|
use fce_wit_interfaces::WITAstType;
|
||||||
use multimap::MultiMap;
|
|
||||||
|
|
||||||
let exports_type_to_names = wit
|
wit
|
||||||
.exports
|
.implementations()
|
||||||
.iter()
|
.filter_map(|(adapter_function_type, core_function_type)|
|
||||||
.map(|export| (export.function_type, export.name.to_string()))
|
match wit.export_by_type(*core_function_type) {
|
||||||
.collect::<MultiMap<_, _>>();
|
Some(export_function_name) => Some((adapter_function_type, *export_function_name)),
|
||||||
|
// pass functions that aren't export
|
||||||
let adapter_type_to_instructions = wit
|
None => None
|
||||||
.adapters
|
|
||||||
.iter()
|
|
||||||
.map(|adapter| (adapter.function_type, &adapter.instructions))
|
|
||||||
.collect::<HashMap<_, _>>();
|
|
||||||
|
|
||||||
let mut wit_callable_exports = HashMap::new();
|
|
||||||
for i in wit.implementations.iter() {
|
|
||||||
let export_function_names = match exports_type_to_names.get_vec(&i.core_function_type) {
|
|
||||||
Some(export_function_names) => export_function_names,
|
|
||||||
None => continue,
|
|
||||||
};
|
|
||||||
|
|
||||||
// * just to remove reference
|
|
||||||
let adapter_instructions = *adapter_type_to_instructions
|
|
||||||
.get(&i.adapter_function_type)
|
|
||||||
.ok_or_else(|| FCEError::NoSuchFunction(
|
|
||||||
format!("adapter function with idx = {} hasn't been found during extracting exports by implementations", i.adapter_function_type)
|
|
||||||
))?;
|
|
||||||
|
|
||||||
if i.adapter_function_type >= wit.types.len() as u32 {
|
|
||||||
// TODO: change error type
|
|
||||||
return Err(FCEError::NoSuchFunction(format!(
|
|
||||||
"{} function id is bigger than WIT interface types count",
|
|
||||||
i.adapter_function_type
|
|
||||||
)));
|
|
||||||
};
|
|
||||||
|
|
||||||
if let IAstType::Function { inputs, outputs } =
|
|
||||||
&wit.types[i.adapter_function_type as usize]
|
|
||||||
{
|
|
||||||
for export_function_name in export_function_names.iter() {
|
|
||||||
// TODO: handle errors
|
|
||||||
let interpreter: WITInterpreter = adapter_instructions.try_into().unwrap();
|
|
||||||
wit_callable_exports.insert(
|
|
||||||
export_function_name.to_owned(),
|
|
||||||
(interpreter, inputs.clone(), outputs.clone()),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} else {
|
)
|
||||||
return Err(FCEError::NoSuchFunction(format!(
|
.map(|(adapter_function_type, export_function_name)| {
|
||||||
"type with idx = {} isn't a function type",
|
let adapter_instructions = wit.adapter_by_type(*adapter_function_type)
|
||||||
i.adapter_function_type
|
.ok_or_else(|| FCEError::IncorrectWIT(
|
||||||
)));
|
format!("adapter function with idx = {} hasn't been found during extracting exports by implementations", adapter_function_type)
|
||||||
}
|
))?;
|
||||||
}
|
|
||||||
|
|
||||||
Ok(wit_callable_exports)
|
let wit_type = wit.type_by_idx(*adapter_function_type).ok_or_else(
|
||||||
|
// TODO: change error type
|
||||||
|
|| FCEError::IncorrectWIT(format!(
|
||||||
|
"{} function id is bigger than WIT interface types count",
|
||||||
|
adapter_function_type
|
||||||
|
)))?;
|
||||||
|
|
||||||
|
match wit_type {
|
||||||
|
WITAstType::Function { inputs, outputs, .. } => {
|
||||||
|
let interpreter: WITInterpreter = adapter_instructions.try_into().map_err(|_| FCEError::IncorrectWIT(
|
||||||
|
format!("failed to parse instructions for adapter type {}", adapter_function_type)
|
||||||
|
))?;
|
||||||
|
|
||||||
|
Ok((
|
||||||
|
export_function_name.to_string(),
|
||||||
|
WITModuleFunc {
|
||||||
|
interpreter,
|
||||||
|
inputs: inputs.clone(),
|
||||||
|
outputs: outputs.clone(),
|
||||||
|
}
|
||||||
|
))
|
||||||
|
},
|
||||||
|
_ => Err(FCEError::IncorrectWIT(format!(
|
||||||
|
"type with idx = {} isn't a function type",
|
||||||
|
adapter_function_type
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Result<HashMap<String, WITModuleFunc>, FCEError>>()
|
||||||
}
|
}
|
||||||
|
|
||||||
// this function deals only with import functions that have an adaptor implementation
|
// this function deals only with import functions that have an adaptor implementation
|
||||||
fn adjust_imports(
|
fn adjust_wit_imports(
|
||||||
interfaces: &Interfaces<'_>,
|
wit: &FCEWITInterfaces<'_>,
|
||||||
wit_instance: Arc<MaybeUninit<WITInstance>>,
|
wit_instance: Arc<MaybeUninit<WITInstance>>,
|
||||||
) -> Result<ImportObject, FCEError> {
|
) -> Result<ImportObject, FCEError> {
|
||||||
use super::IAstType;
|
use fce_wit_interfaces::WITAstType;
|
||||||
use super::type_converters::{itype_to_wtype, wval_to_ival};
|
use super::type_converters::{itype_to_wtype, wval_to_ival};
|
||||||
use wasmer_core::typed_func::DynamicFunc;
|
use wasmer_core::typed_func::DynamicFunc;
|
||||||
use wasmer_core::types::FuncSig;
|
use wasmer_core::types::FuncSig;
|
||||||
use wasmer_core::vm::Ctx;
|
use wasmer_core::vm::Ctx;
|
||||||
|
|
||||||
// returns function that will be called from imports of Wasmer module
|
// returns function that will be called from imports of Wasmer module
|
||||||
fn dyn_func_from_imports<F>(inputs: Vec<IType>, func: F) -> DynamicFunc<'static>
|
fn dyn_func_from_imports(
|
||||||
where
|
inputs: Vec<IType>,
|
||||||
F: Fn(&mut Ctx, &[WValue]) -> Vec<WValue> + 'static,
|
func: Box<dyn Fn(&mut Ctx, &[WValue]) -> Vec<WValue> + 'static>,
|
||||||
{
|
) -> DynamicFunc<'static> {
|
||||||
let signature = inputs.iter().map(itype_to_wtype).collect::<Vec<_>>();
|
let signature = inputs.iter().map(itype_to_wtype).collect::<Vec<_>>();
|
||||||
DynamicFunc::new(Arc::new(FuncSig::new(signature, vec![])), func)
|
DynamicFunc::new(Arc::new(FuncSig::new(signature, vec![])), func)
|
||||||
}
|
}
|
||||||
|
|
||||||
// uses to filter out import functions that have an adapter implementation
|
fn create_raw_import(
|
||||||
let adapter_to_core = interfaces
|
wit_instance: Arc<MaybeUninit<WITInstance>>,
|
||||||
.implementations
|
interpreter: WITInterpreter,
|
||||||
.iter()
|
) -> Box<dyn for<'a, 'b> Fn(&'a mut Ctx, &'b [WValue]) -> Vec<WValue> + 'static> {
|
||||||
.map(|i| (i.adapter_function_type, i.core_function_type))
|
Box::new(move |_: &mut Ctx, inputs: &[WValue]| -> Vec<WValue> {
|
||||||
.collect::<HashMap<_, _>>();
|
// copy here because otherwise wit_instance will be consumed by the closure
|
||||||
|
let wit_instance_callable = wit_instance.clone();
|
||||||
|
let converted_inputs = inputs.iter().map(wval_to_ival).collect::<Vec<_>>();
|
||||||
|
unsafe {
|
||||||
|
// error here will be propagated by the special error instruction
|
||||||
|
let _ = interpreter.run(
|
||||||
|
&converted_inputs,
|
||||||
|
Arc::make_mut(&mut wit_instance_callable.assume_init()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// all wit imports
|
// wit import functions should only change the stack state -
|
||||||
let mut export_type_to_name = interfaces
|
// the result will be returned by an export function
|
||||||
.imports
|
vec![]
|
||||||
.iter()
|
|
||||||
.map(|import| {
|
|
||||||
(
|
|
||||||
import.function_type,
|
|
||||||
(import.namespace.to_string(), import.name.to_string()),
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
.collect::<HashMap<_, _>>();
|
|
||||||
|
|
||||||
let mut import_namespaces: HashMap<String, Namespace> = HashMap::new();
|
|
||||||
|
|
||||||
for adapter in interfaces.adapters.iter() {
|
|
||||||
let core_function_idx = adapter_to_core
|
|
||||||
.get(&adapter.function_type)
|
|
||||||
.ok_or_else(|| FCEError::NoSuchFunction(format!("function with idx = {} hasn't been found during adjusting imports in WIT implementation", adapter.function_type)))?;
|
|
||||||
|
|
||||||
let (namespace, func_name) = match export_type_to_name.remove(core_function_idx) {
|
|
||||||
Some(v) => (v.0, v.1),
|
|
||||||
None => continue,
|
|
||||||
};
|
|
||||||
|
|
||||||
if adapter.function_type >= interfaces.types.len() as u32 {
|
|
||||||
// TODO: change error type
|
|
||||||
return Err(FCEError::NoSuchFunction(format!(
|
|
||||||
"{} function id is bigger than WIT interface types count",
|
|
||||||
adapter.function_type
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
|
|
||||||
if let IAstType::Function { inputs, .. } =
|
|
||||||
&interfaces.types[adapter.function_type as usize]
|
|
||||||
{
|
|
||||||
let instructions = &adapter.instructions;
|
|
||||||
let interpreter: WITInterpreter = instructions.try_into().unwrap();
|
|
||||||
|
|
||||||
let wit_instance = wit_instance.clone();
|
|
||||||
let wit_inner_import =
|
|
||||||
Box::new(move |_: &mut Ctx, inputs: &[WValue]| -> Vec<WValue> {
|
|
||||||
// copy here to because otherwise wit_instance will be consumed by the closure
|
|
||||||
let wit_instance_callable = wit_instance.clone();
|
|
||||||
let converted_inputs = inputs.iter().map(wval_to_ival).collect::<Vec<_>>();
|
|
||||||
unsafe {
|
|
||||||
// error here will be propagated by the special error instruction
|
|
||||||
let _ = interpreter.run(
|
|
||||||
&converted_inputs,
|
|
||||||
Arc::make_mut(&mut wit_instance_callable.assume_init()),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// wit import functions should only change the stack state -
|
|
||||||
// the result will be returned by an export function
|
|
||||||
vec![]
|
|
||||||
});
|
|
||||||
|
|
||||||
let wit_import = dyn_func_from_imports(inputs.clone(), wit_inner_import);
|
|
||||||
|
|
||||||
// TODO: refactor this
|
|
||||||
let mut module_namespace = Namespace::new();
|
|
||||||
module_namespace.insert(func_name.clone(), wit_import);
|
|
||||||
|
|
||||||
import_namespaces.insert(namespace, module_namespace);
|
|
||||||
} else {
|
|
||||||
// TODO: change error type
|
|
||||||
return Err(FCEError::WasmerResolveError(format!(
|
|
||||||
"WIT type with idx = {} doesn't refer to function",
|
|
||||||
adapter.function_type
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let namespaces = wit
|
||||||
|
.implementations()
|
||||||
|
.filter_map(|(adapter_function_type, core_function_type)|
|
||||||
|
match wit.import_by_type(*core_function_type) {
|
||||||
|
Some(import) => Some((adapter_function_type, *import)),
|
||||||
|
// pass functions that aren't export
|
||||||
|
None => None
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.map(|(adapter_function_type, (import_namespace, import_name))| {
|
||||||
|
let adapter_instructions = wit.adapter_by_type(*adapter_function_type)
|
||||||
|
.ok_or_else(|| FCEError::IncorrectWIT(
|
||||||
|
format!("adapter function with idx = {} hasn't been found during extracting adjusting wit imports", adapter_function_type)
|
||||||
|
))?;
|
||||||
|
|
||||||
|
let wit_type = wit.type_by_idx(*adapter_function_type).ok_or_else(
|
||||||
|
|| FCEError::IncorrectWIT(format!(
|
||||||
|
"{} function id is bigger than WIT interface types count",
|
||||||
|
adapter_function_type
|
||||||
|
)))?;
|
||||||
|
|
||||||
|
match wit_type {
|
||||||
|
WITAstType::Function { inputs, .. } => {
|
||||||
|
let interpreter: WITInterpreter = adapter_instructions.try_into().map_err(|_| FCEError::IncorrectWIT(
|
||||||
|
format!("failed to parse instructions for adapter type {}", adapter_function_type)
|
||||||
|
))?;
|
||||||
|
|
||||||
|
let inner_import = create_raw_import(wit_instance.clone(), interpreter);
|
||||||
|
let wit_import = dyn_func_from_imports(inputs.clone(), inner_import);
|
||||||
|
let mut namespace = Namespace::new();
|
||||||
|
namespace.insert(import_name, wit_import);
|
||||||
|
|
||||||
|
Ok((
|
||||||
|
import_namespace.to_string(),
|
||||||
|
namespace
|
||||||
|
))
|
||||||
|
},
|
||||||
|
_ => Err(FCEError::IncorrectWIT(format!(
|
||||||
|
"type with idx = {} isn't a function type",
|
||||||
|
adapter_function_type
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}).collect::<Result<HashMap<String, Namespace>, FCEError>>()?;
|
||||||
|
|
||||||
let mut import_object = ImportObject::new();
|
let mut import_object = ImportObject::new();
|
||||||
|
|
||||||
for (namespace_name, namespace) in import_namespaces.into_iter() {
|
for (namespace_name, namespace) in namespaces {
|
||||||
import_object.register(namespace_name, namespace);
|
import_object.register(namespace_name, namespace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +25,6 @@ pub(crate) use fce_module::FCEModule;
|
|||||||
|
|
||||||
pub use wasmer_wit::types::InterfaceType as IType;
|
pub use wasmer_wit::types::InterfaceType as IType;
|
||||||
pub use wasmer_wit::values::InterfaceValue as IValue;
|
pub use wasmer_wit::values::InterfaceValue as IValue;
|
||||||
pub(self) use wasmer_wit::ast::Type as IAstType;
|
|
||||||
pub(self) use wasmer_core::types::Type as WType;
|
pub(self) use wasmer_core::types::Type as WType;
|
||||||
pub(self) use wasmer_core::types::Value as WValue;
|
pub(self) use wasmer_core::types::Value as WValue;
|
||||||
|
|
||||||
|
@ -17,9 +17,9 @@
|
|||||||
use super::wit_prelude::*;
|
use super::wit_prelude::*;
|
||||||
use super::fce_module::FCEModule;
|
use super::fce_module::FCEModule;
|
||||||
|
|
||||||
|
use fce_wit_interfaces::FCEWITInterfaces;
|
||||||
use wasmer_wit::interpreter::wasm;
|
use wasmer_wit::interpreter::wasm;
|
||||||
use super::IAstType;
|
use fce_wit_interfaces::WITAstType;
|
||||||
use wasmer_wit::ast::Interfaces;
|
|
||||||
use wasmer_wit::interpreter::wasm::structures::{LocalImportIndex, TypedIndex};
|
use wasmer_wit::interpreter::wasm::structures::{LocalImportIndex, TypedIndex};
|
||||||
use wasmer_core::Instance as WasmerInstance;
|
use wasmer_core::Instance as WasmerInstance;
|
||||||
|
|
||||||
@ -36,11 +36,11 @@ pub(super) struct WITInstance {
|
|||||||
impl WITInstance {
|
impl WITInstance {
|
||||||
pub(super) fn new(
|
pub(super) fn new(
|
||||||
wasmer_instance: &WasmerInstance,
|
wasmer_instance: &WasmerInstance,
|
||||||
interfaces: &Interfaces<'_>,
|
wit: &FCEWITInterfaces<'_>,
|
||||||
modules: &HashMap<String, Arc<FCEModule>>,
|
modules: &HashMap<String, Arc<FCEModule>>,
|
||||||
) -> Result<Self, FCEError> {
|
) -> Result<Self, FCEError> {
|
||||||
let mut exports = Self::extract_raw_exports(&wasmer_instance, interfaces)?;
|
let mut exports = Self::extract_raw_exports(&wasmer_instance, wit)?;
|
||||||
let imports = Self::extract_imports(modules, interfaces, exports.len())?;
|
let imports = Self::extract_imports(modules, wit, exports.len())?;
|
||||||
let memories = Self::extract_memories(&wasmer_instance);
|
let memories = Self::extract_memories(&wasmer_instance);
|
||||||
|
|
||||||
exports.extend(imports);
|
exports.extend(imports);
|
||||||
@ -51,18 +51,16 @@ impl WITInstance {
|
|||||||
|
|
||||||
fn extract_raw_exports(
|
fn extract_raw_exports(
|
||||||
wasmer_instance: &WasmerInstance,
|
wasmer_instance: &WasmerInstance,
|
||||||
interfaces: &Interfaces<'_>,
|
wit: &FCEWITInterfaces<'_>,
|
||||||
) -> Result<HashMap<usize, WITFunction>, FCEError> {
|
) -> Result<HashMap<usize, WITFunction>, FCEError> {
|
||||||
use wasmer_core::DynFunc;
|
use wasmer_core::DynFunc;
|
||||||
|
|
||||||
let module_exports = &wasmer_instance.exports;
|
let module_exports = &wasmer_instance.exports;
|
||||||
|
|
||||||
interfaces
|
wit.exports()
|
||||||
.exports
|
|
||||||
.iter()
|
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(export_id, export)| {
|
.map(|(export_id, (_, export_name))| {
|
||||||
let export_func = module_exports.get(export.name)?;
|
let export_func = module_exports.get(*export_name)?;
|
||||||
unsafe {
|
unsafe {
|
||||||
// TODO: refactor this with new Wasmer API when it is ready
|
// TODO: refactor this with new Wasmer API when it is ready
|
||||||
// here it is safe because dyn func is never lives WITInstance
|
// here it is safe because dyn func is never lives WITInstance
|
||||||
@ -77,34 +75,26 @@ impl WITInstance {
|
|||||||
/// Extracts only those imports that don't have implementations.
|
/// Extracts only those imports that don't have implementations.
|
||||||
fn extract_imports(
|
fn extract_imports(
|
||||||
modules: &HashMap<String, Arc<FCEModule>>,
|
modules: &HashMap<String, Arc<FCEModule>>,
|
||||||
interfaces: &Interfaces<'_>,
|
wit: &FCEWITInterfaces<'_>,
|
||||||
start_index: usize,
|
start_index: usize,
|
||||||
) -> Result<HashMap<usize, WITFunction>, FCEError> {
|
) -> Result<HashMap<usize, WITFunction>, FCEError> {
|
||||||
// uses to filter import functions that have an adapter implementation
|
wit.imports()
|
||||||
let core_to_adapter = interfaces
|
.filter(|(core_function_type, _)| {
|
||||||
.implementations
|
// filter out imports that have implementations
|
||||||
.iter()
|
matches!(wit.adapter_by_type(**core_function_type), None)
|
||||||
.map(|i| (i.core_function_type, i.adapter_function_type))
|
})
|
||||||
.collect::<HashMap<u32, u32>>();
|
.enumerate()
|
||||||
|
.map(|(idx, (_, (import_namespace, import_name)))| {
|
||||||
let mut non_wit_callable_imports = HashMap::new();
|
match modules.get(*import_namespace) {
|
||||||
|
Some(module) => {
|
||||||
for import in interfaces.imports.iter() {
|
let func =
|
||||||
if core_to_adapter.get(&import.function_type).is_some() {
|
WITFunction::from_import(module.clone(), import_name.to_string())?;
|
||||||
continue;
|
Ok((start_index + idx as usize, func))
|
||||||
}
|
}
|
||||||
|
None => Err(FCEError::NoSuchModule),
|
||||||
match modules.get(import.namespace) {
|
|
||||||
Some(module) => {
|
|
||||||
let func = WITFunction::from_import(module.clone(), import.name.to_string())?;
|
|
||||||
non_wit_callable_imports
|
|
||||||
.insert(start_index + non_wit_callable_imports.len() as usize, func);
|
|
||||||
}
|
}
|
||||||
None => return Err(FCEError::NoSuchModule),
|
})
|
||||||
}
|
.collect::<Result<HashMap<_, _>, _>>()
|
||||||
}
|
|
||||||
|
|
||||||
Ok(non_wit_callable_imports)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_memories(wasmer_instance: &WasmerInstance) -> Vec<WITMemory> {
|
fn extract_memories(wasmer_instance: &WasmerInstance) -> Vec<WITMemory> {
|
||||||
@ -152,7 +142,7 @@ impl wasm::structures::Instance<WITExport, WITFunction, WITMemory, WITMemoryView
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wit_type(&self, _index: u32) -> Option<&IAstType> {
|
fn wit_type(&self, _index: u32) -> Option<&WITAstType> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user