add complex type support

This commit is contained in:
vms
2020-07-26 19:38:11 +03:00
parent fa3ae391ec
commit 3c5dcd1e78
15 changed files with 555 additions and 129 deletions

92
Cargo.lock generated
View File

@ -35,9 +35,9 @@ dependencies = [
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.31" version = "1.0.32"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85bb70cc08ec97ca5450e6eba421deeea5f172c0fc61f78b5357b2a8e8be195f" checksum = "6b602bfe940d21c130f3895acd65221e8a61270debe89d628b9cb4e3ccb8569b"
[[package]] [[package]]
name = "arrayref" name = "arrayref"
@ -403,7 +403,7 @@ dependencies = [
"parity-wasm", "parity-wasm",
"pwasm-utils", "pwasm-utils",
"serde", "serde",
"wasmer-interface-types", "wasmer-interface-types 0.17.0 (git+http://github.com/fluencelabs/interface-types?branch=struct_support)",
"wasmer-runtime", "wasmer-runtime",
"wasmer-runtime-core", "wasmer-runtime-core",
"wasmer-wasi", "wasmer-wasi",
@ -415,7 +415,7 @@ name = "fce-wit-interfaces"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"multimap", "multimap",
"wasmer-interface-types", "wasmer-interface-types 0.17.0 (git+https://github.com/fluencelabs/interface-types?branch=byte_array)",
] ]
[[package]] [[package]]
@ -434,10 +434,18 @@ dependencies = [
[[package]] [[package]]
name = "fluence" name = "fluence"
version = "0.2.0" version = "0.2.0"
source = "git+https://github.com/fluencelabs/rust-sdk#79a5896015659ddb1c20526c4aa142b8afae35ad" source = "git+https://github.com/fluencelabs/rust-sdk#e589d52c7247462f194800f50595029d224a5e43"
dependencies = [ dependencies = [
"fluence-sdk-macro", "fluence-sdk-macro 0.2.0 (git+https://github.com/fluencelabs/rust-sdk)",
"fluence-sdk-main", "fluence-sdk-main 0.2.0 (git+https://github.com/fluencelabs/rust-sdk)",
]
[[package]]
name = "fluence"
version = "0.2.0"
dependencies = [
"fluence-sdk-macro 0.2.0",
"fluence-sdk-main 0.2.0",
] ]
[[package]] [[package]]
@ -459,15 +467,29 @@ dependencies = [
[[package]] [[package]]
name = "fluence-sdk-macro" name = "fluence-sdk-macro"
version = "0.2.0" version = "0.2.0"
source = "git+https://github.com/fluencelabs/rust-sdk#79a5896015659ddb1c20526c4aa142b8afae35ad" source = "git+https://github.com/fluencelabs/rust-sdk#e589d52c7247462f194800f50595029d224a5e43"
dependencies = [ dependencies = [
"fluence-sdk-wit", "fluence-sdk-wit 0.2.0 (git+https://github.com/fluencelabs/rust-sdk)",
]
[[package]]
name = "fluence-sdk-macro"
version = "0.2.0"
dependencies = [
"fluence-sdk-wit 0.2.0",
]
[[package]]
name = "fluence-sdk-main"
version = "0.2.0"
source = "git+https://github.com/fluencelabs/rust-sdk#e589d52c7247462f194800f50595029d224a5e43"
dependencies = [
"log",
] ]
[[package]] [[package]]
name = "fluence-sdk-main" name = "fluence-sdk-main"
version = "0.2.0" version = "0.2.0"
source = "git+https://github.com/fluencelabs/rust-sdk#79a5896015659ddb1c20526c4aa142b8afae35ad"
dependencies = [ dependencies = [
"log", "log",
] ]
@ -475,7 +497,19 @@ dependencies = [
[[package]] [[package]]
name = "fluence-sdk-wit" name = "fluence-sdk-wit"
version = "0.2.0" version = "0.2.0"
source = "git+https://github.com/fluencelabs/rust-sdk#79a5896015659ddb1c20526c4aa142b8afae35ad" source = "git+https://github.com/fluencelabs/rust-sdk#e589d52c7247462f194800f50595029d224a5e43"
dependencies = [
"proc-macro2",
"quote",
"serde",
"serde_json",
"syn",
"uuid",
]
[[package]]
name = "fluence-sdk-wit"
version = "0.2.0"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -1010,6 +1044,12 @@ version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
[[package]]
name = "safe-transmute"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50b8b2cd387f744f69469aaed197954ba4c0ecdb31e02edf99b023e0df11178a"
[[package]] [[package]]
name = "scopeguard" name = "scopeguard"
version = "1.1.0" version = "1.1.0"
@ -1107,9 +1147,9 @@ checksum = "502d53007c02d7605a05df1c1a73ee436952781653da5d0bf57ad608f66932c1"
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.34" version = "1.0.35"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "936cae2873c940d92e697597c5eee105fb570cd5689c695806f672883653349b" checksum = "fb7f4c519df8c117855e19dd8cc851e89eb746fe7a73f0157e0d95fdec5369b0"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -1311,14 +1351,14 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
name = "wasm_greeting" name = "wasm_greeting"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"fluence", "fluence 0.2.0 (git+https://github.com/fluencelabs/rust-sdk)",
] ]
[[package]] [[package]]
name = "wasm_ipfs_node" name = "wasm_ipfs_node"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"fluence", "fluence 0.2.0 (git+https://github.com/fluencelabs/rust-sdk)",
"log", "log",
] ]
@ -1326,7 +1366,7 @@ dependencies = [
name = "wasm_ipfs_rpc" name = "wasm_ipfs_rpc"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"fluence", "fluence 0.2.0",
"log", "log",
] ]
@ -1384,13 +1424,25 @@ dependencies = [
[[package]] [[package]]
name = "wasmer-interface-types" name = "wasmer-interface-types"
version = "0.17.0" version = "0.17.0"
source = "git+https://github.com/fluencelabs/interface-types?branch=byte_array#b65b34b0f627b3da5cd5761fe309cefc4980449b" source = "git+https://github.com/fluencelabs/interface-types?branch=byte_array#4521e79a50e39dfa155d07e74ffc7d12203fa198"
dependencies = [ dependencies = [
"nom", "nom",
"serde", "serde",
"wast", "wast",
] ]
[[package]]
name = "wasmer-interface-types"
version = "0.17.0"
source = "git+http://github.com/fluencelabs/interface-types?branch=struct_support#053056c1eb5063b8aab480022301e4b5cd5baa81"
dependencies = [
"nom",
"safe-transmute",
"serde",
"serde_json",
"wast",
]
[[package]] [[package]]
name = "wasmer-runtime" name = "wasmer-runtime"
version = "0.17.0" version = "0.17.0"
@ -1518,12 +1570,12 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
name = "wit-generator" name = "wit-generator"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"fluence-sdk-wit", "fluence-sdk-wit 0.2.0 (git+https://github.com/fluencelabs/rust-sdk)",
"once_cell", "once_cell",
"serde", "serde",
"serde_json", "serde_json",
"walrus", "walrus",
"wasmer-interface-types", "wasmer-interface-types 0.17.0 (git+http://github.com/fluencelabs/interface-types?branch=struct_support)",
"wit-parser", "wit-parser",
] ]
@ -1534,6 +1586,6 @@ dependencies = [
"anyhow", "anyhow",
"fce-wit-interfaces", "fce-wit-interfaces",
"walrus", "walrus",
"wasmer-interface-types", "wasmer-interface-types 0.17.0 (git+http://github.com/fluencelabs/interface-types?branch=struct_support)",
"wasmer-runtime-core", "wasmer-runtime-core",
] ]

View File

@ -22,7 +22,7 @@ FCE is intended to run various Wasm binaries. At now, it is in the heavily devel
- Init simple rust project `cargo init --bin` - Init simple rust project `cargo init --bin`
- `Config.toml`: - `Config.toml`:
``` ```rust
[[bin]] [[bin]]
name = "wasm_application" name = "wasm_application"
path = "src/main.rs" path = "src/main.rs"
@ -33,7 +33,7 @@ fluence = { git = "https://github.com/fluencelabs/rust-sdk", features = ["logger
``` ```
- Methods that will be exported from this module marked with `#[fce]` - Methods that will be exported from this module marked with `#[fce]`
``` ```rust
use fluence::fce; use fluence::fce;
#[fce] #[fce]
@ -48,7 +48,7 @@ pub fn get(url: String) -> String {
- Copy wasm file from `target/wasm32-wasi/debug` to directory with other modules - Copy wasm file from `target/wasm32-wasi/debug` to directory with other modules
- To import other wasm modules to your project use similar code: - To import other wasm modules to your project use similar code:
``` ```rust
#[fce] #[fce]
#[link(wasm_import_module = "wasm_curl.wasm")] #[link(wasm_import_module = "wasm_curl.wasm")]
extern "C" { extern "C" {
@ -68,7 +68,7 @@ extern "C" {
- Create simple Rust project - Create simple Rust project
- Create `Config.toml` to describe existed wasm modules and give accesses to host binaries and local storage if needed: - Create `Config.toml` to describe existed wasm modules and give accesses to host binaries and local storage if needed:
``` ```rust
core_modules_dir = "wasm/artifacts/modules" core_modules_dir = "wasm/artifacts/modules"
[[core_module]] [[core_module]]
@ -97,7 +97,7 @@ core_modules_dir = "wasm/artifacts/modules"
`curl = "/usr/bin/curl"` - gives possibility to call binary file `/usr/bin/curl` as method `curl` in Rust code `curl = "/usr/bin/curl"` - gives possibility to call binary file `/usr/bin/curl` as method `curl` in Rust code
Import example: Import example:
``` ```rust
#[link(wasm_import_module = "host")] #[link(wasm_import_module = "host")]
extern "C" { extern "C" {
fn curl(args: String) -> String; fn curl(args: String) -> String;
@ -112,7 +112,7 @@ Call binary with arguments: `curl("-vvv ya.ru")`
`mapped_dirs` - mapping between paths `mapped_dirs` - mapping between paths
Working with files as usual: Working with files as usual:
``` ```rust
fs::write(PathBuf::from("/tmp/somefile"), vec!(1,2,3)); fs::write(PathBuf::from("/tmp/somefile"), vec!(1,2,3));
fs::read(...); fs::read(...);
``` ```

View File

@ -9,6 +9,6 @@ wit-parser = { path = "../wit-parser" }
walrus = "0.17.0" walrus = "0.17.0"
fluence-sdk-wit = { git = "https://github.com/fluencelabs/rust-sdk" } fluence-sdk-wit = { git = "https://github.com/fluencelabs/rust-sdk" }
once_cell = "1.4.0" once_cell = "1.4.0"
wasmer-wit = { package = "wasmer-interface-types", git = "http://github.com/fluencelabs/interface-types", branch = "byte_array", features = ["serde"] } wasmer-wit = { package = "wasmer-interface-types", git = "http://github.com/fluencelabs/interface-types", branch = "struct_support", features = ["serde"] }
serde = { version = "1.0.110", features = ["derive"] } serde = { version = "1.0.110", features = ["derive"] }
serde_json = "1.0.56" serde_json = "1.0.56"

View File

@ -22,6 +22,9 @@ pub enum WITGeneratorError {
/// An error related to serde deserialization. /// An error related to serde deserialization.
DeserializationError(SerdeDeserializationError), DeserializationError(SerdeDeserializationError),
/// Various errors related to records
CorruptedRecord(String),
/// Various errors occurred during the parsing/emitting a Wasm file. /// Various errors occurred during the parsing/emitting a Wasm file.
IOError(String), IOError(String),
} }
@ -36,6 +39,7 @@ impl std::fmt::Display for WITGeneratorError {
"Embedded by rust-sdk metadata could't be parsed by serde: {:?}", "Embedded by rust-sdk metadata could't be parsed by serde: {:?}",
err err
), ),
WITGeneratorError::CorruptedRecord(err) => write!(f, "{:?}", err),
WITGeneratorError::IOError(err) => write!(f, "I/O error occurred: {:?}", err), WITGeneratorError::IOError(err) => write!(f, "I/O error occurred: {:?}", err),
} }
} }

View File

@ -19,34 +19,47 @@ mod foreign_mod_instructions;
mod record_instructions; mod record_instructions;
mod utils; mod utils;
use fluence_sdk_wit::FCEAst; use crate::Result;
use wasmer_wit::types::InterfaceType as IType; use wasmer_wit::types::InterfaceType as IType;
use wasmer_wit::ast::Interfaces; use wasmer_wit::ast::Interfaces;
use wasmer_wit::interpreter::Instruction;
pub trait WITGenerator { #[derive(PartialEq, Debug, Default)]
fn generate_wit<'a>(&'a self, interfaces: &mut Interfaces<'a>); pub(crate) struct WITResolver<'a> {
pub(crate) types: std::collections::HashMap<String, u32>,
pub(crate) interfaces: Interfaces<'a>,
} }
trait FnInstructionGenerator { impl<'a> WITResolver<'a> {
fn generate_instructions_for_input_type(&self, arg_id: u32) -> Vec<Instruction>; pub(crate) fn get_record_type_id(&self, record_name: &str) -> Result<u32> {
match self.types.get(record_name) {
fn generate_instructions_for_output_type(&self) -> Vec<Instruction>; Some(type_index) => Ok(*type_index),
None => Err(crate::errors::WITGeneratorError::CorruptedRecord(format!(
"Can't find record with name='{}', don't you forget to wrap it with #[fce]",
record_name
))),
}
} }
trait ForeignModInstructionGenerator { pub(crate) fn get_record_type(
fn generate_instructions_for_input_type(&self, arg_id: u32) -> Vec<Instruction>; &self,
record_name: &str,
fn generate_instructions_for_output_type(&self) -> Vec<Instruction>; ) -> Result<wasmer_wit::types::RecordType> {
match self.types.get(record_name) {
Some(type_index) => match &self.interfaces.types[*type_index as usize] {
wasmer_wit::ast::Type::Function { .. } => {
panic!("internal error inside WITResolver")
} }
wasmer_wit::ast::Type::Record(record_type) => Ok(record_type.clone()),
impl WITGenerator for FCEAst { },
fn generate_wit<'a>(&'a self, interfaces: &mut Interfaces<'a>) { None => Err(crate::errors::WITGeneratorError::CorruptedRecord(format!(
match self { "Can't find record with name='{}', don't you forget to wrap it with #[fce]",
FCEAst::Function(func) => func.generate_wit(interfaces), record_name
FCEAst::ExternMod(extern_mod) => extern_mod.generate_wit(interfaces), ))),
FCEAst::Record(record) => record.generate_wit(interfaces),
} }
} }
} }
pub(crate) trait WITGenerator {
fn generate_wit<'a>(&'a self, wit_resolver: &mut WITResolver<'a>) -> Result<()>;
}

View File

@ -15,17 +15,17 @@
*/ */
use super::WITGenerator; use super::WITGenerator;
use super::Interfaces; use super::WITResolver;
use super::FnInstructionGenerator;
use super::utils::ptype_to_itype; use super::utils::ptype_to_itype;
use crate::default_export_api_config::*; use crate::default_export_api_config::*;
use crate::Result;
use fluence_sdk_wit::AstFunctionItem; use fluence_sdk_wit::AstFunctionItem;
use fluence_sdk_wit::ParsedType; use fluence_sdk_wit::ParsedType;
use wasmer_wit::interpreter::Instruction; use wasmer_wit::interpreter::Instruction;
impl WITGenerator for AstFunctionItem { impl WITGenerator for AstFunctionItem {
fn generate_wit<'a>(&'a self, interfaces: &mut Interfaces<'a>) { fn generate_wit<'a>(&'a self, wit_resolver: &mut WITResolver<'a>) -> Result<()> {
use wasmer_wit::ast::Type; use wasmer_wit::ast::Type;
use wasmer_wit::ast::Adapter; use wasmer_wit::ast::Adapter;
@ -33,14 +33,15 @@ impl WITGenerator for AstFunctionItem {
.signature .signature
.input_types .input_types
.iter() .iter()
.map(ptype_to_itype) .map(|input_type| ptype_to_itype(input_type, wit_resolver))
.collect::<Vec<_>>(); .collect::<Result<Vec<_>>>()?;
let outputs = match self.signature.output_type { let outputs = match self.signature.output_type {
Some(ref output_type) => vec![ptype_to_itype(output_type)], Some(ref output_type) => vec![ptype_to_itype(output_type, wit_resolver)?],
None => vec![], None => vec![],
}; };
let interfaces = &mut wit_resolver.interfaces;
interfaces.types.push(Type::Function { interfaces.types.push(Type::Function {
inputs: inputs.clone(), inputs: inputs.clone(),
outputs: outputs.clone(), outputs: outputs.clone(),
@ -57,22 +58,27 @@ impl WITGenerator for AstFunctionItem {
function_type: export_idx, function_type: export_idx,
}); });
let mut instructions: Vec<Instruction> = self // TODO: rewrite with try_fold
let mut instructions = self
.signature .signature
.input_types .input_types
.iter() .iter()
.enumerate() .enumerate()
.map(|(id, input_type)| input_type.generate_instructions_for_input_type(id as _)) .map(|(id, input_type)| {
input_type.generate_instructions_for_input_type(id as _, wit_resolver)
})
.collect::<Result<Vec<_>>>()?
.into_iter()
.flatten() .flatten()
.collect(); .collect::<Vec<Instruction>>();
let export_function_index = (interfaces.exports.len() - 1) as u32; let export_function_index = (wit_resolver.interfaces.exports.len() - 1) as u32;
instructions.push(Instruction::CallCore { instructions.push(Instruction::CallCore {
function_index: export_function_index, function_index: export_function_index,
}); });
instructions.extend(match &self.signature.output_type { instructions.extend(match &self.signature.output_type {
Some(output_type) => output_type.generate_instructions_for_output_type(), Some(output_type) => output_type.generate_instructions_for_output_type(wit_resolver)?,
None => vec![], None => vec![],
}); });
@ -81,20 +87,37 @@ impl WITGenerator for AstFunctionItem {
instructions, instructions,
}; };
interfaces.adapters.push(adapter); wit_resolver.interfaces.adapters.push(adapter);
let implementation = wasmer_wit::ast::Implementation { let implementation = wasmer_wit::ast::Implementation {
core_function_type: export_idx, core_function_type: export_idx,
adapter_function_type: adapter_idx, adapter_function_type: adapter_idx,
}; };
interfaces.implementations.push(implementation); wit_resolver.interfaces.implementations.push(implementation);
Ok(())
} }
} }
/// Generate WIT instructions for a function.
trait FnInstructionGenerator {
fn generate_instructions_for_input_type<'a>(
&self,
arg_id: u32,
wit_resolver: &mut WITResolver<'a>,
) -> Result<Vec<Instruction>>;
fn generate_instructions_for_output_type<'a>(
&self,
wit_resolver: &mut WITResolver<'a>,
) -> Result<Vec<Instruction>>;
}
impl FnInstructionGenerator for ParsedType { impl FnInstructionGenerator for ParsedType {
#[rustfmt::skip] #[rustfmt::skip]
fn generate_instructions_for_input_type(&self, index: u32) -> Vec<Instruction> { fn generate_instructions_for_input_type<'a>(&self, index: u32, wit_resolver: &mut WITResolver<'a>) -> Result<Vec<Instruction>> {
match self { let instructions = match self {
ParsedType::Boolean => vec![Instruction::ArgumentGet { index }],
ParsedType::I8 => vec![Instruction::ArgumentGet { index }, Instruction::I32FromS8], ParsedType::I8 => vec![Instruction::ArgumentGet { index }, Instruction::I32FromS8],
ParsedType::I16 => vec![Instruction::ArgumentGet { index }, Instruction::I32FromS16], ParsedType::I16 => vec![Instruction::ArgumentGet { index }, Instruction::I32FromS16],
ParsedType::I32 => vec![Instruction::ArgumentGet { index }], ParsedType::I32 => vec![Instruction::ArgumentGet { index }],
@ -119,13 +142,23 @@ impl FnInstructionGenerator for ParsedType {
Instruction::ArgumentGet { index }, Instruction::ArgumentGet { index },
Instruction::ByteArrayLowerMemory, Instruction::ByteArrayLowerMemory,
], ],
_ => unimplemented!(), ParsedType::Record(record_name) => {
} let type_index = wit_resolver.get_record_type_id(record_name)?;
vec! [
Instruction::ArgumentGet { index },
Instruction::RecordLowerMemory { type_index },
]
},
};
Ok(instructions)
} }
#[rustfmt::skip] #[rustfmt::skip]
fn generate_instructions_for_output_type(&self) -> Vec<Instruction> { fn generate_instructions_for_output_type<'a>(&self, wit_resolver: &mut WITResolver<'a>) -> Result<Vec<Instruction>> {
match self { let instructions = match self {
ParsedType::Boolean => vec![],
ParsedType::I8 => vec![Instruction::S8FromI32], ParsedType::I8 => vec![Instruction::S8FromI32],
ParsedType::I16 => vec![Instruction::S16FromI32], ParsedType::I16 => vec![Instruction::S16FromI32],
ParsedType::I32 => vec![], ParsedType::I32 => vec![],
@ -152,7 +185,16 @@ impl FnInstructionGenerator for ParsedType {
Instruction::CallCore { function_index: GET_RESULT_SIZE_FUNC.id }, Instruction::CallCore { function_index: GET_RESULT_SIZE_FUNC.id },
Instruction::CallCore { function_index: DEALLOCATE_FUNC.id }, Instruction::CallCore { function_index: DEALLOCATE_FUNC.id },
], ],
_ => unimplemented!(), ParsedType::Record(record_name) => {
} let type_index = wit_resolver.get_record_type_id(record_name)?;
vec! [
Instruction::CallCore { function_index: GET_RESULT_PTR_FUNC.id },
Instruction::RecordLiftMemory { type_index },
]
},
};
Ok(instructions)
} }
} }

View File

@ -15,10 +15,10 @@
*/ */
use super::WITGenerator; use super::WITGenerator;
use super::Interfaces; use super::WITResolver;
use super::utils::ptype_to_itype; use super::utils::ptype_to_itype;
use super::ForeignModInstructionGenerator;
use crate::default_export_api_config::*; use crate::default_export_api_config::*;
use crate::Result;
use fluence_sdk_wit::AstExternModItem; use fluence_sdk_wit::AstExternModItem;
use fluence_sdk_wit::AstExternFnItem; use fluence_sdk_wit::AstExternFnItem;
@ -29,23 +29,25 @@ use crate::instructions_generator::utils::wtype_to_itype;
const HOST_NAMESPACE_NAME: &str = "host"; const HOST_NAMESPACE_NAME: &str = "host";
impl WITGenerator for AstExternModItem { impl WITGenerator for AstExternModItem {
fn generate_wit<'a>(&'a self, interfaces: &mut Interfaces<'a>) { fn generate_wit<'a>(&'a self, wit_resolver: &mut WITResolver<'a>) -> Result<()> {
// host imports should be left as is // host imports should be left as is
if self.namespace == HOST_NAMESPACE_NAME { if self.namespace == HOST_NAMESPACE_NAME {
return; return Ok(());
} }
for import in &self.imports { for import in &self.imports {
generate_wit_for_import(import, &self.namespace, interfaces); generate_wit_for_import(import, &self.namespace, wit_resolver)?;
} }
Ok(())
} }
} }
fn generate_wit_for_import<'a>( fn generate_wit_for_import<'a>(
import: &'a AstExternFnItem, import: &'a AstExternFnItem,
namespace: &'a str, namespace: &'a str,
interfaces: &mut Interfaces<'a>, wit_resolver: &mut WITResolver<'a>,
) { ) -> Result<()> {
use wasmer_wit::ast::Type; use wasmer_wit::ast::Type;
use wasmer_wit::ast::Adapter; use wasmer_wit::ast::Adapter;
@ -53,14 +55,15 @@ fn generate_wit_for_import<'a>(
.signature .signature
.input_types .input_types
.iter() .iter()
.map(ptype_to_itype) .map(|input_type| ptype_to_itype(input_type, wit_resolver))
.collect::<Vec<_>>(); .collect::<Result<Vec<_>>>()?;
let outputs = match import.signature.output_type { let outputs = match import.signature.output_type {
Some(ref output_type) => vec![ptype_to_itype(output_type)], Some(ref output_type) => vec![ptype_to_itype(output_type, wit_resolver)?],
None => vec![], None => vec![],
}; };
let interfaces = &mut wit_resolver.interfaces;
interfaces.types.push(Type::Function { inputs, outputs }); interfaces.types.push(Type::Function { inputs, outputs });
let raw_inputs = import let raw_inputs = import
@ -116,19 +119,24 @@ fn generate_wit_for_import<'a>(
.input_types .input_types
.iter() .iter()
.enumerate() .enumerate()
.map(|(id, input_type)| input_type.generate_instructions_for_input_type(id as _)) .map(|(id, input_type)| {
input_type.generate_instructions_for_input_type(id as _, wit_resolver)
})
.collect::<Result<Vec<_>>>()?
.into_iter()
.flatten() .flatten()
.collect(); .collect();
// TODO: refactor // TODO: refactor
let import_function_index = let import_function_index = (wit_resolver.interfaces.exports.len()
(interfaces.exports.len() + interfaces.imports.len() / 2 - 1) as u32; + wit_resolver.interfaces.imports.len() / 2
- 1) as u32;
instructions.push(Instruction::CallCore { instructions.push(Instruction::CallCore {
function_index: import_function_index, function_index: import_function_index,
}); });
instructions.extend(match &import.signature.output_type { instructions.extend(match &import.signature.output_type {
Some(output_type) => output_type.generate_instructions_for_output_type(), Some(output_type) => output_type.generate_instructions_for_output_type(wit_resolver)?,
None => vec![], None => vec![],
}); });
@ -136,18 +144,39 @@ fn generate_wit_for_import<'a>(
function_type: adapter_idx, function_type: adapter_idx,
instructions, instructions,
}; };
interfaces.adapters.push(adapter); wit_resolver.interfaces.adapters.push(adapter);
let implementation = wasmer_wit::ast::Implementation { let implementation = wasmer_wit::ast::Implementation {
core_function_type: raw_import_idx, core_function_type: raw_import_idx,
adapter_function_type: adapter_idx, adapter_function_type: adapter_idx,
}; };
interfaces.implementations.push(implementation); wit_resolver.interfaces.implementations.push(implementation);
Ok(())
}
/// Generate WIT instructions for a foreign mod.
trait ForeignModInstructionGenerator {
fn generate_instructions_for_input_type<'a>(
&self,
arg_id: u32,
wit_resolver: &mut WITResolver<'a>,
) -> Result<Vec<Instruction>>;
fn generate_instructions_for_output_type<'a>(
&self,
wit_resolver: &mut WITResolver<'a>,
) -> Result<Vec<Instruction>>;
} }
impl ForeignModInstructionGenerator for ParsedType { impl ForeignModInstructionGenerator for ParsedType {
fn generate_instructions_for_input_type(&self, index: u32) -> Vec<Instruction> { fn generate_instructions_for_input_type<'a>(
match self { &self,
index: u32,
wit_resolver: &mut WITResolver<'a>,
) -> Result<Vec<Instruction>> {
let instructions = match self {
ParsedType::Boolean => vec![Instruction::ArgumentGet { index }],
ParsedType::I8 => vec![Instruction::ArgumentGet { index }, Instruction::S8FromI32], ParsedType::I8 => vec![Instruction::ArgumentGet { index }, Instruction::S8FromI32],
ParsedType::I16 => vec![Instruction::ArgumentGet { index }, Instruction::S16FromI32], ParsedType::I16 => vec![Instruction::ArgumentGet { index }, Instruction::S16FromI32],
ParsedType::I32 => vec![Instruction::ArgumentGet { index }], ParsedType::I32 => vec![Instruction::ArgumentGet { index }],
@ -168,13 +197,23 @@ impl ForeignModInstructionGenerator for ParsedType {
Instruction::ArgumentGet { index: index + 1 }, Instruction::ArgumentGet { index: index + 1 },
Instruction::StringLiftMemory, Instruction::StringLiftMemory,
], ],
_ => unimplemented!(), ParsedType::Record(record_name) => {
let type_index = wit_resolver.get_record_type_id(record_name)?;
vec![
Instruction::ArgumentGet { index },
Instruction::RecordLiftMemory { type_index },
]
} }
};
Ok(instructions)
} }
#[rustfmt::skip] #[rustfmt::skip]
fn generate_instructions_for_output_type(&self) -> Vec<Instruction> { fn generate_instructions_for_output_type<'a>(&self, wit_resolver: &mut WITResolver<'a>) -> Result<Vec<Instruction>> {
match self { let instructions = match self {
ParsedType::Boolean => vec![],
ParsedType::I8 => vec![Instruction::I32FromS8], ParsedType::I8 => vec![Instruction::I32FromS8],
ParsedType::I16 => vec![Instruction::I32FromS16], ParsedType::I16 => vec![Instruction::I32FromS16],
ParsedType::I32 => vec![], ParsedType::I32 => vec![],
@ -203,8 +242,17 @@ impl ForeignModInstructionGenerator for ParsedType {
Instruction::CallCore { function_index: SET_RESULT_SIZE_FUNC.id }, Instruction::CallCore { function_index: SET_RESULT_SIZE_FUNC.id },
Instruction::CallCore { function_index: SET_RESULT_PTR_FUNC.id }, Instruction::CallCore { function_index: SET_RESULT_PTR_FUNC.id },
], ],
_ => unimplemented!(), ParsedType::Record(record_name) => {
} let type_index = wit_resolver.get_record_type_id(record_name)?;
vec![
Instruction::RecordLowerMemory {type_index},
Instruction::CallCore { function_index: SET_RESULT_SIZE_FUNC.id },
]
},
};
Ok(instructions)
} }
} }

View File

@ -15,12 +15,40 @@
*/ */
use super::WITGenerator; use super::WITGenerator;
use super::Interfaces; use super::WITResolver;
use crate::Result;
use fluence_sdk_wit::AstRecordItem; use fluence_sdk_wit::AstRecordItem;
use wasmer_wit::ast::Type;
use wasmer_wit::types::RecordType;
use wasmer_wit::vec1::Vec1;
impl WITGenerator for AstRecordItem { impl WITGenerator for AstRecordItem {
fn generate_wit<'a>(&'a self, _interfaces: &mut Interfaces<'a>) { fn generate_wit<'a>(&'a self, wit_resolver: &mut WITResolver<'a>) -> Result<()> {
unimplemented!() let fields = self
.fields
.iter()
.map(|field| super::utils::ptype_to_itype(&field.ty, wit_resolver))
.collect::<Result<Vec<_>>>()?;
let fields = Vec1::new(fields).map_err(|_| {
crate::errors::WITGeneratorError::CorruptedRecord(format!(
"serialized record with name '{}' contains no fields",
self.name
))
})?;
wit_resolver
.interfaces
.types
.push(Type::Record(RecordType { fields }));
wit_resolver.types.insert(
self.name.clone(),
(wit_resolver.interfaces.types.len() - 1) as _,
);
Ok(())
} }
} }

View File

@ -15,25 +15,30 @@
*/ */
use super::IType; use super::IType;
use crate::instructions_generator::WITResolver;
use crate::Result;
use fluence_sdk_wit::ParsedType; use fluence_sdk_wit::ParsedType;
use fluence_sdk_wit::WasmType; use fluence_sdk_wit::WasmType;
pub(crate) fn ptype_to_itype(pty: &ParsedType) -> IType { pub(crate) fn ptype_to_itype(pty: &ParsedType, wit_resolver: &WITResolver) -> Result<IType> {
match pty { match pty {
ParsedType::I8 => IType::S8, ParsedType::I8 => Ok(IType::S8),
ParsedType::I16 => IType::S16, ParsedType::I16 => Ok(IType::S16),
ParsedType::I32 => IType::S32, ParsedType::I32 => Ok(IType::S32),
ParsedType::I64 => IType::S64, ParsedType::I64 => Ok(IType::S64),
ParsedType::U8 => IType::U8, ParsedType::U8 => Ok(IType::U8),
ParsedType::U16 => IType::U16, ParsedType::U16 => Ok(IType::U16),
ParsedType::U32 => IType::U32, ParsedType::U32 => Ok(IType::U32),
ParsedType::U64 => IType::U64, ParsedType::U64 => Ok(IType::U64),
ParsedType::F32 => IType::F32, ParsedType::F32 => Ok(IType::F32),
ParsedType::F64 => IType::F64, ParsedType::F64 => Ok(IType::F64),
ParsedType::Boolean => IType::I32, ParsedType::Boolean => Ok(IType::I32),
ParsedType::Utf8String => IType::String, ParsedType::Utf8String => Ok(IType::String),
ParsedType::ByteVector => IType::ByteArray, ParsedType::ByteVector => Ok(IType::ByteArray),
ParsedType::Record(_) => unimplemented!(), ParsedType::Record(record_name) => {
Ok(IType::Record(wit_resolver.get_record_type(record_name)?))
}
} }
} }

View File

@ -28,20 +28,30 @@ pub fn embed_wit(path: std::path::PathBuf) -> Result<()> {
.parse_file(path.clone()) .parse_file(path.clone())
.map_err(|e| WITGeneratorError::IOError(format!("{:?} can't be parsed: {:?}", path, e)))?; .map_err(|e| WITGeneratorError::IOError(format!("{:?} can't be parsed: {:?}", path, e)))?;
let ast_set = wasm_ast_extractor(&wasm_module)?; let module_ast = wasm_ast_extractor(&wasm_module)?;
let interfaces = generate_interfaces(&ast_set); let interfaces = generate_interfaces(&module_ast)?;
let wasm_module = wit_parser::delete_wit_section(wasm_module); let wasm_module = wit_parser::delete_wit_section(wasm_module);
let mut wasm_module = wit_parser::embed_wit(wasm_module, &interfaces); let mut wasm_module = wit_parser::embed_wit(wasm_module, &interfaces);
wasm_module.emit_wasm_file(path).map_err(|e| { wasm_module.emit_wasm_file(path).map_err(|e| {
WITGeneratorError::IOError(format!("resulted Wasm fule can't be emitted: {:?}", e)) WITGeneratorError::IOError(format!("resulted Wasm file can't be emitted: {:?}", e))
}) })
} }
pub(crate) struct ModuleAST {
pub(crate) records: Vec<fluence_sdk_wit::AstRecordItem>,
pub(crate) functions: Vec<fluence_sdk_wit::AstFunctionItem>,
pub(crate) extern_mods: Vec<fluence_sdk_wit::AstExternModItem>,
}
/// Extract all custom AST types previously embedded by rust-sdk from compiled binary. /// Extract all custom AST types previously embedded by rust-sdk from compiled binary.
fn wasm_ast_extractor(wasm_module: &walrus::Module) -> Result<Vec<fluence_sdk_wit::FCEAst>> { fn wasm_ast_extractor(wasm_module: &walrus::Module) -> Result<ModuleAST> {
let mut extracted_ast = Vec::new(); use fluence_sdk_wit::*;
let mut records: Vec<AstRecordItem> = Vec::new();
let mut functions: Vec<AstFunctionItem> = Vec::new();
let mut extern_mods: Vec<AstExternModItem> = Vec::new();
// consider only sections name of that starts with GENERATED_SECTION_PREFIX // consider only sections name of that starts with GENERATED_SECTION_PREFIX
for custom_module in wasm_module.customs.iter().filter(|(_, section)| { for custom_module in wasm_module.customs.iter().filter(|(_, section)| {
@ -51,22 +61,36 @@ fn wasm_ast_extractor(wasm_module: &walrus::Module) -> Result<Vec<fluence_sdk_wi
}) { }) {
let default_ids = walrus::IdsToIndices::default(); let default_ids = walrus::IdsToIndices::default();
let raw_data = custom_module.1.data(&default_ids); let raw_data = custom_module.1.data(&default_ids);
let decoded_json: fluence_sdk_wit::FCEAst = serde_json::from_slice(&raw_data)?; let decoded_json: FCEAst = serde_json::from_slice(&raw_data)?;
extracted_ast.push(decoded_json); match decoded_json {
FCEAst::Record(record) => records.push(record),
FCEAst::Function(function) => functions.push(function),
FCEAst::ExternMod(extern_mod) => extern_mods.push(extern_mod),
}
} }
Ok(extracted_ast) Ok(ModuleAST {
records,
functions,
extern_mods,
})
} }
fn generate_interfaces(ast_set: &[FCEAst]) -> Interfaces<'_> { fn generate_interfaces(module_ast: &ModuleAST) -> Result<Interfaces<'_>> {
let mut interfaces = Interfaces::default(); let mut wit_resolver = crate::instructions_generator::WITResolver::default();
generate_default_export_api(&mut interfaces); generate_default_export_api(&mut wit_resolver.interfaces);
for ast in ast_set { for record in &module_ast.records {
ast.generate_wit(&mut interfaces); record.generate_wit(&mut wit_resolver)?;
}
for function in &module_ast.functions {
function.generate_wit(&mut wit_resolver)?;
}
for extern_mod in &module_ast.extern_mods {
extern_mod.generate_wit(&mut wit_resolver)?;
} }
interfaces Ok(wit_resolver.interfaces)
} }
fn generate_default_export_api(interfaces: &mut Interfaces) { fn generate_default_export_api(interfaces: &mut Interfaces) {

View File

@ -11,7 +11,7 @@ path = "src/lib.rs"
[dependencies] [dependencies]
walrus = "0.17.0" walrus = "0.17.0"
wasmer-core = { package = "wasmer-runtime-core", git = "https://github.com/fluencelabs/wasmer", branch = "fluence" } wasmer-core = { package = "wasmer-runtime-core", git = "https://github.com/fluencelabs/wasmer", branch = "fluence" }
wasmer-wit = { package = "wasmer-interface-types", git = "https://github.com/fluencelabs/interface-types", branch = "byte_array" } wasmer-wit = { package = "wasmer-interface-types", git = "https://github.com/fluencelabs/interface-types", branch = "struct_support" }
fce-wit-interfaces = { path = "../fce-wit-interfaces" } fce-wit-interfaces = { path = "../fce-wit-interfaces" }
anyhow = "1.0.31" anyhow = "1.0.31"

View File

@ -11,7 +11,7 @@ wit-parser = { path = "../crates/wit-parser", version = "0.1.0" }
wasmer-runtime = { git = "https://github.com/fluencelabs/wasmer", branch = "fluence" } wasmer-runtime = { git = "https://github.com/fluencelabs/wasmer", branch = "fluence" }
# dynamicfunc-fat-closures allows using state inside DynamicFunc # dynamicfunc-fat-closures allows using state inside DynamicFunc
wasmer-core = { package = "wasmer-runtime-core", git = "http://github.com/fluencelabs/wasmer", branch = "fluence", features = ["dynamicfunc-fat-closures"] } wasmer-core = { package = "wasmer-runtime-core", git = "http://github.com/fluencelabs/wasmer", branch = "fluence", features = ["dynamicfunc-fat-closures"] }
wasmer-wit = { package = "wasmer-interface-types", git = "http://github.com/fluencelabs/interface-types", branch = "byte_array", features = ["serde"] } wasmer-wit = { package = "wasmer-interface-types", git = "http://github.com/fluencelabs/interface-types", branch = "struct_support", features = ["serde"] }
wasmer-wasi = { git = "https://github.com/fluencelabs/wasmer", branch = "fluence" } wasmer-wasi = { git = "https://github.com/fluencelabs/wasmer", branch = "fluence" }
serde = { version = "1.0.114", default-features = false, features = [ "derive" ] } serde = { version = "1.0.114", default-features = false, features = [ "derive" ] }

View File

@ -9,5 +9,5 @@ name = "ipfs_rpc"
path = "src/main.rs" path = "src/main.rs"
[dependencies] [dependencies]
fluence = { git = "https://github.com/fluencelabs/rust-sdk", features = ["logger"] } fluence = { path = "/Users/mike/dev/work/fluence/wasm/rust-sdk", features = ["logger"] }
log = "0.4.11" log = "0.4.11"

View File

@ -0,0 +1,205 @@
#![feature(prelude_import)]
#[prelude_import]
use std::prelude::v1::*;
#[macro_use]
extern crate std;
use fluence::fce;
use fluence::WasmLogger;
use std::fs;
use std::path::PathBuf;
const RPC_TMP_FILEPATH: &str = "/tmp/ipfs_rpc_file";
pub fn main() {
WasmLogger::init_with_level(log::Level::Info).unwrap();
}
pub struct Asadasd {
pub a: i32,
}
#[cfg(target_arch = "wasm32")]
#[doc(hidden)]
#[allow(clippy::all)]
pub(crate) fn __fce_generated_record_serializer_Asadasd(record: Asadasd) -> i32 {
let mut raw_record = Vec::new();
raw_record.push(record.a as u64);
let raw_record_ptr = raw_record.as_ptr();
std::mem::forget(raw_record);
raw_record_ptr as _
}
#[cfg(target_arch = "wasm32")]
#[doc(hidden)]
#[allow(clippy::all)]
unsafe fn __fce_generated_record_deserializer_Asadasd(offset: i32, size: i32) -> Asadasd {
let raw_record: Vec<u64> = Vec::from_raw_parts(offset as _, size as _, size as _);
let field_0 = raw_record[0usize] as i32;
Asadasd { a: field_0 }
}
#[cfg(target_arch = "wasm32")]
#[doc(hidden)]
#[allow(clippy::all)]
#[link_section = "__fce_generated_section__Asadasd"]
pub static __fce_generated_static_global_Asadasd: [u8; 73usize] = {
*b"{\"ast_type\":\"Record\",\"name\":\"Asadasd\",\"fields\":[{\"name\":\"a\",\"ty\":\"I32\"}]}"
};
pub fn invoke(_a: Asadasd) -> String {
"IPFS_RPC wasm example, it allows to:\ninvoke\nput\nget".to_string()
}
#[export_name = "invoke"]
#[no_mangle]
#[doc(hidden)]
#[allow(clippy::all)]
pub unsafe fn __fce_generated_wrapper_func_invoke(arg_0: i32, arg_1: i32) {
let converted_arg_0 = __fce_generated_record_deserializer_Asadasd(arg_0, arg_1);
let result = invoke(converted_arg_0);
fluence::internal::set_result_ptr(result.as_ptr() as _);
fluence::internal::set_result_size(result.len() as _);
std::mem::forget(result);
}
#[cfg(target_arch = "wasm32")]
#[doc(hidden)]
#[allow(clippy::all)]
#[link_section = "__fce_generated_section__invoke"]
pub static __fce_generated_static_global_invoke: [u8; 117usize] = {
* b"{\"ast_type\":\"Function\",\"signature\":{\"name\":\"invoke\",\"input_types\":[{\"Record\":\"Asadasd\"}],\"output_type\":\"Utf8String\"}}"
};
pub fn put(file_content: Vec<u8>) -> String {
{
let lvl = ::log::Level::Info;
if lvl <= ::log::STATIC_MAX_LEVEL && lvl <= ::log::max_level() {
::log::__private_api_log(
::core::fmt::Arguments::new_v1(
&["put called with "],
&match (&file_content,) {
(arg0,) => [::core::fmt::ArgumentV1::new(arg0, ::core::fmt::Debug::fmt)],
},
),
lvl,
&(
"ipfs_rpc",
"ipfs_rpc",
"examples/ipfs_node/wasm/ipfs_rpc/src/main.rs",
41u32,
),
);
}
};
let rpc_tmp_filepath = RPC_TMP_FILEPATH.to_string();
let r = fs::write(PathBuf::from(rpc_tmp_filepath.clone()), file_content);
if let Err(e) = r {
return {
let res = ::alloc::fmt::format(::core::fmt::Arguments::new_v1(
&["file can\'t be written: "],
&match (&e,) {
(arg0,) => [::core::fmt::ArgumentV1::new(
arg0,
::core::fmt::Display::fmt,
)],
},
));
res
};
}
ipfs_put(rpc_tmp_filepath)
}
#[export_name = "put"]
#[no_mangle]
#[doc(hidden)]
#[allow(clippy::all)]
pub unsafe fn __fce_generated_wrapper_func_put(arg_0: i32, arg_1: i32) {
let converted_arg_0 = Vec::from_raw_parts(arg_0 as _, arg_1 as _, arg_1 as _);
let result = put(converted_arg_0);
fluence::internal::set_result_ptr(result.as_ptr() as _);
fluence::internal::set_result_size(result.len() as _);
std::mem::forget(result);
}
#[cfg(target_arch = "wasm32")]
#[doc(hidden)]
#[allow(clippy::all)]
#[link_section = "__fce_generated_section__put"]
pub static __fce_generated_static_global_put: [u8; 106usize] = {
* b"{\"ast_type\":\"Function\",\"signature\":{\"name\":\"put\",\"input_types\":[\"ByteVector\"],\"output_type\":\"Utf8String\"}}"
};
pub fn get(hash: String) -> Vec<u8> {
{
let lvl = ::log::Level::Info;
if lvl <= ::log::STATIC_MAX_LEVEL && lvl <= ::log::max_level() {
::log::__private_api_log(
::core::fmt::Arguments::new_v1(
&["get called with hash: "],
&match (&hash,) {
(arg0,) => [::core::fmt::ArgumentV1::new(
arg0,
::core::fmt::Display::fmt,
)],
},
),
lvl,
&(
"ipfs_rpc",
"ipfs_rpc",
"examples/ipfs_node/wasm/ipfs_rpc/src/main.rs",
55u32,
),
);
}
};
let file_path = ipfs_get(hash);
fs::read(file_path).unwrap_or_else(|_| b"error while reading file".to_vec())
}
#[export_name = "get"]
#[no_mangle]
#[doc(hidden)]
#[allow(clippy::all)]
pub unsafe fn __fce_generated_wrapper_func_get(arg_0: i32, arg_1: i32) {
let converted_arg_0 = String::from_raw_parts(arg_0 as _, arg_1 as _, arg_1 as _);
let result = get(converted_arg_0);
fluence::internal::set_result_ptr(result.as_ptr() as _);
fluence::internal::set_result_size(result.len() as _);
std::mem::forget(result);
}
#[cfg(target_arch = "wasm32")]
#[doc(hidden)]
#[allow(clippy::all)]
#[link_section = "__fce_generated_section__get"]
pub static __fce_generated_static_global_get: [u8; 106usize] = {
* b"{\"ast_type\":\"Function\",\"signature\":{\"name\":\"get\",\"input_types\":[\"Utf8String\"],\"output_type\":\"ByteVector\"}}"
};
#[link(wasm_import_module = "ipfs_node.wasm")]
#[cfg(target_arch = "wasm32")]
extern "C" {
#[link_name = "put"]
fn __fce_generated_wrapper_func__ipfs_put(arg_0: i32, arg_1: i32);
#[link_name = "get"]
fn __fce_generated_wrapper_func__ipfs_get(arg_0: i32, arg_1: i32);
}
#[cfg(target_arch = "wasm32")]
#[doc(hidden)]
#[allow(clippy::all)]
pub fn ipfs_put(arg_0: String) -> String {
unsafe {
let result = __fce_generated_wrapper_func__ipfs_put(arg_0.as_ptr() as _, arg_0.len() as _);
String::from_raw_parts(
fluence::internal::get_result_ptr() as _,
fluence::internal::get_result_size() as _,
fluence::internal::get_result_size() as _,
)
}
}
#[cfg(target_arch = "wasm32")]
#[doc(hidden)]
#[allow(clippy::all)]
pub fn ipfs_get(arg_0: String) -> String {
unsafe {
let result = __fce_generated_wrapper_func__ipfs_get(arg_0.as_ptr() as _, arg_0.len() as _);
String::from_raw_parts(
fluence::internal::get_result_ptr() as _,
fluence::internal::get_result_size() as _,
fluence::internal::get_result_size() as _,
)
}
}
#[cfg(target_arch = "wasm32")]
#[doc(hidden)]
#[allow(clippy::all)]
#[link_section = "__fce_generated_section__ipfs_node_wasm"]
pub static __fce_generated_static_global_ipfs_node_wasm: [u8; 281usize] = {
* b"{\"ast_type\":\"ExternMod\",\"namespace\":\"ipfs_node.wasm\",\"imports\":[{\"link_name\":\"put\",\"signature\":{\"name\":\"ipfs_put\",\"input_types\":[\"Utf8String\"],\"output_type\":\"Utf8String\"}},{\"link_name\":\"get\",\"signature\":{\"name\":\"ipfs_get\",\"input_types\":[\"Utf8String\"],\"output_type\":\"Utf8String\"}}]}"
};

View File

@ -27,7 +27,12 @@ pub fn main() {
} }
#[fce] #[fce]
pub fn invoke() -> String { pub struct Asadasd {
pub a: i32,
}
#[fce]
pub fn invoke(_a: Asadasd) -> String {
"IPFS_RPC wasm example, it allows to:\ninvoke\nput\nget".to_string() "IPFS_RPC wasm example, it allows to:\ninvoke\nput\nget".to_string()
} }