diff --git a/asn1rs-model/src/ast/attribute.rs b/asn1rs-model/src/ast/attribute.rs index adff4390..be39ac3c 100644 --- a/asn1rs-model/src/ast/attribute.rs +++ b/asn1rs-model/src/ast/attribute.rs @@ -133,7 +133,6 @@ impl PrimaryContext for Type { ident_or_literal_or_punct(*c) .ok_or_else(|| c.error("Expected type, number or extension marker")) })? - .to_string() .to_lowercase(); Ok(parse_type_pre_stepped(&lowercase_ident, input)?) @@ -150,8 +149,7 @@ impl PrimaryContext for Option { .ok() .as_ref() .map(ToString::to_string) - .as_ref() - .map(String::as_str) + .as_deref() .map(str::to_lowercase) .map(|lowercase_ident| { lowercase_ident diff --git a/asn1rs-model/src/ast/mod.rs b/asn1rs-model/src/ast/mod.rs index f0287507..31510bd4 100644 --- a/asn1rs-model/src/ast/mod.rs +++ b/asn1rs-model/src/ast/mod.rs @@ -80,8 +80,10 @@ pub fn parse_asn_definition( let item_span = item.span(); let attr_span = attr.span(); - println!("ATTRIBUTE: {}", attr.to_string()); - println!("ITEM: {}", item.to_string()); + if cfg!(feature = "debug-proc-macro") { + println!("ATTRIBUTE: {}", attr.to_string()); + println!("ITEM: {}", item.to_string()); + } let item = syn::parse2::(item) .map_err(|e| compile_error_ts(item_span, format!("Invalid Item: {}", e)))?; diff --git a/asn1rs-model/src/gen/rust/async_psql.rs b/asn1rs-model/src/gen/rust/async_psql.rs index 64e36926..358b58e7 100644 --- a/asn1rs-model/src/gen/rust/async_psql.rs +++ b/asn1rs-model/src/gen/rust/async_psql.rs @@ -1,8 +1,8 @@ use crate::gen::rust::shared_psql::*; use crate::gen::rust::GeneratorSupplement; use crate::gen::RustCodeGenerator; -use crate::model::rust::DataEnum; use crate::model::rust::PlainEnum; +use crate::model::rust::{DataEnum, Field}; use crate::model::sql::{Sql, SqlType, ToSql}; use crate::model::{Definition, Model, Rust, RustType}; use codegen::{Block, Function, Impl, Scope}; @@ -20,19 +20,20 @@ impl GeneratorSupplement for AsyncPsqlInserter { fn impl_supplement(&self, _scope: &mut Scope, _definition: &Definition) {} - fn extend_impl_of_struct( - &self, - name: &str, - impl_scope: &mut Impl, - fields: &[(String, RustType)], - ) { + fn extend_impl_of_struct<'a>(&self, name: &str, impl_scope: &mut Impl, fields: &[Field]) { AsyncPsqlInserter::append_retrieve_many_for_container_type(name, impl_scope); AsyncPsqlInserter::append_retrieve_for_container_type(name, impl_scope); AsyncPsqlInserter::append_load_struct(name, impl_scope, fields); let fn_insert = create_insert_fn(impl_scope, true); fn_insert.line(prepare_struct_insert_statement(name, fields)); - impl_insert_fn_content(false, true, name, fields, fn_insert); + impl_insert_fn_content( + false, + true, + name, + || fields.iter().map(Field::fallback_representation), + fn_insert, + ); } fn extend_impl_of_enum(&self, _name: &str, impl_scope: &mut Impl, _r_enum: &PlainEnum) { @@ -87,7 +88,7 @@ impl GeneratorSupplement for AsyncPsqlInserter { RustType::Option(Box::new(variant.r#type().clone())), )); } - impl_insert_fn_content(false, false, name, &updated_variants[..], fn_insert); + impl_insert_fn_content(false, false, name, || updated_variants.iter(), fn_insert); } fn extend_impl_of_tuple(&self, name: &str, impl_scope: &mut Impl, definition: &RustType) { @@ -104,20 +105,20 @@ impl GeneratorSupplement for AsyncPsqlInserter { "let statement = context.prepared(\"{}\");", tuple_struct_insert_statement(name) )); - impl_insert_fn_content(true, true, name, &fields[..], fn_insert); + impl_insert_fn_content(true, true, name, || fields.iter(), fn_insert); } } -fn impl_insert_fn_content( +fn impl_insert_fn_content<'a, I: ExactSizeIterator>( is_tuple_struct: bool, on_self: bool, name: &str, - fields: &[(String, RustType)], + fields: impl Fn() -> I, container: &mut impl Container, ) { let mut params = Vec::default(); let mut to_await = Vec::default(); - for insert in fields.iter().filter_map(|(field_name, r_type)| { + for insert in fields().filter_map(|(field_name, r_type)| { let field_name = RustCodeGenerator::rust_field_name(field_name, true); let field_name_as_variable = if field_name .chars() @@ -178,7 +179,7 @@ fn impl_insert_fn_content( .join(", ") )); to_await.clear(); - for insert in fields.iter().filter_map(|(field_name, r_type)| { + for insert in fields().filter_map(|(field_name, r_type)| { if r_type.is_vec() { Some(insert_field( is_tuple_struct, @@ -211,7 +212,7 @@ fn impl_insert_fn_content( container.line("Ok(id)"); } -fn prepare_struct_insert_statement(name: &str, fields: &[(String, RustType)]) -> String { +fn prepare_struct_insert_statement(name: &str, fields: &[Field]) -> String { format!( "let statement = context.prepared(\"{}\");", struct_insert_statement(name, fields) @@ -616,23 +617,30 @@ impl AsyncPsqlInserter { fn_retrieve.line(format!("Self::{}(context, &row).await", load_fn_name())); } - fn append_load_struct(name: &str, impl_scope: &mut Impl, fields: &[(String, RustType)]) { + fn append_load_struct(name: &str, impl_scope: &mut Impl, fields: &[Field]) { let fn_load = create_load_fn( impl_scope, - fields.iter().any(|(_name, f_type)| { - !Model::::is_primitive(f_type) - || Model::::has_no_column_in_embedded_struct(f_type.as_no_option()) + fields.iter().any(|field| { + !Model::::is_primitive(field.r#type()) + || Model::::has_no_column_in_embedded_struct(field.r#type().as_no_option()) }), ); - for (index, (field, f_type)) in fields.iter().enumerate() { - AsyncPsqlInserter::append_load_field(false, name, fn_load, index, field, f_type); + for (index, field) in fields.iter().enumerate() { + AsyncPsqlInserter::append_load_field( + false, + name, + fn_load, + index, + field.name(), + field.r#type(), + ); } let mut result_block = Block::new("Ok(Self"); - for (field, _type) in fields { + for field in fields { result_block.line(format!( "{},", - RustCodeGenerator::rust_field_name(field, true) + RustCodeGenerator::rust_field_name(field.name(), true) )); } result_block.after(")"); diff --git a/asn1rs-model/src/gen/rust/mod.rs b/asn1rs-model/src/gen/rust/mod.rs index e4ddcd7c..7c8c9315 100644 --- a/asn1rs-model/src/gen/rust/mod.rs +++ b/asn1rs-model/src/gen/rust/mod.rs @@ -14,8 +14,8 @@ pub(crate) mod shared_psql; use self::protobuf::ProtobufSerializer; use self::uper::UperSerializer; use crate::gen::Generator; -use crate::model::rust::DataEnum; use crate::model::rust::PlainEnum; +use crate::model::rust::{DataEnum, Field}; use crate::model::Model; use crate::model::Range; use crate::model::Rust; @@ -42,13 +42,7 @@ const KEYWORDS: [&str; 9] = [ pub trait GeneratorSupplement { fn add_imports(&self, scope: &mut Scope); fn impl_supplement(&self, scope: &mut Scope, definition: &Definition); - fn extend_impl_of_struct( - &self, - _name: &str, - _impl_scope: &mut Impl, - _fields: &[(String, RustType)], - ) { - } + fn extend_impl_of_struct(&self, _name: &str, _impl_scope: &mut Impl, _fields: &[Field]) {} fn extend_impl_of_enum(&self, _name: &str, _impl_scope: &mut Impl, _enumeration: &PlainEnum) {} fn extend_impl_of_data_enum( &self, @@ -184,7 +178,7 @@ impl RustCodeGenerator { scope.raw(&Self::asn_attribute( "enumerated", None, - plain.extension_after_variant().map(|v| v.clone()), + plain.extension_after_variant().cloned(), )); Self::add_enum(self.new_enum(scope, name, true), name, plain) } @@ -209,25 +203,20 @@ impl RustCodeGenerator { } } - fn add_struct( - str_ct: &mut Struct, - _name: &str, - fields: &[(String, RustType)], - pub_access: bool, - ) { - for (field_name, field_type) in fields.iter() { + fn add_struct(str_ct: &mut Struct, _name: &str, fields: &[Field], pub_access: bool) { + for field in fields { str_ct.field( &format!( "{} {}{}", Self::asn_attribute( - &Self::asn_attribute_type(&field_type.clone().into_asn()), - None, // TODO missing tag + &Self::asn_attribute_type(&field.r#type().clone().into_asn()), + field.tag(), None ), if pub_access { "pub " } else { "" }, - Self::rust_field_name(field_name, true), + Self::rust_field_name(field.name(), true), ), - field_type.to_string(), + field.r#type().to_string(), ); } } @@ -390,19 +379,19 @@ impl RustCodeGenerator { fn impl_struct<'a>( scope: &'a mut Scope, name: &str, - fields: &[(String, RustType)], + fields: &[Field], getter_and_setter: bool, ) -> &'a mut Impl { let implementation = scope.new_impl(name); - for (field_name, field_type) in fields.iter() { + for field in fields { if getter_and_setter { - Self::impl_struct_field_get(implementation, field_name, field_type); - Self::impl_struct_field_get_mut(implementation, field_name, field_type); - Self::impl_struct_field_set(implementation, field_name, field_type); + Self::impl_struct_field_get(implementation, field.name(), field.r#type()); + Self::impl_struct_field_get_mut(implementation, field.name(), field.r#type()); + Self::impl_struct_field_set(implementation, field.name(), field.r#type()); } - Self::add_min_max_fn_if_applicable(implementation, Some(field_name), field_type); + Self::add_min_max_fn_if_applicable(implementation, Some(field.name()), field.r#type()); } implementation } diff --git a/asn1rs-model/src/gen/rust/protobuf.rs b/asn1rs-model/src/gen/rust/protobuf.rs index bed7daf9..6b6de083 100644 --- a/asn1rs-model/src/gen/rust/protobuf.rs +++ b/asn1rs-model/src/gen/rust/protobuf.rs @@ -1,8 +1,8 @@ use crate::gen::rust::GeneratorSupplement; use crate::gen::rust::RustCodeGenerator; use crate::model::protobuf::ToProtobufType; -use crate::model::rust::DataEnum; use crate::model::rust::PlainEnum; +use crate::model::rust::{DataEnum, Field}; use crate::model::Definition; use crate::model::ProtobufType; use crate::model::Rust; @@ -125,11 +125,11 @@ impl ProtobufSerializer { function.line("Ok(me)"); } - fn impl_read_fn_for_struct(function: &mut Function, name: &str, fields: &[(String, RustType)]) { - for (field_name, _field_type) in fields.iter() { + fn impl_read_fn_for_struct(function: &mut Function, name: &str, fields: &[Field]) { + for field in fields.iter() { function.line(format!( "let mut read_{} = None;", - RustCodeGenerator::rust_field_name(field_name, false), + RustCodeGenerator::rust_field_name(field.name(), false), )); } @@ -137,14 +137,14 @@ impl ProtobufSerializer { let mut block_match_tag = Block::new("match tag.0"); block_match_tag.line("0 => break,"); - for (prev_tag, (field_name, field_type)) in fields.iter().enumerate() { - match &field_type.clone().into_inner_type() { + for (prev_tag, field) in fields.iter().enumerate() { + match &field.r#type().clone().into_inner_type() { RustType::Complex(name) => { let mut block_case = Block::new(&format!( "{} => read_{}{}(", prev_tag + 1, - RustCodeGenerator::rust_field_name(field_name, false), - if let RustType::Vec(_) = field_type.clone().no_option() { + RustCodeGenerator::rust_field_name(field.name(), false), + if let RustType::Vec(_) = field.r#type().clone().no_option() { ".get_or_insert_with(Vec::default).push" } else { " = Some" @@ -168,18 +168,18 @@ impl ProtobufSerializer { block_match_tag.push_block(block_case); } role => { - if let RustType::Vec(_) = field_type.clone().no_option() { + if let RustType::Vec(_) = field.r#type().clone().no_option() { block_match_tag.line(format!( "{} => read_{}.get_or_insert_with(Vec::default).push({}),", prev_tag + 1, - RustCodeGenerator::rust_field_name(field_name, false), + RustCodeGenerator::rust_field_name(field.name(), false), format!("reader.read_{}()?", role.to_protobuf().to_string(),) )); } else { block_match_tag.line(format!( "{} => read_{} = Some({}),", prev_tag + 1, - RustCodeGenerator::rust_field_name(field_name, false), + RustCodeGenerator::rust_field_name(field.name(), false), format!("reader.read_{}()?", role.to_protobuf().to_string(),) )); } @@ -194,16 +194,16 @@ impl ProtobufSerializer { block_reader_loop.push_block(block_match_tag); function.push_block(block_reader_loop); let mut return_block = Block::new(&format!("Ok({}", name)); - for (field_name, field_type) in fields.iter() { + for field in fields.iter() { let as_rust_statement = - Self::get_as_rust_type_statement(&field_type.clone().into_inner_type()); + Self::get_as_rust_type_statement(&field.r#type().clone().into_inner_type()); return_block.line(&format!( "{}: read_{}{}{},", - RustCodeGenerator::rust_field_name(field_name, true), - RustCodeGenerator::rust_field_name(field_name, false), + RustCodeGenerator::rust_field_name(field.name(), true), + RustCodeGenerator::rust_field_name(field.name(), false), if as_rust_statement.is_empty() { "".into() - } else if let RustType::Vec(_) = field_type.clone().no_option() { + } else if let RustType::Vec(_) = field.r#type().clone().no_option() { format!( ".map(|v| v.into_iter().map(|v| v{}).collect())", as_rust_statement @@ -211,7 +211,7 @@ impl ProtobufSerializer { } else { format!(".map(|v| v{})", as_rust_statement) }, - if let RustType::Option(_) = field_type { + if let RustType::Option(_) = field.r#type() { "" } else { ".unwrap_or_default()" @@ -366,11 +366,11 @@ impl ProtobufSerializer { function.push_block(block_writer); } - fn impl_write_fn_for_struct(function: &mut Function, fields: &[(String, RustType)]) { - for (prev_tag, (field_name, field_type)) in fields.iter().enumerate() { + fn impl_write_fn_for_struct(function: &mut Function, fields: &[Field]) { + for (prev_tag, field) in fields.iter().enumerate() { let block_: &mut Function = function; - let field_name = RustCodeGenerator::rust_field_name(field_name, true); - let mut block = if let RustType::Option(_) = field_type { + let field_name = RustCodeGenerator::rust_field_name(field.name(), true); + let mut block = if let RustType::Option(_) = field.r#type() { Block::new(&format!( "if let Some(ref {}) = self.{}", &field_name, &field_name, @@ -379,7 +379,7 @@ impl ProtobufSerializer { Block::new("") }; - Self::impl_write_field(prev_tag + 1, field_type, &field_name, &mut block, false); + Self::impl_write_field(prev_tag + 1, field.r#type(), &field_name, &mut block, false); block_.push_block(block); } } @@ -551,11 +551,11 @@ impl ProtobufSerializer { )); } Rust::Struct(fields) => { - for (num, (field_name, _field_type)) in fields.iter().enumerate() { + for (num, field) in fields.iter().enumerate() { if num > 0 { function.line("&&"); } - let field_name = RustCodeGenerator::rust_field_name(field_name, true); + let field_name = RustCodeGenerator::rust_field_name(field.name(), true); function.line(&format!( "self.{}.{}_eq(&other.{})", field_name, diff --git a/asn1rs-model/src/gen/rust/psql.rs b/asn1rs-model/src/gen/rust/psql.rs index 0bc20bb2..47a0fffe 100644 --- a/asn1rs-model/src/gen/rust/psql.rs +++ b/asn1rs-model/src/gen/rust/psql.rs @@ -1,8 +1,8 @@ use crate::gen::rust::shared_psql::*; use crate::gen::rust::GeneratorSupplement; use crate::gen::rust::RustCodeGenerator; -use crate::model::rust::DataEnum; use crate::model::rust::PlainEnum; +use crate::model::rust::{DataEnum, Field}; use crate::model::sql::Sql; use crate::model::sql::ToSql; use crate::model::Definition; @@ -79,12 +79,12 @@ impl PsqlInserter { Self::impl_struct_insert_statement( Self::new_insert_statement_fn(implementation), name, - &fields[..], + fields, ); Self::impl_struct_insert_fn( Self::new_insert_fn(implementation, true), name, - &fields[..], + fields.iter().map(Field::fallback_representation), ); } Rust::DataEnum(enumeration) => { @@ -146,11 +146,7 @@ impl PsqlInserter { function.line(&format!("\"{}\"", name)); } - fn impl_struct_insert_statement( - function: &mut Function, - name: &str, - fields: &[(String, RustType)], - ) { + fn impl_struct_insert_statement(function: &mut Function, name: &str, fields: &[Field]) { if fields.is_empty() { Self::impl_tuple_insert_statement(function, name); } else { @@ -181,10 +177,10 @@ impl PsqlInserter { function.line(&format!("\"{}\"", tuple_struct_insert_statement(name))); } - fn impl_struct_insert_fn( + fn impl_struct_insert_fn<'a>( function: &mut Function, struct_name: &str, - fields: &[(String, RustType)], + fields: impl ExactSizeIterator, ) { let mut variables = Vec::with_capacity(fields.len()); let mut vecs = Vec::new(); @@ -404,12 +400,12 @@ impl PsqlInserter { Self::impl_struct_load_fn( Self::new_load_fn( implementation, - fields - .iter() - .any(|(_, rust)| !Model::::is_primitive(rust) || rust.is_vec()), + fields.iter().any(|field| { + !Model::::is_primitive(field.r#type()) || field.r#type().is_vec() + }), ), name, - &fields[..], + fields.iter().map(Field::fallback_representation), ); } Rust::DataEnum(enumeration) => { @@ -462,15 +458,15 @@ impl PsqlInserter { name, ERROR_TYPE, )); } - fn impl_struct_load_fn( + fn impl_struct_load_fn<'a>( func: &mut Function, struct_name: &str, - variants: &[(String, RustType)], + variants: impl ExactSizeIterator, ) { let mut block = Block::new(&format!("Ok({}", struct_name)); let mut index_negative_offset = 0; - for (index, (name, rust)) in variants.iter().enumerate() { + for (index, (name, rust)) in variants.enumerate() { let index = index - index_negative_offset; // Lists do not have a entry in the `holding` table but diff --git a/asn1rs-model/src/gen/rust/shared_psql.rs b/asn1rs-model/src/gen/rust/shared_psql.rs index 5a6b51ab..f7be8af2 100644 --- a/asn1rs-model/src/gen/rust/shared_psql.rs +++ b/asn1rs-model/src/gen/rust/shared_psql.rs @@ -1,5 +1,5 @@ use crate::gen::RustCodeGenerator; -use crate::model::rust::DataEnum; +use crate::model::rust::{DataEnum, Field}; use crate::model::sql::Sql; use crate::model::{Model, RustType}; @@ -16,22 +16,26 @@ pub(crate) fn tuple_struct_insert_statement(name: &str) -> String { format!("INSERT INTO {} DEFAULT VALUES RETURNING id", name) } -pub(crate) fn struct_insert_statement(name: &str, fields: &[(String, RustType)]) -> String { +pub(crate) fn struct_insert_statement(name: &str, fields: &[Field]) -> String { format!( "INSERT INTO {}({}) VALUES({}) RETURNING id", name, fields .iter() - .filter_map(|(name, field)| if field.is_vec() { + .filter_map(|field| if field.r#type().is_vec() { None } else { - Some(Model::sql_column_name(name)) + Some(Model::sql_column_name(field.name())) }) .collect::>() .join(", "), fields .iter() - .filter_map(|(name, field)| if field.is_vec() { None } else { Some(name) }) + .filter_map(|field| if field.r#type().is_vec() { + None + } else { + Some(field.name()) + }) .enumerate() .map(|(num, _)| format!("${}", num + 1)) .collect::>() diff --git a/asn1rs-model/src/gen/rust/uper.rs b/asn1rs-model/src/gen/rust/uper.rs index 417a630c..f93a4bcc 100644 --- a/asn1rs-model/src/gen/rust/uper.rs +++ b/asn1rs-model/src/gen/rust/uper.rs @@ -1,7 +1,7 @@ use crate::gen::rust::GeneratorSupplement; use crate::gen::rust::RustCodeGenerator; -use crate::model::rust::PlainEnum; use crate::model::rust::{DataEnum, Enumeration}; +use crate::model::rust::{Field, PlainEnum}; use crate::model::Definition; use crate::model::Rust; use crate::model::RustType; @@ -54,8 +54,8 @@ impl UperSerializer { Self::impl_read_fn_for_tuple_struct(function, name, aliased); } Rust::Struct(fields) => { - for (field_name, field_type) in fields.iter() { - Self::impl_read_fn_header_for_type(function, field_name, field_type); + for field in fields.iter() { + Self::impl_read_fn_header_for_type(function, field.name(), field.r#type()); } Self::impl_read_fn_for_struct(function, fields); } @@ -196,18 +196,18 @@ impl UperSerializer { } } - fn impl_read_fn_for_struct(function: &mut Function, fields: &[(String, RustType)]) { + fn impl_read_fn_for_struct(function: &mut Function, fields: &[Field]) { function.line("let mut me = Self::default();"); - for (field_name, field_type) in fields.iter() { + for field in fields { let mut block = Block::new(&format!( "me.{} = ", - RustCodeGenerator::rust_field_name(field_name, true) + RustCodeGenerator::rust_field_name(field.name(), true) )); Self::impl_read_fn_for_type( &mut block, - &field_type.to_inner_type_string(), - Some(Member::Instance(field_name.clone(), false, false)), - field_type, + &field.r#type().to_inner_type_string(), + Some(Member::Instance(field.name().to_string(), false, false)), + field.r#type(), ); block.after(";"); function.push_block(block); @@ -308,8 +308,8 @@ impl UperSerializer { Self::impl_write_fn_for_tuple_struct(function, inner); } Rust::Struct(fields) => { - for (field_name, field_type) in fields.iter() { - Self::impl_write_fn_header_for_type(function, field_name, field_type); + for field in fields.iter() { + Self::impl_write_fn_header_for_type(function, field.name(), field.r#type()); } Self::impl_write_fn_for_struct(function, fields); } @@ -473,17 +473,17 @@ impl UperSerializer { } } } - fn impl_write_fn_for_struct(function: &mut Function, fields: &[(String, RustType)]) { + fn impl_write_fn_for_struct(function: &mut Function, fields: &[Field]) { let mut block = Block::new(""); - for (field_name, field_type) in fields.iter() { + for field in fields.iter() { Self::impl_write_fn_for_type( &mut block, Some(Member::Instance( - field_name.clone(), - !field_type.clone().no_option().is_primitive(), + field.name().to_string(), + !field.r#type().clone().no_option().is_primitive(), false, )), - field_type, + field.r#type(), ); } function.push_block(block); diff --git a/asn1rs-model/src/gen/rust/walker.rs b/asn1rs-model/src/gen/rust/walker.rs index 2ba1fc64..fb68ad37 100644 --- a/asn1rs-model/src/gen/rust/walker.rs +++ b/asn1rs-model/src/gen/rust/walker.rs @@ -1,5 +1,5 @@ use crate::gen::RustCodeGenerator; -use crate::model::rust::{DataEnum, PlainEnum}; +use crate::model::rust::{DataEnum, Field, PlainEnum}; use crate::model::{Definition, Model, Range, Rust, RustType}; use codegen::{Block, Impl, Scope}; use std::fmt::Display; @@ -20,8 +20,8 @@ impl AsnDefWriter { "type AsnDef{} = {}Sequence<{}>;", name, CRATE_SYN_PREFIX, name )); - for (field, r#type) in fields { - self.write_type_declaration(scope, &name, &field, r#type); + for field in fields { + self.write_type_declaration(scope, &name, field.name(), field.r#type()); } } Rust::Enum(_enm) => { @@ -106,76 +106,71 @@ impl AsnDefWriter { } Rust::DataEnum(data) => self.write_choice_constraint(scope, &name, data), Rust::TupleStruct(field) => { - let fields = [(String::from("0"), field.clone())]; + let fields = [Field::from_name_type("0", field.clone())]; self.write_field_constraints(scope, &name, &fields[..]); self.write_sequence_constraint(scope, &name, &fields[..]); } } } - fn write_field_constraints( - &self, - scope: &mut Scope, - name: &str, - fields: &[(String, RustType)], - ) { - for (field, r#type) in fields { - match r#type { + fn write_field_constraints(&self, scope: &mut Scope, name: &str, fields: &[Field]) { + for field in fields { + match field.r#type() { RustType::Bool => {} RustType::I8(range) => Self::write_integer_constraint_type( scope, name, - field, - &r#type.to_string(), + field.name(), + &field.r#type().to_string(), range, ), RustType::U8(range) => Self::write_integer_constraint_type( scope, name, - field, - &r#type.to_string(), + field.name(), + &field.r#type().to_string(), range, ), RustType::I16(range) => Self::write_integer_constraint_type( scope, name, - field, - &r#type.to_string(), + field.name(), + &field.r#type().to_string(), range, ), RustType::U16(range) => Self::write_integer_constraint_type( scope, name, - field, - &r#type.to_string(), + field.name(), + &field.r#type().to_string(), range, ), RustType::I32(range) => Self::write_integer_constraint_type( scope, name, - field, - &r#type.to_string(), + field.name(), + &field.r#type().to_string(), range, ), RustType::U32(range) => Self::write_integer_constraint_type( scope, name, - field, - &r#type.to_string(), + field.name(), + &field.r#type().to_string(), range, ), RustType::I64(range) => Self::write_integer_constraint_type( scope, name, - field, - &r#type.to_string(), + field.name(), + &field.r#type().to_string(), range, ), RustType::U64(Some(range)) => Self::write_integer_constraint_type( scope, name, - field, - &r#type.to_string(), + field.name(), + &field.r#type().to_string(), range, ), RustType::U64(_) => {} @@ -184,24 +179,19 @@ impl AsnDefWriter { RustType::Vec(inner) => self.write_field_constraints( scope, name, - &[(field.to_string(), *inner.clone())], + &[Field::from_name_type(field.name(), *inner.clone())], ), RustType::Option(inner) => self.write_field_constraints( scope, name, - &[(field.to_string(), *inner.clone())], + &[Field::from_name_type(field.name(), *inner.clone())], ), RustType::Complex(_) => {} } } } - fn write_sequence_constraint( - &self, - scope: &mut Scope, - name: &str, - fields: &[(String, RustType)], - ) { + fn write_sequence_constraint(&self, scope: &mut Scope, name: &str, fields: &[Field]) { let mut imp = Impl::new(name); imp.impl_trait(format!("{}sequence::Constraint", CRATE_SYN_PREFIX)); @@ -373,7 +363,7 @@ impl AsnDefWriter { fn write_sequence_constraint_insert_consts( scope: &mut Scope, name: &str, - fields: &[(String, RustType)], + fields: &[Field], imp: Impl, ) { Self::insert_consts( @@ -382,7 +372,7 @@ impl AsnDefWriter { &[ format!( "const OPTIONAL_FIELDS: usize = {};", - fields.iter().filter(|f| f.1.is_option()).count() + fields.iter().filter(|f| f.r#type().is_option()).count() ), format!("const NAME: &'static str = \"{}\";", name), ], @@ -404,12 +394,7 @@ impl AsnDefWriter { scope.raw(&lines.join("\n")); } - fn write_sequence_constraint_read_fn( - &self, - imp: &mut Impl, - name: &str, - fields: &[(String, RustType)], - ) { + fn write_sequence_constraint_read_fn(&self, imp: &mut Impl, name: &str, fields: &[Field]) { imp.new_fn("read_seq") .generic(&format!("R: {}Reader", CRATE_SYN_PREFIX)) .arg("reader", "&mut R") @@ -418,11 +403,11 @@ impl AsnDefWriter { .push_block({ let mut block = Block::new("Ok(Self"); - for (field, _type) in fields { + for field in fields { block.line(format!( "{}: AsnDef{}::read_value(reader)?,", - field, - Self::combined_field_type_name(name, field) + field.name(), + Self::combined_field_type_name(name, field.name()) )); } @@ -431,12 +416,7 @@ impl AsnDefWriter { }); } - fn write_sequence_constraint_write_fn( - &self, - imp: &mut Impl, - name: &str, - fields: &[(String, RustType)], - ) { + fn write_sequence_constraint_write_fn(&self, imp: &mut Impl, name: &str, fields: &[Field]) { let body = imp .new_fn("write_seq") .generic(&format!("W: {}Writer", CRATE_SYN_PREFIX)) @@ -444,11 +424,11 @@ impl AsnDefWriter { .arg("writer", "&mut W") .ret("Result<(), W::Error>"); - for (field, _type) in fields { + for field in fields { body.line(format!( "AsnDef{}::write_value(writer, &self.{})?;", - Self::combined_field_type_name(name, field), - field, + Self::combined_field_type_name(name, field.name()), + field.name(), )); } @@ -473,6 +453,7 @@ impl AsnDefWriter { #[cfg(test)] pub mod tests { use crate::gen::rust::walker::AsnDefWriter; + use crate::model::rust::Field; use crate::model::{Definition, Rust, RustType}; use codegen::Scope; @@ -480,15 +461,9 @@ pub mod tests { Definition( String::from("Whatever"), Rust::Struct(vec![ - (String::from("name"), RustType::String), - ( - String::from("opt"), - RustType::Option(Box::new(RustType::String)), - ), - ( - String::from("some"), - RustType::Option(Box::new(RustType::String)), - ), + Field::from_name_type("name", RustType::String), + Field::from_name_type("opt", RustType::Option(Box::new(RustType::String))), + Field::from_name_type("some", RustType::Option(Box::new(RustType::String))), ]), ) } diff --git a/asn1rs-model/src/model/protobuf.rs b/asn1rs-model/src/model/protobuf.rs index 44b0bb6e..263014bb 100644 --- a/asn1rs-model/src/model/protobuf.rs +++ b/asn1rs-model/src/model/protobuf.rs @@ -123,10 +123,10 @@ impl Model { match rust { Rust::Struct(fields) => { let mut proto_fields = Vec::with_capacity(fields.len()); - for (name, rust) in fields.iter() { + for field in fields.iter() { proto_fields.push(( - proto_field_name(name), - Self::definition_type_to_protobuf_type(rust), + proto_field_name(field.name()), + Self::definition_type_to_protobuf_type(field.r#type()), )); } @@ -229,7 +229,10 @@ mod tests { test_model_definition_conversion( &[Definition( "Mine".into(), - Rust::Struct(vec![("field".into(), RustType::U8(Range(0, 255)))]), + Rust::Struct(vec![Field::from_name_type( + "field", + RustType::U8(Range(0, 255)), + )]), )], &[Definition( "Mine".into(), @@ -274,8 +277,8 @@ mod tests { test_model_definition_conversion( &[Definition( "SuchStruct".into(), - Rust::Struct(vec![( - "very_optional".into(), + Rust::Struct(vec![Field::from_name_type( + "very_optional", RustType::Option(Box::new(RustType::String)), )]), )], diff --git a/asn1rs-model/src/model/rust.rs b/asn1rs-model/src/model/rust.rs index 1c608513..f460b5d3 100644 --- a/asn1rs-model/src/model/rust.rs +++ b/asn1rs-model/src/model/rust.rs @@ -1,3 +1,4 @@ +use crate::model::rust::Field as RustField; use crate::model::Model; use crate::model::Range; use crate::model::Type as AsnType; @@ -262,7 +263,7 @@ impl RustType { #[derive(Debug, Clone, PartialOrd, PartialEq)] pub enum Rust { - Struct(Vec<(String, RustType)>), + Struct(Vec), Enum(PlainEnum), DataEnum(DataEnum), @@ -292,6 +293,47 @@ impl ToString for RustType { } } +#[derive(Debug, Clone, PartialOrd, PartialEq)] +pub struct Field { + name_type: (String, RustType), + tag: Option, +} + +impl Field { + pub fn from_name_type(name: T, r#type: RustType) -> Self { + Self { + name_type: (name.to_string(), r#type), + tag: None, + } + } + + pub fn fallback_representation(&self) -> &(String, RustType) { + &self.name_type + } + + pub fn name(&self) -> &str { + &self.name_type.0 + } + + pub fn r#type(&self) -> &RustType { + &self.name_type.1 + } +} + +impl TagProperty for Field { + fn tag(&self) -> Option { + self.tag + } + + fn set_tag(&mut self, tag: Tag) { + self.tag = Some(tag); + } + + fn reset_tag(&mut self) { + self.tag = None; + } +} + #[derive(Debug, Clone, PartialOrd, PartialEq)] pub struct Enumeration { variants: Vec, @@ -331,7 +373,7 @@ impl Enumeration { pub fn extension_after_variant(&self) -> Option<&T> { self.extended_after_index - .and_then(|index| self.variants.iter().nth(index)) + .and_then(|index| self.variants.get(index)) } pub fn is_extensible(&self) -> bool { @@ -440,7 +482,7 @@ impl Model { let rust_role = Self::definition_type_to_rust_type(&rust_name, &field.role.r#type, defs); let rust_field_name = rust_field_name(&field.name); - rust_fields.push((rust_field_name, rust_role)); + rust_fields.push(RustField::from_name_type(rust_field_name, rust_role)); } defs.push(Definition(name.into(), Rust::Struct(rust_fields))); @@ -613,11 +655,11 @@ mod tests { Definition( "Simple".into(), Rust::Struct(vec![ - ("small".into(), RustType::U8(Range(0, 255))), - ("bigger".into(), RustType::U16(Range(0, 65535))), - ("negative".into(), RustType::I16(Range(-1, 255))), - ( - "unlimited".into(), + RustField::from_name_type("small", RustType::U8(Range(0, 255))), + RustField::from_name_type("bigger", RustType::U16(Range(0, 65535))), + RustField::from_name_type("negative", RustType::I16(Range(-1, 255))), + RustField::from_name_type( + "unlimited", RustType::Option(Box::new(RustType::U64(None))) ), ]) @@ -654,8 +696,8 @@ mod tests { assert_eq!( Definition( "Woah".into(), - Rust::Struct(vec![( - "decision".into(), + Rust::Struct(vec![RustField::from_name_type( + "decision", RustType::Option(Box::new(RustType::Complex("WoahDecision".into()))) )]) ), @@ -692,16 +734,16 @@ mod tests { Definition( "Woah".into(), Rust::Struct(vec![ - ( - "also_ones".into(), + RustField::from_name_type( + "also_ones", RustType::Vec(Box::new(RustType::U8(Range(0, 1)))) ), - ( - "nesteds".into(), + RustField::from_name_type( + "nesteds", RustType::Vec(Box::new(RustType::Vec(Box::new(RustType::U8(Range(0, 1)))))) ), - ( - "optionals".into(), + RustField::from_name_type( + "optionals", RustType::Option(Box::new(RustType::Vec(Box::new(RustType::Vec( Box::new(RustType::U64(None)) ))))) @@ -761,8 +803,8 @@ mod tests { assert_eq!( Definition( "Woah".into(), - Rust::Struct(vec![( - "decision".into(), + Rust::Struct(vec![RustField::from_name_type( + "decision", RustType::Complex("WoahDecision".into()) )]) ), @@ -783,13 +825,13 @@ mod tests { Definition( "WoahComplex".into(), Rust::Struct(vec![ - ("ones".into(), RustType::U8(Range(0, 1))), - ( - "list_ones".into(), + RustField::from_name_type("ones", RustType::U8(Range(0, 1))), + RustField::from_name_type( + "list_ones", RustType::Vec(Box::new(RustType::U8(Range(0, 1)))) ), - ( - "optional_ones".into(), + RustField::from_name_type( + "optional_ones", RustType::Option(Box::new(RustType::Vec(Box::new(RustType::U8(Range( 0, 1 )))))) @@ -801,8 +843,8 @@ mod tests { assert_eq!( Definition( "Woah".into(), - Rust::Struct(vec![( - "complex".into(), + Rust::Struct(vec![RustField::from_name_type( + "complex", RustType::Option(Box::new(RustType::Complex("WoahComplex".into()))) )]) ), @@ -973,8 +1015,8 @@ mod tests { assert_eq!( Definition( "OptionalStructListTest".into(), - Rust::Struct(vec![( - "strings".into(), + Rust::Struct(vec![RustField::from_name_type( + "strings", RustType::Option(Box::new(RustType::Vec(Box::new(RustType::String)))) )]) ), @@ -1001,8 +1043,8 @@ mod tests { assert_eq!( Definition( "StructListTest".into(), - Rust::Struct(vec![( - "strings".into(), + Rust::Struct(vec![RustField::from_name_type( + "strings", RustType::Vec(Box::new(RustType::String)) )]) ), @@ -1032,8 +1074,8 @@ mod tests { assert_eq!( Definition( "NestedStructListTest".into(), - Rust::Struct(vec![( - "strings".into(), + Rust::Struct(vec![RustField::from_name_type( + "strings", RustType::Vec(Box::new(RustType::Vec(Box::new(RustType::String)))) )]) ), diff --git a/asn1rs-model/src/model/sql.rs b/asn1rs-model/src/model/sql.rs index 31abcec3..61ff94b5 100644 --- a/asn1rs-model/src/model/sql.rs +++ b/asn1rs-model/src/model/sql.rs @@ -1,6 +1,6 @@ use crate::gen::RustCodeGenerator; -use crate::model::rust::PlainEnum; use crate::model::rust::{DataEnum, DataVariant}; +use crate::model::rust::{Field, PlainEnum}; use crate::model::Definition; use crate::model::Model; use crate::model::Range; @@ -153,7 +153,7 @@ impl Model { pub fn rust_struct_to_sql_table( name: &str, - fields: &[(String, RustType)], + fields: &[Field], definitions: &mut Vec>, ) { let mut deferred = Vec::default(); @@ -163,15 +163,15 @@ impl Model { sql: SqlType::Serial, primary_key: true, }); - for (column, rust) in fields { - if rust.is_vec() { - let list_entry_name = Self::struct_list_entry_table_name(name, column); - let value_sql_type = rust.clone().into_inner_type().to_sql(); + for field in fields { + if field.r#type().is_vec() { + let list_entry_name = Self::struct_list_entry_table_name(name, field.name()); + let value_sql_type = field.r#type().clone().into_inner_type().to_sql(); Self::add_list_table(name, &mut deferred, &list_entry_name, &value_sql_type); } else { columns.push(Column { - name: Self::sql_column_name(column), - sql: rust.to_sql(), + name: Self::sql_column_name(field.name()), + sql: field.r#type().to_sql(), primary_key: false, }); } @@ -181,7 +181,11 @@ impl Model { Sql::Table(columns, Default::default()), )); - Self::append_index_and_abandon_function(name, fields.iter(), definitions); + Self::append_index_and_abandon_function( + name, + fields.iter().map(Field::fallback_representation), + definitions, + ); deferred.into_iter().for_each(|e| definitions.push(e)); } @@ -454,6 +458,7 @@ impl ToSql for RustType { #[cfg(test)] mod tests { use super::*; + use crate::model::rust::Field; use crate::model::Import; use crate::model::Model; @@ -468,8 +473,8 @@ mod tests { definitions: vec![Definition( "Person".into(), Rust::Struct(vec![ - ("name".into(), RustType::String), - ("birth".into(), RustType::Complex("City".into())), + Field::from_name_type("name", RustType::String), + Field::from_name_type("birth", RustType::Complex("City".into())), ]), )], } @@ -635,12 +640,12 @@ mod tests { definitions: vec![Definition( "SomeStruct".into(), Rust::Struct(vec![ - ( - "list_of_primitive".into(), + Field::from_name_type( + "list_of_primitive", RustType::Vec(Box::new(RustType::String)), ), - ( - "list_of_reference".into(), + Field::from_name_type( + "list_of_reference", RustType::Vec(Box::new(RustType::Complex("ComplexType".into()))), ), ]), @@ -913,7 +918,7 @@ mod tests { }], definitions: vec![Definition( "City".into(), - Rust::Struct(vec![("id".into(), RustType::String)]), + Rust::Struct(vec![Field::from_name_type("id", RustType::String)]), )], } .to_sql(); diff --git a/tests/proc_macro_reparse.rs b/tests/proc_macro_reparse.rs index b648828e..e338eef3 100644 --- a/tests/proc_macro_reparse.rs +++ b/tests/proc_macro_reparse.rs @@ -62,6 +62,21 @@ fn test_standard_choice() { ghi Utf8String } +END"#, + ) +} +#[test] +fn test_extensible_choice() { + parse_asn_map_to_rust_map_to_stringify_with_proc_macro_annotation_re_parse_check_equal( + r#"BasicSchema DEFINITIONS AUTOMATIC TAGS ::= BEGIN + + MyType ::= [PRIVATE 1] CHOICE { + abc Utf8String, + def [APPLICATION 7] INTEGER, + ..., + ghi Utf8String + } + END"#, ) }