1use crate::ast::*;
4use std::collections::{HashMap, HashSet};
5use std::fmt::Write;
6
7#[derive(Debug, Clone, Default, PartialEq, Eq)]
37pub enum StringTypeMode {
38 #[default]
41 Owned,
42 Borrowed,
46}
47
48#[derive(Debug, Clone, Default, PartialEq, Eq)]
59pub enum DeriveMode {
60 #[default]
67 FeatureGated,
68 Always,
73 Custom(String),
79}
80
81#[derive(Debug, Clone, Default)]
83pub struct CodeGenConfig {
84 pub module_path_prefix: Option<String>,
87 pub use_core: bool,
90 pub skip_imported_types: std::collections::HashSet<String>,
93 pub imported_type_lifetimes: std::collections::HashMap<String, String>,
97 pub string_type_mode: StringTypeMode,
102 pub any_as_raw_der: bool,
113 pub derive_mode: DeriveMode,
121 pub raw_der_fields: std::collections::HashSet<String>,
134}
135
136impl CodeGenConfig {
137 pub fn with_lifetime(
139 mut self,
140 type_name: impl Into<String>,
141 lifetime: impl Into<String>,
142 ) -> Self {
143 self.imported_type_lifetimes
144 .insert(type_name.into(), lifetime.into());
145 self
146 }
147
148 pub fn with_x509_lifetimes(mut self) -> Self {
152 let skip_types = vec![
154 "AlgorithmIdentifier",
155 "SubjectPublicKeyInfo",
156 "TBSCertificate",
157 "Certificate",
158 "Validity", ];
160
161 let types_with_lifetimes = vec![
163 "AlgorithmIdentifier",
164 "SubjectPublicKeyInfo",
165 "TBSCertificate",
166 "Certificate",
167 ];
170
171 for type_name in skip_types {
172 self.skip_imported_types.insert(type_name.to_string());
173 }
174
175 for type_name in types_with_lifetimes {
176 self.imported_type_lifetimes
177 .insert(type_name.to_string(), "'a".to_string());
178 }
179
180 self
181 }
182}
183
184impl CodeGenConfig {
185 pub fn with_crate_imports() -> Self {
187 Self {
188 module_path_prefix: Some("crate".to_string()),
189 use_core: false,
190 skip_imported_types: std::collections::HashSet::new(),
191 imported_type_lifetimes: std::collections::HashMap::new(),
192 string_type_mode: StringTypeMode::Owned,
193 any_as_raw_der: false,
194 derive_mode: DeriveMode::default(),
195 raw_der_fields: std::collections::HashSet::new(),
196 }
197 }
198
199 pub fn with_super_imports() -> Self {
201 Self {
202 module_path_prefix: Some("super".to_string()),
203 use_core: false,
204 skip_imported_types: std::collections::HashSet::new(),
205 imported_type_lifetimes: std::collections::HashMap::new(),
206 string_type_mode: StringTypeMode::Owned,
207 any_as_raw_der: false,
208 derive_mode: DeriveMode::default(),
209 raw_der_fields: std::collections::HashSet::new(),
210 }
211 }
212
213 pub fn with_custom_prefix(prefix: impl Into<String>) -> Self {
215 Self {
216 module_path_prefix: Some(prefix.into()),
217 use_core: false,
218 skip_imported_types: std::collections::HashSet::new(),
219 imported_type_lifetimes: std::collections::HashMap::new(),
220 string_type_mode: StringTypeMode::Owned,
221 any_as_raw_der: false,
222 derive_mode: DeriveMode::default(),
223 raw_der_fields: std::collections::HashSet::new(),
224 }
225 }
226}
227
228fn is_rust_keyword(s: &str) -> bool {
230 matches!(
231 s,
232 "as" | "break"
233 | "const"
234 | "continue"
235 | "crate"
236 | "else"
237 | "enum"
238 | "extern"
239 | "false"
240 | "fn"
241 | "for"
242 | "if"
243 | "impl"
244 | "in"
245 | "let"
246 | "loop"
247 | "match"
248 | "mod"
249 | "move"
250 | "mut"
251 | "pub"
252 | "ref"
253 | "return"
254 | "self"
255 | "Self"
256 | "static"
257 | "struct"
258 | "super"
259 | "trait"
260 | "true"
261 | "type"
262 | "unsafe"
263 | "use"
264 | "where"
265 | "while"
266 | "async"
267 | "await"
268 | "dyn"
269 | "abstract"
270 | "become"
271 | "box"
272 | "do"
273 | "final"
274 | "macro"
275 | "override"
276 | "priv"
277 | "typeof"
278 | "unsized"
279 | "virtual"
280 | "yield"
281 | "try"
282 )
283}
284
285fn escape_rust_keyword(s: String) -> String {
287 if is_rust_keyword(&s) {
288 format!("r#{}", s)
289 } else {
290 s
291 }
292}
293
294fn to_snake_case(s: &str) -> String {
296 let mut result = String::new();
297 let mut prev_lower = false;
298
299 for (i, ch) in s.chars().enumerate() {
300 if ch == '-' {
301 result.push('_');
302 prev_lower = false;
303 } else if ch.is_uppercase() {
304 if i > 0 && prev_lower {
305 result.push('_');
306 }
307 result.push(ch.to_ascii_lowercase());
308 prev_lower = false;
309 } else {
310 result.push(ch);
311 prev_lower = ch.is_lowercase();
312 }
313 }
314
315 escape_rust_keyword(result)
316}
317
318fn to_pascal_case(s: &str) -> String {
327 s.split('-').map(pascal_segment).collect()
328}
329
330fn pascal_segment(seg: &str) -> String {
332 if seg.is_empty() {
333 return String::new();
334 }
335 let all_caps = seg.chars().all(|c| !c.is_alphabetic() || c.is_uppercase());
338 let mut out = String::with_capacity(seg.len());
339 for (i, c) in seg.chars().enumerate() {
340 if i == 0 {
341 out.push(c.to_ascii_uppercase());
342 } else if all_caps && c.is_alphabetic() {
343 out.push(c.to_ascii_lowercase());
344 } else {
345 out.push(c);
346 }
347 }
348 out
349}
350
351fn to_screaming_snake_case(s: &str) -> String {
353 let mut result = String::new();
354 let mut prev_lower = false;
355
356 for (i, ch) in s.chars().enumerate() {
357 if ch == '-' {
358 result.push('_');
359 prev_lower = false;
360 } else if ch.is_ascii_uppercase() {
361 if i > 0 && prev_lower {
362 result.push('_');
363 }
364 result.push(ch);
365 prev_lower = false;
366 } else {
367 result.push(ch.to_ascii_uppercase());
368 prev_lower = true;
369 }
370 }
371
372 result
373}
374
375fn module_name_to_rust(s: &str) -> String {
377 let mut result = String::new();
383 let mut prev_lower = false;
384
385 for (i, ch) in s.chars().enumerate() {
386 if ch == '-' {
387 result.push('_');
388 prev_lower = false;
389 } else if ch.is_uppercase() {
390 if i > 0 && prev_lower {
391 result.push('_');
392 }
393 result.push(ch.to_ascii_lowercase());
394 prev_lower = false;
395 } else {
396 result.push(ch);
397 prev_lower = ch.is_lowercase();
398 }
399 }
400
401 result
402}
403
404pub struct CodeGenerator {
406 output: String,
407 config: CodeGenConfig,
408 pattern_counter: usize, imported_types: HashSet<String>, types_with_lifetimes: HashSet<String>, type_definitions: HashMap<String, Type>, }
413
414impl CodeGenerator {
415 pub fn new() -> Self {
416 Self {
417 output: String::new(),
418 config: CodeGenConfig::default(),
419 pattern_counter: 0,
420 imported_types: HashSet::new(),
421 types_with_lifetimes: HashSet::new(),
422 type_definitions: HashMap::new(),
423 }
424 }
425
426 pub fn with_config(config: CodeGenConfig) -> Self {
427 Self {
428 output: String::new(),
429 config,
430 pattern_counter: 0,
431 imported_types: HashSet::new(),
432 types_with_lifetimes: HashSet::new(),
433 type_definitions: HashMap::new(),
434 }
435 }
436
437 fn try_from_path(&self) -> &'static str {
443 "core"
444 }
445
446 fn derive_feature_name(&self) -> Option<&str> {
449 match &self.config.derive_mode {
450 DeriveMode::Always => None,
451 DeriveMode::FeatureGated => Some("derive"),
452 DeriveMode::Custom(name) => Some(name.as_str()),
453 }
454 }
455
456 fn derive_cfg_attr(&self, attr: &str) -> String {
462 match self.derive_feature_name() {
463 None => format!("#[{}]", attr),
464 Some(feat) => format!("#[cfg_attr(feature = \"{}\", {})]", feat, attr),
465 }
466 }
467
468 fn field_derive_cfg_attr(&self, attr: &str) -> String {
470 match self.derive_feature_name() {
471 None => format!(" #[{}]", attr),
472 Some(feat) => format!(" #[cfg_attr(feature = \"{}\", {})]", feat, attr),
473 }
474 }
475
476 fn has_pattern_constraints(&self, module: &Module) -> bool {
478 for def in &module.definitions {
479 if self.type_has_pattern(&def.ty) {
480 return true;
481 }
482 }
483 false
484 }
485
486 fn type_has_pattern(&self, ty: &Type) -> bool {
488 match ty {
489 Type::Constrained {
490 constraint,
491 base_type,
492 } => {
493 if let ConstraintSpec::Subtype(subtype) = &constraint.spec {
494 if self.constraint_has_pattern(subtype) {
495 return true;
496 }
497 }
498 self.type_has_pattern(base_type)
499 }
500 Type::Sequence(fields) | Type::Set(fields) => {
501 fields.iter().any(|f| self.type_has_pattern(&f.ty))
502 }
503 Type::Choice(variants) => variants.iter().any(|v| self.type_has_pattern(&v.ty)),
504 Type::SequenceOf(inner, _) | Type::SetOf(inner, _) => self.type_has_pattern(inner),
505 Type::Tagged { inner, .. } => self.type_has_pattern(inner),
506 _ => false,
507 }
508 }
509
510 fn constraint_has_pattern(&self, constraint: &SubtypeConstraint) -> bool {
512 match constraint {
513 SubtypeConstraint::Pattern(_) => true,
514 SubtypeConstraint::SizeConstraint(inner)
515 | SubtypeConstraint::InnerType(inner)
516 | SubtypeConstraint::Complement(inner) => self.constraint_has_pattern(inner),
517 SubtypeConstraint::Union(elements) | SubtypeConstraint::Intersection(elements) => {
518 elements.iter().any(|e| self.constraint_has_pattern(e))
519 }
520 _ => false,
521 }
522 }
523
524 pub fn generate_module(&mut self, module: &Module) -> Result<String, std::fmt::Error> {
526 writeln!(
528 &mut self.output,
529 "// Auto-generated from ASN.1 module: {}",
530 module.name
531 )?;
532 writeln!(&mut self.output)?;
533
534 if !module.exports.is_empty() {
536 writeln!(&mut self.output, "// EXPORTS:")?;
537 for export in &module.exports {
538 writeln!(&mut self.output, "// {}", export)?;
539 }
540 writeln!(&mut self.output)?;
541 }
542
543 if !module.imports.is_empty() {
545 writeln!(&mut self.output, "// IMPORTS:")?;
546 for import in &module.imports {
547 write!(&mut self.output, "// ")?;
548 for (i, symbol) in import.symbols.iter().enumerate() {
549 if i > 0 {
550 write!(&mut self.output, ", ")?;
551 }
552 write!(&mut self.output, "{}", symbol)?;
553 }
554 writeln!(&mut self.output, " FROM {}", import.module_name)?;
555 }
556 writeln!(&mut self.output)?;
557 }
558
559 writeln!(&mut self.output, "#[allow(unused_imports)]")?;
563 writeln!(&mut self.output, "use synta::types::string::*;")?;
564 writeln!(&mut self.output, "#[allow(unused_imports)]")?;
568 writeln!(
569 &mut self.output,
570 "use synta::{{Encode, Decode, Tagged, Encoder, Decoder, \
571 GeneralizedTime, ObjectIdentifier, UtcTime, \
572 Integer, Boolean, Enumerated, Null, Real, \
573 ExplicitTag, ImplicitTag, Element, RawDer, SetOf}};"
574 )?;
575 let derive_feat = self.derive_feature_name().map(str::to_owned);
576 if let Some(feat) = derive_feat {
577 writeln!(&mut self.output, "#[cfg(feature = \"{feat}\")]")?;
578 }
579 writeln!(&mut self.output, "#[allow(unused_imports)]")?;
580 writeln!(
581 &mut self.output,
582 "use synta_derive::{{Asn1Sequence, Asn1Choice, Asn1Set}};"
583 )?;
584
585 if self.has_pattern_constraints(module) {
587 writeln!(&mut self.output, "#[cfg(feature = \"regex\")]")?;
588 writeln!(&mut self.output, "use regex::Regex;")?;
589 writeln!(&mut self.output, "#[cfg(feature = \"regex\")]")?;
590 writeln!(&mut self.output, "use once_cell::sync::Lazy;")?;
591 }
592 writeln!(&mut self.output)?;
593
594 if let Some(ref prefix) = self.config.module_path_prefix {
596 if !module.imports.is_empty() {
597 for import in &module.imports {
598 let module_path = module_name_to_rust(&import.module_name);
599 write!(&mut self.output, "use {}::{}", prefix, module_path)?;
600
601 if import.symbols.len() == 1 {
602 writeln!(&mut self.output, "::{};", import.symbols[0])?;
603 } else {
604 write!(&mut self.output, "::{{")?;
605 for (i, symbol) in import.symbols.iter().enumerate() {
606 if i > 0 {
607 write!(&mut self.output, ", ")?;
608 }
609 write!(&mut self.output, "{}", symbol)?;
610 }
611 writeln!(&mut self.output, "}};")?;
612 }
613 }
614 writeln!(&mut self.output)?;
615 }
616 }
617
618 self.imported_types = module
620 .imports
621 .iter()
622 .flat_map(|import| import.symbols.iter())
623 .cloned()
624 .collect();
625
626 if !module.values.is_empty() {
628 writeln!(
629 &mut self.output,
630 "// ============================================================================"
631 )?;
632 writeln!(&mut self.output, "// Constants")?;
633 writeln!(
634 &mut self.output,
635 "// ============================================================================\n"
636 )?;
637
638 let oid_registry = self.build_oid_registry(&module.values);
640
641 for value_assignment in &module.values {
642 self.generate_value_assignment(value_assignment, &oid_registry)?;
643 }
644 writeln!(&mut self.output)?;
645 }
646
647 for def in &module.definitions {
649 let type_name = to_pascal_case(&def.name);
650 self.type_definitions.insert(type_name, def.ty.clone());
651 }
652
653 self.prescan_types_for_lifetimes(&module.definitions);
656
657 for def in &module.definitions {
659 if self.config.skip_imported_types.contains(&def.name) {
661 continue;
662 }
663
664 self.generate_definition(def)?;
665 writeln!(&mut self.output)?;
666 }
667
668 Ok(self.output.clone())
669 }
670
671 fn generate_definition(&mut self, def: &Definition) -> Result<(), std::fmt::Error> {
672 let type_name = to_pascal_case(&def.name);
673
674 match &def.ty {
675 Type::Sequence(fields) => {
676 self.generate_sequence_type(&type_name, fields)?;
677 }
678 Type::Set(fields) => {
679 self.generate_set_type(&type_name, fields)?;
680 }
681 Type::Choice(variants) => {
682 self.generate_choice_type(&type_name, variants)?;
683 }
684 Type::SequenceOf(inner, size_constraint) => {
685 self.generate_sequence_of_type(&type_name, inner, size_constraint.as_ref())?;
686 }
687 Type::SetOf(inner, size_constraint) => {
688 self.generate_set_of_type(&type_name, inner, size_constraint.as_ref())?;
689 }
690 Type::Constrained {
692 base_type,
693 constraint,
694 } => {
695 match (base_type.as_ref(), &constraint.spec) {
696 (
697 Type::Integer(_, named_numbers),
698 ConstraintSpec::Subtype(subtype_constraint),
699 ) => {
700 self.generate_constrained_integer(&type_name, subtype_constraint)?;
701
702 if !named_numbers.is_empty() {
704 let prim = Self::constrained_integer_rust_type(subtype_constraint);
705 writeln!(&mut self.output)?;
706 writeln!(&mut self.output, "impl {} {{", type_name)?;
707
708 for named_number in named_numbers {
709 let const_name = to_screaming_snake_case(&named_number.name);
710 writeln!(
711 &mut self.output,
712 " pub const {}: {} = {};",
713 const_name, prim, named_number.value
714 )?;
715 }
716
717 writeln!(&mut self.output, "}}")?;
718 }
719 }
720 (Type::IA5String(_), ConstraintSpec::Subtype(subtype_constraint)) => {
721 self.generate_constrained_string(
722 &type_name,
723 "IA5String",
724 subtype_constraint,
725 )?;
726 }
727 (Type::PrintableString(_), ConstraintSpec::Subtype(subtype_constraint)) => {
728 self.generate_constrained_string(
729 &type_name,
730 "PrintableString",
731 subtype_constraint,
732 )?;
733 }
734 (Type::Utf8String(_), ConstraintSpec::Subtype(subtype_constraint)) => {
735 self.generate_constrained_string(
736 &type_name,
737 "Utf8String",
738 subtype_constraint,
739 )?;
740 }
741 (Type::TeletexString(_), ConstraintSpec::Subtype(subtype_constraint)) => {
742 self.generate_constrained_string(
743 &type_name,
744 "TeletexString",
745 subtype_constraint,
746 )?;
747 }
748 (Type::UniversalString(_), ConstraintSpec::Subtype(subtype_constraint)) => {
749 self.generate_constrained_string(
750 &type_name,
751 "UniversalString",
752 subtype_constraint,
753 )?;
754 }
755 (Type::BmpString(_), ConstraintSpec::Subtype(subtype_constraint)) => {
756 self.generate_constrained_string(
757 &type_name,
758 "BmpString",
759 subtype_constraint,
760 )?;
761 }
762 (Type::GeneralString(_), ConstraintSpec::Subtype(subtype_constraint)) => {
763 self.generate_constrained_string(
764 &type_name,
765 "GeneralString",
766 subtype_constraint,
767 )?;
768 }
769 (Type::NumericString(_), ConstraintSpec::Subtype(subtype_constraint)) => {
770 self.generate_constrained_string(
771 &type_name,
772 "NumericString",
773 subtype_constraint,
774 )?;
775 }
776 (Type::VisibleString(_), ConstraintSpec::Subtype(subtype_constraint)) => {
777 self.generate_constrained_string(
778 &type_name,
779 "VisibleString",
780 subtype_constraint,
781 )?;
782 }
783 (Type::OctetString(_), ConstraintSpec::Subtype(subtype_constraint)) => {
784 self.generate_constrained_string(
785 &type_name,
786 "OctetString",
787 subtype_constraint,
788 )?;
789 }
790 (
791 Type::BitString(_),
792 ConstraintSpec::Subtype(SubtypeConstraint::NamedBitList(named_bits)),
793 ) => {
794 writeln!(&mut self.output, "pub type {} = BitString;", type_name)?;
796 self.generate_named_bit_constants(&type_name, named_bits)?;
797 }
798 (
799 Type::BitString(_),
800 ConstraintSpec::Subtype(SubtypeConstraint::Intersection(constraints)),
801 ) if constraints
802 .iter()
803 .any(|c| matches!(c, SubtypeConstraint::NamedBitList(_))) =>
804 {
805 let size_con = constraints
807 .iter()
808 .find(|c| matches!(c, SubtypeConstraint::SizeConstraint(_)));
809 let named_bits_opt = constraints.iter().find_map(|c| {
810 if let SubtypeConstraint::NamedBitList(bits) = c {
811 Some(bits)
812 } else {
813 None
814 }
815 });
816
817 if let Some(size_con) = size_con {
818 self.generate_constrained_string(&type_name, "BitString", size_con)?;
819 } else {
820 writeln!(&mut self.output, "pub type {} = BitString;", type_name)?;
821 }
822
823 if let Some(named_bits) = named_bits_opt {
824 self.generate_named_bit_constants(&type_name, named_bits)?;
825 }
826 }
827 (Type::BitString(_), ConstraintSpec::Subtype(subtype_constraint)) => {
828 self.generate_constrained_string(
829 &type_name,
830 "BitString",
831 subtype_constraint,
832 )?;
833 }
834 (Type::TypeRef(_), ConstraintSpec::Subtype(subtype_constraint)) => {
835 self.generate_subtype(&type_name, base_type, subtype_constraint)?;
837 }
838 _ => {
839 writeln!(
841 &mut self.output,
842 "// Constrained type (validation not yet implemented)"
843 )?;
844 let rust_type = self.rust_type(base_type);
845 self.generate_type_alias(&type_name, &rust_type, base_type)?;
846 }
847 }
848 }
849 Type::Integer(_, named_numbers) if !named_numbers.is_empty() => {
850 writeln!(&mut self.output, "pub type {} = Integer;", type_name)?;
852 writeln!(&mut self.output)?;
853 writeln!(&mut self.output, "impl {} {{", type_name)?;
854
855 for named_number in named_numbers {
856 let const_name = to_screaming_snake_case(&named_number.name);
857 writeln!(
858 &mut self.output,
859 " pub const {}: Integer = Integer::from({});",
860 const_name, named_number.value
861 )?;
862 }
863
864 writeln!(&mut self.output, "}}")?;
865 }
866 Type::Integer(Some(constraint), _) => {
867 let constraint_str = self.format_value_constraint(constraint);
869 writeln!(&mut self.output, "// Constraint: {}", constraint_str)?;
870 writeln!(&mut self.output, "pub type {} = Integer;", type_name)?;
871 }
872 Type::OctetString(Some(constraint))
873 | Type::BitString(Some(constraint))
874 | Type::Utf8String(Some(constraint))
875 | Type::PrintableString(Some(constraint))
876 | Type::IA5String(Some(constraint))
877 | Type::TeletexString(Some(constraint))
878 | Type::UniversalString(Some(constraint))
879 | Type::BmpString(Some(constraint))
880 | Type::GeneralString(Some(constraint))
881 | Type::NumericString(Some(constraint))
882 | Type::VisibleString(Some(constraint)) => {
883 let constraint_str = self.format_size_constraint(constraint);
885 writeln!(&mut self.output, "// Constraint: {}", constraint_str)?;
886 let rust_type = self.rust_type(&def.ty);
887 self.generate_type_alias(&type_name, &rust_type, &def.ty)?;
888 }
889 Type::Enumerated(named_values) => {
890 self.generate_enumerated_type(&type_name, named_values)?;
891 }
892 Type::Tagged { tag, inner } => {
893 let class_str = match tag.class {
895 TagClass::Application => "APPLICATION",
896 TagClass::Universal => "UNIVERSAL",
897 TagClass::Private => "PRIVATE",
898 TagClass::ContextSpecific => "CONTEXT",
899 };
900 let tagging_str = match tag.tagging {
901 Tagging::Explicit => "EXPLICIT",
902 Tagging::Implicit => "IMPLICIT",
903 };
904 writeln!(
905 &mut self.output,
906 "/// [{} {}] {} outer tag",
907 class_str, tag.number, tagging_str
908 )?;
909 let inner_def = Definition {
911 name: def.name.clone(),
912 ty: *inner.clone(),
913 };
914 self.generate_definition(&inner_def)?;
915 }
916 Type::Class(fields) => {
917 writeln!(
921 &mut self.output,
922 "// ASN.1 Information Object Class: {} (no Rust type generated)",
923 type_name
924 )?;
925 if !fields.is_empty() {
926 write!(&mut self.output, "// Fields:")?;
927 for field in fields {
928 write!(&mut self.output, " &{}", field.name)?;
929 if field.unique {
930 write!(&mut self.output, " UNIQUE")?;
931 }
932 if field.optional {
933 write!(&mut self.output, " OPTIONAL")?;
934 }
935 write!(&mut self.output, ";")?;
936 }
937 writeln!(&mut self.output)?;
938 }
939 }
940 _ => {
941 let rust_type = self.rust_type(&def.ty);
943 self.generate_type_alias(&type_name, &rust_type, &def.ty)?;
944 }
945 }
946
947 Ok(())
948 }
949
950 fn format_value_constraint(&self, constraint: &ValueConstraint) -> String {
951 match constraint {
952 ValueConstraint::Single(val) => format!("value = {}", val),
953 ValueConstraint::Range(min, max) => {
954 let min_str = min
955 .map(|v| v.to_string())
956 .unwrap_or_else(|| "MIN".to_string());
957 let max_str = max
958 .map(|v| v.to_string())
959 .unwrap_or_else(|| "MAX".to_string());
960 format!("{}..{}", min_str, max_str)
961 }
962 }
963 }
964
965 fn format_size_constraint(&self, constraint: &SizeConstraint) -> String {
966 match constraint {
967 SizeConstraint::Fixed(size) => format!("SIZE ({})", size),
968 SizeConstraint::Range(min, max) => {
969 let min_str = min
970 .map(|v| v.to_string())
971 .unwrap_or_else(|| "0".to_string());
972 let max_str = max
973 .map(|v| v.to_string())
974 .unwrap_or_else(|| "MAX".to_string());
975 format!("SIZE ({}..{})", min_str, max_str)
976 }
977 }
978 }
979
980 fn constrained_integer_rust_type(constraint: &SubtypeConstraint) -> &'static str {
993 let (lo, hi) = match constraint {
994 SubtypeConstraint::SingleValue(ConstraintValue::Integer(n)) => (*n, *n),
995 SubtypeConstraint::ValueRange {
996 min: ConstraintValue::Integer(lo),
997 max: ConstraintValue::Integer(hi),
998 } => (*lo, *hi),
999 _ => return "i64",
1000 };
1001 if lo >= 0 {
1002 if hi <= u8::MAX as i64 {
1004 "u8"
1005 } else if hi <= u16::MAX as i64 {
1006 "u16"
1007 } else if hi <= u32::MAX as i64 {
1008 "u32"
1009 } else {
1010 "u64"
1011 }
1012 } else {
1013 if lo >= i8::MIN as i64 && hi <= i8::MAX as i64 {
1015 "i8"
1016 } else if lo >= i16::MIN as i64 && hi <= i16::MAX as i64 {
1017 "i16"
1018 } else if lo >= i32::MIN as i64 && hi <= i32::MAX as i64 {
1019 "i32"
1020 } else {
1021 "i64"
1022 }
1023 }
1024 }
1025
1026 fn generate_constraint_value_check(&self, var: &str, value: &ConstraintValue) -> String {
1028 match value {
1029 ConstraintValue::Integer(n) => format!("{} == {}", var, n),
1030 ConstraintValue::Min => "true /* MIN */".to_string(),
1031 ConstraintValue::Max => "true /* MAX */".to_string(),
1032 ConstraintValue::NamedValue(name) => format!("{} == {} /* named value */", var, name),
1033 }
1034 }
1035
1036 fn generate_constraint_validation(&self, var: &str, constraint: &SubtypeConstraint) -> String {
1038 match constraint {
1039 SubtypeConstraint::SingleValue(val) => self.generate_constraint_value_check(var, val),
1040 SubtypeConstraint::ValueRange { min, max } => {
1041 if let (ConstraintValue::Integer(lo), ConstraintValue::Integer(hi)) = (min, max) {
1044 return format!("({}..={}).contains(&{})", lo, hi, var);
1045 }
1046 let mut parts: Vec<String> = Vec::new();
1047 match min {
1048 ConstraintValue::Integer(n) => parts.push(format!("{} >= {}", var, n)),
1049 ConstraintValue::Min => {}
1050 ConstraintValue::NamedValue(name) => parts.push(format!("{} >= {}", var, name)),
1051 ConstraintValue::Max => parts.push(format!("{} <= i64::MAX", var)),
1052 }
1053 match max {
1054 ConstraintValue::Integer(n) => parts.push(format!("{} <= {}", var, n)),
1055 ConstraintValue::Max => {}
1056 ConstraintValue::NamedValue(name) => parts.push(format!("{} <= {}", var, name)),
1057 ConstraintValue::Min => parts.push(format!("{} >= i64::MIN", var)),
1058 }
1059 if parts.is_empty() {
1060 "true".to_string()
1061 } else {
1062 format!("({})", parts.join(" && "))
1063 }
1064 }
1065 SubtypeConstraint::Union(elements) => {
1066 let checks: Vec<String> = elements
1067 .iter()
1068 .map(|e| self.generate_constraint_validation(var, e))
1069 .collect();
1070 format!("({})", checks.join(" || "))
1071 }
1072 SubtypeConstraint::Intersection(elements) => {
1073 let checks: Vec<String> = elements
1074 .iter()
1075 .map(|e| self.generate_constraint_validation(var, e))
1076 .collect();
1077 format!("({})", checks.join(" && "))
1078 }
1079 SubtypeConstraint::Complement(inner) => {
1080 let inner_check = self.generate_constraint_validation(var, inner);
1081 format!("!({})", inner_check)
1082 }
1083 _ => "true /* unsupported constraint */".to_string(),
1084 }
1085 }
1086
1087 fn generate_constraint_description(&self, constraint: &SubtypeConstraint) -> String {
1089 match constraint {
1090 SubtypeConstraint::SingleValue(ConstraintValue::Integer(n)) => {
1091 format!("must equal {}", n)
1092 }
1093 SubtypeConstraint::ValueRange { min, max } => {
1094 let min_str = match min {
1095 ConstraintValue::Integer(n) => n.to_string(),
1096 ConstraintValue::Min => "MIN".to_string(),
1097 ConstraintValue::NamedValue(n) => n.clone(),
1098 ConstraintValue::Max => "MAX".to_string(),
1099 };
1100 let max_str = match max {
1101 ConstraintValue::Integer(n) => n.to_string(),
1102 ConstraintValue::Max => "MAX".to_string(),
1103 ConstraintValue::NamedValue(n) => n.clone(),
1104 ConstraintValue::Min => "MIN".to_string(),
1105 };
1106 format!("must be in range {}..{}", min_str, max_str)
1107 }
1108 SubtypeConstraint::Union(elements) => {
1109 let descriptions: Vec<String> = elements
1110 .iter()
1111 .map(|e| self.generate_constraint_description(e))
1112 .collect();
1113 format!("must satisfy one of: {}", descriptions.join(", "))
1114 }
1115 SubtypeConstraint::Complement(inner) => {
1116 format!(
1117 "must not be {}",
1118 self.generate_constraint_description(inner)
1119 )
1120 }
1121 _ => "must satisfy constraint".to_string(),
1122 }
1123 }
1124
1125 fn generate_enumerated_type(
1127 &mut self,
1128 name: &str,
1129 named_values: &[NamedNumber],
1130 ) -> Result<(), std::fmt::Error> {
1131 writeln!(&mut self.output, "/// ENUMERATED")?;
1132 writeln!(
1133 &mut self.output,
1134 "#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]"
1135 )?;
1136 writeln!(&mut self.output, "#[repr(i64)]")?;
1137 writeln!(&mut self.output, "pub enum {} {{", name)?;
1138
1139 for nv in named_values {
1140 let variant_name = to_pascal_case(&nv.name);
1141 writeln!(&mut self.output, " {} = {},", variant_name, nv.value)?;
1142 }
1143
1144 writeln!(&mut self.output, "}}")?;
1145 writeln!(&mut self.output)?;
1146
1147 let try_from_path = self.try_from_path();
1149 writeln!(
1150 &mut self.output,
1151 "impl {}::convert::TryFrom<Integer> for {} {{",
1152 try_from_path, name
1153 )?;
1154 writeln!(&mut self.output, " type Error = &'static str;")?;
1155 writeln!(&mut self.output)?;
1156 writeln!(
1157 &mut self.output,
1158 " fn try_from(value: Integer) -> Result<Self, Self::Error> {{"
1159 )?;
1160 writeln!(
1161 &mut self.output,
1162 " let discriminant = value.as_i64().map_err(|_| \"ENUMERATED value out of i64 range\")?;"
1163 )?;
1164 writeln!(&mut self.output, " match discriminant {{")?;
1165
1166 for nv in named_values {
1167 let variant_name = to_pascal_case(&nv.name);
1168 writeln!(
1169 &mut self.output,
1170 " {} => Ok({}::{}),",
1171 nv.value, name, variant_name
1172 )?;
1173 }
1174
1175 writeln!(
1176 &mut self.output,
1177 " _ => Err(\"unknown ENUMERATED value\"),"
1178 )?;
1179 writeln!(&mut self.output, " }}")?;
1180 writeln!(&mut self.output, " }}")?;
1181 writeln!(&mut self.output, "}}")?;
1182 writeln!(&mut self.output)?;
1183
1184 writeln!(&mut self.output, "impl From<{}> for Integer {{", name)?;
1186 writeln!(&mut self.output, " fn from(value: {}) -> Self {{", name)?;
1187 writeln!(&mut self.output, " Integer::from(value as i64)")?;
1188 writeln!(&mut self.output, " }}")?;
1189 writeln!(&mut self.output, "}}")?;
1190 writeln!(&mut self.output)?;
1191
1192 writeln!(&mut self.output, "impl Encode for {} {{", name)?;
1196 writeln!(
1197 &mut self.output,
1198 " fn encode(&self, encoder: &mut Encoder) -> synta::Result<()> {{"
1199 )?;
1200 writeln!(
1201 &mut self.output,
1202 " let as_int = Integer::from(*self as i64);"
1203 )?;
1204 writeln!(
1205 &mut self.output,
1206 " let tag = synta::Tag::universal(synta::tag::TAG_ENUMERATED);"
1207 )?;
1208 writeln!(&mut self.output, " encoder.write_tag(tag)?;")?;
1209 writeln!(
1210 &mut self.output,
1211 " encoder.write_length(as_int.as_bytes().len())?;"
1212 )?;
1213 writeln!(
1214 &mut self.output,
1215 " encoder.write_bytes(as_int.as_bytes());"
1216 )?;
1217 writeln!(&mut self.output, " Ok(())")?;
1218 writeln!(&mut self.output, " }}")?;
1219 writeln!(
1220 &mut self.output,
1221 " fn encoded_len(&self) -> synta::Result<usize> {{"
1222 )?;
1223 writeln!(
1224 &mut self.output,
1225 " let as_int = Integer::from(*self as i64);"
1226 )?;
1227 writeln!(&mut self.output, " let tag_len = 1usize;")?;
1228 writeln!(
1229 &mut self.output,
1230 " let length = as_int.as_bytes().len();"
1231 )?;
1232 writeln!(
1233 &mut self.output,
1234 " let length_len = synta::Length::Definite(length).encoded_len()?;"
1235 )?;
1236 writeln!(
1237 &mut self.output,
1238 " Ok(tag_len + length_len + length)"
1239 )?;
1240 writeln!(&mut self.output, " }}")?;
1241 writeln!(&mut self.output, "}}")?;
1242 writeln!(&mut self.output)?;
1243
1244 writeln!(&mut self.output, "impl<'a> Decode<'a> for {} {{", name)?;
1245 writeln!(
1246 &mut self.output,
1247 " fn decode(decoder: &mut Decoder<'a>) -> synta::Result<Self> {{"
1248 )?;
1249 writeln!(&mut self.output, " let tag = decoder.read_tag()?;")?;
1250 writeln!(
1251 &mut self.output,
1252 " let expected = synta::Tag::universal(synta::tag::TAG_ENUMERATED);"
1253 )?;
1254 writeln!(&mut self.output, " if tag != expected {{")?;
1255 writeln!(
1256 &mut self.output,
1257 " return Err(synta::Error::UnexpectedTag {{"
1258 )?;
1259 writeln!(
1260 &mut self.output,
1261 " position: decoder.position(),"
1262 )?;
1263 writeln!(&mut self.output, " expected,")?;
1264 writeln!(&mut self.output, " actual: tag,")?;
1265 writeln!(&mut self.output, " }});")?;
1266 writeln!(&mut self.output, " }}")?;
1267 writeln!(
1268 &mut self.output,
1269 " let length = decoder.read_length()?;"
1270 )?;
1271 writeln!(&mut self.output, " let len = length.definite()?;")?;
1272 writeln!(
1273 &mut self.output,
1274 " let bytes = decoder.read_bytes(len)?;"
1275 )?;
1276 writeln!(
1277 &mut self.output,
1278 " let integer = Integer::from_bytes(bytes);"
1279 )?;
1280 writeln!(
1281 &mut self.output,
1282 " core::convert::TryFrom::try_from(integer)\
1283 .map_err(|_| synta::Error::LengthOverflow)"
1284 )?;
1285 writeln!(&mut self.output, " }}")?;
1286 writeln!(&mut self.output, "}}")?;
1287 writeln!(&mut self.output)?;
1288
1289 writeln!(&mut self.output, "impl Tagged for {} {{", name)?;
1290 writeln!(
1291 &mut self.output,
1292 " fn tag() -> synta::Tag {{ synta::Tag::universal(synta::tag::TAG_ENUMERATED) }}"
1293 )?;
1294 writeln!(&mut self.output, "}}")?;
1295
1296 self.generate_format_asn1_impl(name, false)?;
1297
1298 Ok(())
1299 }
1300
1301 fn generate_named_bit_constants(
1303 &mut self,
1304 name: &str,
1305 named_bits: &[NamedNumber],
1306 ) -> Result<(), std::fmt::Error> {
1307 if named_bits.is_empty() {
1308 return Ok(());
1309 }
1310
1311 writeln!(&mut self.output)?;
1312 writeln!(
1313 &mut self.output,
1314 "// Named bit positions for {} (defined as module-level constants to avoid orphan rule issues)",
1315 name
1316 )?;
1317
1318 for bit in named_bits {
1319 let const_name = to_screaming_snake_case(&bit.name);
1320 let full_const_name = format!("{}_{}", to_screaming_snake_case(name), const_name);
1321 writeln!(
1322 &mut self.output,
1323 "/// Bit position for `{}` in {}",
1324 bit.name, name
1325 )?;
1326 writeln!(
1327 &mut self.output,
1328 "pub const {}: usize = {};",
1329 full_const_name, bit.value
1330 )?;
1331 }
1332
1333 Ok(())
1334 }
1335
1336 fn generate_constrained_integer(
1346 &mut self,
1347 name: &str,
1348 constraint: &SubtypeConstraint,
1349 ) -> Result<(), std::fmt::Error> {
1350 let prim = Self::constrained_integer_rust_type(constraint);
1351
1352 let constraint_display = self.format_constraint_display(constraint);
1354 writeln!(&mut self.output, "/// INTEGER ({})", constraint_display)?;
1355 writeln!(
1356 &mut self.output,
1357 "#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]"
1358 )?;
1359 writeln!(&mut self.output, "pub struct {}({});", name, prim)?;
1360 writeln!(&mut self.output)?;
1361
1362 writeln!(&mut self.output, "impl {} {{", name)?;
1364 writeln!(
1365 &mut self.output,
1366 " /// Create a new {} with validation",
1367 name
1368 )?;
1369 writeln!(
1370 &mut self.output,
1371 " pub fn new(value: {}) -> Result<Self, &'static str> {{",
1372 prim
1373 )?;
1374
1375 let validation = self.generate_constraint_validation("value", constraint);
1376 let description = self.generate_constraint_description(constraint);
1377
1378 writeln!(&mut self.output, " if {} {{", validation)?;
1379 writeln!(&mut self.output, " Ok({}(value))", name)?;
1380 writeln!(&mut self.output, " }} else {{")?;
1381 writeln!(&mut self.output, " Err(\"{}\")", description)?;
1382 writeln!(&mut self.output, " }}")?;
1383 writeln!(&mut self.output, " }}")?;
1384 writeln!(&mut self.output)?;
1385
1386 writeln!(
1388 &mut self.output,
1389 " /// Create without validation (use with caution)"
1390 )?;
1391 writeln!(
1392 &mut self.output,
1393 " pub const fn new_unchecked(value: {}) -> Self {{",
1394 prim
1395 )?;
1396 writeln!(&mut self.output, " {}(value)", name)?;
1397 writeln!(&mut self.output, " }}")?;
1398 writeln!(&mut self.output)?;
1399
1400 writeln!(&mut self.output, " /// Get the inner value")?;
1402 writeln!(
1403 &mut self.output,
1404 " pub const fn get(&self) -> {} {{",
1405 prim
1406 )?;
1407 writeln!(&mut self.output, " self.0")?;
1408 writeln!(&mut self.output, " }}")?;
1409 writeln!(&mut self.output)?;
1410
1411 writeln!(
1413 &mut self.output,
1414 " /// Consume and return the inner value"
1415 )?;
1416 writeln!(
1417 &mut self.output,
1418 " pub fn into_inner(self) -> {} {{",
1419 prim
1420 )?;
1421 writeln!(&mut self.output, " self.0")?;
1422 writeln!(&mut self.output, " }}")?;
1423 writeln!(&mut self.output, "}}")?;
1424 writeln!(&mut self.output)?;
1425
1426 let as_method = format!("as_{}", prim);
1430 let try_from_path = self.try_from_path();
1431 writeln!(
1432 &mut self.output,
1433 "impl {}::convert::TryFrom<Integer> for {} {{",
1434 try_from_path, name
1435 )?;
1436 writeln!(&mut self.output, " type Error = &'static str;")?;
1437 writeln!(&mut self.output)?;
1438 writeln!(
1439 &mut self.output,
1440 " fn try_from(value: Integer) -> Result<Self, Self::Error> {{"
1441 )?;
1442 writeln!(
1443 &mut self.output,
1444 " let n = value.{as_method}().map_err(|_| \"integer value out of {prim} range\")?;"
1445 )?;
1446 writeln!(&mut self.output, " Self::new(n)")?;
1447 writeln!(&mut self.output, " }}")?;
1448 writeln!(&mut self.output, "}}")?;
1449 writeln!(&mut self.output)?;
1450
1451 writeln!(&mut self.output, "impl Encode for {} {{", name)?;
1455 writeln!(
1456 &mut self.output,
1457 " fn encode(&self, encoder: &mut Encoder) -> synta::Result<()> {{"
1458 )?;
1459 writeln!(
1460 &mut self.output,
1461 " Integer::from(self.0).encode(encoder)"
1462 )?;
1463 writeln!(&mut self.output, " }}")?;
1464 writeln!(
1465 &mut self.output,
1466 " fn encoded_len(&self) -> synta::Result<usize> {{"
1467 )?;
1468 writeln!(
1469 &mut self.output,
1470 " Integer::from(self.0).encoded_len()"
1471 )?;
1472 writeln!(&mut self.output, " }}")?;
1473 writeln!(&mut self.output, "}}")?;
1474 writeln!(&mut self.output)?;
1475
1476 writeln!(&mut self.output, "impl<'a> Decode<'a> for {} {{", name)?;
1478 writeln!(
1479 &mut self.output,
1480 " fn decode(decoder: &mut Decoder<'a>) -> synta::Result<Self> {{"
1481 )?;
1482 writeln!(
1483 &mut self.output,
1484 " Integer::decode(decoder).and_then(|v| {{"
1485 )?;
1486 writeln!(
1487 &mut self.output,
1488 " let n = v.{as_method}().map_err(|_| synta::Error::LengthOverflow)?;"
1489 )?;
1490 writeln!(
1491 &mut self.output,
1492 " Self::new(n).map_err(|_| synta::Error::LengthOverflow)"
1493 )?;
1494 writeln!(&mut self.output, " }})")?;
1495 writeln!(&mut self.output, " }}")?;
1496 writeln!(&mut self.output, "}}")?;
1497 writeln!(&mut self.output)?;
1498
1499 writeln!(&mut self.output, "impl Tagged for {} {{", name)?;
1500 writeln!(
1501 &mut self.output,
1502 " fn tag() -> synta::Tag {{ Integer::tag() }}"
1503 )?;
1504 writeln!(&mut self.output, "}}")?;
1505
1506 self.generate_format_asn1_impl(name, false)?;
1507
1508 Ok(())
1509 }
1510
1511 fn generate_constrained_string(
1513 &mut self,
1514 name: &str,
1515 base_type: &str,
1516 constraint: &SubtypeConstraint,
1517 ) -> Result<(), std::fmt::Error> {
1518 let constraint_display = self.format_constraint_display(constraint);
1520 writeln!(
1521 &mut self.output,
1522 "/// {} ({})",
1523 base_type, constraint_display
1524 )?;
1525 writeln!(&mut self.output, "#[derive(Debug, Clone, PartialEq, Eq)]")?;
1526 writeln!(&mut self.output, "pub struct {}({});", name, base_type)?;
1527 writeln!(&mut self.output)?;
1528
1529 writeln!(&mut self.output, "impl {} {{", name)?;
1531 writeln!(
1532 &mut self.output,
1533 " /// Create a new {} with validation",
1534 name
1535 )?;
1536 writeln!(
1537 &mut self.output,
1538 " pub fn new(value: {}) -> Result<Self, &'static str> {{",
1539 base_type
1540 )?;
1541
1542 let validation_code = self.generate_string_validation("value", base_type, constraint);
1544 writeln!(&mut self.output, "{}", validation_code)?;
1545
1546 writeln!(&mut self.output, " }}")?;
1547 writeln!(&mut self.output)?;
1548
1549 writeln!(
1551 &mut self.output,
1552 " /// Create without validation (use with caution)"
1553 )?;
1554 writeln!(
1555 &mut self.output,
1556 " pub fn new_unchecked(value: {}) -> Self {{",
1557 base_type
1558 )?;
1559 writeln!(&mut self.output, " {}(value)", name)?;
1560 writeln!(&mut self.output, " }}")?;
1561 writeln!(&mut self.output)?;
1562
1563 writeln!(
1565 &mut self.output,
1566 " /// Get a reference to the inner value"
1567 )?;
1568 writeln!(
1569 &mut self.output,
1570 " pub fn get(&self) -> &{} {{",
1571 base_type
1572 )?;
1573 writeln!(&mut self.output, " &self.0")?;
1574 writeln!(&mut self.output, " }}")?;
1575 writeln!(&mut self.output)?;
1576
1577 if base_type != "OctetString" && base_type != "BitString" {
1579 writeln!(&mut self.output, " /// Get the string value")?;
1580 writeln!(&mut self.output, " pub fn as_str(&self) -> &str {{")?;
1581 writeln!(&mut self.output, " self.0.as_str()")?;
1582 writeln!(&mut self.output, " }}")?;
1583 writeln!(&mut self.output)?;
1584 }
1585
1586 writeln!(
1588 &mut self.output,
1589 " /// Consume and return the inner value"
1590 )?;
1591 writeln!(
1592 &mut self.output,
1593 " pub fn into_inner(self) -> {} {{",
1594 base_type
1595 )?;
1596 writeln!(&mut self.output, " self.0")?;
1597 writeln!(&mut self.output, " }}")?;
1598 writeln!(&mut self.output, "}}")?;
1599 writeln!(&mut self.output)?;
1600
1601 let try_from_path = self.try_from_path();
1603 writeln!(
1604 &mut self.output,
1605 "impl {}::convert::TryFrom<{}> for {} {{",
1606 try_from_path, base_type, name
1607 )?;
1608 writeln!(&mut self.output, " type Error = &'static str;")?;
1609 writeln!(&mut self.output)?;
1610 writeln!(
1611 &mut self.output,
1612 " fn try_from(value: {}) -> Result<Self, Self::Error> {{",
1613 base_type
1614 )?;
1615 writeln!(&mut self.output, " Self::new(value)")?;
1616 writeln!(&mut self.output, " }}")?;
1617 writeln!(&mut self.output, "}}")?;
1618 writeln!(&mut self.output)?;
1619
1620 writeln!(&mut self.output, "impl Encode for {} {{", name)?;
1623 writeln!(
1624 &mut self.output,
1625 " fn encode(&self, encoder: &mut Encoder) -> synta::Result<()> {{"
1626 )?;
1627 writeln!(&mut self.output, " self.0.encode(encoder)")?;
1628 writeln!(&mut self.output, " }}")?;
1629 writeln!(
1630 &mut self.output,
1631 " fn encoded_len(&self) -> synta::Result<usize> {{"
1632 )?;
1633 writeln!(&mut self.output, " self.0.encoded_len()")?;
1634 writeln!(&mut self.output, " }}")?;
1635 writeln!(&mut self.output, "}}")?;
1636 writeln!(&mut self.output)?;
1637
1638 writeln!(&mut self.output, "impl<'a> Decode<'a> for {} {{", name)?;
1639 writeln!(
1640 &mut self.output,
1641 " fn decode(decoder: &mut Decoder<'a>) -> synta::Result<Self> {{"
1642 )?;
1643 writeln!(
1644 &mut self.output,
1645 " {}::decode(decoder).and_then(|v| {{",
1646 base_type
1647 )?;
1648 writeln!(
1649 &mut self.output,
1650 " Self::new(v).map_err(|_| synta::Error::LengthOverflow)"
1651 )?;
1652 writeln!(&mut self.output, " }})")?;
1653 writeln!(&mut self.output, " }}")?;
1654 writeln!(&mut self.output, "}}")?;
1655 writeln!(&mut self.output)?;
1656
1657 writeln!(&mut self.output, "impl Tagged for {} {{", name)?;
1658 writeln!(
1659 &mut self.output,
1660 " fn tag() -> synta::Tag {{ {}::tag() }}",
1661 base_type
1662 )?;
1663 writeln!(&mut self.output, "}}")?;
1664
1665 self.generate_format_asn1_impl(name, false)?;
1666
1667 Ok(())
1668 }
1669
1670 fn generate_string_validation(
1672 &mut self,
1673 var: &str,
1674 base_type: &str,
1675 constraint: &SubtypeConstraint,
1676 ) -> String {
1677 match constraint {
1678 SubtypeConstraint::SizeConstraint(inner) => {
1679 self.generate_size_validation(var, base_type, inner)
1681 }
1682 SubtypeConstraint::PermittedAlphabet(ranges) => {
1683 self.generate_alphabet_validation(var, ranges)
1685 }
1686 SubtypeConstraint::Pattern(pattern) => {
1687 self.generate_pattern_validation(var, pattern)
1689 }
1690 SubtypeConstraint::ContainedSubtype(ty) => {
1691 self.generate_containing_validation(var, ty)
1693 }
1694 SubtypeConstraint::Intersection(constraints) => {
1695 self.generate_intersection_string_validation(var, base_type, constraints)
1697 }
1698 _ => {
1699 format!(
1701 " Ok({}({}))",
1702 self.get_struct_name_from_var(var),
1703 var
1704 )
1705 }
1706 }
1707 }
1708
1709 fn generate_intersection_string_validation(
1712 &self,
1713 var: &str,
1714 base_type: &str,
1715 constraints: &[SubtypeConstraint],
1716 ) -> String {
1717 let struct_name = self.get_struct_name_from_var(var);
1718
1719 let size_constraint = constraints.iter().find_map(|c| {
1721 if let SubtypeConstraint::SizeConstraint(inner) = c {
1722 Some(inner.as_ref())
1723 } else {
1724 None
1725 }
1726 });
1727
1728 let alphabet_constraint = constraints.iter().find_map(|c| {
1729 if let SubtypeConstraint::PermittedAlphabet(ranges) = c {
1730 Some(ranges)
1731 } else {
1732 None
1733 }
1734 });
1735
1736 match (size_constraint, alphabet_constraint) {
1738 (Some(size), Some(alphabet)) => {
1739 let length_expr = if base_type == "BitString" {
1741 format!("{}.bit_len()", var)
1742 } else if base_type == "OctetString" {
1743 format!("{}.as_bytes().len()", var)
1744 } else {
1745 format!("{}.as_str().len()", var)
1746 };
1747
1748 let size_check: Option<String> = match size {
1750 SubtypeConstraint::SingleValue(ConstraintValue::Integer(n)) => {
1751 Some(format!("{} == {}", length_expr, n))
1752 }
1753 SubtypeConstraint::ValueRange { min, max } => {
1754 let mut parts: Vec<String> = Vec::new();
1755 if let ConstraintValue::Integer(n) = min {
1756 parts.push(format!("{} >= {}", length_expr, n));
1757 }
1758 if let ConstraintValue::Integer(n) = max {
1759 parts.push(format!("{} <= {}", length_expr, n));
1760 }
1761 if parts.is_empty() {
1762 None
1763 } else {
1764 Some(parts.join(" && "))
1765 }
1766 }
1767 _ => None,
1768 };
1769
1770 let range_checks: Vec<String> = alphabet
1772 .iter()
1773 .map(|r| {
1774 if r.min == r.max {
1775 format!("ch == '{}'", r.min)
1776 } else {
1777 format!("(ch >= '{}' && ch <= '{}')", r.min, r.max)
1778 }
1779 })
1780 .collect();
1781 let alphabet_check = range_checks.join(" || ");
1782
1783 let size_error = match size {
1785 SubtypeConstraint::SingleValue(ConstraintValue::Integer(n)) => {
1786 format!("length must equal {}", n)
1787 }
1788 SubtypeConstraint::ValueRange { min, max } => {
1789 let min_str = match min {
1790 ConstraintValue::Integer(n) => n.to_string(),
1791 _ => "MIN".to_string(),
1792 };
1793 let max_str = match max {
1794 ConstraintValue::Integer(n) => n.to_string(),
1795 _ => "MAX".to_string(),
1796 };
1797 format!("length must be in range {}..{}", min_str, max_str)
1798 }
1799 _ => "invalid length".to_string(),
1800 };
1801
1802 let ranges_display: Vec<String> = alphabet
1803 .iter()
1804 .map(|r| {
1805 if r.min == r.max {
1806 format!("'{}'", r.min)
1807 } else {
1808 format!("'{}'..'{}'", r.min, r.max)
1809 }
1810 })
1811 .collect();
1812 let alphabet_error =
1813 format!("characters must be from: {}", ranges_display.join(", "));
1814
1815 let size_check_block = if let Some(cond) = size_check {
1817 format!(
1818 " // Check SIZE constraint\n if !({}) {{\n return Err(\"{}\");\n }}\n",
1819 cond, size_error
1820 )
1821 } else {
1822 String::new()
1823 };
1824 format!(
1825 "{} // Check FROM constraint\n for ch in {}.as_str().chars() {{\n if !({}) {{\n return Err(\"{}\");\n }}\n }}\n Ok({}({}))",
1826 size_check_block, var, alphabet_check, alphabet_error, struct_name, var
1827 )
1828 }
1829 (Some(size), None) => {
1830 self.generate_size_validation(var, base_type, size)
1832 }
1833 (None, Some(alphabet)) => {
1834 self.generate_alphabet_validation(var, alphabet)
1836 }
1837 (None, None) => {
1838 format!(" Ok({}({}))", struct_name, var)
1840 }
1841 }
1842 }
1843
1844 fn generate_size_validation(
1846 &self,
1847 var: &str,
1848 base_type: &str,
1849 size_constraint: &SubtypeConstraint,
1850 ) -> String {
1851 let length_expr = if base_type == "BitString" {
1852 format!("{}.bit_len()", var)
1854 } else if base_type == "OctetString" {
1855 format!("{}.as_bytes().len()", var)
1856 } else {
1857 format!("{}.as_str().len()", var)
1858 };
1859
1860 let struct_name = self.get_struct_name_from_var(var);
1861
1862 match size_constraint {
1863 SubtypeConstraint::SingleValue(ConstraintValue::Integer(n)) => {
1864 format!(
1865 " if {} == {} {{\n Ok({}({}))\n }} else {{\n Err(\"length must equal {}\")\n }}",
1866 length_expr, n, struct_name, var, n
1867 )
1868 }
1869 SubtypeConstraint::ValueRange { min, max } => {
1870 let mut checks: Vec<String> = Vec::new();
1871 if let ConstraintValue::Integer(n) = min {
1872 checks.push(format!("{} >= {}", length_expr, n));
1873 }
1874 if let ConstraintValue::Integer(n) = max {
1875 checks.push(format!("{} <= {}", length_expr, n));
1876 }
1877
1878 let min_str = match min {
1879 ConstraintValue::Integer(n) => n.to_string(),
1880 _ => "0".to_string(),
1881 };
1882 let max_str = match max {
1883 ConstraintValue::Integer(n) => n.to_string(),
1884 _ => "MAX".to_string(),
1885 };
1886
1887 if checks.is_empty() {
1888 format!(" Ok({}({}))", struct_name, var)
1890 } else {
1891 format!(
1892 " if {} {{\n Ok({}({}))\n }} else {{\n Err(\"length must be in range {}..{}\")\n }}",
1893 checks.join(" && "), struct_name, var, min_str, max_str
1894 )
1895 }
1896 }
1897 _ => format!(" Ok({}({}))", struct_name, var),
1898 }
1899 }
1900
1901 fn generate_alphabet_validation(&self, var: &str, ranges: &[CharRange]) -> String {
1903 let struct_name = self.get_struct_name_from_var(var);
1904
1905 let range_checks: Vec<String> = ranges
1907 .iter()
1908 .map(|r| {
1909 if r.min == r.max {
1910 format!("ch == '{}'", r.min)
1911 } else {
1912 format!("(ch >= '{}' && ch <= '{}')", r.min, r.max)
1913 }
1914 })
1915 .collect();
1916
1917 let check_expr = range_checks.join(" || ");
1918
1919 let ranges_display: Vec<String> = ranges
1920 .iter()
1921 .map(|r| {
1922 if r.min == r.max {
1923 format!("'{}'", r.min)
1924 } else {
1925 format!("'{}'..'{}'", r.min, r.max)
1926 }
1927 })
1928 .collect();
1929
1930 format!(
1931 " for ch in {}.as_str().chars() {{\n if !({}) {{\n return Err(\"characters must be from: {}\");\n }}\n }}\n Ok({}({}))",
1932 var, check_expr, ranges_display.join(", "), struct_name, var
1933 )
1934 }
1935
1936 fn generate_pattern_validation(&mut self, var: &str, pattern: &str) -> String {
1938 let struct_name = self.get_struct_name_from_var(var);
1939
1940 let pattern_name = format!("PATTERN_{}", self.pattern_counter);
1942 self.pattern_counter += 1;
1943
1944 let mut result = String::new();
1946
1947 result.push_str(&format!(
1949 " #[cfg(feature = \"regex\")]\n {{\n static {}: Lazy<Regex> = Lazy::new(|| Regex::new(r\"{}\").unwrap());\n",
1950 pattern_name, pattern.replace("\"", "\\\"")
1951 ));
1952
1953 result.push_str(&format!(
1955 " if !{}.is_match({}.as_ref()) {{\n",
1956 pattern_name, var
1957 ));
1958 result.push_str(&format!(
1959 " return Err(format!(\"value does not match pattern: {}\"));\n",
1960 pattern.replace("\"", "\\\"")
1961 ));
1962 result.push_str(" }\n }\n");
1963
1964 result.push_str(" #[cfg(not(feature = \"regex\"))]\n");
1966 result.push_str(&format!(
1967 " // Pattern validation disabled (requires 'regex' feature): {}\n",
1968 pattern
1969 ));
1970
1971 result.push_str(&format!(" Ok({}({}))", struct_name, var));
1972
1973 result
1974 }
1975
1976 fn generate_containing_validation(&self, var: &str, contained_type: &Type) -> String {
1977 let struct_name = self.get_struct_name_from_var(var);
1978 let type_name = self.rust_type(contained_type);
1979
1980 let mut result = String::new();
1981
1982 result.push_str(" #[cfg(feature = \"validate_containing\")]\n");
1984 result.push_str(" {\n");
1985 result.push_str(" use synta::der::Decoder;\n");
1986 result.push_str(&format!(
1987 " // Validate that {} contains a valid DER-encoded {}\n",
1988 var, type_name
1989 ));
1990 result.push_str(&format!(" let bytes = {}.as_ref();\n", var));
1991 result.push_str(
1992 " let mut decoder = Decoder::new(bytes, synta::Encoding::Der)?;\n",
1993 );
1994 result.push_str(&format!(
1995 " let _decoded: {} = decoder.decode().map_err(|e| {{\n",
1996 type_name
1997 ));
1998 result.push_str(&format!(
1999 " format!(\"invalid {} in CONTAINING constraint: {{}}\", e)\n",
2000 type_name
2001 ));
2002 result.push_str(" })?;\n");
2003 result.push_str(" // Optionally verify complete consumption\n");
2004 result.push_str(" if !decoder.is_empty() {\n");
2005 result.push_str(&format!(" return Err(\"trailing bytes after {} in CONTAINING constraint\".into());\n", type_name));
2006 result.push_str(" }\n");
2007 result.push_str(" }\n");
2008
2009 result.push_str(" #[cfg(not(feature = \"validate_containing\"))]\n");
2011 result.push_str(&format!(
2012 " // CONTAINING validation disabled (requires 'validate_containing' feature): {}\n",
2013 type_name
2014 ));
2015
2016 result.push_str(&format!(" Ok({}({}))", struct_name, var));
2017
2018 result
2019 }
2020
2021 fn get_struct_name_from_var(&self, _var: &str) -> String {
2023 "Self".to_string()
2026 }
2027
2028 fn format_constraint_display(&self, constraint: &SubtypeConstraint) -> String {
2030 match constraint {
2031 SubtypeConstraint::SingleValue(val) => match val {
2032 ConstraintValue::Integer(n) => n.to_string(),
2033 ConstraintValue::NamedValue(name) => name.clone(),
2034 ConstraintValue::Min => "MIN".to_string(),
2035 ConstraintValue::Max => "MAX".to_string(),
2036 },
2037 SubtypeConstraint::ValueRange { min, max } => {
2038 let min_str = match min {
2039 ConstraintValue::Integer(n) => n.to_string(),
2040 ConstraintValue::Min => "MIN".to_string(),
2041 ConstraintValue::Max => "MAX".to_string(),
2042 ConstraintValue::NamedValue(n) => n.clone(),
2043 };
2044 let max_str = match max {
2045 ConstraintValue::Integer(n) => n.to_string(),
2046 ConstraintValue::Max => "MAX".to_string(),
2047 ConstraintValue::Min => "MIN".to_string(),
2048 ConstraintValue::NamedValue(n) => n.clone(),
2049 };
2050 format!("{}..{}", min_str, max_str)
2051 }
2052 SubtypeConstraint::Union(elements) => {
2053 let parts: Vec<String> = elements
2054 .iter()
2055 .map(|e| self.format_constraint_display(e))
2056 .collect();
2057 parts.join(" | ")
2058 }
2059 SubtypeConstraint::Intersection(elements) => {
2060 let parts: Vec<String> = elements
2061 .iter()
2062 .map(|e| format!("({})", self.format_constraint_display(e)))
2063 .collect();
2064 parts.join(" ^ ")
2065 }
2066 SubtypeConstraint::Complement(inner) => {
2067 format!("ALL EXCEPT {}", self.format_constraint_display(inner))
2068 }
2069 SubtypeConstraint::SizeConstraint(inner) => {
2070 format!("SIZE ({})", self.format_constraint_display(inner))
2071 }
2072 SubtypeConstraint::PermittedAlphabet(ranges) => {
2073 let range_strs: Vec<String> = ranges
2074 .iter()
2075 .map(|r| {
2076 if r.min == r.max {
2077 format!("\"{}\"", r.min)
2078 } else {
2079 format!("\"{}\"..\"{}\"", r.min, r.max)
2080 }
2081 })
2082 .collect();
2083 format!("FROM ({})", range_strs.join(" | "))
2084 }
2085 SubtypeConstraint::Pattern(pattern) => {
2086 format!("PATTERN \"{}\"", pattern)
2087 }
2088 SubtypeConstraint::ContainedSubtype(ty) => {
2089 format!("CONTAINING {}", self.rust_type(ty))
2090 }
2091 SubtypeConstraint::InnerType(inner) => {
2092 format!("inner type: {}", self.format_constraint_display(inner))
2093 }
2094 SubtypeConstraint::NamedBitList(bits) => {
2095 let names: Vec<String> = bits
2096 .iter()
2097 .map(|b| format!("{}({})", b.name, b.value))
2098 .collect();
2099 format!("{{ {} }}", names.join(", "))
2100 }
2101 }
2102 }
2103
2104 fn generate_sequence_type(
2105 &mut self,
2106 name: &str,
2107 fields: &[SequenceField],
2108 ) -> Result<(), std::fmt::Error> {
2109 let mut effective_fields: Vec<SequenceField> = Vec::with_capacity(fields.len());
2114 for field in fields {
2115 if let Some(anon) = anonymous_inner_type(&field.ty) {
2116 let anon_name = format!("{}{}", name, to_pascal_case(&field.name));
2117 self.generate_definition(&Definition {
2118 name: anon_name.clone(),
2119 ty: anon.clone(),
2120 })?;
2121 writeln!(&mut self.output)?;
2122 let new_ty = match &field.ty {
2123 Type::Tagged { tag, .. } => Type::Tagged {
2124 tag: tag.clone(),
2125 inner: Box::new(Type::TypeRef(anon_name)),
2126 },
2127 _ => Type::TypeRef(anon_name),
2128 };
2129 effective_fields.push(SequenceField {
2130 name: field.name.clone(),
2131 ty: new_ty,
2132 optional: field.optional,
2133 default: field.default.clone(),
2134 });
2135 } else {
2136 effective_fields.push(field.clone());
2137 }
2138 }
2139 let fields: &[SequenceField] = &effective_fields;
2140
2141 let all_optional = fields.iter().all(|f| f.optional && f.default.is_none());
2144 if all_optional {
2145 writeln!(
2146 &mut self.output,
2147 "#[derive(Debug, Clone, PartialEq, Default)]"
2148 )?;
2149 } else {
2150 writeln!(&mut self.output, "#[derive(Debug, Clone, PartialEq)]")?;
2151 }
2152 let attr = self.derive_cfg_attr("derive(Asn1Sequence)");
2153 writeln!(&mut self.output, "{}", attr)?;
2154
2155 let needs_lifetime = self.sequence_needs_lifetime(fields);
2157 if needs_lifetime {
2158 writeln!(&mut self.output, "pub struct {}<'a> {{", name)?;
2159 self.types_with_lifetimes.insert(name.to_string());
2161 } else {
2162 writeln!(&mut self.output, "pub struct {} {{", name)?;
2163 }
2164
2165 for field in fields {
2166 self.generate_field(field)?;
2167 }
2168
2169 writeln!(&mut self.output, "}}")?;
2170
2171 self.generate_format_asn1_impl(name, needs_lifetime)?;
2172
2173 Ok(())
2174 }
2175
2176 fn generate_set_type(
2177 &mut self,
2178 name: &str,
2179 fields: &[SequenceField],
2180 ) -> Result<(), std::fmt::Error> {
2181 let mut effective_fields: Vec<SequenceField> = Vec::with_capacity(fields.len());
2183 for field in fields {
2184 if let Some(anon) = anonymous_inner_type(&field.ty) {
2185 let anon_name = format!("{}{}", name, to_pascal_case(&field.name));
2186 self.generate_definition(&Definition {
2187 name: anon_name.clone(),
2188 ty: anon.clone(),
2189 })?;
2190 writeln!(&mut self.output)?;
2191 let new_ty = match &field.ty {
2192 Type::Tagged { tag, .. } => Type::Tagged {
2193 tag: tag.clone(),
2194 inner: Box::new(Type::TypeRef(anon_name)),
2195 },
2196 _ => Type::TypeRef(anon_name),
2197 };
2198 effective_fields.push(SequenceField {
2199 name: field.name.clone(),
2200 ty: new_ty,
2201 optional: field.optional,
2202 default: field.default.clone(),
2203 });
2204 } else {
2205 effective_fields.push(field.clone());
2206 }
2207 }
2208 let fields: &[SequenceField] = &effective_fields;
2209
2210 writeln!(&mut self.output, "#[derive(Debug, Clone, PartialEq)]")?;
2211 let attr = self.derive_cfg_attr("derive(Asn1Set)");
2212 writeln!(&mut self.output, "{}", attr)?;
2213
2214 let needs_lifetime = self.sequence_needs_lifetime(fields);
2216 if needs_lifetime {
2217 writeln!(&mut self.output, "pub struct {}<'a> {{", name)?;
2218 self.types_with_lifetimes.insert(name.to_string());
2220 } else {
2221 writeln!(&mut self.output, "pub struct {} {{", name)?;
2222 }
2223
2224 for field in fields {
2225 self.generate_field(field)?;
2226 }
2227
2228 writeln!(&mut self.output, "}}")?;
2229
2230 self.generate_format_asn1_impl(name, needs_lifetime)?;
2231
2232 Ok(())
2233 }
2234
2235 fn generate_choice_type(
2236 &mut self,
2237 name: &str,
2238 variants: &[ChoiceVariant],
2239 ) -> Result<(), std::fmt::Error> {
2240 let mut effective_variants: Vec<ChoiceVariant> = Vec::with_capacity(variants.len());
2245 for variant in variants {
2246 if let Some(anon) = anonymous_inner_type(&variant.ty) {
2247 let anon_name = format!("{}{}", name, to_pascal_case(&variant.name));
2248 self.generate_definition(&Definition {
2249 name: anon_name.clone(),
2250 ty: anon.clone(),
2251 })?;
2252 writeln!(&mut self.output)?;
2253 let new_ty = match &variant.ty {
2254 Type::Tagged { tag, .. } => Type::Tagged {
2255 tag: tag.clone(),
2256 inner: Box::new(Type::TypeRef(anon_name)),
2257 },
2258 _ => Type::TypeRef(anon_name),
2259 };
2260 effective_variants.push(ChoiceVariant {
2261 name: variant.name.clone(),
2262 ty: new_ty,
2263 });
2264 } else {
2265 effective_variants.push(variant.clone());
2266 }
2267 }
2268 let variants: &[ChoiceVariant] = &effective_variants;
2269
2270 writeln!(&mut self.output, "#[derive(Debug, Clone, PartialEq)]")?;
2271 let attr = self.derive_cfg_attr("derive(Asn1Choice)");
2272 writeln!(&mut self.output, "{}", attr)?;
2273
2274 let needs_lifetime = self.choice_needs_lifetime(variants);
2276 if needs_lifetime {
2277 writeln!(&mut self.output, "pub enum {}<'a> {{", name)?;
2278 self.types_with_lifetimes.insert(name.to_string());
2280 } else {
2281 writeln!(&mut self.output, "pub enum {} {{", name)?;
2282 }
2283
2284 for variant in variants {
2285 let variant_name = to_pascal_case(&variant.name);
2286
2287 let rust_type = if let Type::Tagged { tag, .. } = &variant.ty {
2292 if tag.class == TagClass::ContextSpecific && tag.tagging == Tagging::Implicit {
2293 let saved = self.config.string_type_mode.clone();
2294 self.config.string_type_mode = StringTypeMode::Owned;
2295 let ty = self.inline_sequence_of_types(&variant.ty);
2296 self.config.string_type_mode = saved;
2297 ty
2298 } else {
2299 self.inline_sequence_of_types(&variant.ty)
2300 }
2301 } else {
2302 self.inline_sequence_of_types(&variant.ty)
2303 };
2304
2305 if let Type::Tagged { tag, .. } = &variant.ty {
2307 match tag.class {
2308 TagClass::ContextSpecific => {
2309 let tagging_str = match tag.tagging {
2310 Tagging::Explicit => "explicit",
2311 Tagging::Implicit => "implicit",
2312 };
2313 let attr = self.field_derive_cfg_attr(&format!(
2314 "asn1(tag({}, {}))",
2315 tag.number, tagging_str
2316 ));
2317 writeln!(&mut self.output, "{}", attr)?;
2318 }
2319 TagClass::Application => {
2320 writeln!(
2321 &mut self.output,
2322 " // APPLICATION [{}] -- use asn1(application_tag) when supported",
2323 tag.number
2324 )?;
2325 let attr = self
2326 .field_derive_cfg_attr(&format!("asn1(tag({}, explicit))", tag.number));
2327 writeln!(&mut self.output, "{}", attr)?;
2328 }
2329 TagClass::Universal => {
2330 writeln!(&mut self.output, " // UNIVERSAL [{}]", tag.number)?;
2331 }
2332 TagClass::Private => {
2333 writeln!(&mut self.output, " // PRIVATE [{}]", tag.number)?;
2334 }
2335 }
2336 }
2337
2338 writeln!(&mut self.output, " {}({}),", variant_name, rust_type)?;
2339 }
2340
2341 writeln!(&mut self.output, "}}")?;
2342
2343 self.generate_format_asn1_impl(name, needs_lifetime)?;
2344
2345 Ok(())
2346 }
2347
2348 fn generate_sequence_of_type(
2349 &mut self,
2350 name: &str,
2351 inner: &Type,
2352 size_constraint: Option<&SizeConstraint>,
2353 ) -> Result<(), std::fmt::Error> {
2354 if matches!(inner, Type::Sequence(_) | Type::Set(_) | Type::Choice(_)) {
2357 let element_name = format!("{}Element", name);
2358 let element_def = Definition {
2359 name: element_name.clone(),
2360 ty: inner.clone(),
2361 };
2362 self.generate_definition(&element_def)?;
2363 writeln!(&mut self.output)?;
2364 if let Some(constraint) = size_constraint {
2365 let constraint_str = self.format_size_constraint(constraint);
2366 writeln!(&mut self.output, "// Constraint: {}", constraint_str)?;
2367 }
2368 let rust_type = format!("Vec<{}>", element_name);
2369 let seq_of_type = Type::SequenceOf(Box::new(inner.clone()), size_constraint.cloned());
2371 self.generate_type_alias(name, &rust_type, &seq_of_type)?;
2372 return Ok(());
2373 }
2374
2375 if let Type::Constrained {
2377 base_type,
2378 constraint,
2379 } = inner
2380 {
2381 let element_name = format!("{}Element", name);
2383
2384 match base_type.as_ref() {
2386 Type::Integer(_, _) => {
2387 if let ConstraintSpec::Subtype(ref subtype) = constraint.spec {
2388 self.generate_constrained_integer(&element_name, subtype)?;
2389 }
2390 }
2391 Type::IA5String(_)
2392 | Type::Utf8String(_)
2393 | Type::PrintableString(_)
2394 | Type::TeletexString(_)
2395 | Type::UniversalString(_)
2396 | Type::BmpString(_)
2397 | Type::GeneralString(_)
2398 | Type::NumericString(_)
2399 | Type::VisibleString(_) => {
2400 let base_type_str = self.rust_type(base_type);
2401 if let ConstraintSpec::Subtype(ref subtype) = constraint.spec {
2402 self.generate_constrained_string(&element_name, &base_type_str, subtype)?;
2403 }
2404 }
2405 _ => {
2406 let inner_type = self.rust_type(inner);
2408 writeln!(
2409 &mut self.output,
2410 "pub type {} = {};",
2411 element_name, inner_type
2412 )?;
2413 }
2414 }
2415
2416 writeln!(&mut self.output)?;
2417
2418 if let Some(constraint) = size_constraint {
2420 let constraint_str = self.format_size_constraint(constraint);
2421 writeln!(&mut self.output, "// Constraint: {}", constraint_str)?;
2422 }
2423 writeln!(
2424 &mut self.output,
2425 "pub type {} = Vec<{}>;",
2426 name, element_name
2427 )?;
2428 } else {
2429 if let Some(constraint) = size_constraint {
2431 let constraint_str = self.format_size_constraint(constraint);
2432 writeln!(&mut self.output, "// Constraint: {}", constraint_str)?;
2433 }
2434 let inner_type = self.rust_type(inner);
2435 let rust_type = format!("Vec<{}>", inner_type);
2436 let seq_of_type = Type::SequenceOf(Box::new(inner.clone()), size_constraint.cloned());
2438 self.generate_type_alias(name, &rust_type, &seq_of_type)?;
2439 }
2440 Ok(())
2441 }
2442
2443 fn generate_set_of_type(
2444 &mut self,
2445 name: &str,
2446 inner: &Type,
2447 size_constraint: Option<&SizeConstraint>,
2448 ) -> Result<(), std::fmt::Error> {
2449 if matches!(inner, Type::Sequence(_) | Type::Set(_) | Type::Choice(_)) {
2451 let element_name = format!("{}Element", name);
2452 let element_def = Definition {
2453 name: element_name.clone(),
2454 ty: inner.clone(),
2455 };
2456 self.generate_definition(&element_def)?;
2457 writeln!(&mut self.output)?;
2458 if let Some(constraint) = size_constraint {
2459 let constraint_str = self.format_size_constraint(constraint);
2460 writeln!(&mut self.output, "// Constraint: {}", constraint_str)?;
2461 }
2462 let rust_type = format!("SetOf<{}>", element_name);
2463 let seq_of_type = Type::SetOf(Box::new(inner.clone()), size_constraint.cloned());
2465 self.generate_type_alias(name, &rust_type, &seq_of_type)?;
2466 return Ok(());
2467 }
2468
2469 if let Type::Constrained {
2471 base_type,
2472 constraint,
2473 } = inner
2474 {
2475 let element_name = format!("{}Element", name);
2477
2478 match base_type.as_ref() {
2480 Type::Integer(_, _) => {
2481 if let ConstraintSpec::Subtype(ref subtype) = constraint.spec {
2482 self.generate_constrained_integer(&element_name, subtype)?;
2483 }
2484 }
2485 Type::IA5String(_)
2486 | Type::Utf8String(_)
2487 | Type::PrintableString(_)
2488 | Type::TeletexString(_)
2489 | Type::UniversalString(_)
2490 | Type::BmpString(_)
2491 | Type::GeneralString(_)
2492 | Type::NumericString(_)
2493 | Type::VisibleString(_) => {
2494 let base_type_str = self.rust_type(base_type);
2495 if let ConstraintSpec::Subtype(ref subtype) = constraint.spec {
2496 self.generate_constrained_string(&element_name, &base_type_str, subtype)?;
2497 }
2498 }
2499 _ => {
2500 let inner_type = self.rust_type(inner);
2502 writeln!(
2503 &mut self.output,
2504 "pub type {} = {};",
2505 element_name, inner_type
2506 )?;
2507 }
2508 }
2509
2510 writeln!(&mut self.output)?;
2511
2512 if let Some(constraint) = size_constraint {
2514 let constraint_str = self.format_size_constraint(constraint);
2515 writeln!(&mut self.output, "// Constraint: {}", constraint_str)?;
2516 }
2517 writeln!(
2518 &mut self.output,
2519 "pub type {} = SetOf<{}>;",
2520 name, element_name
2521 )?;
2522 } else {
2523 if let Some(constraint) = size_constraint {
2525 let constraint_str = self.format_size_constraint(constraint);
2526 writeln!(&mut self.output, "// Constraint: {}", constraint_str)?;
2527 }
2528 let inner_type = self.rust_type(inner);
2529 let rust_type = format!("SetOf<{}>", inner_type);
2530 let seq_of_type = Type::SetOf(Box::new(inner.clone()), size_constraint.cloned());
2532 self.generate_type_alias(name, &rust_type, &seq_of_type)?;
2533 }
2534 Ok(())
2535 }
2536
2537 fn resolves_to_any(&self, ty: &Type) -> bool {
2540 match ty {
2541 Type::Any | Type::AnyDefinedBy(_) => true,
2542 Type::TypeRef(name) => {
2543 let clean = name.trim_end_matches("{}");
2544 matches!(
2545 self.type_definitions.get(clean),
2546 Some(Type::Any) | Some(Type::AnyDefinedBy(_))
2547 )
2548 }
2549 _ => false,
2550 }
2551 }
2552
2553 fn generate_field(&mut self, field: &SequenceField) -> Result<(), std::fmt::Error> {
2554 let field_name = to_snake_case(&field.name);
2555 let rust_type = self.inline_sequence_of_types(&field.ty);
2557
2558 if let Type::Tagged { tag, inner } = &field.ty {
2560 let tagging = match tag.tagging {
2561 Tagging::Explicit => "explicit",
2562 Tagging::Implicit => "implicit",
2563 };
2564 match tag.class {
2565 TagClass::ContextSpecific => {
2566 let attr = self
2567 .field_derive_cfg_attr(&format!("asn1(tag({}, {}))", tag.number, tagging));
2568 writeln!(&mut self.output, "{}", attr)?;
2569 if self.config.any_as_raw_der
2576 && tag.tagging == Tagging::Implicit
2577 && self.resolves_to_any(inner)
2578 {
2579 let rawder_attr = self.field_derive_cfg_attr("asn1(rawder)");
2580 writeln!(&mut self.output, "{}", rawder_attr)?;
2581 }
2582 }
2583 TagClass::Application => {
2584 writeln!(
2585 &mut self.output,
2586 " // APPLICATION [{} {}] -- use asn1(application_tag) when supported",
2587 tag.number, tagging
2588 )?;
2589 let attr = self
2590 .field_derive_cfg_attr(&format!("asn1(tag({}, {}))", tag.number, tagging));
2591 writeln!(&mut self.output, "{}", attr)?;
2592 }
2593 TagClass::Universal => {
2594 writeln!(
2595 &mut self.output,
2596 " // UNIVERSAL [{}] {}",
2597 tag.number, tagging
2598 )?;
2599 }
2600 TagClass::Private => {
2601 writeln!(
2602 &mut self.output,
2603 " // PRIVATE [{}] {}",
2604 tag.number, tagging
2605 )?;
2606 }
2607 }
2608 }
2609
2610 if field.optional || field.default.is_some() {
2613 let attr = self.field_derive_cfg_attr("asn1(optional)");
2614 writeln!(&mut self.output, "{}", attr)?;
2615 }
2616
2617 let rust_type = if self.config.raw_der_fields.contains(&field_name) {
2619 "RawDer<'a>".to_string()
2620 } else {
2621 rust_type
2622 };
2623
2624 let final_type = if field.optional || field.default.is_some() {
2626 format!("Option<{}>", rust_type)
2627 } else {
2628 rust_type
2629 };
2630
2631 writeln!(&mut self.output, " pub {}: {},", field_name, final_type)?;
2632
2633 Ok(())
2634 }
2635
2636 fn generate_subtype(
2638 &mut self,
2639 type_name: &str,
2640 base_type: &Type,
2641 constraint: &SubtypeConstraint,
2642 ) -> Result<(), std::fmt::Error> {
2643 let base_type_name = self.rust_type(base_type);
2644 let constraint_display = self.format_constraint_display(constraint);
2645
2646 writeln!(
2648 &mut self.output,
2649 "/// {} ({})",
2650 base_type_name, constraint_display
2651 )?;
2652
2653 writeln!(
2655 &mut self.output,
2656 "#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]"
2657 )?;
2658 writeln!(
2659 &mut self.output,
2660 "pub struct {}({});",
2661 type_name, base_type_name
2662 )?;
2663 writeln!(&mut self.output)?;
2664
2665 writeln!(&mut self.output, "impl {} {{", type_name)?;
2666
2667 let validation_code = self.generate_subtype_validation("val", constraint)?;
2670
2671 writeln!(
2672 &mut self.output,
2673 " /// Create a new {} with validation",
2674 type_name
2675 )?;
2676 writeln!(
2677 &mut self.output,
2678 " pub fn new(value: {}) -> Result<Self, &'static str> {{",
2679 base_type_name
2680 )?;
2681
2682 let is_integer_constraint = matches!(
2684 constraint,
2685 SubtypeConstraint::SingleValue(_)
2686 | SubtypeConstraint::ValueRange { .. }
2687 | SubtypeConstraint::Union(_)
2688 | SubtypeConstraint::Intersection(_)
2689 | SubtypeConstraint::Complement(_)
2690 );
2691
2692 let description = self.generate_constraint_description(constraint);
2693
2694 if is_integer_constraint {
2695 writeln!(&mut self.output, " let val = value.into_inner();")?;
2696 writeln!(&mut self.output, " if {} {{", validation_code)?;
2697 writeln!(&mut self.output, " Ok({}(value))", type_name)?;
2698 writeln!(&mut self.output, " }} else {{")?;
2699 writeln!(&mut self.output, " Err(\"{}\")", description)?;
2700 writeln!(&mut self.output, " }}")?;
2701 } else {
2702 let validation_code =
2704 self.generate_string_validation("value", &base_type_name, constraint);
2705 write!(&mut self.output, "{}", validation_code)?;
2706 }
2707
2708 writeln!(&mut self.output, " }}")?;
2709 writeln!(&mut self.output)?;
2710
2711 writeln!(
2713 &mut self.output,
2714 " /// Create without validation (use with caution)"
2715 )?;
2716 writeln!(
2717 &mut self.output,
2718 " pub const fn new_unchecked(value: {}) -> Self {{",
2719 base_type_name
2720 )?;
2721 writeln!(&mut self.output, " {}(value)", type_name)?;
2722 writeln!(&mut self.output, " }}")?;
2723 writeln!(&mut self.output)?;
2724
2725 writeln!(&mut self.output, " /// Get the inner value")?;
2727 writeln!(
2728 &mut self.output,
2729 " pub const fn get(&self) -> &{} {{",
2730 base_type_name
2731 )?;
2732 writeln!(&mut self.output, " &self.0")?;
2733 writeln!(&mut self.output, " }}")?;
2734 writeln!(&mut self.output)?;
2735
2736 writeln!(
2738 &mut self.output,
2739 " /// Consume and return the inner value"
2740 )?;
2741 writeln!(
2742 &mut self.output,
2743 " pub fn into_inner(self) -> {} {{",
2744 base_type_name
2745 )?;
2746 writeln!(&mut self.output, " self.0")?;
2747 writeln!(&mut self.output, " }}")?;
2748
2749 writeln!(&mut self.output, "}}")?;
2750 writeln!(&mut self.output)?;
2751
2752 let try_from_path = self.try_from_path();
2754 writeln!(
2755 &mut self.output,
2756 "impl {}::convert::TryFrom<{}> for {} {{",
2757 try_from_path, base_type_name, type_name
2758 )?;
2759 writeln!(&mut self.output, " type Error = &'static str;")?;
2760 writeln!(&mut self.output)?;
2761 writeln!(
2762 &mut self.output,
2763 " fn try_from(value: {}) -> Result<Self, Self::Error> {{",
2764 base_type_name
2765 )?;
2766 writeln!(&mut self.output, " Self::new(value)")?;
2767 writeln!(&mut self.output, " }}")?;
2768 writeln!(&mut self.output, "}}")?;
2769
2770 Ok(())
2771 }
2772
2773 fn generate_subtype_validation(
2775 &mut self,
2776 var: &str,
2777 constraint: &SubtypeConstraint,
2778 ) -> Result<String, std::fmt::Error> {
2779 Ok(self.generate_constraint_validation(var, constraint))
2782 }
2783
2784 fn generate_format_asn1_impl(
2791 &mut self,
2792 name: &str,
2793 has_lifetime: bool,
2794 ) -> Result<(), std::fmt::Error> {
2795 writeln!(&mut self.output)?;
2796 if has_lifetime {
2797 writeln!(&mut self.output, "impl<'a> {}<'a> {{", name)?;
2798 } else {
2799 writeln!(&mut self.output, "impl {} {{", name)?;
2800 }
2801 writeln!(
2802 &mut self.output,
2803 " /// Format the encoded DER bytes of this value."
2804 )?;
2805 writeln!(&mut self.output, " ///")?;
2806 writeln!(
2807 &mut self.output,
2808 " /// `mode` controls the output style:"
2809 )?;
2810 writeln!(
2811 &mut self.output,
2812 " /// - [`synta::Asn1FormatMode::Hex`] — space-separated uppercase hex bytes"
2813 )?;
2814 writeln!(
2815 &mut self.output,
2816 " /// - [`synta::Asn1FormatMode::Text`] — indented human-readable ASN.1 dump"
2817 )?;
2818 writeln!(
2819 &mut self.output,
2820 " pub fn format_asn1(&self, mode: synta::Asn1FormatMode) -> String {{"
2821 )?;
2822 writeln!(&mut self.output, " use synta::Encode;")?;
2823 writeln!(
2824 &mut self.output,
2825 " let mut encoder = synta::Encoder::new(synta::Encoding::Der);"
2826 )?;
2827 writeln!(
2828 &mut self.output,
2829 " if self.encode(&mut encoder).is_err() {{"
2830 )?;
2831 writeln!(
2832 &mut self.output,
2833 " return String::from(\"<encode error>\");"
2834 )?;
2835 writeln!(&mut self.output, " }}")?;
2836 writeln!(&mut self.output, " match encoder.finish() {{")?;
2837 writeln!(
2838 &mut self.output,
2839 " Ok(bytes) => synta::format_asn1_bytes(&bytes, mode),"
2840 )?;
2841 writeln!(
2842 &mut self.output,
2843 " Err(_) => String::from(\"<encode error>\"),"
2844 )?;
2845 writeln!(&mut self.output, " }}")?;
2846 writeln!(&mut self.output, " }}")?;
2847 writeln!(&mut self.output, "}}")?;
2848 Ok(())
2849 }
2850
2851 #[inline]
2859 fn string_rust_type(&self, owned: &str, borrowed: &str) -> String {
2860 match self.config.string_type_mode {
2861 StringTypeMode::Owned => owned.to_string(),
2862 StringTypeMode::Borrowed => format!("{}<'a>", borrowed),
2863 }
2864 }
2865
2866 fn rust_type(&self, ty: &Type) -> String {
2867 match ty {
2868 Type::Integer(_, _) => "Integer".to_string(),
2869 Type::Enumerated(_) => "Enumerated".to_string(),
2870 Type::Real => "f64".to_string(),
2871 Type::Boolean => "Boolean".to_string(),
2872 Type::OctetString(_) => self.string_rust_type("OctetString", "OctetStringRef"),
2874 Type::BitString(_) => self.string_rust_type("BitString", "BitStringRef"),
2875 Type::Utf8String(_) => self.string_rust_type("Utf8String", "Utf8StringRef"),
2876 Type::PrintableString(_) => {
2877 self.string_rust_type("PrintableString", "PrintableStringRef")
2878 }
2879 Type::IA5String(_) => self.string_rust_type("IA5String", "IA5StringRef"),
2880 Type::ObjectIdentifier => "ObjectIdentifier".to_string(),
2881 Type::Null => "Null".to_string(),
2882 Type::TeletexString(_) => "TeletexString".to_string(),
2884 Type::UniversalString(_) => "UniversalString".to_string(),
2885 Type::BmpString(_) => "BmpString".to_string(),
2886 Type::GeneralString(_) => "GeneralString".to_string(),
2887 Type::NumericString(_) => "NumericString".to_string(),
2888 Type::VisibleString(_) => "VisibleString".to_string(),
2889 Type::UtcTime => "UtcTime".to_string(),
2890 Type::GeneralizedTime => "GeneralizedTime".to_string(),
2891 Type::TypeRef(name) => {
2892 let type_name = to_pascal_case(name);
2893
2894 if let Some(lifetime) = self.config.imported_type_lifetimes.get(name) {
2900 return format!("{}<{}>", type_name, lifetime);
2901 }
2902
2903 if self.types_with_lifetimes.contains(&type_name) {
2905 return format!("{}<'a>", type_name);
2906 }
2907
2908 type_name
2909 }
2910 Type::Class(_) => "/* class */".to_string(),
2911 Type::Sequence(_) => "/* nested sequence */".to_string(),
2912 Type::Set(_) => "/* nested set */".to_string(),
2913 Type::Choice(_) => "/* nested choice */".to_string(),
2914 Type::SequenceOf(inner, _) => format!("Vec<{}>", self.rust_type(inner)),
2915 Type::SetOf(inner, _) => format!("SetOf<{}>", self.rust_type(inner)),
2916 Type::Tagged { inner, .. } => self.rust_type(inner),
2917 Type::Constrained { base_type, .. } => self.rust_type(base_type),
2918 Type::Any => {
2919 if self.config.any_as_raw_der {
2920 "RawDer<'a>".to_string()
2921 } else {
2922 "Element<'a>".to_string()
2923 }
2924 }
2925 Type::AnyDefinedBy(_) => {
2926 if self.config.any_as_raw_der {
2927 "RawDer<'a>".to_string()
2928 } else {
2929 "Element<'a>".to_string()
2930 }
2931 }
2932 }
2933 }
2934
2935 fn type_needs_lifetime(&self, ty: &Type) -> bool {
2948 match ty {
2949 Type::OctetString(_)
2951 | Type::BitString(_)
2952 | Type::Utf8String(_)
2953 | Type::PrintableString(_)
2954 | Type::IA5String(_) => self.config.string_type_mode == StringTypeMode::Borrowed,
2955 Type::Any => true, Type::AnyDefinedBy(_) => true, Type::TypeRef(name) => {
2959 let type_name = to_pascal_case(name);
2960
2961 if self.config.imported_type_lifetimes.contains_key(name) {
2964 return true;
2965 }
2966
2967 if self.types_with_lifetimes.contains(&type_name) {
2969 return true;
2970 }
2971
2972 false
2973 }
2974 Type::SequenceOf(inner, _) | Type::SetOf(inner, _) => self.type_needs_lifetime(inner),
2975 Type::Tagged { inner, .. }
2976 | Type::Constrained {
2977 base_type: inner, ..
2978 } => self.type_needs_lifetime(inner),
2979 Type::Sequence(fields) => fields.iter().any(|f| self.type_needs_lifetime(&f.ty)),
2980 Type::Set(fields) => fields.iter().any(|f| self.type_needs_lifetime(&f.ty)),
2981 Type::Choice(variants) => variants.iter().any(|v| self.type_needs_lifetime(&v.ty)),
2982 _ => false,
2983 }
2984 }
2985
2986 fn sequence_needs_lifetime(&self, fields: &[SequenceField]) -> bool {
2988 fields.iter().any(|field| {
2989 let field_name = to_snake_case(&field.name);
2990 self.config.raw_der_fields.contains(&field_name) || self.type_needs_lifetime(&field.ty)
2991 })
2992 }
2993
2994 fn choice_needs_lifetime(&self, variants: &[ChoiceVariant]) -> bool {
2996 variants
3002 .iter()
3003 .any(|variant| self.type_needs_lifetime(&variant.ty))
3004 }
3005
3006 fn generate_type_alias(
3008 &mut self,
3009 type_name: &str,
3010 rust_type: &str,
3011 asn1_type: &Type,
3012 ) -> Result<(), std::fmt::Error> {
3013 let needs_lifetime = self.type_needs_lifetime(asn1_type);
3017
3018 if needs_lifetime {
3019 writeln!(
3020 &mut self.output,
3021 "pub type {}<'a> = {};",
3022 type_name, rust_type
3023 )?;
3024 self.types_with_lifetimes.insert(type_name.to_string());
3027 } else {
3028 writeln!(&mut self.output, "pub type {} = {};", type_name, rust_type)?;
3029 }
3030 Ok(())
3031 }
3032
3033 fn build_oid_registry(
3035 &self,
3036 values: &[crate::ast::ValueAssignment],
3037 ) -> std::collections::HashMap<String, Vec<u32>> {
3038 use std::collections::HashMap;
3039 let mut registry: HashMap<String, Vec<u32>> = HashMap::new();
3040
3041 let mut changed = true;
3043 while changed {
3044 changed = false;
3045 for value_assignment in values {
3046 if registry.contains_key(&value_assignment.name) {
3047 continue;
3048 }
3049
3050 if let crate::ast::Value::ObjectIdentifier(components) = &value_assignment.value {
3051 let mut resolved = Vec::new();
3052 let mut can_resolve = true;
3053
3054 for component in components {
3055 match component {
3056 crate::ast::OidComponent::Number(n) => {
3057 resolved.push(*n);
3058 }
3059 crate::ast::OidComponent::NamedRef(name) => {
3060 if let Some(base_oid) = registry.get(name) {
3061 resolved.extend_from_slice(base_oid);
3062 } else {
3063 can_resolve = false;
3064 break;
3065 }
3066 }
3067 }
3068 }
3069
3070 if can_resolve {
3071 registry.insert(value_assignment.name.clone(), resolved);
3072 changed = true;
3073 }
3074 }
3075 }
3076 }
3077
3078 registry
3079 }
3080
3081 fn generate_value_assignment(
3083 &mut self,
3084 value_assignment: &crate::ast::ValueAssignment,
3085 oid_registry: &std::collections::HashMap<String, Vec<u32>>,
3086 ) -> Result<(), std::fmt::Error> {
3087 let const_name = to_screaming_snake_case(&value_assignment.name);
3088
3089 match &value_assignment.value {
3090 crate::ast::Value::ObjectIdentifier(_components) => {
3091 if let Some(oid_values) = oid_registry.get(&value_assignment.name) {
3093 write!(&mut self.output, "pub const {}: &[u32] = &[", const_name)?;
3095 for (i, value) in oid_values.iter().enumerate() {
3096 if i > 0 {
3097 write!(&mut self.output, ", ")?;
3098 }
3099 write!(&mut self.output, "{}", value)?;
3100 }
3101 writeln!(&mut self.output, "];")?;
3102 } else {
3103 writeln!(
3105 &mut self.output,
3106 "// Note: Could not resolve OID for {}",
3107 value_assignment.name
3108 )?;
3109 }
3110 }
3111 crate::ast::Value::Integer(n) => {
3112 writeln!(&mut self.output, "pub const {}: i64 = {};", const_name, n)?;
3113 }
3114 crate::ast::Value::Boolean(b) => {
3115 writeln!(&mut self.output, "pub const {}: bool = {};", const_name, b)?;
3116 }
3117 crate::ast::Value::String(s) => {
3118 writeln!(
3119 &mut self.output,
3120 "pub const {}: &str = \"{}\";",
3121 const_name, s
3122 )?;
3123 }
3124 }
3125
3126 Ok(())
3127 }
3128
3129 fn prescan_types_for_lifetimes(&mut self, definitions: &[Definition]) {
3132 let mut changed = true;
3134 while changed {
3135 changed = false;
3136
3137 for def in definitions {
3138 let type_name = to_pascal_case(&def.name);
3140 if self.types_with_lifetimes.contains(&type_name) {
3141 continue;
3142 }
3143 if self.config.skip_imported_types.contains(&def.name) {
3144 continue;
3145 }
3146
3147 let needs_lifetime = match &def.ty {
3149 Type::Sequence(fields) => self.sequence_needs_lifetime(fields),
3150 Type::Set(fields) => self.sequence_needs_lifetime(fields),
3151 Type::Choice(variants) => self.choice_needs_lifetime(variants),
3152 Type::Constrained {
3154 base_type: _,
3155 constraint,
3156 } => match constraint.spec {
3157 ConstraintSpec::Subtype(SubtypeConstraint::NamedBitList(_)) => false,
3158 ConstraintSpec::Subtype(SubtypeConstraint::Intersection(
3159 ref constraints,
3160 )) if constraints
3161 .iter()
3162 .any(|c| matches!(c, SubtypeConstraint::NamedBitList(_))) =>
3163 {
3164 false
3165 }
3166 _ => self.type_needs_lifetime(&def.ty),
3167 },
3168 other => self.type_needs_lifetime(other),
3170 };
3171
3172 if needs_lifetime {
3173 self.types_with_lifetimes.insert(type_name);
3174 changed = true;
3175 }
3176 }
3177 }
3178 }
3179
3180 fn inline_sequence_of_types(&self, ty: &Type) -> String {
3183 match ty {
3184 Type::TypeRef(type_ref_name) => {
3185 let type_name = to_pascal_case(type_ref_name);
3186 if let Some(def_type) = self.type_definitions.get(&type_name) {
3187 match def_type {
3188 Type::SequenceOf(inner, _) => {
3189 let inner_rust_type = self.inline_sequence_of_types(inner);
3191 format!("Vec<{}>", inner_rust_type)
3192 }
3193 Type::SetOf(inner, _) => {
3194 let inner_rust_type = self.inline_sequence_of_types(inner);
3196 format!("SetOf<{}>", inner_rust_type)
3197 }
3198 _ => self.rust_type(ty),
3199 }
3200 } else {
3201 self.rust_type(ty)
3202 }
3203 }
3204 Type::Tagged { inner, .. } => self.inline_sequence_of_types(inner),
3206 Type::Constrained { base_type, .. } => self.inline_sequence_of_types(base_type),
3208 _ => self.rust_type(ty),
3209 }
3210 }
3211}
3212
3213impl Default for CodeGenerator {
3214 fn default() -> Self {
3215 Self::new()
3216 }
3217}
3218
3219fn anonymous_inner_type(ty: &Type) -> Option<&Type> {
3226 let candidate = match ty {
3227 Type::Tagged { inner, .. } => inner.as_ref(),
3228 Type::Constrained { base_type, .. } => base_type.as_ref(),
3229 other => other,
3230 };
3231 matches!(
3232 candidate,
3233 Type::Sequence(_) | Type::Set(_) | Type::Choice(_)
3234 )
3235 .then_some(candidate)
3236}
3237
3238pub fn generate(module: &Module) -> Result<String, std::fmt::Error> {
3245 let mut gen = CodeGenerator::new();
3246 gen.generate_module(module)
3247}
3248
3249pub fn generate_with_config(
3265 module: &Module,
3266 config: CodeGenConfig,
3267) -> Result<String, std::fmt::Error> {
3268 let mut gen = CodeGenerator::with_config(config);
3269 gen.generate_module(module)
3270}