move record logic to a separate module

This commit is contained in:
vms 2020-07-26 14:09:35 +03:00
parent e589d52c72
commit 0c09b32bb7
3 changed files with 284 additions and 181 deletions

View File

@ -14,12 +14,17 @@
* limitations under the License.
*/
mod record_serializer;
mod record_deserializer;
use record_serializer::*;
use record_deserializer::*;
use super::GENERATED_RECORD_SERIALIZER_PREFIX;
use super::GENERATED_RECORD_DESERIALIZER_PREFIX;
use crate::new_ident;
use crate::fce_ast_types;
use crate::ParsedType;
impl quote::ToTokens for fce_ast_types::AstRecordItem {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
@ -34,15 +39,21 @@ impl quote::ToTokens for fce_ast_types::AstRecordItem {
section_name
);
let serializer = generate_serializer(self);
let deserializer = generate_deserializer(self);
let serializer_fn = generate_serializer_fn(self);
let deserializer_fn = generate_deserializer_fn(self);
let glue_code = quote::quote! {
#original
#serializer
#[cfg(target_arch = "wasm32")]
#[doc(hidden)]
#[allow(clippy::all)]
#serializer_fn
#deserializer
#[cfg(target_arch = "wasm32")]
#[doc(hidden)]
#[allow(clippy::all)]
#deserializer_fn
#[cfg(target_arch = "wasm32")]
#[doc(hidden)]
@ -55,60 +66,17 @@ impl quote::ToTokens for fce_ast_types::AstRecordItem {
}
}
fn field_ident(field: &fce_ast_types::AstRecordField, id: usize) -> proc_macro2::TokenStream {
match &field.name {
Some(name) => {
let name = new_ident!(name);
quote::quote! { record.#name }
}
None => {
let id = new_ident!(format!("{}", id));
quote::quote! { record.#id }
}
}
}
fn generate_serializer(record: &fce_ast_types::AstRecordItem) -> proc_macro2::TokenStream {
fn generate_serializer_fn(record: &fce_ast_types::AstRecordItem) -> proc_macro2::TokenStream {
let serializer_fn_name =
new_ident!(GENERATED_RECORD_SERIALIZER_PREFIX.to_string() + &record.name);
let ty = new_ident!(record.name);
let mut serializer = proc_macro2::TokenStream::new();
for (id, field) in record.fields.iter().enumerate() {
let field_ident = field_ident(field, id);
let field_serialization = match &field.ty {
ParsedType::F64 => {
quote::quote! {
raw_record.push(#field_ident.to_bits());
}
}
ParsedType::Utf8String | ParsedType::ByteVector => {
quote::quote! {
raw_record.push(#field_ident.as_ptr() as _);
raw_record.push(#field_ident.len() as _);
}
}
ParsedType::Record(record_name) => {
let serializer_name =
new_ident!(GENERATED_RECORD_SERIALIZER_PREFIX.to_string() + record_name);
quote::quote! {
raw_record.push(#serializer_name(#field_ident) as _);
}
}
_ => quote::quote! {
raw_record.push(#field_ident as u64);
},
};
serializer.extend(field_serialization);
}
let RecordSerializerDescriptor {
serializer,
record_type,
} = record.generate_serializer(&record.name);
quote::quote! {
#[cfg(target_arch = "wasm32")]
#[doc(hidden)]
#[allow(clippy::all)]
pub(crate) fn #serializer_fn_name(record: #ty) -> i32 {
pub(crate) fn #serializer_fn_name(record: #record_type) -> i32 {
let mut raw_record = Vec::new();
#serializer
@ -121,138 +89,18 @@ fn generate_serializer(record: &fce_ast_types::AstRecordItem) -> proc_macro2::To
}
}
fn generate_deserializer(record: &fce_ast_types::AstRecordItem) -> proc_macro2::TokenStream {
let ret_type = new_ident!(record.name);
fn generate_deserializer_fn(record: &fce_ast_types::AstRecordItem) -> proc_macro2::TokenStream {
let deserializer_fn_name =
new_ident!(GENERATED_RECORD_DESERIALIZER_PREFIX.to_string() + &record.name);
let mut field_values = Vec::with_capacity(record.fields.len());
let mut deserializer = proc_macro2::TokenStream::new();
let mut value_id: usize = 0;
for (id, ast_field) in record.fields.iter().enumerate() {
let field = new_ident!(format!("field_{}", id));
let field_d = match &ast_field.ty {
ParsedType::Boolean => {
quote::quote! {
let #field = raw_record[#value_id] as bool;
}
}
ParsedType::I8 => {
quote::quote! {
let #field = raw_record[#value_id] as i8;
}
}
ParsedType::I16 => {
quote::quote! {
let #field = raw_record[#value_id] as i16;
}
}
ParsedType::I32 => {
quote::quote! {
let #field = raw_record[#value_id] as i32;
}
}
ParsedType::I64 => {
quote::quote! {
let #field = raw_record[#value_id] as i64;
}
}
ParsedType::U8 => {
quote::quote! {
let #field = raw_record[#value_id] as u8;
}
}
ParsedType::U16 => {
quote::quote! {
let #field = raw_record[#value_id] as u16;
}
}
ParsedType::U32 => {
quote::quote! {
let #field = raw_record[#value_id] as u32;
}
}
ParsedType::U64 => {
quote::quote! {
let #field = raw_record[#value_id] as u64;
}
}
ParsedType::F32 => {
quote::quote! {
let #field = raw_record[#value_id] as f32;
}
}
ParsedType::F64 => {
quote::quote! {
let #field = f64::from_bits(raw_record[#value_id as _]);
}
}
ParsedType::Utf8String => {
let ptr_id = value_id;
let size_id = value_id + 1;
value_id += 1;
quote::quote! {
let #field = unsafe { String::from_raw_parts(raw_record[#ptr_id] as _, raw_record[#size_id] as _, raw_record[#size_id] as _) };
}
}
ParsedType::ByteVector => {
let ptr_id = value_id;
let size_id = value_id + 1;
value_id += 1;
quote::quote! {
let #field = unsafe { Vec::from_raw_parts(raw_record[#ptr_id] as _, raw_record[#size_id] as _, raw_record[#size_id] as _) };
}
}
ParsedType::Record(record_name) => {
let ptr_id = value_id;
let size_id = value_id + 1;
value_id += 1;
let deserializer_name =
new_ident!(GENERATED_RECORD_DESERIALIZER_PREFIX.to_string() + record_name);
quote::quote! {
let #field = #deserializer_name(raw_record[#ptr_id] as _, raw_record[#size_id] as _);
}
}
};
field_values.push(field);
deserializer.extend(field_d);
value_id += 1;
}
let type_constructor = match record.fields.first() {
Some(ast_field) if ast_field.name.is_some() => {
let field_names = record
.fields
.iter()
.map(|field| new_ident!(field.name.clone().expect("all fields should have name")))
.collect::<Vec<_>>();
quote::quote! {
#ret_type {
#(#field_names: #field_values),*
}
}
}
Some(_) => {
quote::quote! {
#ret_type (
#(#field_values),*
)
}
}
_ => quote::quote! {},
};
let RecordDeserializerDescriptor {
deserializer,
type_constructor,
return_type,
} = record.generate_deserializer(&record.name);
quote::quote! {
#[cfg(target_arch = "wasm32")]
#[doc(hidden)]
#[allow(clippy::all)]
unsafe fn #deserializer_fn_name(offset: i32, size: i32) -> #ret_type {
unsafe fn #deserializer_fn_name(offset: i32, size: i32) -> #return_type {
let raw_record: Vec<u64> = Vec::from_raw_parts(offset as _, size as _, size as _);
#deserializer

View File

@ -0,0 +1,169 @@
/*
* Copyright 2020 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use crate::new_ident;
use crate::parsed_type::ParsedType;
use crate::fce_ast_types;
use crate::token_stream_generator::GENERATED_RECORD_DESERIALIZER_PREFIX;
use quote::quote;
pub(super) struct RecordDeserializerDescriptor {
pub(super) deserializer: proc_macro2::TokenStream,
pub(super) type_constructor: proc_macro2::TokenStream,
pub(super) return_type: syn::Ident,
}
/// This trait could be used to generate various parts of a record serializer func.
pub(super) trait RecordDeserializerGlueCodeGenerator {
fn generate_deserializer(&self, record_name: &str) -> RecordDeserializerDescriptor;
}
impl RecordDeserializerGlueCodeGenerator for fce_ast_types::AstRecordItem {
fn generate_deserializer(&self, record_name: &str) -> RecordDeserializerDescriptor {
let return_type = new_ident!(record_name);
let mut field_values = Vec::with_capacity(self.fields.len());
let mut deserializer = proc_macro2::TokenStream::new();
let mut value_id: usize = 0;
for (id, ast_field) in self.fields.iter().enumerate() {
let field = new_ident!(format!("field_{}", id));
let field_d = match &ast_field.ty {
ParsedType::Boolean => {
quote! {
let #field = raw_record[#value_id] as bool;
}
}
ParsedType::I8 => {
quote! {
let #field = raw_record[#value_id] as i8;
}
}
ParsedType::I16 => {
quote! {
let #field = raw_record[#value_id] as i16;
}
}
ParsedType::I32 => {
quote! {
let #field = raw_record[#value_id] as i32;
}
}
ParsedType::I64 => {
quote! {
let #field = raw_record[#value_id] as i64;
}
}
ParsedType::U8 => {
quote! {
let #field = raw_record[#value_id] as u8;
}
}
ParsedType::U16 => {
quote! {
let #field = raw_record[#value_id] as u16;
}
}
ParsedType::U32 => {
quote! {
let #field = raw_record[#value_id] as u32;
}
}
ParsedType::U64 => {
quote! {
let #field = raw_record[#value_id] as u64;
}
}
ParsedType::F32 => {
quote! {
let #field = raw_record[#value_id] as f32;
}
}
ParsedType::F64 => {
quote! {
let #field = f64::from_bits(raw_record[#value_id as _]);
}
}
ParsedType::Utf8String => {
let ptr_id = value_id;
let size_id = value_id + 1;
value_id += 1;
quote! {
let #field = unsafe { String::from_raw_parts(raw_record[#ptr_id] as _, raw_record[#size_id] as _, raw_record[#size_id] as _) };
}
}
ParsedType::ByteVector => {
let ptr_id = value_id;
let size_id = value_id + 1;
value_id += 1;
quote! {
let #field = unsafe { Vec::from_raw_parts(raw_record[#ptr_id] as _, raw_record[#size_id] as _, raw_record[#size_id] as _) };
}
}
ParsedType::Record(record_name) => {
let ptr_id = value_id;
let size_id = value_id + 1;
value_id += 1;
let deserializer_name =
new_ident!(GENERATED_RECORD_DESERIALIZER_PREFIX.to_string() + record_name);
quote! {
let #field = #deserializer_name(raw_record[#ptr_id] as _, raw_record[#size_id] as _);
}
}
};
field_values.push(field);
deserializer.extend(field_d);
value_id += 1;
}
let type_constructor = match self.fields.first() {
Some(ast_field) if ast_field.name.is_some() => {
let field_names = self
.fields
.iter()
.map(|field| {
new_ident!(field.name.clone().expect("all fields should have name"))
})
.collect::<Vec<_>>();
quote! {
#return_type {
#(#field_names: #field_values),*
}
}
}
Some(_) => {
quote! {
#return_type (
#(#field_values),*
)
}
}
_ => quote! {},
};
RecordDeserializerDescriptor {
deserializer,
type_constructor,
return_type,
}
}
}

View File

@ -0,0 +1,86 @@
/*
* Copyright 2020 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use crate::new_ident;
use crate::parsed_type::ParsedType;
use crate::fce_ast_types;
use crate::token_stream_generator::GENERATED_RECORD_SERIALIZER_PREFIX;
use quote::quote;
pub(super) struct RecordSerializerDescriptor {
pub(super) serializer: proc_macro2::TokenStream,
pub(super) record_type: syn::Ident,
}
/// This trait could be used to generate various parts of a record serializer func.
pub(super) trait RecordSerializerGlueCodeGenerator {
fn generate_serializer(&self, record_name: &str) -> RecordSerializerDescriptor;
}
impl RecordSerializerGlueCodeGenerator for fce_ast_types::AstRecordItem {
fn generate_serializer(&self, record_name: &str) -> RecordSerializerDescriptor {
let mut serializer = proc_macro2::TokenStream::new();
for (id, field) in self.fields.iter().enumerate() {
let field_ident = field_ident(field, id);
let field_serialization = match &field.ty {
ParsedType::F64 => {
quote! {
raw_record.push(#field_ident.to_bits());
}
}
ParsedType::Utf8String | ParsedType::ByteVector => {
quote! {
raw_record.push(#field_ident.as_ptr() as _);
raw_record.push(#field_ident.len() as _);
}
}
ParsedType::Record(record_name) => {
let serializer_name =
new_ident!(GENERATED_RECORD_SERIALIZER_PREFIX.to_string() + &record_name);
quote! {
raw_record.push(#serializer_name(#field_ident) as _);
}
}
_ => quote! {
raw_record.push(#field_ident as u64);
},
};
serializer.extend(field_serialization);
}
let record_type = new_ident!(record_name);
RecordSerializerDescriptor {
serializer,
record_type,
}
}
}
fn field_ident(field: &fce_ast_types::AstRecordField, id: usize) -> proc_macro2::TokenStream {
match &field.name {
Some(name) => {
let name = new_ident!(name);
quote! { record.#name }
}
None => {
let id = new_ident!(format!("{}", id));
quote! { record.#id }
}
}
}