refactor export_types

This commit is contained in:
vms 2021-04-18 14:29:52 +03:00
parent 8ea8e219ef
commit 913317c78e
6 changed files with 114 additions and 61 deletions

View File

@ -32,6 +32,23 @@ pub(crate) struct AstFnSignature {
pub output_type: Option<ParsedType>,
}
#[derive(Clone)]
pub(crate) struct AstRecordItem {
pub name: String,
pub fields: AstRecordFields,
pub original: syn::ItemStruct,
}
#[allow(dead_code)] // at the moment tuple and unit structs aren't supported
#[derive(Debug, Clone, PartialEq)]
pub(crate) enum AstRecordFields {
Named(Vec<AstRecordField>),
// named and unnamed variants have the same inner field types because of it's easy to handle it,
// for additional info look at https://github.com/dtolnay/syn/issues/698
Unnamed(Vec<AstRecordField>),
Unit,
}
#[derive(Debug, Clone, PartialEq)]
pub(crate) struct AstRecordField {
// fields of tuple structs haven't got name
@ -39,13 +56,6 @@ pub(crate) struct AstRecordField {
pub ty: ParsedType,
}
#[derive(Clone)]
pub(crate) struct AstRecordItem {
pub name: String,
pub fields: Vec<AstRecordField>,
pub original: syn::ItemStruct,
}
#[derive(Clone)]
pub(crate) struct AstExternFnItem {
pub link_name: Option<String>,

View File

@ -34,6 +34,21 @@ pub struct FnSignature {
pub output_type: Option<ParsedType>,
}
#[derive(Clone, Serialize, Deserialize)]
pub struct RecordItem {
pub name: String,
pub fields: RecordFields,
}
#[derive(Clone, Serialize, Deserialize)]
pub enum RecordFields {
Named(Vec<RecordField>),
// named and unnamed variants have the same inner field types because of it's easy to handle it,
// for additional info look at https://github.com/dtolnay/syn/issues/698
Unnamed(Vec<RecordField>),
Unit,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RecordField {
// fields of tuple structs haven't got name
@ -41,12 +56,6 @@ pub struct RecordField {
pub ty: ParsedType,
}
#[derive(Clone, Serialize, Deserialize)]
pub struct RecordItem {
pub name: String,
pub fields: Vec<RecordField>,
}
#[derive(Clone, Serialize, Deserialize)]
pub struct ExternFnItem {
pub link_name: Option<String>,
@ -76,7 +85,7 @@ pub enum SDKAst {
use crate::ast_types::{
AstFnItem, AstFnSignature, AstFnArgument, AstExternModItem, AstExternFnItem, AstRecordField,
AstRecordItem,
AstRecordItem, AstRecordFields,
};
impl From<AstFnItem> for SDKAst {
@ -121,11 +130,25 @@ impl From<AstExternModItem> for ExternModItem {
impl From<AstRecordItem> for RecordItem {
fn from(ast_record_item: AstRecordItem) -> Self {
let fields = ast_record_item.fields.into_iter().map(Into::into).collect();
Self {
name: ast_record_item.name,
fields,
fields: ast_record_item.fields.into(),
}
}
}
impl From<AstRecordFields> for RecordFields {
fn from(ast_record_item: AstRecordFields) -> Self {
match ast_record_item {
AstRecordFields::Named(fields) => {
let fields = fields.into_iter().map(Into::into).collect();
Self::Named(fields)
}
AstRecordFields::Unnamed(fields) => {
let fields = fields.into_iter().map(Into::into).collect();
Self::Unnamed(fields)
}
AstRecordFields::Unit => Self::Unit,
}
}
}

View File

@ -17,6 +17,7 @@
use super::ParseMacroInput;
use crate::ast_types;
use crate::ast_types::AstRecordField;
use crate::ast_types::AstRecordFields;
use crate::ast_types::FCEAst;
use crate::syn_error;
use crate::parsed_type::ParsedType;
@ -34,6 +35,7 @@ impl ParseMacroInput for syn::ItemStruct {
};
let fields = fields_into_ast(fields)?;
let fields = AstRecordFields::Named(fields);
let name = self.ident.to_string();
let ast_record_item = ast_types::AstRecordItem {

View File

@ -21,9 +21,10 @@ use record_serializer::*;
use record_deserializer::*;
use crate::new_ident;
use crate::ast_types;
use crate::ast_types::AstRecordItem;
use crate::ast_types::AstRecordFields;
impl quote::ToTokens for ast_types::AstRecordItem {
impl quote::ToTokens for AstRecordItem {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
let original = &self.original;
crate::prepare_global_data!(
@ -65,9 +66,13 @@ impl quote::ToTokens for ast_types::AstRecordItem {
}
}
fn generate_serializer_fn(record: &ast_types::AstRecordItem) -> proc_macro2::TokenStream {
fn generate_serializer_fn(record: &AstRecordItem) -> proc_macro2::TokenStream {
let serializer = record.generate_serializer();
let fields_count = record.fields.len();
let fields_count = match &record.fields {
AstRecordFields::Named(fields) => fields.len(),
AstRecordFields::Unnamed(fields) => fields.len(),
AstRecordFields::Unit => return proc_macro2::TokenStream::new(),
};
quote::quote! {
pub fn __fce_generated_serialize(&self) -> *const u8 {
@ -83,14 +88,19 @@ fn generate_serializer_fn(record: &ast_types::AstRecordItem) -> proc_macro2::Tok
}
}
fn generate_deserializer_fn(record: &ast_types::AstRecordItem) -> proc_macro2::TokenStream {
fn generate_deserializer_fn(record: &AstRecordItem) -> proc_macro2::TokenStream {
let RecordDerDescriptor {
fields_der,
record_ctor,
} = record.generate_der();
let record_size =
crate::utils::get_record_size(record.fields.iter().map(|ast_field| &ast_field.ty));
let fields = match &record.fields {
AstRecordFields::Named(fields) => fields,
AstRecordFields::Unnamed(fields) => fields,
AstRecordFields::Unit => return proc_macro2::TokenStream::new(),
};
let record_size = crate::utils::get_record_size(fields.iter().map(|ast_field| &ast_field.ty));
quote::quote! {
pub unsafe fn __fce_generated_deserialize(record_ptr: *const u8) -> Self {

View File

@ -16,10 +16,11 @@
use crate::new_ident;
use crate::parsed_type::ParsedType;
use crate::ast_types;
use crate::ast_types::*;
use quote::quote;
#[derive(Default)]
pub(super) struct RecordDerDescriptor {
pub(super) fields_der: proc_macro2::TokenStream,
pub(super) record_ctor: proc_macro2::TokenStream,
@ -30,17 +31,33 @@ pub(super) trait RecordDerGlueCodeGenerator {
fn generate_der(&self) -> RecordDerDescriptor;
}
impl RecordDerGlueCodeGenerator for ast_types::AstRecordItem {
impl RecordDerGlueCodeGenerator for AstRecordItem {
fn generate_der(&self) -> RecordDerDescriptor {
let builder = FieldValuesBuilder::build(self.fields.iter());
let record_ctor = build_record_ctor(self.fields.iter(), builder.field_value_idents.iter());
match &self.fields {
AstRecordFields::Named(fields) => record_der_from_named(fields),
AstRecordFields::Unnamed(fields) => record_der_from_unnamed(fields),
AstRecordFields::Unit => RecordDerDescriptor::default(),
}
}
}
let descriptor = RecordDerDescriptor {
fields_der: builder.fields_der,
record_ctor,
};
fn record_der_from_named(fields: &[AstRecordField]) -> RecordDerDescriptor {
let builder = FieldValuesBuilder::build(fields.iter());
let record_ctor = field_ctors_from_named(fields.iter(), builder.field_value_idents.iter());
descriptor
RecordDerDescriptor {
fields_der: builder.fields_der,
record_ctor,
}
}
fn record_der_from_unnamed(fields: &[AstRecordField]) -> RecordDerDescriptor {
let builder = FieldValuesBuilder::build(fields.iter());
let record_ctor = field_ctor_from_unnamed(builder.field_value_idents.iter());
RecordDerDescriptor {
fields_der: builder.fields_der,
record_ctor,
}
}
@ -61,7 +78,7 @@ struct FieldValuesOutcome {
impl FieldValuesBuilder {
pub(self) fn build<'a>(
fields: impl ExactSizeIterator<Item = &'a ast_types::AstRecordField>,
fields: impl ExactSizeIterator<Item = &'a AstRecordField>,
) -> FieldValuesOutcome {
let values_builder = Self::new(fields.len());
values_builder.build_impl(fields)
@ -77,7 +94,7 @@ impl FieldValuesBuilder {
fn build_impl<'r>(
mut self,
fields: impl ExactSizeIterator<Item = &'r ast_types::AstRecordField>,
fields: impl ExactSizeIterator<Item = &'r AstRecordField>,
) -> FieldValuesOutcome {
for (id, ast_field) in fields.enumerate() {
let field_value_ident = new_ident!(format!("field_{}", id));
@ -97,7 +114,7 @@ impl FieldValuesBuilder {
fn field_der(
&mut self,
ast_field: &ast_types::AstRecordField,
ast_field: &AstRecordField,
field: &syn::Ident,
) -> proc_macro2::TokenStream {
let value_id = self.value_id;
@ -161,25 +178,8 @@ impl FieldValuesBuilder {
}
}
fn build_record_ctor<'a, 'v>(
ast_fields: impl ExactSizeIterator<Item = &'a ast_types::AstRecordField>,
field_values: impl ExactSizeIterator<Item = &'v syn::Ident>,
) -> proc_macro2::TokenStream {
let mut ast_fields = ast_fields.peekable();
let is_fields_named = match ast_fields.peek() {
Some(ast_field) => ast_field.name.is_some(),
None => return proc_macro2::TokenStream::new(),
};
if is_fields_named {
build_named_fields_ctor(ast_fields, field_values)
} else {
build_unnamed_fields_ctor(field_values)
}
}
fn build_named_fields_ctor<'a, 'v>(
ast_fields: impl ExactSizeIterator<Item = &'a ast_types::AstRecordField>,
fn field_ctors_from_named<'a, 'v>(
ast_fields: impl ExactSizeIterator<Item = &'a AstRecordField>,
field_values: impl ExactSizeIterator<Item = &'v syn::Ident>,
) -> proc_macro2::TokenStream {
let field_names = ast_fields
@ -198,7 +198,7 @@ fn build_named_fields_ctor<'a, 'v>(
}
}
fn build_unnamed_fields_ctor<'v>(
fn field_ctor_from_unnamed<'v>(
field_values: impl ExactSizeIterator<Item = &'v syn::Ident>,
) -> proc_macro2::TokenStream {
quote! {

View File

@ -16,19 +16,27 @@
use crate::new_ident;
use crate::parsed_type::ParsedType;
use crate::ast_types;
use crate::ast_types::AstRecordItem;
use crate::ast_types::AstRecordField;
use crate::ast_types::AstRecordFields;
use quote::quote;
/// This trait could be used to generate various parts of a record serializer func.
pub(super) trait RecordSerializerGlueCodeGenerator {
pub(super) trait RecordSerGlueCodeGenerator {
fn generate_serializer(&self) -> proc_macro2::TokenStream;
}
impl RecordSerializerGlueCodeGenerator for ast_types::AstRecordItem {
impl RecordSerGlueCodeGenerator for AstRecordItem {
fn generate_serializer(&self) -> proc_macro2::TokenStream {
let mut serializer = proc_macro2::TokenStream::new();
for (id, field) in self.fields.iter().enumerate() {
let fields = match &self.fields {
AstRecordFields::Named(fields) => fields,
AstRecordFields::Unnamed(fields) => fields,
AstRecordFields::Unit => return proc_macro2::TokenStream::new(),
};
for (id, field) in fields.iter().enumerate() {
let field_ident = field_ident(field, id);
let field_serialization = match &field.ty {
@ -82,7 +90,7 @@ impl RecordSerializerGlueCodeGenerator for ast_types::AstRecordItem {
}
}
fn field_ident(field: &ast_types::AstRecordField, id: usize) -> proc_macro2::TokenStream {
fn field_ident(field: &AstRecordField, id: usize) -> proc_macro2::TokenStream {
match &field.name {
Some(name) => {
let name = new_ident!(name);