From 0f61221b5b8eb09b9daf4614630cf7c7f084b4b6 Mon Sep 17 00:00:00 2001 From: v0-e Date: Mon, 15 Jul 2024 14:18:41 +0100 Subject: [PATCH 1/3] chore: Update codegen-rust's compiler --- utils/codegen/codegen-rust/rgen/Cargo.lock | 5 +- utils/codegen/codegen-rust/rgen/Cargo.toml | 2 +- .../codegen-rust/rgen/src/common/mod.rs | 22 +- .../codegen-rust/rgen/src/conversion/bin.rs | 9 +- .../rgen/src/conversion/builder.rs | 932 ++++++------- .../codegen-rust/rgen/src/conversion/mod.rs | 102 +- .../codegen-rust/rgen/src/conversion/utils.rs | 559 ++++---- .../codegen/codegen-rust/rgen/src/msgs/bin.rs | 3 +- .../codegen-rust/rgen/src/msgs/builder.rs | 1133 +++++++-------- .../codegen/codegen-rust/rgen/src/msgs/mod.rs | 98 +- .../codegen-rust/rgen/src/msgs/template.rs | 57 +- .../codegen-rust/rgen/src/msgs/utils.rs | 1213 ++++++++--------- 12 files changed, 2091 insertions(+), 2044 deletions(-) diff --git a/utils/codegen/codegen-rust/rgen/Cargo.lock b/utils/codegen/codegen-rust/rgen/Cargo.lock index c4e1db83e..7bae6be3d 100644 --- a/utils/codegen/codegen-rust/rgen/Cargo.lock +++ b/utils/codegen/codegen-rust/rgen/Cargo.lock @@ -324,9 +324,8 @@ dependencies = [ [[package]] name = "rasn-compiler" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3adfed8c1b48b6b8bb4c889c947376c9d27c69557975de3a490111c6df32aff9" +version = "0.3.0" +source = "git+https://github.com/librasn/compiler.git?rev=ef06d5f827768726efe6a32da9e1ea1329fc4f7a#ef06d5f827768726efe6a32da9e1ea1329fc4f7a" dependencies = [ "chrono", "nom", diff --git a/utils/codegen/codegen-rust/rgen/Cargo.toml b/utils/codegen/codegen-rust/rgen/Cargo.toml index b9e27e986..d8d973870 100644 --- a/utils/codegen/codegen-rust/rgen/Cargo.toml +++ b/utils/codegen/codegen-rust/rgen/Cargo.toml @@ -16,6 +16,6 @@ name = "asn1-to-ros-conversion-headers" path = "src/conversion/bin.rs" [dependencies] -rasn-compiler = "0.1.4" +rasn-compiler = { git = "https://github.com/librasn/compiler.git", rev = "ef06d5f827768726efe6a32da9e1ea1329fc4f7a" } regex = "1.10.4" clap = { version = "4.5.4", features = ["derive"] } diff --git a/utils/codegen/codegen-rust/rgen/src/common/mod.rs b/utils/codegen/codegen-rust/rgen/src/common/mod.rs index 913897a44..36aaa6296 100644 --- a/utils/codegen/codegen-rust/rgen/src/common/mod.rs +++ b/utils/codegen/codegen-rust/rgen/src/common/mod.rs @@ -1,4 +1,4 @@ -use rasn_compiler::prelude::ir::IntegerType; +use rasn_compiler::prelude::ir::{IntegerType, ASN1Value}; pub trait IntegerTypeExt { fn to_str(self) -> &'static str; @@ -19,6 +19,26 @@ impl IntegerTypeExt for IntegerType { } } } + +pub trait ASN1ValueExt { + fn is_const_type(&self) -> bool; +} + +impl ASN1ValueExt for ASN1Value { + fn is_const_type(&self) -> bool { + match self { + ASN1Value::Null | ASN1Value::Boolean(_) | ASN1Value::EnumeratedValue { .. } => true, + ASN1Value::Choice { inner_value, .. } => inner_value.is_const_type(), + ASN1Value::LinkedIntValue { integer_type, .. } => { + integer_type != &IntegerType::Unbounded + } + ASN1Value::LinkedNestedValue { value, .. } => value.is_const_type(), + ASN1Value::LinkedElsewhereDefinedValue { can_be_const, .. } => *can_be_const, + _ => false, + } + } +} + pub fn to_ros_snake_case(input: &str) -> String { let input = input.replace('-', "_"); let mut lowercase = String::with_capacity(input.len()); diff --git a/utils/codegen/codegen-rust/rgen/src/conversion/bin.rs b/utils/codegen/codegen-rust/rgen/src/conversion/bin.rs index d6579e7ef..27977b071 100644 --- a/utils/codegen/codegen-rust/rgen/src/conversion/bin.rs +++ b/utils/codegen/codegen-rust/rgen/src/conversion/bin.rs @@ -2,7 +2,7 @@ use clap::Parser; use regex::Regex; use rasn_compiler::prelude::*; -use ros_backend::conversion::Conversion; +use ros_backend::conversion::{Conversion, ConversionOptions}; #[derive(Parser, Debug)] struct Cli { @@ -19,10 +19,13 @@ struct Cli { fn main() { let args = Cli::parse(); - let backend = Conversion::default().set_main_pdu_name(&args.pdu.clone()); + let config = ConversionOptions { + main_pdu: args.pdu, + }; + let backend = Conversion::from_config(config); // Compile conversion headers - let compiler_res = Compiler::new() + let compiler_res = Compiler::::new() .with_backend(backend) .add_asn_sources_by_path(args.paths.iter()) .compile_to_string(); diff --git a/utils/codegen/codegen-rust/rgen/src/conversion/builder.rs b/utils/codegen/codegen-rust/rgen/src/conversion/builder.rs index f2ae1106e..0ed6a1d97 100644 --- a/utils/codegen/codegen-rust/rgen/src/conversion/builder.rs +++ b/utils/codegen/codegen-rust/rgen/src/conversion/builder.rs @@ -1,530 +1,538 @@ -use std::error::Error; - use rasn_compiler::prelude::{ir::*, *}; -use crate::common::{to_ros_const_case, IntegerTypeExt}; -use crate::conversion::{generate, Conversion, ConversionOptions}; -use crate::conversion::{template::*, utils::*}; +use crate::common::{to_ros_const_case, IntegerTypeExt, ASN1ValueExt}; +use crate::conversion::Conversion; +use crate::conversion::template::*; pub(crate) const INNER_ARRAY_LIKE_PREFIX: &str = "Anonymous_"; -impl Backend for Conversion { - fn generate_module( - &self, - tlds: Vec, - ) -> Result { - let tlds = merge_tlds(tlds); - let (pdus, warnings): (Vec, Vec>) = - tlds.into_iter().fold((vec![], vec![]), |mut acc, tld| { - match generate(&self.options, tld) { - Ok(s) => { - s.len().gt(&0).then(|| { - acc.0.push(format!( - "#\n\ - {s}\n\ - #" - )) - }); - acc - } - Err(e) => { - acc.1.push(Box::new(e)); - acc - } - } - }); - Ok(GeneratedModule { - generated: Some(format!("{}", pdus.join("\n\n"))), - warnings, - }) - } +macro_rules! call_template { + ($self:ident, $fn:ident, $tld:ident, $($args:expr),*) => { + Ok($fn( + &$self.format_comments(&$tld.comments)?, + (&$tld.name), + $($args),* + )) + }; } -pub fn merge_tlds(tlds: Vec) -> Vec { - let mut merged_tlds = Vec::::with_capacity(tlds.len()); - let mut merge_to = Vec::<(&ToplevelDefinition, &String)>::new(); +impl Conversion { - // Add value to type's distinguished values - tlds.iter().for_each(|tld| { - if let ToplevelDefinition::Value(v) = &tld { - if let ASN1Value::LinkedIntValue { .. } = &v.value { - merge_to.push((&tld, &v.associated_type)); + pub fn merge_tlds(&self, tlds: Vec) -> Vec { + let mut merged_tlds = Vec::::with_capacity(tlds.len()); + let mut merge_to = Vec::<(&ToplevelDefinition, String)>::new(); + + // Add value to type's distinguished values + tlds.iter().for_each(|tld| { + if let ToplevelDefinition::Value(v) = &tld { + if let ASN1Value::LinkedIntValue { .. } = &v.value { + merge_to.push((&tld, v.associated_type.as_str().into())); + } else { + merged_tlds.push(tld.clone()); + } } else { merged_tlds.push(tld.clone()); } - } else { - merged_tlds.push(tld.clone()); - } - }); - merge_to.iter().for_each(|(tld, ty)| { - for t in &mut merged_tlds { - if let ToplevelDefinition::Type(tt) = t { - if tt.name == **ty { - if let ASN1Type::Integer(ref mut int) = tt.ty { - let value = match &tld { - ToplevelDefinition::Value(v) => { - if let ASN1Value::LinkedIntValue { - integer_type: _, - value, - } = &v.value - { - value - } else { - unreachable!() + }); + merge_to.iter().for_each(|(tld, ty)| { + for t in &mut merged_tlds { + if let ToplevelDefinition::Type(tt) = t { + if tt.name == **ty { + if let ASN1Type::Integer(ref mut int) = tt.ty { + let value = match &tld { + ToplevelDefinition::Value(v) => { + if let ASN1Value::LinkedIntValue { + integer_type: _, + value, + } = &v.value + { + value + } else { + unreachable!() + } } - } - _ => unreachable!(), - }; - match int.distinguished_values { - Some(ref mut dv) => dv.push(DistinguishedValue { - name: tld.name().clone(), - value: *value, - }), - None => { - int.distinguished_values = Some(vec![DistinguishedValue { + _ => unreachable!(), + }; + match int.distinguished_values { + Some(ref mut dv) => dv.push(DistinguishedValue { name: tld.name().clone(), value: *value, - }]); + }), + None => { + int.distinguished_values = Some(vec![DistinguishedValue { + name: tld.name().clone(), + value: *value, + }]); + } } } + break; } - break; } } - } - }); + }); - // Resolve object set references - let mut object_sets = Vec::<(String, ObjectSet)>::new(); - merged_tlds.iter().for_each(|tld| { - if let ToplevelDefinition::Information(i) = tld { - if let ASN1Information::ObjectSet(os) = &i.value { - object_sets.push((tld.name().clone(), os.clone())); + // Resolve object set references + let mut object_sets = Vec::<(String, ObjectSet)>::new(); + merged_tlds.iter().for_each(|tld| { + if let ToplevelDefinition::Information(i) = tld { + if let ASN1Information::ObjectSet(os) = &i.value { + object_sets.push((tld.name().clone(), os.clone())); + } } - } - }); - merged_tlds.iter_mut().for_each(|tld| { - if let ToplevelDefinition::Type(t) = tld { - if let ASN1Type::Sequence(ref mut s) = t.ty { - s.members.iter_mut().for_each(|m| { - if let ASN1Type::InformationObjectFieldReference(ref mut r) = m.ty { - if let Constraint::TableConstraint(ref mut c) = r.constraints[0] { - if let ObjectSetValue::Reference(ref mut osvr) = c.object_set.values[0] - { - object_sets - .iter() - .find(|s| s.0 == *osvr) - .and_then(|(_, os)| { - let mut os = os.clone(); - os.values.push(c.object_set.values[0].clone()); - c.object_set = os; - Some(()) - }); + }); + merged_tlds.iter_mut().for_each(|tld| { + if let ToplevelDefinition::Type(t) = tld { + if let ASN1Type::Sequence(ref mut s) = t.ty { + s.members.iter_mut().for_each(|m| { + if let ASN1Type::InformationObjectFieldReference(ref mut r) = m.ty { + if let Constraint::TableConstraint(ref mut c) = r.constraints[0] { + if let ObjectSetValue::Reference(ref mut osvr) = c.object_set.values[0] + { + object_sets + .iter() + .find(|s| s.0 == *osvr) + .and_then(|(_, os)| { + let mut os = os.clone(); + os.values.push(c.object_set.values[0].clone()); + c.object_set = os; + Some(()) + }); + } } } + }); + } + } + }); + merged_tlds + } + + pub fn generate_tld( + &self, + tld: ToplevelDefinition, + ) -> Result { + match tld { + ToplevelDefinition::Type(t) => { + if t.parameterization.is_some() { + return Ok("".into()); + } + match t.ty { + ASN1Type::Null => self.generate_null(t), + ASN1Type::Boolean(_) => self.generate_boolean(t), + ASN1Type::Integer(_) => self.generate_integer(t), + ASN1Type::Enumerated(_) => self.generate_enumerated(t), + ASN1Type::BitString(_) => self.generate_bit_string(t), + ASN1Type::CharacterString(_) => self.generate_character_string(t), + ASN1Type::Sequence(_) | ASN1Type::Set(_) => self.generate_sequence_or_set(t), + ASN1Type::SequenceOf(_) | ASN1Type::SetOf(_) => { + self.generate_sequence_or_set_of(t) } - }); + ASN1Type::ElsewhereDeclaredType(_) => self.generate_typealias(t), + ASN1Type::Choice(_) => self.generate_choice(t), + ASN1Type::OctetString(_) => self.generate_octet_string(t), + ASN1Type::Time(_) => unimplemented!("TIME types are currently unsupported!"), + ASN1Type::Real(_) => Err(GeneratorError { + kind: GeneratorErrorType::NotYetInplemented, + details: "Real types are currently unsupported!".into(), + top_level_declaration: None, + }), + ASN1Type::ObjectIdentifier(_) => self.generate_oid(t), + ASN1Type::InformationObjectFieldReference(_) + | ASN1Type::EmbeddedPdv + | ASN1Type::External => self.generate_any(t), + ASN1Type::GeneralizedTime(_) => self.generate_generalized_time(t), + ASN1Type::UTCTime(_) => self.generate_utc_time(t), + ASN1Type::ChoiceSelectionType(_) => unreachable!(), + } } + ToplevelDefinition::Value(v) => self.generate_value(v), + ToplevelDefinition::Information(i) => match i.value { + _ => Ok("".into()), + }, } - }); - merged_tlds -} - -pub fn generate_typealias( - options: &ConversionOptions, - tld: ToplevelTypeDefinition, -) -> Result { - if let ASN1Type::ElsewhereDeclaredType(dec) = &tld.ty { - Ok(typealias_template( - &options, - &format_comments(&tld.comments)?, - &tld.name, - &dec.identifier, - )) - } else { - Err(GeneratorError::new( - Some(ToplevelDefinition::Type(tld)), - "Expected type alias top-level declaration", - GeneratorErrorType::Asn1TypeMismatch, - )) } -} -pub fn generate_integer_value(tld: ToplevelValueDefinition) -> Result { - if let ASN1Value::LinkedIntValue { integer_type, .. } = tld.value { - let formatted_value = value_to_tokens(&tld.value, None)?; - let formatted_name = to_ros_const_case(&tld.name); - let ty = integer_type.to_str(); - if tld.associated_type == INTEGER { - Ok(lazy_static_value_template( - &format_comments(&tld.comments)?, - &formatted_name, - "int64", - &formatted_value, - )) - } else if integer_type.is_unbounded() { - Ok(lazy_static_value_template( - &format_comments(&tld.comments)?, - &formatted_name, - ty, - &formatted_value, + pub fn generate_typealias( + &self, + tld: ToplevelTypeDefinition, + ) -> Result { + if let ASN1Type::ElsewhereDeclaredType(dec) = &tld.ty { + Ok(typealias_template( + &self.options, + &self.format_comments(&tld.comments)?, + &tld.name, + &dec.identifier, )) } else { - Ok(integer_value_template( - &format_comments(&tld.comments)?, - &formatted_name, - ty, - &formatted_value, + Err(GeneratorError::new( + Some(ToplevelDefinition::Type(tld)), + "Expected type alias top-level declaration", + GeneratorErrorType::Asn1TypeMismatch, )) } - } else { - Err(GeneratorError::new( - Some(ToplevelDefinition::Value(tld)), - "Expected INTEGER value top-level declaration", - GeneratorErrorType::Asn1TypeMismatch, - )) } -} -pub fn generate_integer( - options: &ConversionOptions, - tld: ToplevelTypeDefinition, -) -> Result { - if let ASN1Type::Integer(_) = tld.ty { - Ok(integer_template( - &options, - &format_comments(&tld.comments)?, - &tld.name, - )) - } else { - Err(GeneratorError::new( - Some(ToplevelDefinition::Type(tld)), - "Expected INTEGER top-level declaration", - GeneratorErrorType::Asn1TypeMismatch, - )) + pub fn generate_integer_value(&self, tld: ToplevelValueDefinition) -> Result { + if let ASN1Value::LinkedIntValue { integer_type, .. } = tld.value { + let formatted_value = self.value_to_tokens(&tld.value, None)?; + let formatted_name = to_ros_const_case(&tld.name); + let ty = integer_type.to_str(); + if integer_type.is_unbounded() { + Ok(lazy_static_value_template( + &self.format_comments(&tld.comments)?, + &formatted_name, + ty, + &formatted_value, + )) + } else { + Ok(integer_value_template( + &self.format_comments(&tld.comments)?, + &formatted_name, + ty, + &formatted_value, + )) + } + } else { + Err(GeneratorError::new( + Some(ToplevelDefinition::Value(tld)), + "Expected INTEGER value top-level declaration", + GeneratorErrorType::Asn1TypeMismatch, + )) + } } -} -pub fn generate_bit_string( - options: &ConversionOptions, - tld: ToplevelTypeDefinition, -) -> Result { - if let ASN1Type::BitString(_) = tld.ty { - Ok(bit_string_template( - &options, - &format_comments(&tld.comments)?, - &tld.name, - )) - } else { - Err(GeneratorError::new( - Some(ToplevelDefinition::Type(tld)), - "Expected BIT STRING top-level declaration", - GeneratorErrorType::Asn1TypeMismatch, - )) + pub fn generate_integer( + &self, + tld: ToplevelTypeDefinition, + ) -> Result { + if let ASN1Type::Integer(_) = tld.ty { + Ok(integer_template( + &self.options, + &self.format_comments(&tld.comments)?, + &tld.name, + )) + } else { + Err(GeneratorError::new( + Some(ToplevelDefinition::Type(tld)), + "Expected INTEGER top-level declaration", + GeneratorErrorType::Asn1TypeMismatch, + )) + } } -} -pub fn generate_octet_string( - options: &ConversionOptions, - tld: ToplevelTypeDefinition, -) -> Result { - if let ASN1Type::OctetString(ref _oct_str) = tld.ty { - Ok(octet_string_template( - &options, - &format_comments(&tld.comments)?, - &tld.name, - )) - } else { - Err(GeneratorError::new( - Some(ToplevelDefinition::Type(tld)), - "Expected OCTET STRING top-level declaration", - GeneratorErrorType::Asn1TypeMismatch, - )) + pub fn generate_bit_string( + &self, + tld: ToplevelTypeDefinition, + ) -> Result { + if let ASN1Type::BitString(_) = tld.ty { + Ok(bit_string_template( + &self.options, + &self.format_comments(&tld.comments)?, + &tld.name, + )) + } else { + Err(GeneratorError::new( + Some(ToplevelDefinition::Type(tld)), + "Expected BIT STRING top-level declaration", + GeneratorErrorType::Asn1TypeMismatch, + )) + } } -} -pub fn generate_character_string( - options: &ConversionOptions, - tld: ToplevelTypeDefinition, -) -> Result { - if let ASN1Type::CharacterString(ref char_str) = tld.ty { - Ok(char_string_template( - &options, - &format_comments(&tld.comments)?, - &tld.name, - &string_type(&char_str.ty)?, - )) - } else { - Err(GeneratorError::new( - Some(ToplevelDefinition::Type(tld)), - "Expected Character String top-level declaration", - GeneratorErrorType::Asn1TypeMismatch, - )) + pub fn generate_octet_string( + &self, + tld: ToplevelTypeDefinition, + ) -> Result { + if let ASN1Type::OctetString(ref _oct_str) = tld.ty { + Ok(octet_string_template( + &self.options, + &self.format_comments(&tld.comments)?, + &tld.name, + )) + } else { + Err(GeneratorError::new( + Some(ToplevelDefinition::Type(tld)), + "Expected OCTET STRING top-level declaration", + GeneratorErrorType::Asn1TypeMismatch, + )) + } } -} -pub fn generate_boolean( - options: &ConversionOptions, - tld: ToplevelTypeDefinition, -) -> Result { - if let ASN1Type::Boolean(_) = tld.ty { - Ok(boolean_template( - options, - &format_comments(&tld.comments)?, - &tld.name, - )) - } else { - Err(GeneratorError::new( - Some(ToplevelDefinition::Type(tld)), - "Expected BOOLEAN top-level declaration", - GeneratorErrorType::Asn1TypeMismatch, - )) + pub fn generate_character_string( + &self, + tld: ToplevelTypeDefinition, + ) -> Result { + if let ASN1Type::CharacterString(ref char_str) = tld.ty { + Ok(char_string_template( + &self.options, + &self.format_comments(&tld.comments)?, + &tld.name, + &self.string_type(&char_str.ty)?, + )) + } else { + Err(GeneratorError::new( + Some(ToplevelDefinition::Type(tld)), + "Expected Character String top-level declaration", + GeneratorErrorType::Asn1TypeMismatch, + )) + } } -} - -macro_rules! call_template { - ($fn:ident, $tld:ident, $($args:expr),*) => { - Ok($fn( - &format_comments(&$tld.comments)?, - (&$tld.name), - $($args),* - )) - }; -} -pub fn generate_value(tld: ToplevelValueDefinition) -> Result { - let ty = tld.associated_type.as_str(); - match &tld.value { - ASN1Value::Null if ty == NULL => todo!(), - ASN1Value::Null => todo!(), - ASN1Value::Boolean(b) if ty == BOOLEAN => { - call_template!(primitive_value_template, tld, "bool", &b.to_string()) + pub fn generate_boolean( + &self, + tld: ToplevelTypeDefinition, + ) -> Result { + if let ASN1Type::Boolean(_) = tld.ty { + Ok(boolean_template( + &self.options, + &self.format_comments(&tld.comments)?, + &tld.name, + )) + } else { + Err(GeneratorError::new( + Some(ToplevelDefinition::Type(tld)), + "Expected BOOLEAN top-level declaration", + GeneratorErrorType::Asn1TypeMismatch, + )) } - ASN1Value::Boolean(_) => todo!(), - ASN1Value::LinkedIntValue { .. } => generate_integer_value(tld), - ASN1Value::BitString(_) if ty == BIT_STRING => todo!(), - ASN1Value::OctetString(_) if ty == OCTET_STRING => todo!(), - ASN1Value::Choice { - variant_name, - inner_value, - .. - } => { - if inner_value.is_const_type() { - call_template!( - const_choice_value_template, - tld, - &tld.associated_type, - variant_name, - &value_to_tokens(inner_value, None)? - ) - } else { - call_template!( - choice_value_template, - tld, - &tld.associated_type, - &variant_name, - &value_to_tokens(inner_value, None)? - ) + } + + pub fn generate_value(&self, tld: ToplevelValueDefinition) -> Result { + let ty = tld.associated_type.as_str(); + match &tld.value { + ASN1Value::Null if ty == NULL => todo!(), + ASN1Value::Null => todo!(), + ASN1Value::Boolean(b) if ty == BOOLEAN => { + call_template!(self, primitive_value_template, tld, "bool", &b.to_string()) } + ASN1Value::Boolean(_) => todo!(), + ASN1Value::LinkedIntValue { .. } => self.generate_integer_value(tld), + ASN1Value::BitString(_) if ty == BIT_STRING => todo!(), + ASN1Value::OctetString(_) if ty == OCTET_STRING => todo!(), + ASN1Value::Choice { + variant_name, + inner_value, + .. + } => { + if inner_value.is_const_type() { + call_template!( + self, + const_choice_value_template, + tld, + &tld.associated_type.as_str(), + variant_name, + &self.value_to_tokens(inner_value, None)? + ) + } else { + call_template!( + self, + choice_value_template, + tld, + &tld.associated_type.as_str(), + &variant_name, + &self.value_to_tokens(inner_value, None)? + ) + } + } + ASN1Value::EnumeratedValue { + enumerated, + enumerable, + } => call_template!(self, enum_value_template, tld, enumerated, enumerable), + ASN1Value::Time(_) if ty == GENERALIZED_TIME => todo!(), + ASN1Value::Time(_) if ty == UTC_TIME => todo!(), + ASN1Value::LinkedStructLikeValue(s) => { + let _members = s + .iter() + .map(|(_, _, val)| self.value_to_tokens(val.value(), None)) + .collect::, _>>()?; + todo!() + } + ASN1Value::LinkedNestedValue { .. } => todo!(), + ASN1Value::ObjectIdentifier(_) if ty == OBJECT_IDENTIFIER => todo!(), + ASN1Value::LinkedCharStringValue(_, _) if ty == NUMERIC_STRING => todo!(), + ASN1Value::LinkedCharStringValue(_, _) if ty == VISIBLE_STRING => todo!(), + ASN1Value::LinkedCharStringValue(_, _) if ty == IA5_STRING => todo!(), + ASN1Value::LinkedCharStringValue(_, _) if ty == UTF8_STRING => todo!(), + ASN1Value::LinkedCharStringValue(_, _) if ty == BMP_STRING => todo!(), + ASN1Value::LinkedCharStringValue(_, _) if ty == PRINTABLE_STRING => todo!(), + ASN1Value::LinkedCharStringValue(_, _) if ty == GENERAL_STRING => todo!(), + ASN1Value::LinkedArrayLikeValue(_) if ty.contains(SEQUENCE_OF) => todo!(), + ASN1Value::LinkedArrayLikeValue(_) if ty.contains(SET_OF) => todo!(), + ASN1Value::BitString(_) + | ASN1Value::Time(_) + | ASN1Value::LinkedCharStringValue(_, _) + | ASN1Value::ObjectIdentifier(_) + | ASN1Value::LinkedArrayLikeValue(_) + | ASN1Value::ElsewhereDeclaredValue { .. } + | ASN1Value::OctetString(_) => todo!(), + _ => Ok("".to_string()), } - ASN1Value::EnumeratedValue { - enumerated, - enumerable, - } => call_template!(enum_value_template, tld, enumerated, enumerable), - ASN1Value::Time(_) if ty == GENERALIZED_TIME => todo!(), - ASN1Value::Time(_) if ty == UTC_TIME => todo!(), - ASN1Value::LinkedStructLikeValue(s) => { - let _members = s - .iter() - .map(|(_, _, val)| value_to_tokens(val.value(), None)) - .collect::, _>>()?; - todo!() - } - ASN1Value::LinkedNestedValue { .. } => todo!(), - ASN1Value::ObjectIdentifier(_) if ty == OBJECT_IDENTIFIER => todo!(), - ASN1Value::LinkedCharStringValue(_, _) if ty == NUMERIC_STRING => todo!(), - ASN1Value::LinkedCharStringValue(_, _) if ty == VISIBLE_STRING => todo!(), - ASN1Value::LinkedCharStringValue(_, _) if ty == IA5_STRING => todo!(), - ASN1Value::LinkedCharStringValue(_, _) if ty == UTF8_STRING => todo!(), - ASN1Value::LinkedCharStringValue(_, _) if ty == BMP_STRING => todo!(), - ASN1Value::LinkedCharStringValue(_, _) if ty == PRINTABLE_STRING => todo!(), - ASN1Value::LinkedCharStringValue(_, _) if ty == GENERAL_STRING => todo!(), - ASN1Value::LinkedArrayLikeValue(_) if ty.contains(SEQUENCE_OF) => todo!(), - ASN1Value::LinkedArrayLikeValue(_) if ty.contains(SET_OF) => todo!(), - ASN1Value::BitString(_) - | ASN1Value::Time(_) - | ASN1Value::LinkedCharStringValue(_, _) - | ASN1Value::ObjectIdentifier(_) - | ASN1Value::LinkedArrayLikeValue(_) - | ASN1Value::ElsewhereDeclaredValue { .. } - | ASN1Value::OctetString(_) => todo!(), - _ => Ok("".to_string()), } -} -pub fn generate_any(tld: ToplevelTypeDefinition) -> Result { - Ok(any_template(&format_comments(&tld.comments)?, &tld.name)) -} - -pub fn generate_generalized_time(tld: ToplevelTypeDefinition) -> Result { - if let ASN1Type::GeneralizedTime(_) = &tld.ty { - Ok(generalized_time_template( - &format_comments(&tld.comments)?, - &tld.name, - )) - } else { - Err(GeneratorError::new( - Some(ToplevelDefinition::Type(tld)), - "Expected GeneralizedTime top-level declaration", - GeneratorErrorType::Asn1TypeMismatch, - )) + pub fn generate_any(&self, tld: ToplevelTypeDefinition) -> Result { + Ok(any_template(&self.format_comments(&tld.comments)?, &tld.name)) } -} -pub fn generate_utc_time(tld: ToplevelTypeDefinition) -> Result { - if let ASN1Type::UTCTime(_) = &tld.ty { - Ok(utc_time_template( - &format_comments(&tld.comments)?, - &tld.name, - )) - } else { - Err(GeneratorError::new( - Some(ToplevelDefinition::Type(tld)), - "Expected UTCTime top-level declaration", - GeneratorErrorType::Asn1TypeMismatch, - )) + pub fn generate_generalized_time(&self, tld: ToplevelTypeDefinition) -> Result { + if let ASN1Type::GeneralizedTime(_) = &tld.ty { + Ok(generalized_time_template( + &self.format_comments(&tld.comments)?, + &tld.name, + )) + } else { + Err(GeneratorError::new( + Some(ToplevelDefinition::Type(tld)), + "Expected GeneralizedTime top-level declaration", + GeneratorErrorType::Asn1TypeMismatch, + )) + } } -} -pub fn generate_oid(tld: ToplevelTypeDefinition) -> Result { - if let ASN1Type::ObjectIdentifier(_oid) = &tld.ty { - Ok(oid_template(&format_comments(&tld.comments)?, &tld.name)) - } else { - Err(GeneratorError::new( - Some(ToplevelDefinition::Type(tld)), - "Expected OBJECT IDENTIFIER top-level declaration", - GeneratorErrorType::Asn1TypeMismatch, - )) + pub fn generate_utc_time(&self, tld: ToplevelTypeDefinition) -> Result { + if let ASN1Type::UTCTime(_) = &tld.ty { + Ok(utc_time_template( + &self.format_comments(&tld.comments)?, + &tld.name, + )) + } else { + Err(GeneratorError::new( + Some(ToplevelDefinition::Type(tld)), + "Expected UTCTime top-level declaration", + GeneratorErrorType::Asn1TypeMismatch, + )) + } } -} -pub fn generate_null(tld: ToplevelTypeDefinition) -> Result { - if let ASN1Type::Null = tld.ty { - Ok(null_template(&format_comments(&tld.comments)?, &tld.name)) - } else { - Err(GeneratorError::new( - Some(ToplevelDefinition::Type(tld)), - "Expected NULL top-level declaration", - GeneratorErrorType::Asn1TypeMismatch, - )) + pub fn generate_oid(&self, tld: ToplevelTypeDefinition) -> Result { + if let ASN1Type::ObjectIdentifier(_oid) = &tld.ty { + Ok(oid_template(&self.format_comments(&tld.comments)?, &tld.name)) + } else { + Err(GeneratorError::new( + Some(ToplevelDefinition::Type(tld)), + "Expected OBJECT IDENTIFIER top-level declaration", + GeneratorErrorType::Asn1TypeMismatch, + )) + } } -} -pub fn generate_enumerated( - options: &ConversionOptions, - tld: ToplevelTypeDefinition, -) -> Result { - if let ASN1Type::Enumerated(_) = tld.ty { - Ok(enumerated_template( - &options, - &format_comments(&tld.comments)?, - &tld.name, - )) - } else { - Err(GeneratorError::new( - Some(ToplevelDefinition::Type(tld)), - "Expected ENUMERATED top-level declaration", - GeneratorErrorType::Asn1TypeMismatch, - )) + pub fn generate_null(&self, tld: ToplevelTypeDefinition) -> Result { + if let ASN1Type::Null = tld.ty { + Ok(null_template(&self.format_comments(&tld.comments)?, &tld.name)) + } else { + Err(GeneratorError::new( + Some(ToplevelDefinition::Type(tld)), + "Expected NULL top-level declaration", + GeneratorErrorType::Asn1TypeMismatch, + )) + } } -} -pub fn generate_choice( - options: &ConversionOptions, - tld: ToplevelTypeDefinition, -) -> Result { - if let ASN1Type::Choice(ref choice) = tld.ty { - let members = get_choice_members_names(choice); - Ok(choice_template( - &options, - &format_comments(&tld.comments)?, - &tld.name, - &members, - )) - } else { - Err(GeneratorError::new( - Some(ToplevelDefinition::Type(tld)), - "Expected CHOICE top-level declaration", - GeneratorErrorType::Asn1TypeMismatch, - )) + pub fn generate_enumerated( + &self, + tld: ToplevelTypeDefinition, + ) -> Result { + if let ASN1Type::Enumerated(_) = tld.ty { + Ok(enumerated_template( + &self.options, + &self.format_comments(&tld.comments)?, + &tld.name, + )) + } else { + Err(GeneratorError::new( + Some(ToplevelDefinition::Type(tld)), + "Expected ENUMERATED top-level declaration", + GeneratorErrorType::Asn1TypeMismatch, + )) + } } -} -pub fn generate_sequence_or_set( - options: &ConversionOptions, - tld: ToplevelTypeDefinition, -) -> Result { - match tld.ty { - ASN1Type::Sequence(ref seq) | ASN1Type::Set(ref seq) => { - let members = get_sequence_or_set_members_names(seq); - Ok(sequence_or_set_template( - options, - &format_comments(&tld.comments)?, - &tld.name, - members, + pub fn generate_choice( + &self, + tld: ToplevelTypeDefinition, + ) -> Result { + if let ASN1Type::Choice(ref choice) = tld.ty { + let members = self.get_choice_members_names(choice); + Ok(choice_template( + &self.options, + &self.format_comments(&tld.comments)?, + &tld.name, + &members, + )) + } else { + Err(GeneratorError::new( + Some(ToplevelDefinition::Type(tld)), + "Expected CHOICE top-level declaration", + GeneratorErrorType::Asn1TypeMismatch, )) } - _ => Err(GeneratorError::new( - Some(ToplevelDefinition::Type(tld)), - "Expected SEQUENCE top-level declaration", - GeneratorErrorType::Asn1TypeMismatch, - )), } -} -pub fn generate_sequence_or_set_of( - options: &ConversionOptions, - tld: ToplevelTypeDefinition, -) -> Result { - let (is_set_of, seq_or_set_of) = match &tld.ty { - ASN1Type::SetOf(se_of) => (true, se_of), - ASN1Type::SequenceOf(se_of) => (false, se_of), - _ => { - return Err(GeneratorError::new( - Some(ToplevelDefinition::Type(tld)), - "Expected SEQUENCE OF top-level declaration", - GeneratorErrorType::Asn1TypeMismatch, - )) + pub fn generate_sequence_or_set( + &self, + tld: ToplevelTypeDefinition, + ) -> Result { + match tld.ty { + ASN1Type::Sequence(ref seq) | ASN1Type::Set(ref seq) => { + let members = self.get_sequence_or_set_members_names(seq); + Ok(sequence_or_set_template( + &self.options, + &self.format_comments(&tld.comments)?, + &tld.name, + members, + )) + } + _ => Err(GeneratorError::new( + Some(ToplevelDefinition::Type(tld)), + "Expected SEQUENCE top-level declaration", + GeneratorErrorType::Asn1TypeMismatch, + )), } - }; - let anonymous_item = match seq_or_set_of.element_type.as_ref() { - ASN1Type::ElsewhereDeclaredType(_) => None, - n => Some(generate( - &ConversionOptions::default(), - ToplevelDefinition::Type(ToplevelTypeDefinition { - parameterization: None, - comments: format!( - " Anonymous {} OF member ", - if is_set_of { "SET" } else { "SEQUENCE" } - ), - name: String::from(INNER_ARRAY_LIKE_PREFIX) + &tld.name, - ty: n.clone(), - tag: None, - index: None, - }), - )?), } - .unwrap_or_default(); - let member_type = match seq_or_set_of.element_type.as_ref() { - ASN1Type::ElsewhereDeclaredType(d) => d.identifier.clone(), - _ => format!("Anonymous{}", &tld.name), - }; - Ok(sequence_or_set_of_template( - &options, - is_set_of, - &format_comments(&tld.comments)?, - &tld.name, - &anonymous_item, - &member_type, - )) + + pub fn generate_sequence_or_set_of( + &self, + tld: ToplevelTypeDefinition, + ) -> Result { + let (is_set_of, seq_or_set_of) = match &tld.ty { + ASN1Type::SetOf(se_of) => (true, se_of), + ASN1Type::SequenceOf(se_of) => (false, se_of), + _ => { + return Err(GeneratorError::new( + Some(ToplevelDefinition::Type(tld)), + "Expected SEQUENCE OF top-level declaration", + GeneratorErrorType::Asn1TypeMismatch, + )) + } + }; + let anonymous_item = match seq_or_set_of.element_type.as_ref() { + ASN1Type::ElsewhereDeclaredType(_) => None, + n => Some(self.generate_tld( + ToplevelDefinition::Type(ToplevelTypeDefinition { + parameterization: None, + comments: format!( + " Anonymous {} OF member ", + if is_set_of { "SET" } else { "SEQUENCE" } + ), + name: String::from(INNER_ARRAY_LIKE_PREFIX) + &tld.name, + ty: n.clone(), + tag: None, + index: None, + }), + )?), + } + .unwrap_or_default(); + let member_type = match seq_or_set_of.element_type.as_ref() { + ASN1Type::ElsewhereDeclaredType(d) => d.identifier.clone(), + _ => format!("Anonymous{}", &tld.name), + }; + Ok(sequence_or_set_of_template( + &self.options, + is_set_of, + &self.format_comments(&tld.comments)?, + &tld.name, + &anonymous_item, + &member_type, + )) + } } diff --git a/utils/codegen/codegen-rust/rgen/src/conversion/mod.rs b/utils/codegen/codegen-rust/rgen/src/conversion/mod.rs index ee1ff75b5..2d0c19af7 100644 --- a/utils/codegen/codegen-rust/rgen/src/conversion/mod.rs +++ b/utils/codegen/codegen-rust/rgen/src/conversion/mod.rs @@ -1,16 +1,22 @@ -use rasn_compiler::prelude::{ir::ASN1Type, *}; +use std::error::Error; + +use rasn_compiler::prelude::*; mod builder; mod template; mod utils; -#[derive(Default)] +#[derive(Debug, Default)] pub struct Conversion { options: ConversionOptions, } + +#[derive(Debug)] pub struct ConversionOptions { - main_pdu: String, + /// The name of the main PDU. + pub main_pdu: String, } + impl Default for ConversionOptions { fn default() -> Self { Self { @@ -18,56 +24,52 @@ impl Default for ConversionOptions { } } } -impl Conversion { - pub fn set_main_pdu_name(mut self, main_pdu_name: &str) -> Self { - self.options.main_pdu = main_pdu_name.to_owned(); - self + +impl Backend for Conversion { + type Config = ConversionOptions; + + const FILE_EXTENSION: &'static str = ""; + + fn from_config(config: Self::Config) -> Self { + Self { options: config } } -} -use builder::*; + fn config(&self) -> &Self::Config { + &self.options + } -fn generate( - options: &ConversionOptions, - tld: ToplevelDefinition, -) -> Result { - match tld { - ToplevelDefinition::Type(t) => { - if t.parameterization.is_some() { - return Ok("".into()); - } - match t.ty { - ASN1Type::Null => generate_null(t), - ASN1Type::Boolean(_) => generate_boolean(&options, t), - ASN1Type::Integer(_) => generate_integer(&options, t), - ASN1Type::Enumerated(_) => generate_enumerated(&options, t), - ASN1Type::BitString(_) => generate_bit_string(&options, t), - ASN1Type::CharacterString(_) => generate_character_string(&options, t), - ASN1Type::Sequence(_) | ASN1Type::Set(_) => generate_sequence_or_set(&options, t), - ASN1Type::SequenceOf(_) | ASN1Type::SetOf(_) => { - generate_sequence_or_set_of(&options, t) + fn generate_module( + &self, + tlds: Vec, + ) -> Result { + let tlds = self.merge_tlds(tlds); + let (pdus, warnings): (Vec, Vec>) = + tlds.into_iter().fold((vec![], vec![]), |mut acc, tld| { + match self.generate_tld(tld) { + Ok(s) => { + s.len().gt(&0).then(|| { + acc.0.push(format!( + "#\n\ + {s}\n\ + #" + )) + }); + acc + } + Err(e) => { + acc.1.push(Box::new(e)); + acc + } } - ASN1Type::ElsewhereDeclaredType(_) => generate_typealias(&options, t), - ASN1Type::Choice(_) => generate_choice(&options, t), - ASN1Type::OctetString(_) => generate_octet_string(&options, t), - ASN1Type::Time(_) => unimplemented!("TIME types are currently unsupported!"), - ASN1Type::Real(_) => Err(GeneratorError { - kind: GeneratorErrorType::NotYetInplemented, - details: "Real types are currently unsupported!".into(), - top_level_declaration: None, - }), - ASN1Type::ObjectIdentifier(_) => generate_oid(t), - ASN1Type::InformationObjectFieldReference(_) - | ASN1Type::EmbeddedPdv - | ASN1Type::External => generate_any(t), - ASN1Type::GeneralizedTime(_) => generate_generalized_time(t), - ASN1Type::UTCTime(_) => generate_utc_time(t), - ASN1Type::ChoiceSelectionType(_) => unreachable!(), - } - } - ToplevelDefinition::Value(v) => generate_value(v), - ToplevelDefinition::Information(i) => match i.value { - _ => Ok("".into()), - }, + }); + Ok(GeneratedModule { + generated: Some(format!("{}", pdus.join("\n\n"))), + warnings, + }) + } + + fn generate(&self, tld: ToplevelDefinition) -> Result { + self.generate_tld(tld).map(|ts| ts.to_string()) } } + diff --git a/utils/codegen/codegen-rust/rgen/src/conversion/utils.rs b/utils/codegen/codegen-rust/rgen/src/conversion/utils.rs index 65d36720f..c087f32dc 100644 --- a/utils/codegen/codegen-rust/rgen/src/conversion/utils.rs +++ b/utils/codegen/codegen-rust/rgen/src/conversion/utils.rs @@ -6,7 +6,8 @@ use rasn_compiler::intermediate::{ }; use rasn_compiler::prelude::{ir::*, *}; -use crate::common::{to_ros_title_case, IntegerTypeExt}; +use crate::common::to_ros_title_case; +use super::Conversion; macro_rules! error { ($kind:ident, $($arg:tt)*) => { @@ -20,19 +21,6 @@ macro_rules! error { pub(crate) use error; -pub fn format_comments(comments: &str) -> Result { - if comments.is_empty() { - Ok("".into()) - } else { - let joined = String::from("// ") + &comments.replace('\n', "\n//") + "\n"; - Ok(joined) - } -} - -pub fn inner_name(name: &String, parent_name: &String) -> String { - format!("{}{}", parent_name, name) -} - #[derive(Clone, Debug)] pub struct NameType { pub name: String, @@ -59,310 +47,297 @@ pub struct NamedSeqMember { pub has_default: bool, } -fn get_inner_types_names(ty: &ASN1Type) -> Option { - match ty { - ASN1Type::InformationObjectFieldReference(r) => { - if let Constraint::TableConstraint(ref tc) = r.constraints[0] { - let object_set = &tc.object_set; - let mut names = vec![]; - for value in &object_set.values { - if let ObjectSetValue::Inline(ref i) = value { - match i { - InformationObjectFields::DefaultSyntax(ds) => { - let mut name = "".to_string(); - let mut ty: ASN1Type = ASN1Type::Null; - ds.iter().for_each(|f| match f { - InformationObjectField::TypeField(f) => ty = f.ty.clone(), - InformationObjectField::FixedValueField(f) => { - name = value_to_tokens(&f.value, None).unwrap() - } - _ => todo!(), - }); - names.push(NameType { - name: name.clone(), - ty: constraints_and_type_name(&ty, &name, &"".to_string()) - .unwrap() - .1, - is_primitive: ty.is_builtin_type(), - inner_types: None, - }); +impl Conversion { + pub fn format_comments(&self, comments: &str) -> Result { + if comments.is_empty() { + Ok("".into()) + } else { + let joined = String::from("// ") + &comments.replace('\n', "\n//") + "\n"; + Ok(joined) + } + } + + pub fn inner_name(&self, name: &String, parent_name: &String) -> String { + format!("{}{}", parent_name, name) + } + + + fn get_inner_types_names(&self, ty: &ASN1Type) -> Option { + match ty { + ASN1Type::InformationObjectFieldReference(r) => { + if let Constraint::TableConstraint(ref tc) = r.constraints[0] { + let object_set = &tc.object_set; + let mut names = vec![]; + for value in &object_set.values { + if let ObjectSetValue::Inline(ref i) = value { + match i { + InformationObjectFields::DefaultSyntax(ds) => { + let mut name = "".to_string(); + let mut ty: ASN1Type = ASN1Type::Null; + ds.iter().for_each(|f| match f { + InformationObjectField::TypeField(f) => ty = f.ty.clone(), + InformationObjectField::FixedValueField(f) => { + name = self.value_to_tokens(&f.value, None).unwrap() + } + _ => todo!(), + }); + names.push(NameType { + name: name.clone(), + ty: self.constraints_and_type_name(&ty, &name, &"".to_string()) + .unwrap() + .1, + is_primitive: ty.is_builtin_type(), + inner_types: None, + }); + } + _ => todo!(), } - _ => todo!(), } } + let linked_with = tc + .linked_fields + .get(0) + .map(|f| f.field_name.clone()) + .unwrap_or_default(); + Some(InnerTypes::Choice(InnerTypesChoice { + linked_with, + options: names, + })) + } else { + unreachable!() } - let linked_with = tc - .linked_fields - .get(0) - .map(|f| f.field_name.clone()) - .unwrap_or_default(); - Some(InnerTypes::Choice(InnerTypesChoice { - linked_with, - options: names, - })) - } else { - unreachable!() } + _ => None, } - _ => None, } -} -pub fn get_sequence_or_set_members_names(sequence_or_set: &SequenceOrSet) -> Vec { - sequence_or_set - .members - .iter() - .map(|member| NamedSeqMember { - name_type: NameType { - name: member.name.clone(), - ty: constraints_and_type_name(&member.ty, &member.name, &"".to_string()) - .unwrap() - .1, - is_primitive: member.ty.is_builtin_type(), - inner_types: get_inner_types_names(&member.ty), - }, - is_optional: member.is_optional, - has_default: member.default_value.is_some(), - }) + pub fn get_sequence_or_set_members_names(&self, sequence_or_set: &SequenceOrSet) -> Vec { + sequence_or_set + .members + .iter() + .map(|member| NamedSeqMember { + name_type: NameType { + name: member.name.clone(), + ty: self.constraints_and_type_name(&member.ty, &member.name, &"".to_string()) + .unwrap() + .1, + is_primitive: member.ty.is_builtin_type(), + inner_types: self.get_inner_types_names(&member.ty), + }, + is_optional: member.is_optional, + has_default: member.default_value.is_some(), + }) .collect::>() -} + } -pub fn get_choice_members_names(choice: &Choice) -> Vec { - choice - .options - .iter() - .map(|member| - NameType { - name: member.name.clone(), - ty: constraints_and_type_name(&member.ty, &member.name, &"".to_string()) - .unwrap() - .1, - is_primitive: member.ty.is_builtin_type(), - inner_types: None, + pub fn get_choice_members_names(&self, choice: &Choice) -> Vec { + choice + .options + .iter() + .map(|member| + NameType { + name: member.name.clone(), + ty: self.constraints_and_type_name(&member.ty, &member.name, &"".to_string()) + .unwrap() + .1, + is_primitive: member.ty.is_builtin_type(), + inner_types: None, + } + ).collect::>() + } + + fn constraints_and_type_name( + &self, + ty: &ASN1Type, + name: &String, + parent_name: &String, + ) -> Result<(Vec, String), GeneratorError> { + Ok(match ty { + ASN1Type::Null => (vec![], "byte".into()), + ASN1Type::Boolean(b) => (b.constraints.clone(), "BOOLEAN".into()), + ASN1Type::Integer(i) => (i.constraints.clone(), "INTEGER".into()), + ASN1Type::Real(_) => (vec![], "float64".into()), + ASN1Type::ObjectIdentifier(_o) => todo!(), + ASN1Type::BitString(_b) => todo!(), + ASN1Type::OctetString(o) => (o.constraints.clone(), "uint8[]".into()), + ASN1Type::GeneralizedTime(_o) => todo!(), + ASN1Type::UTCTime(_o) => todo!(), + ASN1Type::Time(_t) => todo!(), + ASN1Type::CharacterString(c) => ( + c.constraints.clone(), + self.string_type(&c.ty).unwrap_or("STRING".into()), + ), + ASN1Type::Enumerated(_) + | ASN1Type::Choice(_) + | ASN1Type::Sequence(_) + | ASN1Type::SetOf(_) + | ASN1Type::Set(_) => (vec![], self.inner_name(name, parent_name)), + ASN1Type::SequenceOf(s) => { + let (_, inner_type) = self.constraints_and_type_name(&s.element_type, name, parent_name)?; + (s.constraints().clone(), format!("{inner_type}[]").into()) } - ).collect::>() -} + ASN1Type::ElsewhereDeclaredType(e) => { + (e.constraints.clone(), to_ros_title_case(&e.identifier)) + } + ASN1Type::InformationObjectFieldReference(_) + | ASN1Type::EmbeddedPdv + | ASN1Type::External => { + let tx = &ty.constraints().unwrap()[0]; + let rname = if let Constraint::TableConstraint(ref tc) = tx { + tc.object_set + .values + .iter() + .find_map(|v| match v { + ObjectSetValue::Reference(ref r) => Some(r.clone()), + _ => None, + }) + .unwrap_or_default() + } else { + "".to_string() + }; + (vec![], rname) + } + ASN1Type::ChoiceSelectionType(_) => unreachable!(), + }) + } -fn constraints_and_type_name( - ty: &ASN1Type, - name: &String, - parent_name: &String, -) -> Result<(Vec, String), GeneratorError> { - Ok(match ty { - ASN1Type::Null => (vec![], "byte".into()), - ASN1Type::Boolean(b) => (b.constraints.clone(), "BOOLEAN".into()), - ASN1Type::Integer(i) => (i.constraints.clone(), "INTEGER".into()), - ASN1Type::Real(_) => (vec![], "float64".into()), - ASN1Type::ObjectIdentifier(_o) => todo!(), - ASN1Type::BitString(_b) => todo!(), - ASN1Type::OctetString(o) => (o.constraints.clone(), "uint8[]".into()), - ASN1Type::GeneralizedTime(_o) => todo!(), - ASN1Type::UTCTime(_o) => todo!(), - ASN1Type::Time(_t) => todo!(), - ASN1Type::CharacterString(c) => ( - c.constraints.clone(), - string_type(&c.ty).unwrap_or("STRING".into()), - ), - ASN1Type::Enumerated(_) - | ASN1Type::Choice(_) - | ASN1Type::Sequence(_) - | ASN1Type::SetOf(_) - | ASN1Type::Set(_) => (vec![], inner_name(name, parent_name)), - ASN1Type::SequenceOf(s) => { - let (_, inner_type) = constraints_and_type_name(&s.element_type, name, parent_name)?; - (s.constraints().clone(), format!("{inner_type}[]").into()) - } - ASN1Type::ElsewhereDeclaredType(e) => { - (e.constraints.clone(), to_ros_title_case(&e.identifier)) - } - ASN1Type::InformationObjectFieldReference(_) - | ASN1Type::EmbeddedPdv - | ASN1Type::External => { - let tx = &ty.constraints().unwrap()[0]; - let rname = if let Constraint::TableConstraint(ref tc) = tx { - tc.object_set - .values - .iter() - .find_map(|v| match v { - ObjectSetValue::Reference(ref r) => Some(r.clone()), - _ => None, - }) - .unwrap_or_default() - } else { - "".to_string() - }; - (vec![], rname) + pub fn string_type(&self, c_type: &CharacterStringType) -> Result { + match c_type { + CharacterStringType::NumericString => Ok("NumericString".into()), + CharacterStringType::VisibleString => Ok("VisibleString".into()), + CharacterStringType::IA5String => Ok("IA5String".into()), + CharacterStringType::TeletexString => Ok("TeletexString".into()), + CharacterStringType::VideotexString => Ok("VideotexString".into()), + CharacterStringType::GraphicString => Ok("GraphicString".into()), + CharacterStringType::GeneralString => Ok("GeneralString".into()), + CharacterStringType::UniversalString => Ok("UniversalString".into()), + CharacterStringType::UTF8String => Ok("UTF8String".into()), + CharacterStringType::BMPString => Ok("BMPString".into()), + CharacterStringType::PrintableString => Ok("PrintableString".into()), } - ASN1Type::ChoiceSelectionType(_) => unreachable!(), - }) -} - -pub fn string_type(c_type: &CharacterStringType) -> Result { - match c_type { - CharacterStringType::NumericString => Ok("NumericString".into()), - CharacterStringType::VisibleString => Ok("VisibleString".into()), - CharacterStringType::IA5String => Ok("IA5String".into()), - CharacterStringType::TeletexString => Ok("TeletexString".into()), - CharacterStringType::VideotexString => Ok("VideotexString".into()), - CharacterStringType::GraphicString => Ok("GraphicString".into()), - CharacterStringType::GeneralString => Ok("GeneralString".into()), - CharacterStringType::UniversalString => Ok("UniversalString".into()), - CharacterStringType::UTF8String => Ok("UTF8String".into()), - CharacterStringType::BMPString => Ok("BMPString".into()), - CharacterStringType::PrintableString => Ok("PrintableString".into()), } -} -pub fn value_to_tokens( - value: &ASN1Value, - type_name: Option<&String>, -) -> Result { - match value { - ASN1Value::All => Err(error!( - NotYetInplemented, - "All values are currently unsupported!" - )), - ASN1Value::Null => todo!(), - ASN1Value::Choice { inner_value, .. } => { - if let Some(_ty_n) = type_name { + pub fn value_to_tokens( + &self, + value: &ASN1Value, + type_name: Option<&String>, + ) -> Result { + match value { + ASN1Value::All => Err(error!( + NotYetInplemented, + "All values are currently unsupported!" + )), + ASN1Value::Null => todo!(), + ASN1Value::Choice { inner_value, .. } => { + if let Some(_ty_n) = type_name { + todo!() + } else { + Err(error!( + Unidentified, + "A type name is needed to stringify choice value {:?}", inner_value + )) + } + } + ASN1Value::OctetString(o) => { + let _bytes = o.iter().map(|byte| *byte); todo!() - } else { - Err(error!( + } + ASN1Value::SequenceOrSet(_) => Err(error!( Unidentified, - "A type name is needed to stringify choice value {:?}", inner_value - )) + "Unexpectedly encountered unlinked struct-like ASN1 value!" + )), + ASN1Value::LinkedStructLikeValue(fields) => { + if let Some(_ty_n) = type_name { + let _tokenized_fields = fields + .iter() + .map(|(_, _, val)| self.value_to_tokens(val.value(), None)) + .collect::, _>>()?; + todo!() + } else { + Err(error!( + Unidentified, + "A type name is needed to stringify sequence value {:?}", value + )) + } } - } - ASN1Value::OctetString(o) => { - let _bytes = o.iter().map(|byte| *byte); - todo!() - } - ASN1Value::SequenceOrSet(_) => Err(error!( - Unidentified, - "Unexpectedly encountered unlinked struct-like ASN1 value!" - )), - ASN1Value::LinkedStructLikeValue(fields) => { - if let Some(_ty_n) = type_name { - let _tokenized_fields = fields + ASN1Value::Boolean(b) => Ok(b.to_string()), + ASN1Value::Integer(i) => Ok(i.to_string()), + ASN1Value::String(s) => Ok(s.to_string()), + ASN1Value::Real(r) => Ok(r.to_string()), + ASN1Value::BitString(b) => { + let _bits = b.iter().map(|bit| bit.to_string()); + todo!() + } + ASN1Value::EnumeratedValue { + enumerated, + enumerable, + } => Ok(format!("{}_{}", enumerated, enumerable)), + ASN1Value::LinkedElsewhereDefinedValue { identifier: e, .. } + | ASN1Value::ElsewhereDeclaredValue { identifier: e, .. } => Ok(e.to_string()), + ASN1Value::ObjectIdentifier(oid) => { + let _arcs = oid + .0 .iter() - .map(|(_, _, val)| value_to_tokens(val.value(), None)) - .collect::, _>>()?; + .filter_map(|arc| arc.number.map(|id| id.to_string())); todo!() - } else { - Err(error!( - Unidentified, - "A type name is needed to stringify sequence value {:?}", value - )) } - } - ASN1Value::Boolean(b) => Ok(b.to_string()), - ASN1Value::Integer(i) => Ok(i.to_string()), - ASN1Value::String(s) => Ok(s.to_string()), - ASN1Value::Real(r) => Ok(r.to_string()), - ASN1Value::BitString(b) => { - let _bits = b.iter().map(|bit| bit.to_string()); - todo!() - } - ASN1Value::EnumeratedValue { - enumerated, - enumerable, - } => Ok(format!("{}_{}", enumerated, enumerable)), - ASN1Value::LinkedElsewhereDefinedValue { identifier: e, .. } - | ASN1Value::ElsewhereDeclaredValue { identifier: e, .. } => Ok(e.to_string()), - ASN1Value::ObjectIdentifier(oid) => { - let _arcs = oid - .0 - .iter() - .filter_map(|arc| arc.number.map(|id| id.to_string())); - todo!() - } - ASN1Value::Time(_t) => match type_name { - Some(_time_type) => todo!(), - None => todo!(), - }, - ASN1Value::LinkedArrayLikeValue(seq) => { - let _elems = seq - .iter() - .map(|v| value_to_tokens(v, None)) - .collect::, _>>()?; - todo!() - } - ASN1Value::LinkedNestedValue { - supertypes: _, - value, - } => Ok(value_to_tokens(value, type_name)?), - ASN1Value::LinkedIntValue { - integer_type, - value, - } => { - let val = *value; - match integer_type { - IntegerType::Unbounded => Ok(val.to_string()), - _ => Ok(val.to_string()), + ASN1Value::Time(_t) => match type_name { + Some(_time_type) => todo!(), + None => todo!(), + }, + ASN1Value::LinkedArrayLikeValue(seq) => { + let _elems = seq + .iter() + .map(|v| self.value_to_tokens(v, None)) + .collect::, _>>()?; + todo!() } - } - ASN1Value::LinkedCharStringValue(string_type, value) => { - let _val = value; - match string_type { - CharacterStringType::NumericString => { - todo!() - } - CharacterStringType::VisibleString => { - todo!() + ASN1Value::LinkedNestedValue { + supertypes: _, + value, + } => Ok(self.value_to_tokens(value, type_name)?), + ASN1Value::LinkedIntValue { + integer_type, + value, + } => { + let val = *value; + match integer_type { + IntegerType::Unbounded => Ok(val.to_string()), + _ => Ok(val.to_string()), } - CharacterStringType::IA5String => { - todo!() - } - CharacterStringType::UTF8String => todo!(), - CharacterStringType::BMPString => { - todo!() - } - CharacterStringType::PrintableString => { - todo!() - } - CharacterStringType::GeneralString => { - todo!() - } - CharacterStringType::VideotexString - | CharacterStringType::GraphicString - | CharacterStringType::UniversalString - | CharacterStringType::TeletexString => Err(GeneratorError::new( - None, - &format!("{:?} values are currently unsupported!", string_type), - GeneratorErrorType::NotYetInplemented, - )), } - } - } -} - -pub fn _format_sequence_or_set_of_item_type( - type_name: String, - first_item: Option<&ASN1Value>, -) -> String { - match type_name { - name if name == NULL => todo!(), - name if name == BOOLEAN => "bool".into(), - name if name == INTEGER => { - match first_item { - Some(ASN1Value::LinkedIntValue { integer_type, .. }) => { - integer_type.to_str().into() + ASN1Value::LinkedCharStringValue(string_type, value) => { + let _val = value; + match string_type { + CharacterStringType::NumericString => { + todo!() + } + CharacterStringType::VisibleString => { + todo!() + } + CharacterStringType::IA5String => { + todo!() + } + CharacterStringType::UTF8String => todo!(), + CharacterStringType::BMPString => { + todo!() + } + CharacterStringType::PrintableString => { + todo!() + } + CharacterStringType::GeneralString => { + todo!() + } + CharacterStringType::VideotexString + | CharacterStringType::GraphicString + | CharacterStringType::UniversalString + | CharacterStringType::TeletexString => Err(GeneratorError::new( + None, + &format!("{:?} values are currently unsupported!", string_type), + GeneratorErrorType::NotYetInplemented, + )), } - _ => "int64".into(), // best effort } } - name if name == BIT_STRING => "BitString".into(), - name if name == OCTET_STRING => "OctetString".into(), - name if name == GENERALIZED_TIME => "GeneralizedTime".into(), - name if name == UTC_TIME => "UtcTime".into(), - name if name == OBJECT_IDENTIFIER => "ObjectIdentifier".into(), - name if name == NUMERIC_STRING => "NumericString".into(), - name if name == VISIBLE_STRING => "VisibleString".into(), - name if name == IA5_STRING => "IA5String".into(), - name if name == UTF8_STRING => "UTF8String".into(), - name if name == BMP_STRING => "BMPString".into(), - name if name == PRINTABLE_STRING => "PrintableString".into(), - name if name == GENERAL_STRING => "GeneralString".into(), - name => name, } } diff --git a/utils/codegen/codegen-rust/rgen/src/msgs/bin.rs b/utils/codegen/codegen-rust/rgen/src/msgs/bin.rs index 7eb64b1ed..8d5b279af 100644 --- a/utils/codegen/codegen-rust/rgen/src/msgs/bin.rs +++ b/utils/codegen/codegen-rust/rgen/src/msgs/bin.rs @@ -17,8 +17,7 @@ fn main() { let args = Cli::parse(); // Compile ROS messages - let compiler_res = Compiler::new() - .with_backend(Msgs) + let compiler_res = Compiler::::new() .add_asn_sources_by_path(args.paths.iter()) .compile_to_string(); let generated = &compiler_res.unwrap().generated; diff --git a/utils/codegen/codegen-rust/rgen/src/msgs/builder.rs b/utils/codegen/codegen-rust/rgen/src/msgs/builder.rs index 93b4ae218..88d61cd06 100644 --- a/utils/codegen/codegen-rust/rgen/src/msgs/builder.rs +++ b/utils/codegen/codegen-rust/rgen/src/msgs/builder.rs @@ -1,642 +1,683 @@ -use std::{collections::BTreeMap, error::Error}; +use std::collections::BTreeMap; use rasn_compiler::prelude::ir::*; use rasn_compiler::prelude::*; use crate::common::*; -use crate::msgs::{generate, Msgs}; -use crate::msgs::{template::*, utils::*}; +use crate::msgs::Msgs; +use crate::msgs::template::*; pub(crate) const INNER_ARRAY_LIKE_PREFIX: &str = "Anonymous_"; -impl Backend for Msgs { - fn generate_module( - &self, - tlds: Vec, - ) -> Result { - let tlds = merge_tlds(tlds); - let (pdus, warnings): (Vec, Vec>) = - tlds.into_iter() - .fold((vec![], vec![]), |mut acc, tld| match generate(tld) { - Ok(s) => { - s.len().gt(&0).then(|| { - acc.0.push(format!( - "\n\ - {s}\n\ - " - )) - }); - acc - } - Err(e) => { - acc.1.push(Box::new(e)); - acc - } - }); - Ok(GeneratedModule { - generated: Some(format!("{}", pdus.join("\n\n"))), - warnings, - }) - } +macro_rules! call_template { + ($self:ident, $fn:ident, $tld:ident, $($args:expr),*) => { + Ok($fn( + &$self.format_comments(&$tld.comments)?, + (&$tld.name), + $($args),* + )) + }; } -pub fn merge_tlds(tlds: Vec) -> Vec { - let mut merged_tlds = Vec::::with_capacity(tlds.len()); - let mut merge_to = Vec::<(&ToplevelDefinition, &String)>::new(); - tlds.iter().for_each(|tld| { - if let ToplevelDefinition::Value(v) = &tld { - if let ASN1Value::LinkedIntValue { .. } = &v.value { - merge_to.push((&tld, &v.associated_type)); +impl Msgs { + // This should be part of the linker module + pub fn merge_tlds(&self, tlds: Vec) -> Vec { + let mut merged_tlds = Vec::::with_capacity(tlds.len()); + let mut merge_to = Vec::<(&ToplevelDefinition, String)>::new(); + tlds.iter().for_each(|tld| { + if let ToplevelDefinition::Value(v) = &tld { + if let ASN1Value::LinkedIntValue { .. } = &v.value { + merge_to.push((&tld, v.associated_type.as_str().into())); + } else { + merged_tlds.push(tld.clone()); + } } else { merged_tlds.push(tld.clone()); } - } else { - merged_tlds.push(tld.clone()); - } - }); - merge_to.iter().for_each(|(tld, ty)| { - for t in &mut merged_tlds { - if let ToplevelDefinition::Type(tt) = t { - if tt.name == **ty { - // Add value to type's distinguished values - if let ASN1Type::Integer(ref mut int) = tt.ty { - let value = match &tld { - ToplevelDefinition::Value(v) => { - if let ASN1Value::LinkedIntValue { - integer_type: _, - value, - } = &v.value - { - value - } else { - unreachable!() + }); + merge_to.iter().for_each(|(tld, ty)| { + for t in &mut merged_tlds { + if let ToplevelDefinition::Type(tt) = t { + if tt.name == **ty { + // Add value to type's distinguished values + if let ASN1Type::Integer(ref mut int) = tt.ty { + let value = match &tld { + ToplevelDefinition::Value(v) => { + if let ASN1Value::LinkedIntValue { + integer_type: _, + value, + } = &v.value + { + value + } else { + unreachable!() + } } - } - _ => unreachable!(), - }; - match int.distinguished_values { - Some(ref mut dv) => dv.push(DistinguishedValue { - name: tld.name().clone(), - value: *value, - }), - None => { - int.distinguished_values = Some(vec![DistinguishedValue { + _ => unreachable!(), + }; + match int.distinguished_values { + Some(ref mut dv) => dv.push(DistinguishedValue { name: tld.name().clone(), value: *value, - }]); + }), + None => { + int.distinguished_values = Some(vec![DistinguishedValue { + name: tld.name().clone(), + value: *value, + }]); + } } } + break; } - break; } } - } - }); - merged_tlds -} + }); + merged_tlds + } -pub fn generate_typealias(tld: ToplevelTypeDefinition) -> Result { - if let ASN1Type::ElsewhereDeclaredType(dec) = &tld.ty { - Ok(typealias_template( - &format_comments(&tld.comments)?, - &tld.name, - &dec.identifier, - "", - )) - } else { - Err(GeneratorError::new( - Some(ToplevelDefinition::Type(tld)), - "Expected type alias top-level declaration", - GeneratorErrorType::Asn1TypeMismatch, - )) + pub fn generate_tld(&self, tld: ToplevelDefinition) -> Result { + match tld { + ToplevelDefinition::Type(t) => { + if t.parameterization.is_some() { + return Ok("".into()); + } + match t.ty { + ASN1Type::Null => self.generate_null(t), + ASN1Type::Boolean(_) => self.generate_boolean(t), + ASN1Type::Integer(_) => self.generate_integer(t), + ASN1Type::Enumerated(_) => self.generate_enumerated(t), + ASN1Type::BitString(_) => self.generate_bit_string(t), + ASN1Type::CharacterString(_) => self.generate_character_string(t), + ASN1Type::Sequence(_) | ASN1Type::Set(_) => self.generate_sequence_or_set(t), + ASN1Type::SequenceOf(_) | ASN1Type::SetOf(_) => { + self.generate_sequence_or_set_of(t) + } + ASN1Type::ElsewhereDeclaredType(_) => self.generate_typealias(t), + ASN1Type::Choice(_) => self.generate_choice(t), + ASN1Type::OctetString(_) => self.generate_octet_string(t), + ASN1Type::Time(_) => unimplemented!("TIME are currently unsupported!"), + ASN1Type::Real(_) => Err(GeneratorError { + kind: GeneratorErrorType::NotYetInplemented, + details: "Real types are currently unsupported!".into(), + top_level_declaration: None, + }), + ASN1Type::ObjectIdentifier(_) => self.generate_oid(t), + ASN1Type::InformationObjectFieldReference(_) + | ASN1Type::EmbeddedPdv + | ASN1Type::External => self.generate_any(t), + ASN1Type::GeneralizedTime(_) => self.generate_generalized_time(t), + ASN1Type::UTCTime(_) => self.generate_utc_time(t), + ASN1Type::ChoiceSelectionType(_) => unreachable!(), + } + } + ToplevelDefinition::Value(v) => self.generate_value(v), + ToplevelDefinition::Information(i) => match i.value { + ASN1Information::ObjectSet(_) => self.generate_information_object_set(i), + _ => Ok("".into()), + }, + } } -} -pub fn generate_integer_value(tld: ToplevelValueDefinition) -> Result { - if let ASN1Value::LinkedIntValue { integer_type, .. } = tld.value { - let formatted_value = value_to_tokens(&tld.value, None)?; - let formatted_name = to_ros_const_case(&tld.name); - let ty = integer_type.to_str(); - if tld.associated_type == INTEGER { - Ok(lazy_static_value_template( - &format_comments(&tld.comments)?, - &formatted_name, - "int64", - &formatted_value, - )) - } else if integer_type.is_unbounded() { - Ok(lazy_static_value_template( - &format_comments(&tld.comments)?, - &formatted_name, - ty, - &formatted_value, + pub fn generate_typealias( + &self, + tld: ToplevelTypeDefinition, + ) -> Result { + if let ASN1Type::ElsewhereDeclaredType(dec) = &tld.ty { + Ok(typealias_template( + &self.format_comments(&tld.comments)?, + &tld.name, + &dec.identifier, + "", )) } else { - Ok(integer_value_template( - &format_comments(&tld.comments)?, - &formatted_name, - ty, - &formatted_value, + Err(GeneratorError::new( + Some(ToplevelDefinition::Type(tld)), + "Expected type alias top-level declaration", + GeneratorErrorType::Asn1TypeMismatch, )) } - } else { - Err(GeneratorError::new( - Some(ToplevelDefinition::Value(tld)), - "Expected INTEGER value top-level declaration", - GeneratorErrorType::Asn1TypeMismatch, - )) } -} -pub fn generate_integer(tld: ToplevelTypeDefinition) -> Result { - if let ASN1Type::Integer(ref int) = tld.ty { - Ok(integer_template( - &format_comments(&tld.comments)?, - &to_ros_title_case(&tld.name), - &format_constraints(true, &int.constraints)? - .replace("{prefix}", ""), - int.int_type().to_str(), - &format_distinguished_values(&int.distinguished_values), - )) - } else { - Err(GeneratorError::new( - Some(ToplevelDefinition::Type(tld)), - "Expected INTEGER top-level declaration", - GeneratorErrorType::Asn1TypeMismatch, - )) + pub fn generate_integer_value( + &self, + tld: ToplevelValueDefinition, + ) -> Result { + if let ASN1Value::LinkedIntValue { integer_type, .. } = tld.value { + let formatted_value = self.value_to_tokens(&tld.value, None)?; + let formatted_name = to_ros_const_case(&tld.name); + let ty = integer_type.to_str(); + if integer_type.is_unbounded() { + Ok(lazy_static_value_template( + &self.format_comments(&tld.comments)?, + &formatted_name, + ty, + &formatted_value, + )) + } else { + Ok(integer_value_template( + &self.format_comments(&tld.comments)?, + &formatted_name, + ty, + &formatted_value, + )) + } + } else { + Err(GeneratorError::new( + Some(ToplevelDefinition::Value(tld)), + "Expected INTEGER value top-level declaration", + GeneratorErrorType::Asn1TypeMismatch, + )) + } } -} -pub fn generate_bit_string(tld: ToplevelTypeDefinition) -> Result { - if let ASN1Type::BitString(ref bitstr) = tld.ty { - Ok(bit_string_template( - &format_comments(&tld.comments)?, - &tld.name, - &format_constraints(true, &bitstr.constraints)? - .replace("{prefix}", "") - .replace("SIZE =", "SIZE_BITS ="), - &format_distinguished_values(&bitstr.distinguished_values), - )) - } else { - Err(GeneratorError::new( - Some(ToplevelDefinition::Type(tld)), - "Expected BIT STRING top-level declaration", - GeneratorErrorType::Asn1TypeMismatch, - )) + pub fn generate_integer(&self, tld: ToplevelTypeDefinition) -> Result { + if let ASN1Type::Integer(ref int) = tld.ty { + Ok(integer_template( + &self.format_comments(&tld.comments)?, + &to_ros_title_case(&tld.name), + &self.format_constraints(true, &int.constraints)?.replace("{prefix}", ""), + int.int_type().to_str(), + &self.format_distinguished_values(&int.distinguished_values), + )) + } else { + Err(GeneratorError::new( + Some(ToplevelDefinition::Type(tld)), + "Expected INTEGER top-level declaration", + GeneratorErrorType::Asn1TypeMismatch, + )) + } } -} -pub fn generate_octet_string(tld: ToplevelTypeDefinition) -> Result { - if let ASN1Type::OctetString(ref oct_str) = tld.ty { - Ok(octet_string_template( - &format_comments(&tld.comments)?, - &tld.name, - &format_constraints(false, &oct_str.constraints)? - .replace("{prefix}", ""), - )) - } else { - Err(GeneratorError::new( - Some(ToplevelDefinition::Type(tld)), - "Expected OCTET STRING top-level declaration", - GeneratorErrorType::Asn1TypeMismatch, - )) + pub fn generate_bit_string( + &self, + tld: ToplevelTypeDefinition, + ) -> Result { + if let ASN1Type::BitString(ref bitstr) = tld.ty { + Ok(bit_string_template( + &self.format_comments(&tld.comments)?, + &tld.name, + &self.format_constraints(true, &bitstr.constraints)? + .replace("{prefix}", "") + .replace("SIZE =", "SIZE_BITS ="), + &self.format_distinguished_values(&bitstr.distinguished_values), + )) + } else { + Err(GeneratorError::new( + Some(ToplevelDefinition::Type(tld)), + "Expected BIT STRING top-level declaration", + GeneratorErrorType::Asn1TypeMismatch, + )) + } } -} -pub fn generate_character_string(tld: ToplevelTypeDefinition) -> Result { - if let ASN1Type::CharacterString(ref char_str) = tld.ty { - Ok(char_string_template( - &format_comments(&tld.comments)?, - &tld.name, - &string_type(&char_str.ty)?, - &format_constraints(false, &char_str.constraints)? - .replace("{prefix}", ""), - )) - } else { - Err(GeneratorError::new( - Some(ToplevelDefinition::Type(tld)), - "Expected Character String top-level declaration", - GeneratorErrorType::Asn1TypeMismatch, - )) + pub fn generate_octet_string( + &self, + tld: ToplevelTypeDefinition, + ) -> Result { + if let ASN1Type::OctetString(ref oct_str) = tld.ty { + Ok(octet_string_template( + &self.format_comments(&tld.comments)?, + &tld.name, + &self.format_constraints(false, &oct_str.constraints)?.replace("{prefix}", ""), + )) + } else { + Err(GeneratorError::new( + Some(ToplevelDefinition::Type(tld)), + "Expected OCTET STRING top-level declaration", + GeneratorErrorType::Asn1TypeMismatch, + )) + } } -} -pub fn generate_boolean(tld: ToplevelTypeDefinition) -> Result { - if let ASN1Type::Boolean(_) = tld.ty { - Ok(boolean_template( - &format_comments(&tld.comments)?, - &tld.name, - "", - )) - } else { - Err(GeneratorError::new( - Some(ToplevelDefinition::Type(tld)), - "Expected BOOLEAN top-level declaration", - GeneratorErrorType::Asn1TypeMismatch, - )) + pub fn generate_character_string( + &self, + tld: ToplevelTypeDefinition, + ) -> Result { + if let ASN1Type::CharacterString(ref char_str) = tld.ty { + Ok(char_string_template( + &self.format_comments(&tld.comments)?, + &tld.name, + &self.string_type(&char_str.ty)?, + &self.format_constraints(false, &char_str.constraints)?.replace("{prefix}", ""), + )) + } else { + Err(GeneratorError::new( + Some(ToplevelDefinition::Type(tld)), + "Expected Character String top-level declaration", + GeneratorErrorType::Asn1TypeMismatch, + )) + } } -} -macro_rules! call_template { - ($fn:ident, $tld:ident, $($args:expr),*) => { - Ok($fn( - &format_comments(&$tld.comments)?, - (&$tld.name), - $($args),* - )) - }; -} - -pub fn generate_value(tld: ToplevelValueDefinition) -> Result { - let ty = tld.associated_type.as_str(); - match &tld.value { - ASN1Value::Null if ty == NULL => { - call_template!( - primitive_value_template, - tld, - "quote!(())".into(), - "quote!(())".into() - ) - } - ASN1Value::Null => todo!(), - ASN1Value::Boolean(b) if ty == BOOLEAN => { - call_template!(primitive_value_template, tld, "bool", &b.to_string()) + pub fn generate_boolean(&self, tld: ToplevelTypeDefinition) -> Result { + if let ASN1Type::Boolean(_) = tld.ty { + Ok(boolean_template( + &self.format_comments(&tld.comments)?, + &tld.name, + "", + )) + } else { + Err(GeneratorError::new( + Some(ToplevelDefinition::Type(tld)), + "Expected BOOLEAN top-level declaration", + GeneratorErrorType::Asn1TypeMismatch, + )) } - ASN1Value::Boolean(_) => todo!(), - ASN1Value::LinkedIntValue { .. } => generate_integer_value(tld), - ASN1Value::BitString(_) if ty == BIT_STRING => todo!(), - ASN1Value::OctetString(_) if ty == OCTET_STRING => todo!(), - ASN1Value::Choice { - variant_name, - inner_value, - .. - } => { - if inner_value.is_const_type() { - call_template!( - const_choice_value_template, - tld, - &tld.associated_type, - variant_name, - &value_to_tokens(inner_value, None)? - ) - } else { + } + + pub fn generate_value(&self, tld: ToplevelValueDefinition) -> Result { + let ty = tld.associated_type.as_str(); + match &tld.value { + ASN1Value::Null if ty == NULL => { call_template!( - choice_value_template, + self, + primitive_value_template, tld, - &tld.associated_type, - &variant_name, - &value_to_tokens(inner_value, None)? + "quote!(())".into(), + "quote!(())".into() ) } + ASN1Value::Null => todo!(), + ASN1Value::Boolean(b) if ty == BOOLEAN => { + call_template!(self, primitive_value_template, tld, "bool", &b.to_string()) + } + ASN1Value::Boolean(_) => todo!(), + ASN1Value::LinkedIntValue { .. } => self.generate_integer_value(tld), + ASN1Value::BitString(_) if ty == BIT_STRING => todo!(), + ASN1Value::OctetString(_) if ty == OCTET_STRING => todo!(), + ASN1Value::Choice { + variant_name, + inner_value, + .. + } => { + if inner_value.is_const_type() { + call_template!( + self, + const_choice_value_template, + tld, + &tld.associated_type.as_str(), + variant_name, + &self.value_to_tokens(inner_value, None)? + ) + } else { + call_template!( + self, + choice_value_template, + tld, + &tld.associated_type.as_str(), + &variant_name, + &self.value_to_tokens(inner_value, None)? + ) + } + } + ASN1Value::EnumeratedValue { + enumerated, + enumerable, + } => call_template!(self, enum_value_template, tld, enumerated, enumerable), + ASN1Value::Time(_) if ty == GENERALIZED_TIME => todo!(), + ASN1Value::Time(_) if ty == UTC_TIME => todo!(), + ASN1Value::LinkedStructLikeValue(_) => todo!(), + ASN1Value::LinkedNestedValue { .. } => todo!(), + ASN1Value::ObjectIdentifier(_) if ty == OBJECT_IDENTIFIER => todo!(), + ASN1Value::LinkedCharStringValue(_, _) if ty == NUMERIC_STRING => todo!(), + ASN1Value::LinkedCharStringValue(_, _) if ty == VISIBLE_STRING => todo!(), + ASN1Value::LinkedCharStringValue(_, _) if ty == IA5_STRING => todo!(), + ASN1Value::LinkedCharStringValue(_, _) if ty == UTF8_STRING => todo!(), + ASN1Value::LinkedCharStringValue(_, _) if ty == BMP_STRING => todo!(), + ASN1Value::LinkedCharStringValue(_, _) if ty == PRINTABLE_STRING => todo!(), + ASN1Value::LinkedCharStringValue(_, _) if ty == GENERAL_STRING => todo!(), + ASN1Value::LinkedArrayLikeValue(_) if ty.contains(SEQUENCE_OF) => todo!(), + ASN1Value::LinkedArrayLikeValue(_) if ty.contains(SET_OF) => todo!(), + ASN1Value::BitString(_) + | ASN1Value::Time(_) + | ASN1Value::LinkedCharStringValue(_, _) + | ASN1Value::ObjectIdentifier(_) + | ASN1Value::LinkedArrayLikeValue(_) + | ASN1Value::ElsewhereDeclaredValue { .. } + | ASN1Value::OctetString(_) => todo!(), + _ => Ok("".to_string()), } - ASN1Value::EnumeratedValue { - enumerated, - enumerable, - } => call_template!(enum_value_template, tld, enumerated, enumerable), - ASN1Value::Time(_) if ty == GENERALIZED_TIME => todo!(), - ASN1Value::Time(_) if ty == UTC_TIME => todo!(), - ASN1Value::LinkedStructLikeValue(_) => todo!(), - ASN1Value::LinkedNestedValue { .. } => todo!(), - ASN1Value::ObjectIdentifier(_) if ty == OBJECT_IDENTIFIER => todo!(), - ASN1Value::LinkedCharStringValue(_, _) if ty == NUMERIC_STRING => todo!(), - ASN1Value::LinkedCharStringValue(_, _) if ty == VISIBLE_STRING => todo!(), - ASN1Value::LinkedCharStringValue(_, _) if ty == IA5_STRING => todo!(), - ASN1Value::LinkedCharStringValue(_, _) if ty == UTF8_STRING => todo!(), - ASN1Value::LinkedCharStringValue(_, _) if ty == BMP_STRING => todo!(), - ASN1Value::LinkedCharStringValue(_, _) if ty == PRINTABLE_STRING => todo!(), - ASN1Value::LinkedCharStringValue(_, _) if ty == GENERAL_STRING => todo!(), - ASN1Value::LinkedArrayLikeValue(_) if ty.contains(SEQUENCE_OF) => todo!(), - ASN1Value::LinkedArrayLikeValue(_) if ty.contains(SET_OF) => todo!(), - ASN1Value::BitString(_) - | ASN1Value::Time(_) - | ASN1Value::LinkedCharStringValue(_, _) - | ASN1Value::ObjectIdentifier(_) - | ASN1Value::LinkedArrayLikeValue(_) - | ASN1Value::ElsewhereDeclaredValue { .. } - | ASN1Value::OctetString(_) => todo!(), - _ => Ok("".to_string()), } -} -pub fn generate_any(tld: ToplevelTypeDefinition) -> Result { - Ok(any_template( - &format_comments(&tld.comments)?, - &tld.name, - "", - )) -} - -pub fn generate_generalized_time(tld: ToplevelTypeDefinition) -> Result { - if let ASN1Type::GeneralizedTime(_) = &tld.ty { - Ok(generalized_time_template( - &format_comments(&tld.comments)?, + pub fn generate_any(&self, tld: ToplevelTypeDefinition) -> Result { + Ok(any_template( + &self.format_comments(&tld.comments)?, &tld.name, "", )) - } else { - Err(GeneratorError::new( - Some(ToplevelDefinition::Type(tld)), - "Expected GeneralizedTime top-level declaration", - GeneratorErrorType::Asn1TypeMismatch, - )) } -} -pub fn generate_utc_time(tld: ToplevelTypeDefinition) -> Result { - if let ASN1Type::UTCTime(_) = &tld.ty { - Ok(utc_time_template( - &format_comments(&tld.comments)?, - &tld.name, - "", - )) - } else { - Err(GeneratorError::new( - Some(ToplevelDefinition::Type(tld)), - "Expected UTCTime top-level declaration", - GeneratorErrorType::Asn1TypeMismatch, - )) + pub fn generate_generalized_time( + &self, + tld: ToplevelTypeDefinition, + ) -> Result { + if let ASN1Type::GeneralizedTime(_) = &tld.ty { + Ok(generalized_time_template( + &self.format_comments(&tld.comments)?, + &tld.name, + "", + )) + } else { + Err(GeneratorError::new( + Some(ToplevelDefinition::Type(tld)), + "Expected GeneralizedTime top-level declaration", + GeneratorErrorType::Asn1TypeMismatch, + )) + } } -} -pub fn generate_oid(tld: ToplevelTypeDefinition) -> Result { - if let ASN1Type::ObjectIdentifier(_oid) = &tld.ty { - Ok(oid_template( - &format_comments(&tld.comments)?, - &tld.name, - "", - )) - } else { - Err(GeneratorError::new( - Some(ToplevelDefinition::Type(tld)), - "Expected OBJECT IDENTIFIER top-level declaration", - GeneratorErrorType::Asn1TypeMismatch, - )) + pub fn generate_utc_time(&self, tld: ToplevelTypeDefinition) -> Result { + if let ASN1Type::UTCTime(_) = &tld.ty { + Ok(utc_time_template( + &self.format_comments(&tld.comments)?, + &tld.name, + "", + )) + } else { + Err(GeneratorError::new( + Some(ToplevelDefinition::Type(tld)), + "Expected UTCTime top-level declaration", + GeneratorErrorType::Asn1TypeMismatch, + )) + } } -} -pub fn generate_null(tld: ToplevelTypeDefinition) -> Result { - if let ASN1Type::Null = tld.ty { - Ok(null_template( - &format_comments(&tld.comments)?, - &tld.name, - "", - )) - } else { - Err(GeneratorError::new( - Some(ToplevelDefinition::Type(tld)), - "Expected NULL top-level declaration", - GeneratorErrorType::Asn1TypeMismatch, - )) + pub fn generate_oid(&self, tld: ToplevelTypeDefinition) -> Result { + if let ASN1Type::ObjectIdentifier(_oid) = &tld.ty { + Ok(oid_template( + &self.format_comments(&tld.comments)?, + &tld.name, + "", + )) + } else { + Err(GeneratorError::new( + Some(ToplevelDefinition::Type(tld)), + "Expected OBJECT IDENTIFIER top-level declaration", + GeneratorErrorType::Asn1TypeMismatch, + )) + } } -} -pub fn generate_enumerated(tld: ToplevelTypeDefinition) -> Result { - if let ASN1Type::Enumerated(ref enumerated) = tld.ty { - Ok(enumerated_template( - &format_comments(&tld.comments)?, - &tld.name, - &format_enum_members(enumerated), - "", - )) - } else { - Err(GeneratorError::new( - Some(ToplevelDefinition::Type(tld)), - "Expected ENUMERATED top-level declaration", - GeneratorErrorType::Asn1TypeMismatch, - )) + pub fn generate_null(&self, tld: ToplevelTypeDefinition) -> Result { + if let ASN1Type::Null = tld.ty { + Ok(null_template( + &self.format_comments(&tld.comments)?, + &tld.name, + "", + )) + } else { + Err(GeneratorError::new( + Some(ToplevelDefinition::Type(tld)), + "Expected NULL top-level declaration", + GeneratorErrorType::Asn1TypeMismatch, + )) + } } -} -pub fn generate_choice(tld: ToplevelTypeDefinition) -> Result { - if let ASN1Type::Choice(ref choice) = tld.ty { - let inner_options = format_nested_choice_options(choice, &tld.name)?; - Ok(choice_template( - &format_comments(&tld.comments)?, - &tld.name, - &format_choice_options(choice, &tld.name)?, - inner_options, - "", - )) - } else { - Err(GeneratorError::new( - Some(ToplevelDefinition::Type(tld)), - "Expected CHOICE top-level declaration", - GeneratorErrorType::Asn1TypeMismatch, - )) + pub fn generate_enumerated( + &self, + tld: ToplevelTypeDefinition, + ) -> Result { + if let ASN1Type::Enumerated(ref enumerated) = tld.ty { + Ok(enumerated_template( + &self.format_comments(&tld.comments)?, + &tld.name, + &self.format_enum_members(enumerated), + "", + )) + } else { + Err(GeneratorError::new( + Some(ToplevelDefinition::Type(tld)), + "Expected ENUMERATED top-level declaration", + GeneratorErrorType::Asn1TypeMismatch, + )) + } } -} -pub fn generate_sequence_or_set(tld: ToplevelTypeDefinition) -> Result { - match tld.ty { - ASN1Type::Sequence(ref seq) | ASN1Type::Set(ref seq) => { - let declaration = format_sequence_or_set_members(seq, &tld.name)?; - Ok(sequence_or_set_template( - &format_comments(&tld.comments)?, + pub fn generate_choice(&self, tld: ToplevelTypeDefinition) -> Result { + if let ASN1Type::Choice(ref choice) = tld.ty { + let inner_options = self.format_nested_choice_options(choice, &tld.name)?; + Ok(choice_template( + &self.format_comments(&tld.comments)?, &tld.name, - &declaration, - format_nested_sequence_members(seq, &tld.name)?, - "", - &format_default_methods(&seq.members, &tld.name)?, + &self.format_choice_options(choice, &tld.name)?, + inner_options, "", )) + } else { + Err(GeneratorError::new( + Some(ToplevelDefinition::Type(tld)), + "Expected CHOICE top-level declaration", + GeneratorErrorType::Asn1TypeMismatch, + )) } - _ => Err(GeneratorError::new( - Some(ToplevelDefinition::Type(tld)), - "Expected SEQUENCE top-level declaration", - GeneratorErrorType::Asn1TypeMismatch, - )), } -} -pub fn generate_sequence_or_set_of(tld: ToplevelTypeDefinition) -> Result { - let (is_set_of, seq_or_set_of) = match &tld.ty { - ASN1Type::SetOf(se_of) => (true, se_of), - ASN1Type::SequenceOf(se_of) => (false, se_of), - _ => { - return Err(GeneratorError::new( + pub fn generate_sequence_or_set( + &self, + tld: ToplevelTypeDefinition, + ) -> Result { + match tld.ty { + ASN1Type::Sequence(ref seq) | ASN1Type::Set(ref seq) => { + let declaration = self.format_sequence_or_set_members(seq, &tld.name)?; + Ok(sequence_or_set_template( + &self.format_comments(&tld.comments)?, + &tld.name, + &declaration, + self.format_nested_sequence_members(seq, &tld.name)?, + "", + &self.format_default_methods(&seq.members, &tld.name)?, + "", + )) + } + _ => Err(GeneratorError::new( Some(ToplevelDefinition::Type(tld)), - "Expected SEQUENCE OF top-level declaration", + "Expected SEQUENCE top-level declaration", GeneratorErrorType::Asn1TypeMismatch, - )) + )), } - }; - let anonymous_item = match seq_or_set_of.element_type.as_ref() { - ASN1Type::ElsewhereDeclaredType(_) => None, - n => Some(generate(ToplevelDefinition::Type( - ToplevelTypeDefinition { - parameterization: None, - comments: format!( - " Anonymous {} OF member ", - if is_set_of { "SET" } else { "SEQUENCE" } - ), - name: String::from(INNER_ARRAY_LIKE_PREFIX) + &tld.name, - ty: n.clone(), - tag: None, - index: None, - }, - ))?), } - .unwrap_or_default(); - let member_type = match seq_or_set_of.element_type.as_ref() { - ASN1Type::ElsewhereDeclaredType(d) => d.identifier.clone(), - _ => format!("Anonymous{}", &tld.name), - }; - let constraints = format_constraints(true, &seq_or_set_of.constraints)? - .replace("{prefix}", ""); - Ok(sequence_or_set_of_template( - is_set_of, - &format_comments(&tld.comments)?, - &tld.name, - &anonymous_item, - &member_type, - &constraints, - )) -} -pub fn generate_information_object_set( - tld: ToplevelInformationDefinition, -) -> Result { - if let ASN1Information::ObjectSet(o) = &tld.value { - let class: &InformationObjectClass = match tld.class { - Some(ClassLink::ByReference(ref c)) => c, + pub fn generate_sequence_or_set_of( + &self, + tld: ToplevelTypeDefinition, + ) -> Result { + let (is_set_of, seq_or_set_of) = match &tld.ty { + ASN1Type::SetOf(se_of) => (true, se_of), + ASN1Type::SequenceOf(se_of) => (false, se_of), _ => { return Err(GeneratorError::new( - None, - "Missing class link in Information Object Set", - GeneratorErrorType::MissingClassKey, + Some(ToplevelDefinition::Type(tld)), + "Expected SEQUENCE OF top-level declaration", + GeneratorErrorType::Asn1TypeMismatch, )) } }; - let mut keys_to_types = o - .values - .iter() - .map(|v| match v { - ObjectSetValue::Reference(r) => Err(GeneratorError::new( - None, - &format!("Could not resolve reference of Information Object Set {r}"), - GeneratorErrorType::MissingClassKey, - )), - ObjectSetValue::Inline(InformationObjectFields::CustomSyntax(_)) => { - Err(GeneratorError::new( - Some(ToplevelDefinition::Information(tld.clone())), - "Unexpectedly encountered unresolved custom syntax!", + let anonymous_item = match seq_or_set_of.element_type.as_ref() { + ASN1Type::ElsewhereDeclaredType(_) => None, + n => Some( + self.generate_tld(ToplevelDefinition::Type(ToplevelTypeDefinition { + parameterization: None, + comments: format!( + " Anonymous {} OF member ", + if is_set_of { "SET" } else { "SEQUENCE" } + ), + name: String::from(INNER_ARRAY_LIKE_PREFIX) + &tld.name, + ty: n.clone(), + tag: None, + index: None, + }))?, + ), + } + .unwrap_or_default(); + let member_type = match seq_or_set_of.element_type.as_ref() { + ASN1Type::ElsewhereDeclaredType(d) => d.identifier.clone(), + _ => format!("Anonymous{}", &tld.name), + }; + let constraints = + self.format_constraints(true, &seq_or_set_of.constraints)?.replace("{prefix}", ""); + Ok(sequence_or_set_of_template( + is_set_of, + &self.format_comments(&tld.comments)?, + &tld.name, + &anonymous_item, + &member_type, + &constraints, + )) + } + + pub fn generate_information_object_set( + &self, + tld: ToplevelInformationDefinition, + ) -> Result { + if let ASN1Information::ObjectSet(o) = &tld.value { + let class: &InformationObjectClass = match tld.class { + Some(ClassLink::ByReference(ref c)) => c, + _ => { + return Err(GeneratorError::new( + None, + "Missing class link in Information Object Set", GeneratorErrorType::MissingClassKey, )) } - ObjectSetValue::Inline(InformationObjectFields::DefaultSyntax(s)) => { - resolve_standard_syntax(class, s) - } - }) - .collect::)>, _>>()?; - let mut choices = BTreeMap::>::new(); - for (key, items) in keys_to_types.drain(..) { - for (index, item) in items { - let id = class - .fields - .get(index) - .map(|f| f.identifier.identifier()) - .ok_or_else(|| GeneratorError { - top_level_declaration: Some(ToplevelDefinition::Information(tld.clone())), - details: "Could not find class field for index.".into(), - kind: GeneratorErrorType::SyntaxMismatch, - })?; - match choices.get_mut(id) { - Some(entry) => entry.push((key.clone(), item)), - None => { - choices.insert(id.clone(), vec![(key.clone(), item)]); + }; + let mut keys_to_types = o + .values + .iter() + .map(|v| match v { + ObjectSetValue::Reference(r) => Err(GeneratorError::new( + None, + &format!("Could not resolve reference of Information Object Set {r}"), + GeneratorErrorType::MissingClassKey, + )), + ObjectSetValue::Inline(InformationObjectFields::CustomSyntax(_)) => { + Err(GeneratorError::new( + Some(ToplevelDefinition::Information(tld.clone())), + "Unexpectedly encountered unresolved custom syntax!", + GeneratorErrorType::MissingClassKey, + )) + } + ObjectSetValue::Inline(InformationObjectFields::DefaultSyntax(s)) => { + self.resolve_standard_syntax(class, s) + } + }) + .collect::)>, _>>()?; + let mut choices = BTreeMap::>::new(); + for (key, items) in keys_to_types.drain(..) { + for (index, item) in items { + let id = class + .fields + .get(index) + .map(|f| f.identifier.identifier()) + .ok_or_else(|| GeneratorError { + top_level_declaration: Some(ToplevelDefinition::Information( + tld.clone(), + )), + details: "Could not find class field for index.".into(), + kind: GeneratorErrorType::SyntaxMismatch, + })?; + match choices.get_mut(id) { + Some(entry) => entry.push((key.clone(), item)), + None => { + choices.insert(id.clone(), vec![(key.clone(), item)]); + } } } } - } - if choices.is_empty() { - for InformationObjectClassField { identifier, .. } in &class.fields { - choices.insert(identifier.identifier().clone(), Vec::new()); + if choices.is_empty() { + for InformationObjectClassField { identifier, .. } in &class.fields { + choices.insert(identifier.identifier().clone(), Vec::new()); + } } - } - let name = &tld.name; - let class_unique_id_type = class - .fields - .iter() - .find_map(|f| (f.is_unique).then(|| f.ty.clone())) - .flatten() - .ok_or_else(|| GeneratorError { - top_level_declaration: None, - details: "Could not determine unique class identifier type.".into(), - kind: GeneratorErrorType::SyntaxMismatch, - })?; - let class_unique_id_type_name = type_to_tokens(&class_unique_id_type)?; + let name = &tld.name; + let class_unique_id_type = class + .fields + .iter() + .find_map(|f| (f.is_unique).then(|| f.ty.clone())) + .flatten() + .ok_or_else(|| GeneratorError { + top_level_declaration: None, + details: "Could not determine unique class identifier type.".into(), + kind: GeneratorErrorType::SyntaxMismatch, + })?; + let class_unique_id_type_name = self.type_to_tokens(&class_unique_id_type)?; - let mut field_enums = vec![]; - for (_field_name, fields) in choices.iter() { - let field_enum_name = name.clone(); - let mut ids = vec![]; - for (index, (id, ty)) in fields.iter().enumerate() { - let identifier_value = match id { - ASN1Value::LinkedElsewhereDefinedValue { - can_be_const: false, - .. - } => { - let _tokenized_value = - value_to_tokens(id, Some(&class_unique_id_type_name))?; - todo!() - } - ASN1Value::LinkedNestedValue { value, .. } - if matches![ - &**value, - ASN1Value::LinkedElsewhereDefinedValue { - can_be_const: false, - .. - } - ] => - { - let _tokenized_value = - value_to_tokens(value, Some(&class_unique_id_type_name))?; - todo!() - } - ASN1Value::LinkedNestedValue { value, .. } - if matches![&**value, ASN1Value::LinkedElsewhereDefinedValue { .. }] => - { - value_to_tokens(value, Some(&class_unique_id_type_name))? - } - _ => value_to_tokens(id, Some(&class_unique_id_type_name))?, - }; - let type_id = type_to_tokens(ty).unwrap_or("type?".into()); - let variant_name = match id { - ASN1Value::LinkedElsewhereDefinedValue { - identifier: ref_id, .. + let mut field_enums = vec![]; + for (_field_name, fields) in choices.iter() { + let field_enum_name = name.clone(); + let mut ids = vec![]; + for (index, (id, ty)) in fields.iter().enumerate() { + let identifier_value = match id { + ASN1Value::LinkedElsewhereDefinedValue { + can_be_const: false, + .. + } => { + let _tokenized_value = + self.value_to_tokens(id, Some(&class_unique_id_type_name))?; + todo!() + } + ASN1Value::LinkedNestedValue { value, .. } + if matches![ + &**value, + ASN1Value::LinkedElsewhereDefinedValue { + can_be_const: false, + .. + } + ] => + { + let _tokenized_value = + self.value_to_tokens(value, Some(&class_unique_id_type_name))?; + todo!() + } + ASN1Value::LinkedNestedValue { value, .. } + if matches![ + &**value, + ASN1Value::LinkedElsewhereDefinedValue { .. } + ] => + { + self.value_to_tokens(value, Some(&class_unique_id_type_name))? + } + _ => self.value_to_tokens(id, Some(&class_unique_id_type_name))?, + }; + let type_id = self.type_to_tokens(ty).unwrap_or("type?".into()); + let variant_name = match id { + ASN1Value::LinkedElsewhereDefinedValue { + identifier: ref_id, .. + } + | ASN1Value::ElsewhereDeclaredValue { + identifier: ref_id, .. + } => ref_id.clone(), + _ => format!("{field_enum_name}_{index}"), + }; + if ty.constraints().map_or(true, |c| c.is_empty()) { + ids.push((variant_name, type_id, identifier_value)); } - | ASN1Value::ElsewhereDeclaredValue { - identifier: ref_id, .. - } => ref_id.clone(), - _ => format!("{field_enum_name}_{index}"), - }; - if ty.constraints().map_or(true, |c| c.is_empty()) { - ids.push((variant_name, type_id, identifier_value)); } - } - let variants = ids.iter().map(|(variant_name, type_id, _)| { - format!("{type_id} {}", to_ros_snake_case(variant_name)) - }); + let variants = ids.iter().map(|(variant_name, type_id, _)| { + format!("{type_id} {}", to_ros_snake_case(variant_name)) + }); - field_enums.push(format!( - "## OPEN-TYPE {field_enum_name}\n{class_unique_id_type_name} choice\n{}", - variants.fold("".to_string(), |mut acc, v| { - acc.push_str(&v); - acc.push_str("\n"); - acc - }), - )); - } + field_enums.push(format!( + "## OPEN-TYPE {field_enum_name}\n{class_unique_id_type_name} choice\n{}", + variants.fold("".to_string(), |mut acc, v| { + acc.push_str(&v); + acc.push_str("\n"); + acc + }), + )); + } - Ok(field_enums.join("\n")) - } else { - Err(GeneratorError::new( - Some(ToplevelDefinition::Information(tld)), - "Expected Object Set top-level declaration", - GeneratorErrorType::Asn1TypeMismatch, - )) + Ok(field_enums.join("\n")) + } else { + Err(GeneratorError::new( + Some(ToplevelDefinition::Information(tld)), + "Expected Object Set top-level declaration", + GeneratorErrorType::Asn1TypeMismatch, + )) + } } } diff --git a/utils/codegen/codegen-rust/rgen/src/msgs/mod.rs b/utils/codegen/codegen-rust/rgen/src/msgs/mod.rs index 3bde1ca4a..71612e11c 100644 --- a/utils/codegen/codegen-rust/rgen/src/msgs/mod.rs +++ b/utils/codegen/codegen-rust/rgen/src/msgs/mod.rs @@ -1,51 +1,63 @@ -use rasn_compiler::prelude::ir::{ASN1Information, ASN1Type}; +use std::error::Error; + use rasn_compiler::prelude::*; mod builder; mod template; mod utils; -pub struct Msgs; - -use builder::*; - -fn generate(tld: ToplevelDefinition) -> Result { - match tld { - ToplevelDefinition::Type(t) => { - if t.parameterization.is_some() { - return Ok("".into()); - } - match t.ty { - ASN1Type::Null => generate_null(t), - ASN1Type::Boolean(_) => generate_boolean(t), - ASN1Type::Integer(_) => generate_integer(t), - ASN1Type::Enumerated(_) => generate_enumerated(t), - ASN1Type::BitString(_) => generate_bit_string(t), - ASN1Type::CharacterString(_) => generate_character_string(t), - ASN1Type::Sequence(_) | ASN1Type::Set(_) => generate_sequence_or_set(t), - ASN1Type::SequenceOf(_) | ASN1Type::SetOf(_) => generate_sequence_or_set_of(t), - ASN1Type::ElsewhereDeclaredType(_) => generate_typealias(t), - ASN1Type::Choice(_) => generate_choice(t), - ASN1Type::OctetString(_) => generate_octet_string(t), - ASN1Type::Time(_) => unimplemented!("rasn does not support TIME types yet!"), - ASN1Type::Real(_) => Err(GeneratorError { - kind: GeneratorErrorType::NotYetInplemented, - details: "Real types are currently unsupported!".into(), - top_level_declaration: None, - }), - ASN1Type::ObjectIdentifier(_) => generate_oid(t), - ASN1Type::InformationObjectFieldReference(_) - | ASN1Type::EmbeddedPdv - | ASN1Type::External => generate_any(t), - ASN1Type::GeneralizedTime(_) => generate_generalized_time(t), - ASN1Type::UTCTime(_) => generate_utc_time(t), - ASN1Type::ChoiceSelectionType(_) => unreachable!(), - } - } - ToplevelDefinition::Value(v) => generate_value(v), - ToplevelDefinition::Information(i) => match i.value { - ASN1Information::ObjectSet(_) => generate_information_object_set(i), - _ => Ok("".into()), - }, +#[derive(Debug, Default)] +pub struct Msgs { + config: Config, +} + +#[derive(Debug, Default)] +pub struct Config {} + +impl Backend for Msgs { + type Config = Config; + + const FILE_EXTENSION: &'static str = ".msg"; + + fn from_config(config: Self::Config) -> Self { + Self { config } + } + + fn config(&self) -> &Self::Config { + &self.config + } + + fn generate_module( + &self, + tlds: Vec, + ) -> Result { + let tlds = self.merge_tlds(tlds); + let (pdus, warnings): (Vec, Vec>) = + tlds.into_iter().fold((vec![], vec![]), |mut acc, tld| { + match self.generate_tld(tld) { + Ok(s) => { + s.len().gt(&0).then(|| { + acc.0.push(format!( + "\n\ + {s}\n\ + " + )) + }); + acc + } + Err(e) => { + acc.1.push(Box::new(e)); + acc + } + } + }); + Ok(GeneratedModule { + generated: Some(format!("{}", pdus.join("\n\n"))), + warnings, + }) + } + + fn generate(&self, tld: ToplevelDefinition) -> Result { + self.generate_tld(tld).map(|ts| ts.to_string()) } } diff --git a/utils/codegen/codegen-rust/rgen/src/msgs/template.rs b/utils/codegen/codegen-rust/rgen/src/msgs/template.rs index b3a98b5cf..fb85c89eb 100644 --- a/utils/codegen/codegen-rust/rgen/src/msgs/template.rs +++ b/utils/codegen/codegen-rust/rgen/src/msgs/template.rs @@ -1,5 +1,4 @@ -const MSG_TEMPLATE: &str = -r#"# ============================================================================== +const MSG_TEMPLATE: &str = r#"# ============================================================================== # MIT License # # Copyright (c) 2023-2024 Institute for Automotive Engineering (ika), RWTH Aachen University @@ -194,21 +193,19 @@ pub fn sequence_or_set_template( default_methods: &str, class_fields: &str, ) -> String { - licensed!( - &vec![ - &format!("## SEQUENCE {name}"), - comments, - members, - &nested_members.join("\n"), - annotations, - default_methods, - class_fields - ] - .into_iter() - .filter(|s| !s.is_empty()) - .collect::>() - .join("\n") - ) + licensed!(&vec![ + &format!("## SEQUENCE {name}"), + comments, + members, + &nested_members.join("\n"), + annotations, + default_methods, + class_fields + ] + .into_iter() + .filter(|s| !s.is_empty()) + .collect::>() + .join("\n")) } pub fn sequence_or_set_of_template( @@ -254,18 +251,16 @@ pub fn choice_template( nested_options: Vec, annotations: &str, ) -> String { - licensed!( - &vec![ - &format!("## CHOICE {name}"), - comments, - "uint8 choice\n", - options, - &nested_options.join("\n"), - annotations - ] - .into_iter() - .filter(|s| !s.is_empty()) - .collect::>() - .join("\n") - ) + licensed!(&vec![ + &format!("## CHOICE {name}"), + comments, + "uint8 choice\n", + options, + &nested_options.join("\n"), + annotations + ] + .into_iter() + .filter(|s| !s.is_empty()) + .collect::>() + .join("\n")) } diff --git a/utils/codegen/codegen-rust/rgen/src/msgs/utils.rs b/utils/codegen/codegen-rust/rgen/src/msgs/utils.rs index 527da63be..465a09f5a 100644 --- a/utils/codegen/codegen-rust/rgen/src/msgs/utils.rs +++ b/utils/codegen/codegen-rust/rgen/src/msgs/utils.rs @@ -23,685 +23,678 @@ pub(crate) use error; use super::*; -pub fn inner_name(name: &String, parent_name: &String) -> String { - format!("{}{}", parent_name, name) -} +impl Msgs { + pub fn inner_name(&self, name: &String, parent_name: &String) -> String { + format!("{}{}", parent_name, name) + } -pub fn int_type_token(opt_min: Option, opt_max: Option, is_extensible: bool) -> String { - if let (Some(min), Some(max)) = (opt_min, opt_max) { - format!( - "{}", - if is_extensible { - "int64" - } else if min >= 0 { - match max { - r if r <= u8::MAX.into() => "uint8", - r if r <= u16::MAX.into() => "uint16", - r if r <= u32::MAX.into() => "uint32", - r if r <= u64::MAX.into() => "uint64", - _ => "uint64", - } - } else { - match (min, max) { - (mi, ma) if mi >= i8::MIN.into() && ma <= i8::MAX.into() => "int8", - (mi, ma) if mi >= i16::MIN.into() && ma <= i16::MAX.into() => "int16", - (mi, ma) if mi >= i32::MIN.into() && ma <= i32::MAX.into() => "int32", - (mi, ma) if mi >= i64::MIN.into() && ma <= i64::MAX.into() => "int64", - _ => "int64", + pub fn int_type_token( + &self, + opt_min: Option, + opt_max: Option, + is_extensible: bool, + ) -> String { + if let (Some(min), Some(max)) = (opt_min, opt_max) { + format!( + "{}", + if is_extensible { + "int64" + } else if min >= 0 { + match max { + r if r <= u8::MAX.into() => "uint8", + r if r <= u16::MAX.into() => "uint16", + r if r <= u32::MAX.into() => "uint32", + r if r <= u64::MAX.into() => "uint64", + _ => "uint64", + } + } else { + match (min, max) { + (mi, ma) if mi >= i8::MIN.into() && ma <= i8::MAX.into() => "int8", + (mi, ma) if mi >= i16::MIN.into() && ma <= i16::MAX.into() => "int16", + (mi, ma) if mi >= i32::MIN.into() && ma <= i32::MAX.into() => "int32", + (mi, ma) if mi >= i64::MIN.into() && ma <= i64::MAX.into() => "int64", + _ => "int64", + } } - } - ) - } else { - format!("int64") + ) + } else { + format!("int64") + } } -} -pub fn format_comments(comments: &str) -> Result { - if comments.is_empty() { - Ok("".into()) - } else { - let joined = String::from("# ") + &comments.replace('\n', "\n#") + "\n"; - Ok(joined) + pub fn format_comments(&self, comments: &str) -> Result { + if comments.is_empty() { + Ok("".into()) + } else { + let joined = String::from("# ") + &comments.replace('\n', "\n#") + "\n"; + Ok(joined) + } } -} -pub fn format_constraints( - signed: bool, - constraints: &Vec, -) -> Result { - if constraints.is_empty() { - return Ok("".into()); - } - let per_constraints = per_visible_range_constraints(signed, constraints)?; - let range_type = int_type_token( - per_constraints.min::(), - per_constraints.max::(), - per_constraints.is_extensible(), - ); - let range_suffix = if per_constraints.is_size_constraint() { - "_SIZE" - } else { - "" - }; - // handle default size constraints - if per_constraints.is_size_constraint() - && !per_constraints.is_extensible() - && per_constraints.min::() == Some(0) - && per_constraints.max::().is_none() - { - return Ok("".into()); - } - Ok( - match ( + pub fn format_constraints( + &self, + signed: bool, + constraints: &Vec, + ) -> Result { + if constraints.is_empty() { + return Ok("".into()); + } + let per_constraints = per_visible_range_constraints(signed, constraints)?; + let range_type = self.int_type_token( per_constraints.min::(), per_constraints.max::(), per_constraints.is_extensible(), - ) { - (Some(min), Some(max), true) if min == max => { - format!( - "{range_type} {{prefix}}MIN{range_suffix} = {min}\n\ + ); + let range_suffix = if per_constraints.is_size_constraint() { + "_SIZE" + } else { + "" + }; + // handle default size constraints + if per_constraints.is_size_constraint() + && !per_constraints.is_extensible() + && per_constraints.min::() == Some(0) + && per_constraints.max::().is_none() + { + return Ok("".into()); + } + Ok( + match ( + per_constraints.min::(), + per_constraints.max::(), + per_constraints.is_extensible(), + ) { + (Some(min), Some(max), true) if min == max => { + format!( + "{range_type} {{prefix}}MIN{range_suffix} = {min}\n\ {range_type} {{prefix}}MAX{range_suffix} = {max}" - ) - } - (Some(min), Some(max), true) => { - format!( - "{range_type} {{prefix}}MIN{range_suffix} = {min}\n\ + ) + } + (Some(min), Some(max), true) => { + format!( + "{range_type} {{prefix}}MIN{range_suffix} = {min}\n\ {range_type} {{prefix}}MAX{range_suffix} = {max}" - ) - } - (Some(min), Some(max), false) if min == max => { - format!("{range_type} {{prefix}}{range_suffix} = {min}", range_suffix = range_suffix.replace("_","")) - } - (Some(min), Some(max), false) => { - format!( - "{range_type} {{prefix}}MIN{range_suffix} = {min}\n\ + ) + } + (Some(min), Some(max), false) if min == max => { + format!( + "{range_type} {{prefix}}{range_suffix} = {min}", + range_suffix = range_suffix.replace("_", "") + ) + } + (Some(min), Some(max), false) => { + format!( + "{range_type} {{prefix}}MIN{range_suffix} = {min}\n\ {range_type} {{prefix}}MAX{range_suffix} = {max}" - ) - } - (Some(min), None, true) => { - format!("{range_type} {{prefix}}MIN{range_suffix} = {min}") - } - (Some(min), None, false) => { - format!("{range_type} {{prefix}}MIN{range_suffix} = {min}") - } - (None, Some(max), true) => { - format!("{range_type} {{prefix}}MAX{range_suffix} = {max}") - } - (None, Some(max), false) => { - format!("{range_type} {{prefix}}MAX{range_suffix} = {max}") - } - _ => "".into(), - }, - ) -} + ) + } + (Some(min), None, true) => { + format!("{range_type} {{prefix}}MIN{range_suffix} = {min}") + } + (Some(min), None, false) => { + format!("{range_type} {{prefix}}MIN{range_suffix} = {min}") + } + (None, Some(max), true) => { + format!("{range_type} {{prefix}}MAX{range_suffix} = {max}") + } + (None, Some(max), false) => { + format!("{range_type} {{prefix}}MAX{range_suffix} = {max}") + } + _ => "".into(), + }, + ) + } -pub fn get_distinguished_values(ty: &ASN1Type) -> Option> { - match ty { - ASN1Type::Integer(i) => i.distinguished_values.clone(), - _ => None, + pub fn get_distinguished_values(&self, ty: &ASN1Type) -> Option> { + match ty { + ASN1Type::Integer(i) => i.distinguished_values.clone(), + _ => None, + } + } + + pub fn format_distinguished_values(&self, dvalues: &Option>) -> String { + let mut result = String::from(""); + if let Some(dvalues) = dvalues { + result = dvalues + .iter() + .map(|dvalue| { + format!( + "{{type}} {{prefix}}{} = {}", + to_ros_const_case(&dvalue.name), + dvalue.value + ) + }) + .collect::>() + .join("\n"); + } + result } -} -pub fn format_distinguished_values(dvalues: &Option>) -> String { - let mut result = String::from(""); - if let Some(dvalues) = dvalues { - result = dvalues + pub fn format_enum_members(&self, enumerated: &Enumerated) -> String { + let first_extension_index = enumerated.extensible; + enumerated + .members .iter() - .map(|dvalue| { - format!( - "{{type}} {{prefix}}{} = {}", - to_ros_const_case(&dvalue.name), - dvalue.value - ) + .enumerate() + .map(|(i, e)| { + let name = to_ros_const_case(&e.name); + let index = e.index; + let extension = if i >= first_extension_index.unwrap_or(usize::MAX) { + "# .extended\n".to_string() + } else { + "".to_string() + }; + String::from(&format!("{extension}uint8 {name} = {index}")) + }) + .fold("".to_string(), |mut acc, e| { + acc.push_str(&e); + acc.push_str("\n"); + acc }) - .collect::>() - .join("\n"); } - result -} - -pub fn format_enum_members(enumerated: &Enumerated) -> String { - let first_extension_index = enumerated.extensible; - enumerated - .members - .iter() - .enumerate() - .map(|(i, e)| { - let name = to_ros_const_case(&e.name); - let index = e.index; - let extension = if i >= first_extension_index.unwrap_or(usize::MAX) { - "# .extended\n".to_string() - } else { - "".to_string() - }; - String::from(&format!("{extension}uint8 {name} = {index}")) - }) - .fold("".to_string(), |mut acc, e| { - acc.push_str(&e); - acc.push_str("\n"); - acc - }) -} -pub fn format_sequence_or_set_members( - sequence_or_set: &SequenceOrSet, - parent_name: &String, -) -> Result { - sequence_or_set - .members - .iter() - .try_fold("".to_string(), |mut acc, m| { - format_sequence_member(m, parent_name).map(|declaration| { - acc.push_str(&format!("{declaration}\n\n")); - acc + pub fn format_sequence_or_set_members( + &self, + sequence_or_set: &SequenceOrSet, + parent_name: &String, + ) -> Result { + sequence_or_set + .members + .iter() + .try_fold("".to_string(), |mut acc, m| { + self.format_sequence_member(m, parent_name) + .map(|declaration| { + acc.push_str(&format!("{declaration}\n\n")); + acc + }) }) - }) -} + } -fn format_sequence_member( - member: &SequenceOrSetMember, - parent_name: &String, -) -> Result { - let name = &member.name; - let (mut all_constraints, mut formatted_type_name) = - constraints_and_type_name(&member.ty, &member.name, parent_name)?; - all_constraints.append(&mut member.constraints.clone()); - let formatted_constraints = format_constraints(false, &all_constraints)? - .replace("{prefix}", &(to_ros_const_case(name).to_string() + &"_")); - let distinguished_values = format_distinguished_values(&get_distinguished_values(&member.ty)) - .replace("{prefix}", &(to_ros_const_case(name).to_string() + &"_")) - .replace("{type}", &formatted_type_name); - let name = to_ros_snake_case(name); - if (member.is_optional && member.default_value.is_none()) - || member.name.starts_with("ext_group_") - { - formatted_type_name = format!( - "{formatted_type_name} {name}\n\ + fn format_sequence_member( + &self, + member: &SequenceOrSetMember, + parent_name: &String, + ) -> Result { + let name = &member.name; + let (mut all_constraints, mut formatted_type_name) = + self.constraints_and_type_name(&member.ty, &member.name, parent_name)?; + all_constraints.append(&mut member.constraints.clone()); + let formatted_constraints = self + .format_constraints(false, &all_constraints)? + .replace("{prefix}", &(to_ros_const_case(name).to_string() + &"_")); + let distinguished_values = self + .format_distinguished_values(&self.get_distinguished_values(&member.ty)) + .replace("{prefix}", &(to_ros_const_case(name).to_string() + &"_")) + .replace("{type}", &formatted_type_name); + let name = to_ros_snake_case(name); + if (member.is_optional && member.default_value.is_none()) + || member.name.starts_with("ext_group_") + { + formatted_type_name = format!( + "{formatted_type_name} {name}\n\ bool {name}_is_present" - ) - } else { - formatted_type_name = format!("{formatted_type_name} {name}") - } + ) + } else { + formatted_type_name = format!("{formatted_type_name} {name}") + } - Ok( - vec![ - formatted_type_name, - formatted_constraints, - distinguished_values + Ok(vec![ + formatted_type_name, + formatted_constraints, + distinguished_values, ] .into_iter() .filter(|s| !s.is_empty()) .collect::>() - .join("\n") - ) -} + .join("\n")) + } -pub fn format_choice_options( - choice: &Choice, - parent_name: &String, -) -> Result { - let options = choice - .options - .iter() - .enumerate() - .map(|(i, o)| { - format_choice_option(o, parent_name, i) - }) - .collect::, _>>()?; - let folded_options = options.iter().fold( - "".to_string(), - |mut acc, option| { + pub fn format_choice_options( + &self, + choice: &Choice, + parent_name: &String, + ) -> Result { + let options = choice + .options + .iter() + .enumerate() + .map(|(i, o)| self.format_choice_option(o, parent_name, i)) + .collect::, _>>()?; + let folded_options = options.iter().fold("".to_string(), |mut acc, option| { acc.push_str(&format!("{option}\n\n")); acc - }, - ); - Ok(folded_options) -} + }); + Ok(folded_options) + } -fn format_choice_option( - member: &ChoiceOption, - parent_name: &String, - index: usize, -) -> Result { - let (_, formatted_type_name) = - constraints_and_type_name(&member.ty, &member.name, parent_name)?; - let option = format!("{formatted_type_name} {}\n\ + fn format_choice_option( + &self, + member: &ChoiceOption, + parent_name: &String, + index: usize, + ) -> Result { + let (_, formatted_type_name) = + self.constraints_and_type_name(&member.ty, &member.name, parent_name)?; + let option = format!( + "{formatted_type_name} {}\n\ uint8 CHOICE_{} = {index}", - to_ros_snake_case(&member.name), - to_ros_const_case(&member.name) - ); - Ok(option) -} + to_ros_snake_case(&member.name), + to_ros_const_case(&member.name) + ); + Ok(option) + } -fn constraints_and_type_name( - ty: &ASN1Type, - name: &String, - parent_name: &String, -) -> Result<(Vec, String), GeneratorError> { - Ok(match ty { - ASN1Type::Null => (vec![], "byte".into()), - ASN1Type::Boolean(b) => (b.constraints.clone(), "bool".into()), - ASN1Type::Integer(i) => { - let per_constraints = per_visible_range_constraints(true, &i.constraints)?; - ( - i.constraints.clone(), - int_type_token( - per_constraints.min(), - per_constraints.max(), - per_constraints.is_extensible(), - ), - ) - } - ASN1Type::Real(_) => (vec![], "float64".into()), - ASN1Type::ObjectIdentifier(_o) => todo!(), - ASN1Type::BitString(_b) => todo!(), - ASN1Type::OctetString(o) => (o.constraints.clone(), "uint8[]".into()), - ASN1Type::GeneralizedTime(_o) => todo!(), - ASN1Type::UTCTime(_o) => todo!(), - ASN1Type::Time(_t) => todo!(), - ASN1Type::CharacterString(c) => (c.constraints.clone(), "string".into()), - ASN1Type::Enumerated(_) - | ASN1Type::Choice(_) - | ASN1Type::Sequence(_) - | ASN1Type::SetOf(_) - | ASN1Type::Set(_) => (vec![], inner_name(name, parent_name)), - ASN1Type::SequenceOf(s) => { - let (_, inner_type) = constraints_and_type_name(&s.element_type, name, parent_name)?; - (s.constraints().clone(), format!("{inner_type}[]").into()) - } - ASN1Type::ElsewhereDeclaredType(e) => { - (e.constraints.clone(), to_ros_title_case(&e.identifier)) - } - ASN1Type::InformationObjectFieldReference(_) - | ASN1Type::EmbeddedPdv - | ASN1Type::External => { - let tx = &ty.constraints().unwrap()[0]; - let rname = if let Constraint::TableConstraint(ref tc) = tx { - let v = &tc.object_set.values[0]; - if let ObjectSetValue::Reference(ref r) = v { - r.clone() + fn constraints_and_type_name( + &self, + ty: &ASN1Type, + name: &String, + parent_name: &String, + ) -> Result<(Vec, String), GeneratorError> { + Ok(match ty { + ASN1Type::Null => (vec![], "byte".into()), + ASN1Type::Boolean(b) => (b.constraints.clone(), "bool".into()), + ASN1Type::Integer(i) => { + let per_constraints = per_visible_range_constraints(true, &i.constraints)?; + ( + i.constraints.clone(), + self.int_type_token( + per_constraints.min(), + per_constraints.max(), + per_constraints.is_extensible(), + ), + ) + } + ASN1Type::Real(_) => (vec![], "float64".into()), + ASN1Type::ObjectIdentifier(_o) => todo!(), + ASN1Type::BitString(_b) => todo!(), + ASN1Type::OctetString(o) => (o.constraints.clone(), "uint8[]".into()), + ASN1Type::GeneralizedTime(_o) => todo!(), + ASN1Type::UTCTime(_o) => todo!(), + ASN1Type::Time(_t) => todo!(), + ASN1Type::CharacterString(c) => (c.constraints.clone(), "string".into()), + ASN1Type::Enumerated(_) + | ASN1Type::Choice(_) + | ASN1Type::Sequence(_) + | ASN1Type::SetOf(_) + | ASN1Type::Set(_) => (vec![], self.inner_name(name, parent_name)), + ASN1Type::SequenceOf(s) => { + let (_, inner_type) = + self.constraints_and_type_name(&s.element_type, name, parent_name)?; + (s.constraints().clone(), format!("{inner_type}[]").into()) + } + ASN1Type::ElsewhereDeclaredType(e) => { + (e.constraints.clone(), to_ros_title_case(&e.identifier)) + } + ASN1Type::InformationObjectFieldReference(_) + | ASN1Type::EmbeddedPdv + | ASN1Type::External => { + let tx = &ty.constraints().unwrap()[0]; + let rname = if let Constraint::TableConstraint(ref tc) = tx { + let v = &tc.object_set.values[0]; + if let ObjectSetValue::Reference(ref r) = v { + r.clone() + } else { + "".to_string() + } } else { "".to_string() - } - } else { - "".to_string() - }; - (vec![], rname) - } - ASN1Type::ChoiceSelectionType(_) => unreachable!(), - }) -} - -pub fn string_type(c_type: &CharacterStringType) -> Result { - match c_type { - CharacterStringType::NumericString => Ok("NumericString".into()), - CharacterStringType::VisibleString => Ok("VisibleString".into()), - CharacterStringType::IA5String => Ok("Ia5String".into()), - CharacterStringType::TeletexString => Ok("TeletexString".into()), - CharacterStringType::VideotexString => Ok("VideotexString".into()), - CharacterStringType::GraphicString => Ok("GraphicString".into()), - CharacterStringType::GeneralString => Ok("GeneralString".into()), - CharacterStringType::UniversalString => Ok("UniversalString".into()), - CharacterStringType::UTF8String => Ok("Utf8String".into()), - CharacterStringType::BMPString => Ok("BmpString".into()), - CharacterStringType::PrintableString => Ok("PrintableString".into()), + }; + (vec![], rname) + } + ASN1Type::ChoiceSelectionType(_) => unreachable!(), + }) } -} -pub fn format_default_methods( - members: &Vec, - _parent_name: &str, -) -> Result { - let mut output = "".to_string(); - for member in members { - if let Some(value) = member.default_value.as_ref() { - let val = match value { - ASN1Value::EnumeratedValue { .. } => continue, /* TODO */ - _ => value_to_tokens(value, Some(&type_to_tokens(&member.ty)?.to_string()))?, - }; - // TODO generalize - let ty = match value { - ASN1Value::LinkedNestedValue { - supertypes: _, - value, - } => match value.as_ref() { - ASN1Value::LinkedIntValue { - integer_type, - value: _, - } => integer_type.to_str().to_string(), - _ => type_to_tokens(&member.ty)?, - }, - ASN1Value::EnumeratedValue { .. } => "uint8".into(), - _ => type_to_tokens(&member.ty)?, - }; - let method_name = format!("{}_DEFAULT", to_ros_const_case(&member.name)); - output.push_str(&format!("{ty} {method_name} = {val}\n")); + pub fn string_type(&self, c_type: &CharacterStringType) -> Result { + match c_type { + CharacterStringType::NumericString => Ok("NumericString".into()), + CharacterStringType::VisibleString => Ok("VisibleString".into()), + CharacterStringType::IA5String => Ok("Ia5String".into()), + CharacterStringType::TeletexString => Ok("TeletexString".into()), + CharacterStringType::VideotexString => Ok("VideotexString".into()), + CharacterStringType::GraphicString => Ok("GraphicString".into()), + CharacterStringType::GeneralString => Ok("GeneralString".into()), + CharacterStringType::UniversalString => Ok("UniversalString".into()), + CharacterStringType::UTF8String => Ok("Utf8String".into()), + CharacterStringType::BMPString => Ok("BmpString".into()), + CharacterStringType::PrintableString => Ok("PrintableString".into()), } } - Ok(output) -} -pub fn type_to_tokens(ty: &ASN1Type) -> Result { - match ty { - ASN1Type::Null => todo!(), - ASN1Type::Boolean(_) => Ok("bool".into()), - ASN1Type::Integer(i) => Ok(i.int_type().to_str().to_string()), - ASN1Type::Real(_) => Ok("float64".into()), - ASN1Type::BitString(_) => Ok("BitString".into()), - ASN1Type::OctetString(_) => Ok("OctetString".into()), - ASN1Type::CharacterString(CharacterString { ty, .. }) => string_type(ty), - ASN1Type::Enumerated(_) => Err(error!( - NotYetInplemented, - "Enumerated values are currently unsupported!" - )), - ASN1Type::Choice(_) => Err(error!( - NotYetInplemented, - "Choice values are currently unsupported!" - )), - ASN1Type::Sequence(_) => Err(error!( - NotYetInplemented, - "Sequence values are currently unsupported!" - )), - ASN1Type::SetOf(so) | ASN1Type::SequenceOf(so) => { - let _inner = type_to_tokens(&so.element_type)?; - Ok("SequenceOf".into()) - } - ASN1Type::ObjectIdentifier(_) => Err(error!( - NotYetInplemented, - "Object Identifier values are currently unsupported!" - )), - ASN1Type::Set(_) => Err(error!( - NotYetInplemented, - "Set values are currently unsupported!" - )), - ASN1Type::ElsewhereDeclaredType(e) => Ok(e.identifier.clone()), - ASN1Type::InformationObjectFieldReference(_) => Err(error!( - NotYetInplemented, - "Information Object field reference values are currently unsupported!" - )), - ASN1Type::Time(_) => Err(error!( - NotYetInplemented, - "Time values are currently unsupported!" - )), - ASN1Type::GeneralizedTime(_) => Ok("GeneralizedTime".into()), - ASN1Type::UTCTime(_) => Ok("UtcTime".into()), - ASN1Type::EmbeddedPdv | ASN1Type::External => Ok("Any".into()), - ASN1Type::ChoiceSelectionType(_) => { - todo!() + pub fn format_default_methods( + &self, + members: &Vec, + _parent_name: &str, + ) -> Result { + let mut output = "".to_string(); + for member in members { + if let Some(value) = member.default_value.as_ref() { + let val = match value { + ASN1Value::EnumeratedValue { .. } => continue, /* TODO */ + _ => self.value_to_tokens( + value, + Some(&self.type_to_tokens(&member.ty)?.to_string()), + )?, + }; + // TODO generalize + let ty = match value { + ASN1Value::LinkedNestedValue { + supertypes: _, + value, + } => match value.as_ref() { + ASN1Value::LinkedIntValue { + integer_type, + value: _, + } => integer_type.to_str().to_string(), + _ => self.type_to_tokens(&member.ty)?, + }, + ASN1Value::EnumeratedValue { .. } => "uint8".into(), + _ => self.type_to_tokens(&member.ty)?, + }; + let method_name = format!("{}_DEFAULT", to_ros_const_case(&member.name)); + output.push_str(&format!("{ty} {method_name} = {val}\n")); + } } + Ok(output) } -} -pub fn value_to_tokens( - value: &ASN1Value, - type_name: Option<&String>, -) -> Result { - match value { - ASN1Value::All => Err(error!( - NotYetInplemented, - "All values are currently unsupported!" - )), - ASN1Value::Null => todo!(), - ASN1Value::Choice { inner_value, .. } => { - if let Some(_) = type_name { - todo!() - } else { - Err(error!( - Unidentified, - "A type name is needed to stringify choice value {:?}", inner_value - )) + pub fn type_to_tokens(&self, ty: &ASN1Type) -> Result { + match ty { + ASN1Type::Null => todo!(), + ASN1Type::Boolean(_) => Ok("bool".into()), + ASN1Type::Integer(i) => Ok(i.int_type().to_str().to_string()), + ASN1Type::Real(_) => Ok("float64".into()), + ASN1Type::BitString(_) => Ok("BitString".into()), + ASN1Type::OctetString(_) => Ok("OctetString".into()), + ASN1Type::CharacterString(CharacterString { ty, .. }) => self.string_type(ty), + ASN1Type::Enumerated(_) => Err(error!( + NotYetInplemented, + "Enumerated values are currently unsupported!" + )), + ASN1Type::Choice(_) => Err(error!( + NotYetInplemented, + "Choice values are currently unsupported!" + )), + ASN1Type::Sequence(_) => Err(error!( + NotYetInplemented, + "Sequence values are currently unsupported!" + )), + ASN1Type::SetOf(so) | ASN1Type::SequenceOf(so) => { + let _inner = self.type_to_tokens(&so.element_type)?; + Ok("SequenceOf".into()) } - } - ASN1Value::OctetString(o) => { - let _bytes = o.iter().map(|byte| *byte); - todo!() - } - ASN1Value::SequenceOrSet(_) => Err(error!( - Unidentified, - "Unexpectedly encountered unlinked struct-like ASN1 value!" - )), - ASN1Value::LinkedStructLikeValue(fields) => { - if let Some(_ty_n) = type_name { - let _tokenized_fields = fields - .iter() - .map(|(_, _, val)| value_to_tokens(val.value(), None)) - .collect::, _>>()?; + ASN1Type::ObjectIdentifier(_) => Err(error!( + NotYetInplemented, + "Object Identifier values are currently unsupported!" + )), + ASN1Type::Set(_) => Err(error!( + NotYetInplemented, + "Set values are currently unsupported!" + )), + ASN1Type::ElsewhereDeclaredType(e) => Ok(e.identifier.clone()), + ASN1Type::InformationObjectFieldReference(_) => Err(error!( + NotYetInplemented, + "Information Object field reference values are currently unsupported!" + )), + ASN1Type::Time(_) => Err(error!( + NotYetInplemented, + "Time values are currently unsupported!" + )), + ASN1Type::GeneralizedTime(_) => Ok("GeneralizedTime".into()), + ASN1Type::UTCTime(_) => Ok("UtcTime".into()), + ASN1Type::EmbeddedPdv | ASN1Type::External => Ok("Any".into()), + ASN1Type::ChoiceSelectionType(_) => { todo!() - } else { - Err(error!( - Unidentified, - "A type name is needed to stringify sequence value {:?}", value - )) - } - } - ASN1Value::Boolean(b) => Ok(b.to_string()), - ASN1Value::Integer(i) => Ok(i.to_string()), - ASN1Value::String(s) => Ok(s.to_string()), - ASN1Value::Real(r) => Ok(r.to_string()), - ASN1Value::BitString(b) => { - let _bits = b.iter().map(|bit| bit.to_string()); - todo!() - } - ASN1Value::EnumeratedValue { - enumerated, - enumerable, - } => Ok(format!("{}_{}", enumerated, enumerable)), - ASN1Value::LinkedElsewhereDefinedValue { identifier: e, .. } - | ASN1Value::ElsewhereDeclaredValue { identifier: e, .. } => Ok(e.to_string()), - ASN1Value::ObjectIdentifier(oid) => { - let _arcs = oid - .0 - .iter() - .filter_map(|arc| arc.number.map(|id| id.to_string())); - todo!() - } - ASN1Value::Time(_t) => match type_name { - Some(_time_type) => todo!(), - None => todo!(), - }, - ASN1Value::LinkedArrayLikeValue(seq) => { - let _elems = seq - .iter() - .map(|v| value_to_tokens(v, None)) - .collect::, _>>()?; - todo!() - } - ASN1Value::LinkedNestedValue { - supertypes: _, - value, - } => Ok(value_to_tokens(value, type_name)?), - ASN1Value::LinkedIntValue { - integer_type, - value, - } => { - let val = *value; - match integer_type { - IntegerType::Unbounded => Ok(val.to_string()), - _ => Ok(val.to_string()), } } - ASN1Value::LinkedCharStringValue(string_type, value) => { - let _val = value; - match string_type { - CharacterStringType::NumericString => { - todo!() - } - CharacterStringType::VisibleString => { - todo!() - } - CharacterStringType::IA5String => { + } + + pub fn value_to_tokens( + &self, + value: &ASN1Value, + type_name: Option<&String>, + ) -> Result { + match value { + ASN1Value::All => Err(error!( + NotYetInplemented, + "All values are currently unsupported!" + )), + ASN1Value::Null => todo!(), + ASN1Value::Choice { inner_value, .. } => { + if let Some(_) = type_name { todo!() + } else { + Err(error!( + Unidentified, + "A type name is needed to stringify choice value {:?}", inner_value + )) } - CharacterStringType::UTF8String => todo!(), - CharacterStringType::BMPString => { + } + ASN1Value::OctetString(o) => { + let _bytes = o.iter().map(|byte| *byte); + todo!() + } + ASN1Value::SequenceOrSet(_) => Err(error!( + Unidentified, + "Unexpectedly encountered unlinked struct-like ASN1 value!" + )), + ASN1Value::LinkedStructLikeValue(fields) => { + if let Some(_ty_n) = type_name { + let _tokenized_fields = fields + .iter() + .map(|(_, _, val)| self.value_to_tokens(val.value(), None)) + .collect::, _>>()?; todo!() + } else { + Err(error!( + Unidentified, + "A type name is needed to stringify sequence value {:?}", value + )) } - CharacterStringType::PrintableString => { - todo!() + } + ASN1Value::Boolean(b) => Ok(b.to_string()), + ASN1Value::Integer(i) => Ok(i.to_string()), + ASN1Value::String(s) => Ok(s.to_string()), + ASN1Value::Real(r) => Ok(r.to_string()), + ASN1Value::BitString(b) => { + let _bits = b.iter().map(|bit| bit.to_string()); + todo!() + } + ASN1Value::EnumeratedValue { + enumerated, + enumerable, + } => Ok(format!("{}_{}", enumerated, enumerable)), + ASN1Value::LinkedElsewhereDefinedValue { identifier: e, .. } + | ASN1Value::ElsewhereDeclaredValue { identifier: e, .. } => Ok(e.to_string()), + ASN1Value::ObjectIdentifier(oid) => { + let _arcs = oid + .0 + .iter() + .filter_map(|arc| arc.number.map(|id| id.to_string())); + todo!() + } + ASN1Value::Time(_t) => match type_name { + Some(_time_type) => todo!(), + None => todo!(), + }, + ASN1Value::LinkedArrayLikeValue(seq) => { + let _elems = seq + .iter() + .map(|v| self.value_to_tokens(v, None)) + .collect::, _>>()?; + todo!() + } + ASN1Value::LinkedNestedValue { + supertypes: _, + value, + } => Ok(self.value_to_tokens(value, type_name)?), + ASN1Value::LinkedIntValue { + integer_type, + value, + } => { + let val = *value; + match integer_type { + IntegerType::Unbounded => Ok(val.to_string()), + _ => Ok(val.to_string()), } - CharacterStringType::GeneralString => { - todo!() + } + ASN1Value::LinkedCharStringValue(string_type, value) => { + let _val = value; + match string_type { + CharacterStringType::NumericString => { + todo!() + } + CharacterStringType::VisibleString => { + todo!() + } + CharacterStringType::IA5String => { + todo!() + } + CharacterStringType::UTF8String => todo!(), + CharacterStringType::BMPString => { + todo!() + } + CharacterStringType::PrintableString => { + todo!() + } + CharacterStringType::GeneralString => { + todo!() + } + CharacterStringType::VideotexString + | CharacterStringType::GraphicString + | CharacterStringType::UniversalString + | CharacterStringType::TeletexString => Err(GeneratorError::new( + None, + &format!("{:?} values are currently unsupported!", string_type), + GeneratorErrorType::NotYetInplemented, + )), } - CharacterStringType::VideotexString - | CharacterStringType::GraphicString - | CharacterStringType::UniversalString - | CharacterStringType::TeletexString => Err(GeneratorError::new( - None, - &format!("{:?} values are currently unsupported!", string_type), - GeneratorErrorType::NotYetInplemented, - )), } } } -} - -pub fn format_nested_sequence_members( - sequence_or_set: &SequenceOrSet, - parent_name: &String, -) -> Result, GeneratorError> { - sequence_or_set - .members - .iter() - .filter(|m| needs_unnesting(&m.ty)) - .map(|m| { - generate(ToplevelDefinition::Type(ToplevelTypeDefinition { - parameterization: None, - comments: " Inner type ".into(), - name: inner_name(&m.name, parent_name).to_string(), - ty: m.ty.clone(), - tag: None, - index: None, - })) - }) - .collect::, _>>() -} -fn needs_unnesting(ty: &ASN1Type) -> bool { - match ty { - ASN1Type::Enumerated(_) - | ASN1Type::Choice(_) - | ASN1Type::Sequence(_) - | ASN1Type::Set(_) => true, - ASN1Type::SequenceOf(SequenceOrSetOf { element_type, .. }) - | ASN1Type::SetOf(SequenceOrSetOf { element_type, .. }) => needs_unnesting(element_type), - _ => false, + pub fn format_nested_sequence_members( + &self, + sequence_or_set: &SequenceOrSet, + parent_name: &String, + ) -> Result, GeneratorError> { + sequence_or_set + .members + .iter() + .filter(|m| self.needs_unnesting(&m.ty)) + .map(|m| { + self.generate_tld(ToplevelDefinition::Type(ToplevelTypeDefinition { + parameterization: None, + comments: " Inner type ".into(), + name: self.inner_name(&m.name, parent_name).to_string(), + ty: m.ty.clone(), + tag: None, + index: None, + })) + }) + .collect::, _>>() } -} -pub fn format_nested_choice_options( - choice: &Choice, - parent_name: &String, -) -> Result, GeneratorError> { - choice - .options - .iter() - .filter(|m| { - matches!( - m.ty, - ASN1Type::Enumerated(_) - | ASN1Type::Choice(_) - | ASN1Type::Sequence(_) - | ASN1Type::SequenceOf(_) - | ASN1Type::Set(_) - ) - }) - .map(|m| { - generate(ToplevelDefinition::Type(ToplevelTypeDefinition { - parameterization: None, - comments: " Inner type ".into(), - name: inner_name(&m.name, parent_name).to_string(), - ty: m.ty.clone(), - tag: None, - index: None, - })) - }) - .collect::, _>>() -} - -pub fn _format_sequence_or_set_of_item_type( - type_name: String, - first_item: Option<&ASN1Value>, -) -> String { - match type_name { - name if name == NULL => todo!(), - name if name == BOOLEAN => "bool".into(), - name if name == INTEGER => { - match first_item { - Some(ASN1Value::LinkedIntValue { integer_type, .. }) => { - integer_type.to_str().into() - } - _ => "int64".into(), // best effort + fn needs_unnesting(&self, ty: &ASN1Type) -> bool { + match ty { + ASN1Type::Enumerated(_) + | ASN1Type::Choice(_) + | ASN1Type::Sequence(_) + | ASN1Type::Set(_) => true, + ASN1Type::SequenceOf(SequenceOrSetOf { element_type, .. }) + | ASN1Type::SetOf(SequenceOrSetOf { element_type, .. }) => { + self.needs_unnesting(element_type) } + _ => false, } - name if name == BIT_STRING => "BitString".into(), - name if name == OCTET_STRING => "OctetString".into(), - name if name == GENERALIZED_TIME => "GeneralizedTime".into(), - name if name == UTC_TIME => "UtcTime".into(), - name if name == OBJECT_IDENTIFIER => "ObjectIdentifier".into(), - name if name == NUMERIC_STRING => "NumericString".into(), - name if name == VISIBLE_STRING => "VisibleString".into(), - name if name == IA5_STRING => "IA5String".into(), - name if name == UTF8_STRING => "UTF8String".into(), - name if name == BMP_STRING => "BMPString".into(), - name if name == PRINTABLE_STRING => "PrintableString".into(), - name if name == GENERAL_STRING => "GeneralString".into(), - name => name, } -} -/// Resolves the custom syntax declared in an information object class' WITH SYNTAX clause -pub fn resolve_standard_syntax( - class: &InformationObjectClass, - application: &[InformationObjectField], -) -> Result<(ASN1Value, Vec<(usize, ASN1Type)>), GeneratorError> { - let mut key = None; - let mut field_index_map = Vec::<(usize, ASN1Type)>::new(); + pub fn format_nested_choice_options( + &self, + choice: &Choice, + parent_name: &String, + ) -> Result, GeneratorError> { + choice + .options + .iter() + .filter(|m| { + matches!( + m.ty, + ASN1Type::Enumerated(_) + | ASN1Type::Choice(_) + | ASN1Type::Sequence(_) + | ASN1Type::SequenceOf(_) + | ASN1Type::Set(_) + ) + }) + .map(|m| { + self.generate_tld(ToplevelDefinition::Type(ToplevelTypeDefinition { + parameterization: None, + comments: " Inner type ".into(), + name: self.inner_name(&m.name, parent_name).to_string(), + ty: m.ty.clone(), + tag: None, + index: None, + })) + }) + .collect::, _>>() + } + + /// Resolves the custom syntax declared in an information object class' WITH SYNTAX clause + pub fn resolve_standard_syntax( + &self, + class: &InformationObjectClass, + application: &[InformationObjectField], + ) -> Result<(ASN1Value, Vec<(usize, ASN1Type)>), GeneratorError> { + let mut key = None; + let mut field_index_map = Vec::<(usize, ASN1Type)>::new(); - let key_index = class - .fields - .iter() - .enumerate() - .find_map(|(i, f)| f.is_unique.then_some(i)) - .ok_or_else(|| GeneratorError { - details: format!("Could not find key for class {class:?}"), - kind: GeneratorErrorType::MissingClassKey, - ..Default::default() - })?; + let key_index = class + .fields + .iter() + .enumerate() + .find_map(|(i, f)| f.is_unique.then_some(i)) + .ok_or_else(|| GeneratorError { + details: format!("Could not find key for class {class:?}"), + kind: GeneratorErrorType::MissingClassKey, + ..Default::default() + })?; - let mut appl_iter = application.iter().enumerate(); - 'syntax_matching: for class_field in &class.fields { - if let Some((index, field)) = appl_iter.next() { - if class_field.identifier.identifier() == field.identifier() { - match field { - InformationObjectField::TypeField(f) => { - field_index_map.push((index, f.ty.clone())); - } - InformationObjectField::FixedValueField(f) => { - if index == key_index { - key = Some(f.value.clone()); + let mut appl_iter = application.iter().enumerate(); + 'syntax_matching: for class_field in &class.fields { + if let Some((index, field)) = appl_iter.next() { + if class_field.identifier.identifier() == field.identifier() { + match field { + InformationObjectField::TypeField(f) => { + field_index_map.push((index, f.ty.clone())); } + InformationObjectField::FixedValueField(f) => { + if index == key_index { + key = Some(f.value.clone()); + } + } + InformationObjectField::ObjectSetField(_) => todo!(), } - InformationObjectField::ObjectSetField(_) => todo!(), + } else if !class_field.is_optional { + return Err(GeneratorError { + top_level_declaration: None, + details: "Syntax mismatch while resolving information object.".to_string(), + kind: GeneratorErrorType::SyntaxMismatch, + }); + } else { + continue 'syntax_matching; } - } else if !class_field.is_optional { - return Err(GeneratorError { - top_level_declaration: None, - details: "Syntax mismatch while resolving information object.".to_string(), - kind: GeneratorErrorType::SyntaxMismatch, - }); - } else { - continue 'syntax_matching; } } - } - field_index_map.sort_by(|&(a, _), &(b, _)| a.cmp(&b)); - let types = field_index_map.into_iter().collect(); - match key { - Some(k) => Ok((k, types)), - None => Err(GeneratorError { - top_level_declaration: None, - details: "Could not find class key!".into(), - kind: GeneratorErrorType::MissingClassKey, - }), + field_index_map.sort_by(|&(a, _), &(b, _)| a.cmp(&b)); + let types = field_index_map.into_iter().collect(); + match key { + Some(k) => Ok((k, types)), + None => Err(GeneratorError { + top_level_declaration: None, + details: "Could not find class key!".into(), + kind: GeneratorErrorType::MissingClassKey, + }), + } } } From ae43ca6f848f99939221d837c1ab9b11d3a16978 Mon Sep 17 00:00:00 2001 From: v0-e Date: Tue, 16 Jul 2024 08:04:55 +0100 Subject: [PATCH 2/3] Trigger GH CI on PRs Co-authored-by: Lennart Reiher --- .github/workflows/codegen.yml | 8 +++++++- .github/workflows/doc.yml | 10 ++++++++-- .github/workflows/docker-ros.yml | 10 ++++++++-- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/.github/workflows/codegen.yml b/.github/workflows/codegen.yml index 88dc0b2d3..b5c882756 100644 --- a/.github/workflows/codegen.yml +++ b/.github/workflows/codegen.yml @@ -1,6 +1,12 @@ name: Code Generation -on: push +on: + push: + branches: + - main + pull_request: + branches: + - main jobs: diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml index bd1b8a124..b6f9a9cea 100644 --- a/.github/workflows/doc.yml +++ b/.github/workflows/doc.yml @@ -1,6 +1,12 @@ name: Documentation -on: push +on: + push: + branches: + - main + pull_request: + branches: + - main jobs: build: @@ -20,4 +26,4 @@ jobs: if: github.ref == 'refs/heads/main' with: github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: doc/html \ No newline at end of file + publish_dir: doc/html diff --git a/.github/workflows/docker-ros.yml b/.github/workflows/docker-ros.yml index 2b6a04864..cd7381d54 100644 --- a/.github/workflows/docker-ros.yml +++ b/.github/workflows/docker-ros.yml @@ -1,6 +1,12 @@ name: docker-ros -on: push +on: + push: + branches: + - main + pull_request: + branches: + - main jobs: @@ -56,4 +62,4 @@ jobs: command: ros2 launch etsi_its_conversion converter.launch.py enable-industrial-ci: 'true' enable-push-as-latest: 'true' - enable-recursive-vcs-import: 'false' \ No newline at end of file + enable-recursive-vcs-import: 'false' From 783b79bdff01916c66639453e3ed3f02a16b75b1 Mon Sep 17 00:00:00 2001 From: v0-e Date: Wed, 31 Jul 2024 16:35:41 +0100 Subject: [PATCH 3/3] Revert "Trigger GH CI on PRs" This reverts commit ae43ca6f848f99939221d837c1ab9b11d3a16978. --- .github/workflows/codegen.yml | 8 +------- .github/workflows/doc.yml | 10 ++-------- .github/workflows/docker-ros.yml | 10 ++-------- 3 files changed, 5 insertions(+), 23 deletions(-) diff --git a/.github/workflows/codegen.yml b/.github/workflows/codegen.yml index b5c882756..88dc0b2d3 100644 --- a/.github/workflows/codegen.yml +++ b/.github/workflows/codegen.yml @@ -1,12 +1,6 @@ name: Code Generation -on: - push: - branches: - - main - pull_request: - branches: - - main +on: push jobs: diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml index b6f9a9cea..bd1b8a124 100644 --- a/.github/workflows/doc.yml +++ b/.github/workflows/doc.yml @@ -1,12 +1,6 @@ name: Documentation -on: - push: - branches: - - main - pull_request: - branches: - - main +on: push jobs: build: @@ -26,4 +20,4 @@ jobs: if: github.ref == 'refs/heads/main' with: github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: doc/html + publish_dir: doc/html \ No newline at end of file diff --git a/.github/workflows/docker-ros.yml b/.github/workflows/docker-ros.yml index cd7381d54..2b6a04864 100644 --- a/.github/workflows/docker-ros.yml +++ b/.github/workflows/docker-ros.yml @@ -1,12 +1,6 @@ name: docker-ros -on: - push: - branches: - - main - pull_request: - branches: - - main +on: push jobs: @@ -62,4 +56,4 @@ jobs: command: ros2 launch etsi_its_conversion converter.launch.py enable-industrial-ci: 'true' enable-push-as-latest: 'true' - enable-recursive-vcs-import: 'false' + enable-recursive-vcs-import: 'false' \ No newline at end of file