This commit is contained in:
vms 2020-09-21 01:52:09 +03:00
parent 04e2538661
commit fe78083ecc
13 changed files with 362 additions and 92 deletions

View File

@ -19,6 +19,7 @@ path = "src/lib.rs"
[dependencies]
fluence-sdk-macro = { path = "crates/macro", version = "=0.2.3" }
fluence-sdk-main = { path = "crates/main", version = "=0.2.3" }
safe-transmute = "0.11.0"
[features]
# Print some internal logs by log_utf8_string

View File

@ -20,17 +20,20 @@ mod fn_prolog;
mod foreign_mod_arg;
mod foreign_mod_epilog;
mod foreign_mod_prolog;
mod vector_utils;
pub(crate) use fn_arg::*;
pub(crate) use fn_epilog::*;
pub(crate) use fn_prolog::*;
pub(crate) use foreign_mod_prolog::*;
pub(crate) use foreign_mod_epilog::*;
pub(crate) use vector_utils::*;
use serde::Serialize;
use serde::Deserialize;
use syn::parse::Error;
use syn::spanned::Spanned;
use proc_macro2::TokenStream;
/// An internal representation of supported Rust types.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
@ -47,15 +50,16 @@ pub enum ParsedType {
F64,
Boolean,
Utf8String,
ByteVector,
Vector(Box<ParsedType>),
Record(String), // short type name
}
impl ParsedType {
pub fn from_type(input_type: &syn::Type) -> syn::Result<Self> {
use quote::ToTokens;
// parses generic param T in Vec<T> to string representation
fn parse_vec_bracket(args: &syn::PathArguments) -> syn::Result<String> {
// parse generic param T in Vec<T> to syn::Type
fn parse_vec_bracket(args: &syn::PathArguments) -> syn::Result<&syn::Type> {
// checks that T is angle bracketed
let generic_arg = match args {
syn::PathArguments::AngleBracketed(args) => Ok(args),
@ -73,41 +77,13 @@ impl ParsedType {
})?;
// converts T to syn::Type
let arg_type = match arg {
match arg {
syn::GenericArgument::Type(ty) => Ok(ty),
_ => Err(Error::new(
arg.span(),
"Unsuitable type in Vec brackets - only Vec<u8> is supported",
)),
}?;
// converts T to syn::path
let arg_path = match arg_type {
syn::Type::Path(path) => Ok(&path.path),
_ => Err(Error::new(
arg_type.span(),
"Unsuitable type in Vec brackets - only Vec<u8> is supported",
)),
}?;
// There could be cases like Vec<some_crate::some_module::u8>
// that why this segments count check is needed
if arg_path.segments.len() != 1 {
return Err(Error::new(
arg_path.span(),
"Unsuitable type in Vec brackets - only Vec<u8> is supported",
));
}
// converts T to String
let arg_segment = arg_path.segments.first().ok_or_else(|| {
Error::new(
arg_path.span(),
"Unsuitable type in Vec brackets - only Vec<u8> is supported",
)
})?;
Ok(arg_segment.ident.to_string())
}
let path = match input_type {
@ -138,16 +114,12 @@ impl ParsedType {
"f64" => Ok(ParsedType::F64),
"bool" => Ok(ParsedType::Boolean),
"String" => Ok(ParsedType::Utf8String),
"Vec" => match parse_vec_bracket(&type_segment.arguments) {
Ok(value) => match value.as_str() {
"u8" => Ok(ParsedType::ByteVector),
_ => Err(Error::new(
value.span(),
"Unsuitable type in Vec brackets - only Vec<u8> is supported",
)),
},
Err(e) => Err(e),
},
"Vec" => {
let vec_type = parse_vec_bracket(&type_segment.arguments)?;
let parsed_type = ParsedType::from_type(vec_type)?;
Ok(ParsedType::Vector(Box::new(parsed_type)))
}
_ if !type_segment.arguments.is_empty() => Err(Error::new(
type_segment.span(),
"type with lifetimes or generics aren't allowed".to_string(),
@ -175,7 +147,30 @@ impl ParsedType {
}
}
pub fn to_token_stream(&self) -> proc_macro2::TokenStream {
pub fn is_complex_type(&self) -> bool {
match self {
ParsedType::Boolean
| ParsedType::I8
| ParsedType::I16
| ParsedType::I32
| ParsedType::I64
| ParsedType::U8
| ParsedType::U16
| ParsedType::U32
| ParsedType::U64
| ParsedType::F32
| ParsedType::F64 => false,
ParsedType::Utf8String | ParsedType::Vector(_) | ParsedType::Record(_) => true,
}
}
}
impl quote::ToTokens for ParsedType {
fn to_tokens(&self, tokens: &mut TokenStream) {
tokens.extend(self.to_token_stream());
}
fn to_token_stream(&self) -> proc_macro2::TokenStream {
use quote::quote;
match self {
@ -191,28 +186,14 @@ impl ParsedType {
ParsedType::F64 => quote! { f64 },
ParsedType::Boolean => quote! { bool },
ParsedType::Utf8String => quote! { String },
ParsedType::ByteVector => quote! { Vec<u8> },
ParsedType::Vector(ty) => {
let quoted_type = ty.to_token_stream();
quote! { Vec<#quoted_type> }
}
ParsedType::Record(name) => {
let ty = crate::new_ident!(name);
quote! { #ty }
}
}
}
pub fn is_complex_type(&self) -> bool {
match self {
ParsedType::Boolean
| ParsedType::I8
| ParsedType::I16
| ParsedType::I32
| ParsedType::I64
| ParsedType::U8
| ParsedType::U16
| ParsedType::U32
| ParsedType::U64
| ParsedType::F32
| ParsedType::F64 => false,
ParsedType::Utf8String | ParsedType::ByteVector | ParsedType::Record(_) => true,
}
}
}

View File

@ -37,7 +37,7 @@ impl FnArgGlueCodeGenerator for (String, ParsedType) {
ParsedType::Record(_) => vec![RustType::U32],
ParsedType::F32 => vec![RustType::F32],
ParsedType::F64 => vec![RustType::F64],
ParsedType::Utf8String | ParsedType::ByteVector => vec![RustType::U32, RustType::U32],
ParsedType::Utf8String | ParsedType::Vector(_) => vec![RustType::U32, RustType::U32],
}
}
}

View File

@ -66,7 +66,7 @@ fn generate_fn_return_type(ty: &Option<ParsedType>) -> proc_macro2::TokenStream
Some(ParsedType::F64) => Some("f64"),
None
| Some(ParsedType::Utf8String)
| Some(ParsedType::ByteVector)
| Some(ParsedType::Vector(_))
| Some(ParsedType::Record(_)) => None,
};
@ -91,22 +91,33 @@ fn generate_return_expression(ty: &Option<ParsedType>) -> proc_macro2::TokenStre
fn generate_epilog(ty: &Option<ParsedType>) -> proc_macro2::TokenStream {
match ty {
None => quote!(),
Some(ty) if !ty.is_complex_type() => quote! {
return result as _;
},
Some(ParsedType::Record(_)) => {
quote! {
let result_ptr = result.__fce_generated_serialize();
fluence::internal::set_result_ptr(result_ptr as _);
}
}
Some(ty) if ty.is_complex_type() => quote! {
Some(ParsedType::Utf8String) => quote! {
fluence::internal::set_result_ptr(result.as_ptr() as _);
fluence::internal::set_result_size(result.len() as _);
std::mem::forget(result);
},
_ => {
panic!("perhaps new type's been added to ParsedType, and this match became incomplete")
Some(ParsedType::Vector(ty)) => {
let generated_serializer_name = format!("__fce_generated_vec_serializer");
let generated_serializer_ident = new_ident!(generated_serializer_name);
let vector_serializer =
super::vector_utils::generate_vector_serializer(ty, &generated_serializer_name);
quote! {
#vector_serializer
let result = #generated_serializer_ident(result);
fluence::internal::set_result_ptr(result.as_ptr() as _);
fluence::internal::set_result_size(result.len() as _);
std::mem::forget(result);
}
}
Some(_) => quote! {
return result as _;
},
}
}

View File

@ -107,9 +107,20 @@ fn generate_type_prolog(
ParsedType::Utf8String => quote! {
let #generated_arg_id = String::from_raw_parts(#ptr as _, #size as _ , #size as _);
},
ParsedType::ByteVector => quote! {
let #generated_arg_id = Vec::from_raw_parts(#ptr as _, #size as _, #size as _);
},
ParsedType::Vector(ty) => {
let generated_deserializer_name =
format!("__fce_generated_vec_deserializer_{}", supplied_arg_start_id);
let generated_deserializer_ident = new_ident!(generated_deserializer_name);
let vector_deserializer = super::vector_utils::generate_vector_deserializer(
ty,
&generated_deserializer_name,
);
quote! {
#vector_deserializer
let #generated_arg_id = #generated_deserializer_ident(#ptr, #size);
}
}
ParsedType::Record(record_name) => {
let record_ident = new_ident!(record_name);
quote! {

View File

@ -28,14 +28,12 @@ impl ForeignModArgGlueCodeGenerator for ParsedType {
let arg = crate::new_ident!(format!("arg_{}", arg_start_id));
match self {
ParsedType::Utf8String | ParsedType::ByteVector => {
ParsedType::Vector(_) | ParsedType::Utf8String => {
quote! { #arg.as_ptr() as _, #arg.len() as _ }
}
ParsedType::Record(_) => {
quote! {
#arg.__fce_generated_serialize() as _
}
}
ParsedType::Record(_) => quote! {
#arg.__fce_generated_serialize() as _
},
ParsedType::Boolean => quote! { #arg as _ },
_ => quote! { #arg },
}

View File

@ -29,6 +29,8 @@ pub(crate) trait ForeignModEpilogGlueCodeGenerator {
impl ForeignModEpilogGlueCodeGenerator for Option<ParsedType> {
fn generate_wrapper_return_type(&self) -> proc_macro2::TokenStream {
use quote::ToTokens;
match self {
Some(ty) => {
let ty = ty.to_token_stream();
@ -54,13 +56,22 @@ impl ForeignModEpilogGlueCodeGenerator for Option<ParsedType> {
fluence::internal::get_result_size() as _
)
},
Some(ParsedType::ByteVector) => quote! {
Vec::from_raw_parts(
fluence::internal::get_result_ptr() as _,
fluence::internal::get_result_size() as _,
fluence::internal::get_result_size() as _
)
},
Some(ParsedType::Vector(ty)) => {
let generated_deserializer_name = String::from("__fce_generated_vec_deserializer");
let generated_deserializer_ident = new_ident!(generated_deserializer_name);
let vector_deserializer = super::vector_utils::generate_vector_deserializer(
ty,
&generated_deserializer_name,
);
quote! {
#vector_deserializer
#generated_deserializer_ident(
fluence::internal::get_result_ptr() as _,
fluence::internal::get_result_size() as _,
);
}
}
Some(ParsedType::Record(record_name)) => {
let record_ident = new_ident!(record_name);

View File

@ -60,6 +60,7 @@ pub(crate) trait ForeignModPrologGlueCodeGenerator {
impl ForeignModPrologGlueCodeGenerator for Vec<(String, ParsedType)> {
fn generate_wrapper_prolog(&self) -> WrapperDescriptor {
use crate::parsed_type::foreign_mod_arg::ForeignModArgGlueCodeGenerator;
use quote::ToTokens;
let arg_types: Vec<proc_macro2::TokenStream> = self
.iter()
@ -70,14 +71,28 @@ impl ForeignModPrologGlueCodeGenerator for Vec<(String, ParsedType)> {
.iter()
.enumerate()
.fold((Vec::new(), proc_macro2::TokenStream::new(), proc_macro2::TokenStream::new()), |(mut arg_names, mut arg_transforms, mut arg_drops), (id, (_, ty))| {
let arg_ident = new_ident!(format!("arg_{}", id));
let arg_name = format!("arg_{}", id);
let arg_ident = new_ident!(arg_name);
arg_names.push(arg_ident.clone());
match ty {
ParsedType::ByteVector | ParsedType::Utf8String => {
arg_transforms.extend(quote::quote! { let mut #arg_ident = std::mem::ManuallyDrop::new(#arg_ident); });
ParsedType::Utf8String => {
arg_transforms.extend(quote::quote! { let #arg_ident = std::mem::ManuallyDrop::new(#arg_ident); });
arg_drops.extend(quote::quote! { std::mem::ManuallyDrop::drop(&mut #arg_ident); });
},
ParsedType::Vector(ty) => {
let generated_serializer_name = format!("__fce_generated_vec_serializer_{}", arg_name);
let generated_serializer_ident = new_ident!(generated_serializer_name);
let vector_serializer = super::vector_utils::generate_vector_serializer(ty, &generated_serializer_name);
let arg_transform = quote::quote! {
#vector_serializer
let #arg_ident = std::mem::ManuallyDrop::new(#arg_ident);
let #arg_ident = #generated_serializer_ident(#arg_ident);
};
arg_transforms.extend(arg_transform);
}
_ => {}
}

View File

@ -0,0 +1,212 @@
/*
* 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::ParsedType;
use quote::quote;
pub(crate) fn generate_vector_serializer(
value_ty: &ParsedType,
arg_name: &str,
) -> proc_macro2::TokenStream {
let values_serializer = match value_ty {
ParsedType::Boolean
| ParsedType::I8
| ParsedType::I16
| ParsedType::I32
| ParsedType::U8
| ParsedType::U16
| ParsedType::U32 => {
quote! {
let mut result: Vec<u32> = Vec::with_capacity(arg.len());
for value in arg {
result.push(value as _);
}
fluence::transmute_vec::<u64, u8>(result)
}
}
ParsedType::I64 | ParsedType::U64 => {
quote! {
let mut result: Vec<u64> = Vec::with_capacity(arg.len());
for value in arg {
result.push(value as _);
}
fluence::transmute_vec::<u64, u8>(result)
}
}
ParsedType::F32 => {
quote! {
let mut result: Vec<u32> = Vec::with_capacity(arg.len());
for value in arg {
result.push(value.to_bits());
}
fluence::transmute_vec::<u32, u8>(result)
}
}
ParsedType::F64 => {
quote! {
let mut result: Vec<u64> = Vec::with_capacity(arg.len());
for value in arg {
result.push(value.to_bits());
}
fluence::transmute_vec::<u64, u8>(result)
}
}
ParsedType::Utf8String => {
quote! {
let mut result: Vec<u32> = Vec::with_capacity(arg.len());
for value in arg {
result.push(value.as_ptr() as _);
result.push(value.len() as _);
}
fluence::transmute_vec::<u32, u8>(result)
}
}
ParsedType::Vector(ty) => {
let serializer_name = format!("{}_{:?}", arg_name, ty);
let inner_vector_serializer = generate_vector_serializer(&*ty, &serializer_name);
let serializer_ident = crate::new_ident!(serializer_name);
quote! {
#inner_vector_serializer
let mut result: Vec<u32> = Vec::with_capacity(2 * arg.len());
for value in arg {
result.push(#serializer_ident(arg, &serializer_name));
}
fluence::transmute_vec::<u32, u8>(result)
}
}
ParsedType::Record(record_name) => {
let record_ident = crate::new_ident!(record_name);
quote! {
let mut result: Vec<u32> = Vec::with_capacity(arg.len());
for value in arg {
result.push(#record_ident.__fce_generated_serialize() as _);
}
fluence::transmute_vec::<u32, u8>(result)
}
}
};
let arg = crate::new_ident!(arg_name);
quote! {
fn serialize_vector_#arg(arg: Vec<#value_ty>) -> Vec<u8> {
std::mem::forget(arg);
if arg.is_empty() {
return vec![];
}
#values_serializer
}
}
}
pub(crate) fn generate_vector_deserializer(
value_ty: &ParsedType,
arg_name: &str,
) -> proc_macro2::TokenStream {
let arg = crate::new_ident!(arg_name);
let values_deserializer = match value_ty {
ParsedType::F32 => {
quote! {
let arg = fluence::transmute_vec::<u8, u32>().unwrap();
arg.iter().map(f32::from_bits).collect::<Vec<_>>()
}
}
ParsedType::F64 => {
quote! {
let arg = fluence::transmute_vec::<u8, u64>().unwrap();
arg.iter().map(f64::from_bits).collect::<Vec<_>>()
}
}
ParsedType::Utf8String => {
quote! {
let arg = fluence::transmute_vec::<u8, u32>().unwrap();
let arg = arg.iter();
let mut result = Vec::with_capacity(arg.len() / 2);
while let Some(offset) = arg.next() {
let size = arg.next().unwrap();
let value = String::from_raw_parts(offset as _, size as _, size as _);
result.push(value);
}
result
}
}
ParsedType::Vector(ty) => {
let deserializer_name = format!("{}_{:?}", arg_name, ty);
let inner_vector_deserializer = generate_vector_deserializer(&*ty, &deserializer_name);
let deserializer_ident = crate::new_ident!(deserializer_name);
quote! {
#inner_vector_deserializer
let arg = fluence::transmute_vec::<u8, u32>().unwrap();
let mut result = Vec::with_capacity(arg.len());
for offset in arg.iter() {
let value = #deserializer_ident(offset, &deserializer_name);
result.push(value);
}
result
}
}
ParsedType::Record(record_name) => {
quote! {
let arg = fluence::transmute_vec::<u8, u32>().unwrap();
let mut result = Vec::with_capacity(arg.len());
for offset in arg {
let value = #record_name.__fce_generated_deserialize(arg.as_ptr());
result.push(value);
}
result
}
}
v => {
quote! {
fluence::transmute_vec::<u8, #v>().unwrap()
}
}
};
quote! {
fn deserialize_vector_#arg(offset: u32, size: u32) -> Vec<#value_ty> {
let arg: Vec<u8> = Vec::from_raw_parts(offset as _, size as _, size _);
if arg.is_empty() {
return vec![];
}
#values_deserializer
}
}
}

View File

@ -103,13 +103,22 @@ impl RecordDeserializerGlueCodeGenerator for fce_ast_types::AstRecordItem {
let #field = unsafe { String::from_raw_parts(raw_record[#ptr_id] as _, raw_record[#size_id] as _, raw_record[#size_id] as _) };
}
}
ParsedType::ByteVector => {
ParsedType::Vector(ty) => {
let ptr_id = value_id;
let size_id = value_id + 1;
value_id += 1;
let generated_deserializer_name =
String::from("__fce_generated_vec_deserializer");
let generated_deserializer_ident = new_ident!(generated_deserializer_name);
let vector_deserializer = crate::parsed_type::generate_vector_deserializer(
ty,
&generated_deserializer_name,
);
quote! {
let #field = unsafe { Vec::from_raw_parts(raw_record[#ptr_id] as _, raw_record[#size_id] as _, raw_record[#size_id] as _) };
#vector_deserializer
#generated_deserializer_ident(raw_record[#ptr_id] as _, raw_record[#size_id] as _);
}
}
ParsedType::Record(record_name) => {

View File

@ -37,13 +37,33 @@ impl RecordSerializerGlueCodeGenerator for fce_ast_types::AstRecordItem {
raw_record.push(#field_ident.to_bits());
}
}
ParsedType::Utf8String | ParsedType::ByteVector => {
ParsedType::Utf8String => {
quote! {
raw_record.push(#field_ident.as_ptr() as _);
raw_record.push(#field_ident.len() as _);
std::mem::forget(#field_ident);
}
}
ParsedType::Vector(ty) => {
let generated_serializer_name = format!(
"__fce_generated_vec_serializer_{}_{}",
field.name.as_ref().unwrap(),
id
);
let generated_serializer_ident = new_ident!(generated_serializer_name);
let vector_serializer = crate::parsed_type::generate_vector_serializer(
ty,
&generated_serializer_name,
);
quote::quote! {
#vector_serializer
let #field_ident = #generated_serializer_ident(#field_ident);
raw_record.push(#field_ident.as_ptr() as _);
raw_record.push(#field_ident.len() as _);
std::mem::forget(#field_ident);
}
}
ParsedType::Record(_) => {
quote! {
raw_record.push(#field_ident.__fce_generated_serialize() as _);

View File

@ -54,7 +54,7 @@ pub fn get_record_size<'a>(
for field in fields {
let params_count = match field {
ParsedType::ByteVector | ParsedType::Utf8String => 2,
ParsedType::Vector(_) | ParsedType::Utf8String => 2,
_ => 1,
};

View File

@ -84,4 +84,5 @@ pub mod internal {
pub use fluence_sdk_main::get_result_size;
pub use fluence_sdk_main::set_result_ptr;
pub use fluence_sdk_main::set_result_size;
pub use safe_transmute::transmute_vec;
}