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]]
name = "anyhow"
version = "1.0.31"
version = "1.0.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85bb70cc08ec97ca5450e6eba421deeea5f172c0fc61f78b5357b2a8e8be195f"
checksum = "6b602bfe940d21c130f3895acd65221e8a61270debe89d628b9cb4e3ccb8569b"
[[package]]
name = "arrayref"
@ -403,7 +403,7 @@ dependencies = [
"parity-wasm",
"pwasm-utils",
"serde",
"wasmer-interface-types",
"wasmer-interface-types 0.17.0 (git+http://github.com/fluencelabs/interface-types?branch=struct_support)",
"wasmer-runtime",
"wasmer-runtime-core",
"wasmer-wasi",
@ -415,7 +415,7 @@ name = "fce-wit-interfaces"
version = "0.1.0"
dependencies = [
"multimap",
"wasmer-interface-types",
"wasmer-interface-types 0.17.0 (git+https://github.com/fluencelabs/interface-types?branch=byte_array)",
]
[[package]]
@ -434,10 +434,18 @@ dependencies = [
[[package]]
name = "fluence"
version = "0.2.0"
source = "git+https://github.com/fluencelabs/rust-sdk#79a5896015659ddb1c20526c4aa142b8afae35ad"
source = "git+https://github.com/fluencelabs/rust-sdk#e589d52c7247462f194800f50595029d224a5e43"
dependencies = [
"fluence-sdk-macro",
"fluence-sdk-main",
"fluence-sdk-macro 0.2.0 (git+https://github.com/fluencelabs/rust-sdk)",
"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]]
@ -459,15 +467,29 @@ dependencies = [
[[package]]
name = "fluence-sdk-macro"
version = "0.2.0"
source = "git+https://github.com/fluencelabs/rust-sdk#79a5896015659ddb1c20526c4aa142b8afae35ad"
source = "git+https://github.com/fluencelabs/rust-sdk#e589d52c7247462f194800f50595029d224a5e43"
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]]
name = "fluence-sdk-main"
version = "0.2.0"
source = "git+https://github.com/fluencelabs/rust-sdk#79a5896015659ddb1c20526c4aa142b8afae35ad"
dependencies = [
"log",
]
@ -475,7 +497,19 @@ dependencies = [
[[package]]
name = "fluence-sdk-wit"
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 = [
"proc-macro2",
"quote",
@ -1010,6 +1044,12 @@ version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
[[package]]
name = "safe-transmute"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50b8b2cd387f744f69469aaed197954ba4c0ecdb31e02edf99b023e0df11178a"
[[package]]
name = "scopeguard"
version = "1.1.0"
@ -1107,9 +1147,9 @@ checksum = "502d53007c02d7605a05df1c1a73ee436952781653da5d0bf57ad608f66932c1"
[[package]]
name = "syn"
version = "1.0.34"
version = "1.0.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "936cae2873c940d92e697597c5eee105fb570cd5689c695806f672883653349b"
checksum = "fb7f4c519df8c117855e19dd8cc851e89eb746fe7a73f0157e0d95fdec5369b0"
dependencies = [
"proc-macro2",
"quote",
@ -1311,14 +1351,14 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
name = "wasm_greeting"
version = "0.1.0"
dependencies = [
"fluence",
"fluence 0.2.0 (git+https://github.com/fluencelabs/rust-sdk)",
]
[[package]]
name = "wasm_ipfs_node"
version = "0.1.0"
dependencies = [
"fluence",
"fluence 0.2.0 (git+https://github.com/fluencelabs/rust-sdk)",
"log",
]
@ -1326,7 +1366,7 @@ dependencies = [
name = "wasm_ipfs_rpc"
version = "0.1.0"
dependencies = [
"fluence",
"fluence 0.2.0",
"log",
]
@ -1384,13 +1424,25 @@ dependencies = [
[[package]]
name = "wasmer-interface-types"
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 = [
"nom",
"serde",
"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]]
name = "wasmer-runtime"
version = "0.17.0"
@ -1518,12 +1570,12 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
name = "wit-generator"
version = "0.1.0"
dependencies = [
"fluence-sdk-wit",
"fluence-sdk-wit 0.2.0 (git+https://github.com/fluencelabs/rust-sdk)",
"once_cell",
"serde",
"serde_json",
"walrus",
"wasmer-interface-types",
"wasmer-interface-types 0.17.0 (git+http://github.com/fluencelabs/interface-types?branch=struct_support)",
"wit-parser",
]
@ -1534,6 +1586,6 @@ dependencies = [
"anyhow",
"fce-wit-interfaces",
"walrus",
"wasmer-interface-types",
"wasmer-interface-types 0.17.0 (git+http://github.com/fluencelabs/interface-types?branch=struct_support)",
"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`
- `Config.toml`:
```
```rust
[[bin]]
name = "wasm_application"
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]`
```
```rust
use fluence::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
- To import other wasm modules to your project use similar code:
```
```rust
#[fce]
#[link(wasm_import_module = "wasm_curl.wasm")]
extern "C" {
@ -68,7 +68,7 @@ extern "C" {
- Create simple Rust project
- 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_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
Import example:
```
```rust
#[link(wasm_import_module = "host")]
extern "C" {
fn curl(args: String) -> String;
@ -112,7 +112,7 @@ Call binary with arguments: `curl("-vvv ya.ru")`
`mapped_dirs` - mapping between paths
Working with files as usual:
```
```rust
fs::write(PathBuf::from("/tmp/somefile"), vec!(1,2,3));
fs::read(...);
```

View File

@ -9,6 +9,6 @@ wit-parser = { path = "../wit-parser" }
walrus = "0.17.0"
fluence-sdk-wit = { git = "https://github.com/fluencelabs/rust-sdk" }
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_json = "1.0.56"

View File

@ -22,6 +22,9 @@ pub enum WITGeneratorError {
/// An error related to serde deserialization.
DeserializationError(SerdeDeserializationError),
/// Various errors related to records
CorruptedRecord(String),
/// Various errors occurred during the parsing/emitting a Wasm file.
IOError(String),
}
@ -36,6 +39,7 @@ impl std::fmt::Display for WITGeneratorError {
"Embedded by rust-sdk metadata could't be parsed by serde: {:?}",
err
),
WITGeneratorError::CorruptedRecord(err) => write!(f, "{:?}", 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 utils;
use fluence_sdk_wit::FCEAst;
use crate::Result;
use wasmer_wit::types::InterfaceType as IType;
use wasmer_wit::ast::Interfaces;
use wasmer_wit::interpreter::Instruction;
pub trait WITGenerator {
fn generate_wit<'a>(&'a self, interfaces: &mut Interfaces<'a>);
#[derive(PartialEq, Debug, Default)]
pub(crate) struct WITResolver<'a> {
pub(crate) types: std::collections::HashMap<String, u32>,
pub(crate) interfaces: Interfaces<'a>,
}
trait FnInstructionGenerator {
fn generate_instructions_for_input_type(&self, arg_id: u32) -> Vec<Instruction>;
fn generate_instructions_for_output_type(&self) -> Vec<Instruction>;
impl<'a> WITResolver<'a> {
pub(crate) fn get_record_type_id(&self, record_name: &str) -> Result<u32> {
match self.types.get(record_name) {
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 {
fn generate_instructions_for_input_type(&self, arg_id: u32) -> Vec<Instruction>;
fn generate_instructions_for_output_type(&self) -> Vec<Instruction>;
pub(crate) fn get_record_type(
&self,
record_name: &str,
) -> 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")
}
impl WITGenerator for FCEAst {
fn generate_wit<'a>(&'a self, interfaces: &mut Interfaces<'a>) {
match self {
FCEAst::Function(func) => func.generate_wit(interfaces),
FCEAst::ExternMod(extern_mod) => extern_mod.generate_wit(interfaces),
FCEAst::Record(record) => record.generate_wit(interfaces),
wasmer_wit::ast::Type::Record(record_type) => Ok(record_type.clone()),
},
None => Err(crate::errors::WITGeneratorError::CorruptedRecord(format!(
"Can't find record with name='{}', don't you forget to wrap it with #[fce]",
record_name
))),
}
}
}
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::Interfaces;
use super::FnInstructionGenerator;
use super::WITResolver;
use super::utils::ptype_to_itype;
use crate::default_export_api_config::*;
use crate::Result;
use fluence_sdk_wit::AstFunctionItem;
use fluence_sdk_wit::ParsedType;
use wasmer_wit::interpreter::Instruction;
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::Adapter;
@ -33,14 +33,15 @@ impl WITGenerator for AstFunctionItem {
.signature
.input_types
.iter()
.map(ptype_to_itype)
.collect::<Vec<_>>();
.map(|input_type| ptype_to_itype(input_type, wit_resolver))
.collect::<Result<Vec<_>>>()?;
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![],
};
let interfaces = &mut wit_resolver.interfaces;
interfaces.types.push(Type::Function {
inputs: inputs.clone(),
outputs: outputs.clone(),
@ -57,22 +58,27 @@ impl WITGenerator for AstFunctionItem {
function_type: export_idx,
});
let mut instructions: Vec<Instruction> = self
// TODO: rewrite with try_fold
let mut instructions = self
.signature
.input_types
.iter()
.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()
.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 {
function_index: export_function_index,
});
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![],
});
@ -81,20 +87,37 @@ impl WITGenerator for AstFunctionItem {
instructions,
};
interfaces.adapters.push(adapter);
wit_resolver.interfaces.adapters.push(adapter);
let implementation = wasmer_wit::ast::Implementation {
core_function_type: export_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 {
#[rustfmt::skip]
fn generate_instructions_for_input_type(&self, index: u32) -> Vec<Instruction> {
match self {
fn generate_instructions_for_input_type<'a>(&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::I32FromS8],
ParsedType::I16 => vec![Instruction::ArgumentGet { index }, Instruction::I32FromS16],
ParsedType::I32 => vec![Instruction::ArgumentGet { index }],
@ -119,13 +142,23 @@ impl FnInstructionGenerator for ParsedType {
Instruction::ArgumentGet { index },
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]
fn generate_instructions_for_output_type(&self) -> Vec<Instruction> {
match self {
fn generate_instructions_for_output_type<'a>(&self, wit_resolver: &mut WITResolver<'a>) -> Result<Vec<Instruction>> {
let instructions = match self {
ParsedType::Boolean => vec![],
ParsedType::I8 => vec![Instruction::S8FromI32],
ParsedType::I16 => vec![Instruction::S16FromI32],
ParsedType::I32 => vec![],
@ -152,7 +185,16 @@ impl FnInstructionGenerator for ParsedType {
Instruction::CallCore { function_index: GET_RESULT_SIZE_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::Interfaces;
use super::WITResolver;
use super::utils::ptype_to_itype;
use super::ForeignModInstructionGenerator;
use crate::default_export_api_config::*;
use crate::Result;
use fluence_sdk_wit::AstExternModItem;
use fluence_sdk_wit::AstExternFnItem;
@ -29,23 +29,25 @@ use crate::instructions_generator::utils::wtype_to_itype;
const HOST_NAMESPACE_NAME: &str = "host";
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
if self.namespace == HOST_NAMESPACE_NAME {
return;
return Ok(());
}
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>(
import: &'a AstExternFnItem,
namespace: &'a str,
interfaces: &mut Interfaces<'a>,
) {
wit_resolver: &mut WITResolver<'a>,
) -> Result<()> {
use wasmer_wit::ast::Type;
use wasmer_wit::ast::Adapter;
@ -53,14 +55,15 @@ fn generate_wit_for_import<'a>(
.signature
.input_types
.iter()
.map(ptype_to_itype)
.collect::<Vec<_>>();
.map(|input_type| ptype_to_itype(input_type, wit_resolver))
.collect::<Result<Vec<_>>>()?;
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![],
};
let interfaces = &mut wit_resolver.interfaces;
interfaces.types.push(Type::Function { inputs, outputs });
let raw_inputs = import
@ -116,19 +119,24 @@ fn generate_wit_for_import<'a>(
.input_types
.iter()
.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()
.collect();
// TODO: refactor
let import_function_index =
(interfaces.exports.len() + interfaces.imports.len() / 2 - 1) as u32;
let import_function_index = (wit_resolver.interfaces.exports.len()
+ wit_resolver.interfaces.imports.len() / 2
- 1) as u32;
instructions.push(Instruction::CallCore {
function_index: import_function_index,
});
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![],
});
@ -136,18 +144,39 @@ fn generate_wit_for_import<'a>(
function_type: adapter_idx,
instructions,
};
interfaces.adapters.push(adapter);
wit_resolver.interfaces.adapters.push(adapter);
let implementation = wasmer_wit::ast::Implementation {
core_function_type: raw_import_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 {
fn generate_instructions_for_input_type(&self, index: u32) -> Vec<Instruction> {
match self {
fn generate_instructions_for_input_type<'a>(
&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::I16 => vec![Instruction::ArgumentGet { index }, Instruction::S16FromI32],
ParsedType::I32 => vec![Instruction::ArgumentGet { index }],
@ -168,13 +197,23 @@ impl ForeignModInstructionGenerator for ParsedType {
Instruction::ArgumentGet { index: index + 1 },
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]
fn generate_instructions_for_output_type(&self) -> Vec<Instruction> {
match self {
fn generate_instructions_for_output_type<'a>(&self, wit_resolver: &mut WITResolver<'a>) -> Result<Vec<Instruction>> {
let instructions = match self {
ParsedType::Boolean => vec![],
ParsedType::I8 => vec![Instruction::I32FromS8],
ParsedType::I16 => vec![Instruction::I32FromS16],
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_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::Interfaces;
use super::WITResolver;
use crate::Result;
use fluence_sdk_wit::AstRecordItem;
use wasmer_wit::ast::Type;
use wasmer_wit::types::RecordType;
use wasmer_wit::vec1::Vec1;
impl WITGenerator for AstRecordItem {
fn generate_wit<'a>(&'a self, _interfaces: &mut Interfaces<'a>) {
unimplemented!()
fn generate_wit<'a>(&'a self, wit_resolver: &mut WITResolver<'a>) -> Result<()> {
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 crate::instructions_generator::WITResolver;
use crate::Result;
use fluence_sdk_wit::ParsedType;
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 {
ParsedType::I8 => IType::S8,
ParsedType::I16 => IType::S16,
ParsedType::I32 => IType::S32,
ParsedType::I64 => IType::S64,
ParsedType::U8 => IType::U8,
ParsedType::U16 => IType::U16,
ParsedType::U32 => IType::U32,
ParsedType::U64 => IType::U64,
ParsedType::F32 => IType::F32,
ParsedType::F64 => IType::F64,
ParsedType::Boolean => IType::I32,
ParsedType::Utf8String => IType::String,
ParsedType::ByteVector => IType::ByteArray,
ParsedType::Record(_) => unimplemented!(),
ParsedType::I8 => Ok(IType::S8),
ParsedType::I16 => Ok(IType::S16),
ParsedType::I32 => Ok(IType::S32),
ParsedType::I64 => Ok(IType::S64),
ParsedType::U8 => Ok(IType::U8),
ParsedType::U16 => Ok(IType::U16),
ParsedType::U32 => Ok(IType::U32),
ParsedType::U64 => Ok(IType::U64),
ParsedType::F32 => Ok(IType::F32),
ParsedType::F64 => Ok(IType::F64),
ParsedType::Boolean => Ok(IType::I32),
ParsedType::Utf8String => Ok(IType::String),
ParsedType::ByteVector => Ok(IType::ByteArray),
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())
.map_err(|e| WITGeneratorError::IOError(format!("{:?} can't be parsed: {:?}", path, e)))?;
let ast_set = wasm_ast_extractor(&wasm_module)?;
let interfaces = generate_interfaces(&ast_set);
let module_ast = wasm_ast_extractor(&wasm_module)?;
let interfaces = generate_interfaces(&module_ast)?;
let wasm_module = wit_parser::delete_wit_section(wasm_module);
let mut wasm_module = wit_parser::embed_wit(wasm_module, &interfaces);
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.
fn wasm_ast_extractor(wasm_module: &walrus::Module) -> Result<Vec<fluence_sdk_wit::FCEAst>> {
let mut extracted_ast = Vec::new();
fn wasm_ast_extractor(wasm_module: &walrus::Module) -> Result<ModuleAST> {
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
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 raw_data = custom_module.1.data(&default_ids);
let decoded_json: fluence_sdk_wit::FCEAst = serde_json::from_slice(&raw_data)?;
extracted_ast.push(decoded_json);
let decoded_json: FCEAst = serde_json::from_slice(&raw_data)?;
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<'_> {
let mut interfaces = Interfaces::default();
generate_default_export_api(&mut interfaces);
fn generate_interfaces(module_ast: &ModuleAST) -> Result<Interfaces<'_>> {
let mut wit_resolver = crate::instructions_generator::WITResolver::default();
generate_default_export_api(&mut wit_resolver.interfaces);
for ast in ast_set {
ast.generate_wit(&mut interfaces);
for record in &module_ast.records {
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) {

View File

@ -11,7 +11,7 @@ path = "src/lib.rs"
[dependencies]
walrus = "0.17.0"
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" }
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" }
# 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-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" }
serde = { version = "1.0.114", default-features = false, features = [ "derive" ] }

View File

@ -9,5 +9,5 @@ name = "ipfs_rpc"
path = "src/main.rs"
[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"

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]
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()
}