From 913317c78ead211779ace99703b0dbaec17c69cd Mon Sep 17 00:00:00 2001 From: vms Date: Sun, 18 Apr 2021 14:29:52 +0300 Subject: [PATCH] refactor export_types --- crates/wit/src/ast_types.rs | 24 +++++-- crates/wit/src/export_ast_types.rs | 43 ++++++++++--- .../wit/src/parse_macro_input/item_record.rs | 2 + .../record_generator.rs | 24 +++++-- .../record_generator/record_deserializer.rs | 64 +++++++++---------- .../record_generator/record_serializer.rs | 18 ++++-- 6 files changed, 114 insertions(+), 61 deletions(-) diff --git a/crates/wit/src/ast_types.rs b/crates/wit/src/ast_types.rs index 51f0ed0..c47c1fe 100644 --- a/crates/wit/src/ast_types.rs +++ b/crates/wit/src/ast_types.rs @@ -32,6 +32,23 @@ pub(crate) struct AstFnSignature { pub output_type: Option, } +#[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), + // 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), + 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, - pub original: syn::ItemStruct, -} - #[derive(Clone)] pub(crate) struct AstExternFnItem { pub link_name: Option, diff --git a/crates/wit/src/export_ast_types.rs b/crates/wit/src/export_ast_types.rs index 80f26e3..db251db 100644 --- a/crates/wit/src/export_ast_types.rs +++ b/crates/wit/src/export_ast_types.rs @@ -34,6 +34,21 @@ pub struct FnSignature { pub output_type: Option, } +#[derive(Clone, Serialize, Deserialize)] +pub struct RecordItem { + pub name: String, + pub fields: RecordFields, +} + +#[derive(Clone, Serialize, Deserialize)] +pub enum RecordFields { + Named(Vec), + // 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), + 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, -} - #[derive(Clone, Serialize, Deserialize)] pub struct ExternFnItem { pub link_name: Option, @@ -76,7 +85,7 @@ pub enum SDKAst { use crate::ast_types::{ AstFnItem, AstFnSignature, AstFnArgument, AstExternModItem, AstExternFnItem, AstRecordField, - AstRecordItem, + AstRecordItem, AstRecordFields, }; impl From for SDKAst { @@ -121,11 +130,25 @@ impl From for ExternModItem { impl From 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 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, } } } diff --git a/crates/wit/src/parse_macro_input/item_record.rs b/crates/wit/src/parse_macro_input/item_record.rs index 36dad3a..5806547 100644 --- a/crates/wit/src/parse_macro_input/item_record.rs +++ b/crates/wit/src/parse_macro_input/item_record.rs @@ -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 { diff --git a/crates/wit/src/token_stream_generator/record_generator.rs b/crates/wit/src/token_stream_generator/record_generator.rs index 768b628..a798835 100644 --- a/crates/wit/src/token_stream_generator/record_generator.rs +++ b/crates/wit/src/token_stream_generator/record_generator.rs @@ -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 { diff --git a/crates/wit/src/token_stream_generator/record_generator/record_deserializer.rs b/crates/wit/src/token_stream_generator/record_generator/record_deserializer.rs index 3f62038..a553890 100644 --- a/crates/wit/src/token_stream_generator/record_generator/record_deserializer.rs +++ b/crates/wit/src/token_stream_generator/record_generator/record_deserializer.rs @@ -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, + fields: impl ExactSizeIterator, ) -> 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, + fields: impl ExactSizeIterator, ) -> 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, - field_values: impl ExactSizeIterator, -) -> 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, +fn field_ctors_from_named<'a, 'v>( + ast_fields: impl ExactSizeIterator, field_values: impl ExactSizeIterator, ) -> 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, ) -> proc_macro2::TokenStream { quote! { diff --git a/crates/wit/src/token_stream_generator/record_generator/record_serializer.rs b/crates/wit/src/token_stream_generator/record_generator/record_serializer.rs index 3bc2a24..fdf0b7d 100644 --- a/crates/wit/src/token_stream_generator/record_generator/record_serializer.rs +++ b/crates/wit/src/token_stream_generator/record_generator/record_serializer.rs @@ -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);