diff --git a/Cargo.lock b/Cargo.lock index 96579f55..27e5000d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -361,6 +361,16 @@ dependencies = [ "synstructure", ] +[[package]] +name = "fce_interface" +version = "0.1.0" +dependencies = [ + "anyhow", + "multimap", + "walrus", + "wasmer-interface-types", +] + [[package]] name = "gcc" version = "0.3.55" @@ -629,12 +639,6 @@ version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9cbca9424c482ee628fa549d9c812e2cd22f1180b9222c9200fdfa6eb31aecb2" -[[package]] -name = "options" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cae662c78308e9d468ee0548cd8852e66a9b4a945c16ddcc6eed3dd9ef14cb0" - [[package]] name = "page_size" version = "0.4.2" @@ -1201,10 +1205,8 @@ name = "wit_embedder" version = "0.1.0" dependencies = [ "clap", - "either", "exitfailure", "failure", - "options", "walrus", "wasmer-interface-types", ] diff --git a/Cargo.toml b/Cargo.toml index 9f443cf0..80be2fe3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,10 +1,11 @@ [workspace] members = [ - "fce", - "tools/wit_embedder", + "crates/fce_wit_interfaces", "examples/export_test", "examples/ipfs_node", "examples/ipfs_rpc", + "fce", + "tools/wit_embedder", ] [profile.release] diff --git a/crates/fce_wit_interfaces/Cargo.toml b/crates/fce_wit_interfaces/Cargo.toml new file mode 100644 index 00000000..6b0bfaad --- /dev/null +++ b/crates/fce_wit_interfaces/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "fce_interface" +version = "0.1.0" +authors = ["Fluence Labs"] +edition = "2018" + +[lib] +name = "fce_interface" +src = "src/lib.rs" + +[dependencies] +walrus = "0.17.0" +wasmer-wit = { package = "wasmer-interface-types", git = "https://github.com/fluencelabs/interface-types", branch = "master"} +multimap = "0.8.1" +anyhow = "1.0.31" \ No newline at end of file diff --git a/crates/fce_wit_interfaces/src/fce_wit_interfaces.rs b/crates/fce_wit_interfaces/src/fce_wit_interfaces.rs new file mode 100644 index 00000000..405bfe34 --- /dev/null +++ b/crates/fce_wit_interfaces/src/fce_wit_interfaces.rs @@ -0,0 +1,156 @@ +/* + * Copyright 2020 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use crate::types::*; + +use wasmer_wit::interpreter::Instruction; +use wasmer_wit::ast::*; +use multimap::MultiMap; + +use std::iter::Iterator; +use std::collections::HashMap; + +pub struct FCEWITInterfaces { + /// All the types. + types: Vec, + + /// All the imported functions. + imports: HashMap, + + /// All the adapters. + adapters: HashMap>, + + /// All the exported functions. + exports: HashMap, + + /// All the implementations. + adapter_type_to_core: MultiMap, + core_type_to_adapter: MultiMap, +} + +#[allow(unused)] +impl FCEWITInterfaces { + pub fn new(interfaces: Interfaces) -> Self { + let imports = interfaces + .imports + .into_iter() + .map(|import| { + ( + import.function_type, + (import.namespace.to_owned(), import.name.to_owned()), + ) + }) + .collect::>(); + + let adapters = interfaces + .adapters + .into_iter() + .map(|adapter| (adapter.function_type, adapter.instructions)) + .collect::>(); + + let exports = interfaces + .exports + .into_iter() + .map(|export| (export.function_type, export.name.to_owned())) + .collect::>(); + + let adapter_type_to_core = interfaces + .implementations + .iter() + .map(|implementation| { + ( + implementation.adapter_function_type, + implementation.core_function_type, + ) + }) + .collect::>(); + + let core_type_to_adapter = interfaces + .implementations + .iter() + .map(|implementation| { + ( + implementation.core_function_type, + implementation.adapter_function_type, + ) + }) + .collect::>(); + + Self { + types: interfaces.types, + imports, + adapters, + exports, + adapter_type_to_core, + core_type_to_adapter, + } + } + + pub fn type_by_idx(&self, idx: usize) -> Option<&Type> { + self.types.get(idx) + } + + pub fn types(&self) -> impl Iterator { + self.types.iter() + } + + pub fn import_by_type( + &self, + import_type: CoreFunctionType, + ) -> Option<&(ImportName, ImportNamespace)> { + self.imports.get(&import_type) + } + + pub fn imports( + &self, + ) -> impl Iterator { + self.imports.iter() + } + + pub fn adapter_by_type(&self, adapter_type: AdapterFunctionType) -> Option<&Vec> { + self.adapters.get(&adapter_type) + } + + pub fn export_by_type(&self, export_type: u32) -> Option<&ExportName> { + self.exports.get(&export_type) + } + + pub fn adapter_func_implementations( + &self, + ) -> impl Iterator { + self.adapter_type_to_core.iter() + } + + pub fn core_func_implementations( + &self, + ) -> impl Iterator { + self.core_type_to_adapter.iter() + } + + pub fn adapter_types_by_core_type( + &self, + core_function_type: CoreFunctionType, + ) -> Option<&Vec> { + self.adapter_type_to_core.get_vec(&core_function_type) + } + + pub fn core_types_by_adapter_type( + &self, + adapter_function_type: AdapterFunctionType, + ) -> Option<&Vec> { + self.core_type_to_adapter.get_vec(&adapter_function_type) + } +} diff --git a/crates/fce_wit_interfaces/src/lib.rs b/crates/fce_wit_interfaces/src/lib.rs new file mode 100644 index 00000000..18b69c02 --- /dev/null +++ b/crates/fce_wit_interfaces/src/lib.rs @@ -0,0 +1,28 @@ +/* + * Copyright 2020 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +mod fce_wit_interfaces; +mod wit_parser; + +pub use fce_wit_interfaces::FCEWITInterfaces; + +pub mod types { + pub type CoreFunctionType = u32; + pub type AdapterFunctionType = u32; + pub type ExportName = String; + pub type ImportName = String; + pub type ImportNamespace = String; +} diff --git a/crates/fce_wit_interfaces/src/wit_parser/custom.rs b/crates/fce_wit_interfaces/src/wit_parser/custom.rs new file mode 100644 index 00000000..db49aa08 --- /dev/null +++ b/crates/fce_wit_interfaces/src/wit_parser/custom.rs @@ -0,0 +1,33 @@ +/* + * Copyright 2020 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use std::borrow::Cow; +use walrus::{CustomSection, IdsToIndices}; + +pub const WIT_SECTION_NAME: &str = "interface-types"; + +#[derive(Debug, Clone)] +pub(crate) struct WITCustom(pub Vec); + +impl CustomSection for WITCustom { + fn name(&self) -> &str { + WIT_SECTION_NAME + } + + fn data(&self, _ids_to_indices: &IdsToIndices) -> Cow<[u8]> { + Cow::Borrowed(&self.0) + } +} diff --git a/crates/fce_wit_interfaces/src/wit_parser/embedder.rs b/crates/fce_wit_interfaces/src/wit_parser/embedder.rs new file mode 100644 index 00000000..556fe99d --- /dev/null +++ b/crates/fce_wit_interfaces/src/wit_parser/embedder.rs @@ -0,0 +1,52 @@ +/* + * Copyright 2020 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use super::custom::WITCustom; +use super::errors::WITParserError; + +use walrus::ModuleConfig; +use wasmer_wit::{ + decoders::wat::{parse, Buffer}, + encoders::binary::ToBytes, +}; + +use std::path::PathBuf; + +pub struct EmbedderConfig { + pub in_wasm_path: PathBuf, + pub out_wasm_path: PathBuf, + pub wit: String, +} + +pub fn embed_text_wit(options: &EmbedderConfig) -> Result<(), WITParserError> { + let mut module = ModuleConfig::new() + .parse_file(&options.in_wasm_path) + .map_err(WITParserError::CorruptedWasmFile)?; + + let buffer = Buffer::new(&options.wit)?; + let ast = parse(&buffer)?; + + let mut bytes = vec![]; + ast.to_bytes(&mut bytes)?; + + let custom = WITCustom(bytes); + module.customs.add(custom); + module + .emit_wasm_file(&options.out_wasm_path) + .map_err(WITParserError::WasmEmitError)?; + + Ok(()) +} diff --git a/crates/fce_wit_interfaces/src/wit_parser/errors.rs b/crates/fce_wit_interfaces/src/wit_parser/errors.rs new file mode 100644 index 00000000..38dcac5d --- /dev/null +++ b/crates/fce_wit_interfaces/src/wit_parser/errors.rs @@ -0,0 +1,87 @@ +/* + * Copyright 2020 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use wasmer_wit::decoders::wat::Error as WATError; +use std::io::Error as StdIOError; +use std::error::Error; + +#[derive(Debug)] +pub enum WITParserError { + /// WIT section is absent. + NoWITSection, + + /// Multiple WIT sections. + MultipleWITSections, + + /// WIT section remainder isn't empty. + WITRemainderNotEmpty, + + /// An error occurred while parsing WIT section. + CorruptedWITSection, + + /// An error occurred while parsing file in Wat format. + CorruptedWATFile(WATError), + + /// An error occurred while parsing Wasm file + CorruptedWasmFile(anyhow::Error), + + /// An error occurred while manipulating with converting ast to bytes. + AstToBytesError(StdIOError), + + // Wasm emittig file error. + WasmEmitError(anyhow::Error), +} + +impl Error for WITParserError {} + +impl std::fmt::Display for WITParserError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + match self { + WITParserError::NoWITSection => write!(f, "Loaded module doesn't contain WIT section"), + WITParserError::MultipleWITSections => write!( + f, + "Loaded module contains multiple WIT sections that is unsupported now" + ), + WITParserError::WITRemainderNotEmpty => write!( + f, + "WIT section remainder isn't empty - WIT section possibly corrupted" + ), + WITParserError::CorruptedWITSection => write!(f, "WIT section is corrupted"), + WITParserError::CorruptedWATFile(err) => { + write!(f, "an error occurred while parsing wat file: {}", err) + } + WITParserError::CorruptedWasmFile(err) => { + write!(f, "Failed to parse the Wasm module: {}", err) + } + WITParserError::AstToBytesError(err) => { + write!(f, "Wasm AST converting to bytes failed with: {}", err) + } + WITParserError::WasmEmitError(err) => write!(f, "Failed to emit Wasm file: {}", err), + } + } +} + +impl From for WITParserError { + fn from(err: WATError) -> Self { + WITParserError::CorruptedWATFile(err) + } +} + +impl From for WITParserError { + fn from(err: StdIOError) -> Self { + WITParserError::AstToBytesError(err) + } +} diff --git a/crates/fce_wit_interfaces/src/wit_parser/extracter.rs b/crates/fce_wit_interfaces/src/wit_parser/extracter.rs new file mode 100644 index 00000000..4a512f6a --- /dev/null +++ b/crates/fce_wit_interfaces/src/wit_parser/extracter.rs @@ -0,0 +1,89 @@ +/* + * Copyright 2020 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use super::custom::WIT_SECTION_NAME; +use super::errors::WITParserError; +use crate::fce_wit_interfaces::FCEWITInterfaces; + +use walrus::{IdsToIndices, Module, ModuleConfig}; +use wasmer_wit::ast::Interfaces; + +use std::path::PathBuf; + +pub fn extract_text_wit(wasm_file_path: PathBuf) -> Result { + extract_wit_with_fn( + wasm_file_path, + |wit: Interfaces| -> Result { Ok((&wit).to_string()) }, + ) +} + +pub fn extract_fce_wit(wasm_file_path: PathBuf) -> Result { + extract_wit_with_fn( + wasm_file_path, + |wit: Interfaces| -> Result { + Ok(FCEWITInterfaces::new(wit)) + }, + ) +} + +fn extract_wit_with_fn( + wasm_file_path: PathBuf, + func: F, +) -> Result +where + F: FnOnce(Interfaces) -> Result, +{ + let wit_section_bytes = extract_wit_section_bytes(wasm_file_path)?; + let raw_wit = extract_raw_interfaces(&wit_section_bytes)?; + + func(raw_wit) +} + +fn extract_raw_interfaces(wit_section_bytes: &[u8]) -> Result { + let wit = match wasmer_wit::decoders::binary::parse::<()>(&wit_section_bytes) { + Ok((remainder, wit)) if remainder.is_empty() => wit, + Ok(_) => { + return Err(WITParserError::WITRemainderNotEmpty); + } + Err(_) => { + return Err(WITParserError::CorruptedWITSection); + } + }; + + Ok(wit) +} + +fn extract_wit_section_bytes(wasm_file_path: PathBuf) -> Result, WITParserError> { + let module = ModuleConfig::new() + .parse_file(wasm_file_path) + .map_err(WITParserError::CorruptedWasmFile)?; + + let sections = module + .customs + .iter() + .filter(|(_, section)| section.name() == WIT_SECTION_NAME) + .collect::>(); + + if sections.is_empty() { + return Err(WITParserError::NoWITSection); + } + if sections.len() > 1 { + return Err(WITParserError::MultipleWITSections); + } + + let default_ids = IdsToIndices::default(); + Ok(sections[0].1.data(&default_ids).into_owned()) +} diff --git a/crates/fce_wit_interfaces/src/wit_parser/mod.rs b/crates/fce_wit_interfaces/src/wit_parser/mod.rs new file mode 100644 index 00000000..b8493fec --- /dev/null +++ b/crates/fce_wit_interfaces/src/wit_parser/mod.rs @@ -0,0 +1,6 @@ +mod custom; +mod errors; +mod extracter; +mod embedder; + +pub use errors::WITParserError; diff --git a/tools/wit_embedder/Cargo.toml b/tools/wit_embedder/Cargo.toml index 407593ef..d0cdcdd2 100644 --- a/tools/wit_embedder/Cargo.toml +++ b/tools/wit_embedder/Cargo.toml @@ -7,8 +7,6 @@ edition = "2018" [dependencies] walrus = "0.17.0" wasmer-wit = { package = "wasmer-interface-types", git = "https://github.com/fluencelabs/interface-types", branch = "master"} -options = "0.5.1" -either = "1.5.3" clap = "2.33.1" exitfailure = "0.5.1" failure = "0.1.5" diff --git a/tools/wit_embedder/src/custom.rs b/tools/wit_embedder/src/custom.rs index dd363452..aea94699 100644 --- a/tools/wit_embedder/src/custom.rs +++ b/tools/wit_embedder/src/custom.rs @@ -1,8 +1,22 @@ +/* + * Copyright 2020 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + use std::borrow::Cow; use walrus::{CustomSection, IdsToIndices}; -pub const WIT_SECTION_NAME: &str = "interface-types"; - #[derive(Debug, Clone)] pub(crate) struct WITCustom(pub Vec); diff --git a/tools/wit_embedder/src/embedder.rs b/tools/wit_embedder/src/embedder.rs index fa14ce9d..e850f985 100644 --- a/tools/wit_embedder/src/embedder.rs +++ b/tools/wit_embedder/src/embedder.rs @@ -1,3 +1,19 @@ +/* + * Copyright 2020 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + use crate::custom::WITCustom; use walrus::ModuleConfig; @@ -10,8 +26,8 @@ use std::path::PathBuf; pub struct Config { pub in_wasm_path: PathBuf, - pub wit: String, pub out_wasm_path: PathBuf, + pub wit: String, } pub fn embed_wit(options: &Config) -> Result<(), String> { diff --git a/tools/wit_embedder/src/extracter.rs b/tools/wit_embedder/src/extracter.rs index d8a4e073..7d0273f8 100644 --- a/tools/wit_embedder/src/extracter.rs +++ b/tools/wit_embedder/src/extracter.rs @@ -1,3 +1,19 @@ +/* + * Copyright 2020 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + use crate::custom::WIT_SECTION_NAME; use walrus::{IdsToIndices, ModuleConfig}; diff --git a/tools/wit_embedder/src/main.rs b/tools/wit_embedder/src/main.rs index 64d3e8fe..28e29a60 100644 --- a/tools/wit_embedder/src/main.rs +++ b/tools/wit_embedder/src/main.rs @@ -1,3 +1,19 @@ +/* + * Copyright 2020 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + mod custom; mod embedder; mod extracter;