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 all_optional = fields.iter().all(|f| f.optional && f.default.is_none());
2112 if all_optional {
2113 writeln!(
2114 &mut self.output,
2115 "#[derive(Debug, Clone, PartialEq, Default)]"
2116 )?;
2117 } else {
2118 writeln!(&mut self.output, "#[derive(Debug, Clone, PartialEq)]")?;
2119 }
2120 let attr = self.derive_cfg_attr("derive(Asn1Sequence)");
2121 writeln!(&mut self.output, "{}", attr)?;
2122
2123 let needs_lifetime = self.sequence_needs_lifetime(fields);
2125 if needs_lifetime {
2126 writeln!(&mut self.output, "pub struct {}<'a> {{", name)?;
2127 self.types_with_lifetimes.insert(name.to_string());
2129 } else {
2130 writeln!(&mut self.output, "pub struct {} {{", name)?;
2131 }
2132
2133 for field in fields {
2134 self.generate_field(field)?;
2135 }
2136
2137 writeln!(&mut self.output, "}}")?;
2138
2139 self.generate_format_asn1_impl(name, needs_lifetime)?;
2140
2141 Ok(())
2142 }
2143
2144 fn generate_set_type(
2145 &mut self,
2146 name: &str,
2147 fields: &[SequenceField],
2148 ) -> Result<(), std::fmt::Error> {
2149 writeln!(&mut self.output, "#[derive(Debug, Clone, PartialEq)]")?;
2150 let attr = self.derive_cfg_attr("derive(Asn1Set)");
2151 writeln!(&mut self.output, "{}", attr)?;
2152
2153 let needs_lifetime = self.sequence_needs_lifetime(fields);
2155 if needs_lifetime {
2156 writeln!(&mut self.output, "pub struct {}<'a> {{", name)?;
2157 self.types_with_lifetimes.insert(name.to_string());
2159 } else {
2160 writeln!(&mut self.output, "pub struct {} {{", name)?;
2161 }
2162
2163 for field in fields {
2164 self.generate_field(field)?;
2165 }
2166
2167 writeln!(&mut self.output, "}}")?;
2168
2169 self.generate_format_asn1_impl(name, needs_lifetime)?;
2170
2171 Ok(())
2172 }
2173
2174 fn generate_choice_type(
2175 &mut self,
2176 name: &str,
2177 variants: &[ChoiceVariant],
2178 ) -> Result<(), std::fmt::Error> {
2179 writeln!(&mut self.output, "#[derive(Debug, Clone, PartialEq)]")?;
2180 let attr = self.derive_cfg_attr("derive(Asn1Choice)");
2181 writeln!(&mut self.output, "{}", attr)?;
2182
2183 let needs_lifetime = self.choice_needs_lifetime(variants);
2185 if needs_lifetime {
2186 writeln!(&mut self.output, "pub enum {}<'a> {{", name)?;
2187 self.types_with_lifetimes.insert(name.to_string());
2189 } else {
2190 writeln!(&mut self.output, "pub enum {} {{", name)?;
2191 }
2192
2193 for variant in variants {
2194 let variant_name = to_pascal_case(&variant.name);
2195
2196 let rust_type = if let Type::Tagged { tag, .. } = &variant.ty {
2201 if tag.class == TagClass::ContextSpecific && tag.tagging == Tagging::Implicit {
2202 let saved = self.config.string_type_mode.clone();
2203 self.config.string_type_mode = StringTypeMode::Owned;
2204 let ty = self.inline_sequence_of_types(&variant.ty);
2205 self.config.string_type_mode = saved;
2206 ty
2207 } else {
2208 self.inline_sequence_of_types(&variant.ty)
2209 }
2210 } else {
2211 self.inline_sequence_of_types(&variant.ty)
2212 };
2213
2214 if let Type::Tagged { tag, .. } = &variant.ty {
2216 match tag.class {
2217 TagClass::ContextSpecific => {
2218 let tagging_str = match tag.tagging {
2219 Tagging::Explicit => "explicit",
2220 Tagging::Implicit => "implicit",
2221 };
2222 let attr = self.field_derive_cfg_attr(&format!(
2223 "asn1(tag({}, {}))",
2224 tag.number, tagging_str
2225 ));
2226 writeln!(&mut self.output, "{}", attr)?;
2227 }
2228 TagClass::Application => {
2229 writeln!(
2230 &mut self.output,
2231 " // APPLICATION [{}] -- use asn1(application_tag) when supported",
2232 tag.number
2233 )?;
2234 let attr = self
2235 .field_derive_cfg_attr(&format!("asn1(tag({}, explicit))", tag.number));
2236 writeln!(&mut self.output, "{}", attr)?;
2237 }
2238 TagClass::Universal => {
2239 writeln!(&mut self.output, " // UNIVERSAL [{}]", tag.number)?;
2240 }
2241 TagClass::Private => {
2242 writeln!(&mut self.output, " // PRIVATE [{}]", tag.number)?;
2243 }
2244 }
2245 }
2246
2247 writeln!(&mut self.output, " {}({}),", variant_name, rust_type)?;
2248 }
2249
2250 writeln!(&mut self.output, "}}")?;
2251
2252 self.generate_format_asn1_impl(name, needs_lifetime)?;
2253
2254 Ok(())
2255 }
2256
2257 fn generate_sequence_of_type(
2258 &mut self,
2259 name: &str,
2260 inner: &Type,
2261 size_constraint: Option<&SizeConstraint>,
2262 ) -> Result<(), std::fmt::Error> {
2263 if matches!(inner, Type::Sequence(_) | Type::Set(_) | Type::Choice(_)) {
2266 let element_name = format!("{}Element", name);
2267 let element_def = Definition {
2268 name: element_name.clone(),
2269 ty: inner.clone(),
2270 };
2271 self.generate_definition(&element_def)?;
2272 writeln!(&mut self.output)?;
2273 if let Some(constraint) = size_constraint {
2274 let constraint_str = self.format_size_constraint(constraint);
2275 writeln!(&mut self.output, "// Constraint: {}", constraint_str)?;
2276 }
2277 let rust_type = format!("Vec<{}>", element_name);
2278 let seq_of_type = Type::SequenceOf(Box::new(inner.clone()), size_constraint.cloned());
2280 self.generate_type_alias(name, &rust_type, &seq_of_type)?;
2281 return Ok(());
2282 }
2283
2284 if let Type::Constrained {
2286 base_type,
2287 constraint,
2288 } = inner
2289 {
2290 let element_name = format!("{}Element", name);
2292
2293 match base_type.as_ref() {
2295 Type::Integer(_, _) => {
2296 if let ConstraintSpec::Subtype(ref subtype) = constraint.spec {
2297 self.generate_constrained_integer(&element_name, subtype)?;
2298 }
2299 }
2300 Type::IA5String(_)
2301 | Type::Utf8String(_)
2302 | Type::PrintableString(_)
2303 | Type::TeletexString(_)
2304 | Type::UniversalString(_)
2305 | Type::BmpString(_)
2306 | Type::GeneralString(_)
2307 | Type::NumericString(_)
2308 | Type::VisibleString(_) => {
2309 let base_type_str = self.rust_type(base_type);
2310 if let ConstraintSpec::Subtype(ref subtype) = constraint.spec {
2311 self.generate_constrained_string(&element_name, &base_type_str, subtype)?;
2312 }
2313 }
2314 _ => {
2315 let inner_type = self.rust_type(inner);
2317 writeln!(
2318 &mut self.output,
2319 "pub type {} = {};",
2320 element_name, inner_type
2321 )?;
2322 }
2323 }
2324
2325 writeln!(&mut self.output)?;
2326
2327 if let Some(constraint) = size_constraint {
2329 let constraint_str = self.format_size_constraint(constraint);
2330 writeln!(&mut self.output, "// Constraint: {}", constraint_str)?;
2331 }
2332 writeln!(
2333 &mut self.output,
2334 "pub type {} = Vec<{}>;",
2335 name, element_name
2336 )?;
2337 } else {
2338 if let Some(constraint) = size_constraint {
2340 let constraint_str = self.format_size_constraint(constraint);
2341 writeln!(&mut self.output, "// Constraint: {}", constraint_str)?;
2342 }
2343 let inner_type = self.rust_type(inner);
2344 let rust_type = format!("Vec<{}>", inner_type);
2345 let seq_of_type = Type::SequenceOf(Box::new(inner.clone()), size_constraint.cloned());
2347 self.generate_type_alias(name, &rust_type, &seq_of_type)?;
2348 }
2349 Ok(())
2350 }
2351
2352 fn generate_set_of_type(
2353 &mut self,
2354 name: &str,
2355 inner: &Type,
2356 size_constraint: Option<&SizeConstraint>,
2357 ) -> Result<(), std::fmt::Error> {
2358 if matches!(inner, Type::Sequence(_) | Type::Set(_) | Type::Choice(_)) {
2360 let element_name = format!("{}Element", name);
2361 let element_def = Definition {
2362 name: element_name.clone(),
2363 ty: inner.clone(),
2364 };
2365 self.generate_definition(&element_def)?;
2366 writeln!(&mut self.output)?;
2367 if let Some(constraint) = size_constraint {
2368 let constraint_str = self.format_size_constraint(constraint);
2369 writeln!(&mut self.output, "// Constraint: {}", constraint_str)?;
2370 }
2371 let rust_type = format!("SetOf<{}>", element_name);
2372 let seq_of_type = Type::SetOf(Box::new(inner.clone()), size_constraint.cloned());
2374 self.generate_type_alias(name, &rust_type, &seq_of_type)?;
2375 return Ok(());
2376 }
2377
2378 if let Type::Constrained {
2380 base_type,
2381 constraint,
2382 } = inner
2383 {
2384 let element_name = format!("{}Element", name);
2386
2387 match base_type.as_ref() {
2389 Type::Integer(_, _) => {
2390 if let ConstraintSpec::Subtype(ref subtype) = constraint.spec {
2391 self.generate_constrained_integer(&element_name, subtype)?;
2392 }
2393 }
2394 Type::IA5String(_)
2395 | Type::Utf8String(_)
2396 | Type::PrintableString(_)
2397 | Type::TeletexString(_)
2398 | Type::UniversalString(_)
2399 | Type::BmpString(_)
2400 | Type::GeneralString(_)
2401 | Type::NumericString(_)
2402 | Type::VisibleString(_) => {
2403 let base_type_str = self.rust_type(base_type);
2404 if let ConstraintSpec::Subtype(ref subtype) = constraint.spec {
2405 self.generate_constrained_string(&element_name, &base_type_str, subtype)?;
2406 }
2407 }
2408 _ => {
2409 let inner_type = self.rust_type(inner);
2411 writeln!(
2412 &mut self.output,
2413 "pub type {} = {};",
2414 element_name, inner_type
2415 )?;
2416 }
2417 }
2418
2419 writeln!(&mut self.output)?;
2420
2421 if let Some(constraint) = size_constraint {
2423 let constraint_str = self.format_size_constraint(constraint);
2424 writeln!(&mut self.output, "// Constraint: {}", constraint_str)?;
2425 }
2426 writeln!(
2427 &mut self.output,
2428 "pub type {} = SetOf<{}>;",
2429 name, element_name
2430 )?;
2431 } else {
2432 if let Some(constraint) = size_constraint {
2434 let constraint_str = self.format_size_constraint(constraint);
2435 writeln!(&mut self.output, "// Constraint: {}", constraint_str)?;
2436 }
2437 let inner_type = self.rust_type(inner);
2438 let rust_type = format!("SetOf<{}>", inner_type);
2439 let seq_of_type = Type::SetOf(Box::new(inner.clone()), size_constraint.cloned());
2441 self.generate_type_alias(name, &rust_type, &seq_of_type)?;
2442 }
2443 Ok(())
2444 }
2445
2446 fn resolves_to_any(&self, ty: &Type) -> bool {
2449 match ty {
2450 Type::Any | Type::AnyDefinedBy(_) => true,
2451 Type::TypeRef(name) => {
2452 let clean = name.trim_end_matches("{}");
2453 matches!(
2454 self.type_definitions.get(clean),
2455 Some(Type::Any) | Some(Type::AnyDefinedBy(_))
2456 )
2457 }
2458 _ => false,
2459 }
2460 }
2461
2462 fn generate_field(&mut self, field: &SequenceField) -> Result<(), std::fmt::Error> {
2463 let field_name = to_snake_case(&field.name);
2464 let rust_type = self.inline_sequence_of_types(&field.ty);
2466
2467 if let Type::Tagged { tag, inner } = &field.ty {
2469 let tagging = match tag.tagging {
2470 Tagging::Explicit => "explicit",
2471 Tagging::Implicit => "implicit",
2472 };
2473 match tag.class {
2474 TagClass::ContextSpecific => {
2475 let attr = self
2476 .field_derive_cfg_attr(&format!("asn1(tag({}, {}))", tag.number, tagging));
2477 writeln!(&mut self.output, "{}", attr)?;
2478 if self.config.any_as_raw_der
2485 && tag.tagging == Tagging::Implicit
2486 && self.resolves_to_any(inner)
2487 {
2488 let rawder_attr = self.field_derive_cfg_attr("asn1(rawder)");
2489 writeln!(&mut self.output, "{}", rawder_attr)?;
2490 }
2491 }
2492 TagClass::Application => {
2493 writeln!(
2494 &mut self.output,
2495 " // APPLICATION [{} {}] -- use asn1(application_tag) when supported",
2496 tag.number, tagging
2497 )?;
2498 let attr = self
2499 .field_derive_cfg_attr(&format!("asn1(tag({}, {}))", tag.number, tagging));
2500 writeln!(&mut self.output, "{}", attr)?;
2501 }
2502 TagClass::Universal => {
2503 writeln!(
2504 &mut self.output,
2505 " // UNIVERSAL [{}] {}",
2506 tag.number, tagging
2507 )?;
2508 }
2509 TagClass::Private => {
2510 writeln!(
2511 &mut self.output,
2512 " // PRIVATE [{}] {}",
2513 tag.number, tagging
2514 )?;
2515 }
2516 }
2517 }
2518
2519 if field.optional || field.default.is_some() {
2522 let attr = self.field_derive_cfg_attr("asn1(optional)");
2523 writeln!(&mut self.output, "{}", attr)?;
2524 }
2525
2526 let rust_type = if self.config.raw_der_fields.contains(&field_name) {
2528 "RawDer<'a>".to_string()
2529 } else {
2530 rust_type
2531 };
2532
2533 let final_type = if field.optional || field.default.is_some() {
2535 format!("Option<{}>", rust_type)
2536 } else {
2537 rust_type
2538 };
2539
2540 writeln!(&mut self.output, " pub {}: {},", field_name, final_type)?;
2541
2542 Ok(())
2543 }
2544
2545 fn generate_subtype(
2547 &mut self,
2548 type_name: &str,
2549 base_type: &Type,
2550 constraint: &SubtypeConstraint,
2551 ) -> Result<(), std::fmt::Error> {
2552 let base_type_name = self.rust_type(base_type);
2553 let constraint_display = self.format_constraint_display(constraint);
2554
2555 writeln!(
2557 &mut self.output,
2558 "/// {} ({})",
2559 base_type_name, constraint_display
2560 )?;
2561
2562 writeln!(
2564 &mut self.output,
2565 "#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]"
2566 )?;
2567 writeln!(
2568 &mut self.output,
2569 "pub struct {}({});",
2570 type_name, base_type_name
2571 )?;
2572 writeln!(&mut self.output)?;
2573
2574 writeln!(&mut self.output, "impl {} {{", type_name)?;
2575
2576 let validation_code = self.generate_subtype_validation("val", constraint)?;
2579
2580 writeln!(
2581 &mut self.output,
2582 " /// Create a new {} with validation",
2583 type_name
2584 )?;
2585 writeln!(
2586 &mut self.output,
2587 " pub fn new(value: {}) -> Result<Self, &'static str> {{",
2588 base_type_name
2589 )?;
2590
2591 let is_integer_constraint = matches!(
2593 constraint,
2594 SubtypeConstraint::SingleValue(_)
2595 | SubtypeConstraint::ValueRange { .. }
2596 | SubtypeConstraint::Union(_)
2597 | SubtypeConstraint::Intersection(_)
2598 | SubtypeConstraint::Complement(_)
2599 );
2600
2601 let description = self.generate_constraint_description(constraint);
2602
2603 if is_integer_constraint {
2604 writeln!(&mut self.output, " let val = value.into_inner();")?;
2605 writeln!(&mut self.output, " if {} {{", validation_code)?;
2606 writeln!(&mut self.output, " Ok({}(value))", type_name)?;
2607 writeln!(&mut self.output, " }} else {{")?;
2608 writeln!(&mut self.output, " Err(\"{}\")", description)?;
2609 writeln!(&mut self.output, " }}")?;
2610 } else {
2611 let validation_code =
2613 self.generate_string_validation("value", &base_type_name, constraint);
2614 write!(&mut self.output, "{}", validation_code)?;
2615 }
2616
2617 writeln!(&mut self.output, " }}")?;
2618 writeln!(&mut self.output)?;
2619
2620 writeln!(
2622 &mut self.output,
2623 " /// Create without validation (use with caution)"
2624 )?;
2625 writeln!(
2626 &mut self.output,
2627 " pub const fn new_unchecked(value: {}) -> Self {{",
2628 base_type_name
2629 )?;
2630 writeln!(&mut self.output, " {}(value)", type_name)?;
2631 writeln!(&mut self.output, " }}")?;
2632 writeln!(&mut self.output)?;
2633
2634 writeln!(&mut self.output, " /// Get the inner value")?;
2636 writeln!(
2637 &mut self.output,
2638 " pub const fn get(&self) -> &{} {{",
2639 base_type_name
2640 )?;
2641 writeln!(&mut self.output, " &self.0")?;
2642 writeln!(&mut self.output, " }}")?;
2643 writeln!(&mut self.output)?;
2644
2645 writeln!(
2647 &mut self.output,
2648 " /// Consume and return the inner value"
2649 )?;
2650 writeln!(
2651 &mut self.output,
2652 " pub fn into_inner(self) -> {} {{",
2653 base_type_name
2654 )?;
2655 writeln!(&mut self.output, " self.0")?;
2656 writeln!(&mut self.output, " }}")?;
2657
2658 writeln!(&mut self.output, "}}")?;
2659 writeln!(&mut self.output)?;
2660
2661 let try_from_path = self.try_from_path();
2663 writeln!(
2664 &mut self.output,
2665 "impl {}::convert::TryFrom<{}> for {} {{",
2666 try_from_path, base_type_name, type_name
2667 )?;
2668 writeln!(&mut self.output, " type Error = &'static str;")?;
2669 writeln!(&mut self.output)?;
2670 writeln!(
2671 &mut self.output,
2672 " fn try_from(value: {}) -> Result<Self, Self::Error> {{",
2673 base_type_name
2674 )?;
2675 writeln!(&mut self.output, " Self::new(value)")?;
2676 writeln!(&mut self.output, " }}")?;
2677 writeln!(&mut self.output, "}}")?;
2678
2679 Ok(())
2680 }
2681
2682 fn generate_subtype_validation(
2684 &mut self,
2685 var: &str,
2686 constraint: &SubtypeConstraint,
2687 ) -> Result<String, std::fmt::Error> {
2688 Ok(self.generate_constraint_validation(var, constraint))
2691 }
2692
2693 fn generate_format_asn1_impl(
2700 &mut self,
2701 name: &str,
2702 has_lifetime: bool,
2703 ) -> Result<(), std::fmt::Error> {
2704 writeln!(&mut self.output)?;
2705 if has_lifetime {
2706 writeln!(&mut self.output, "impl<'a> {}<'a> {{", name)?;
2707 } else {
2708 writeln!(&mut self.output, "impl {} {{", name)?;
2709 }
2710 writeln!(
2711 &mut self.output,
2712 " /// Format the encoded DER bytes of this value."
2713 )?;
2714 writeln!(&mut self.output, " ///")?;
2715 writeln!(
2716 &mut self.output,
2717 " /// `mode` controls the output style:"
2718 )?;
2719 writeln!(
2720 &mut self.output,
2721 " /// - [`synta::Asn1FormatMode::Hex`] — space-separated uppercase hex bytes"
2722 )?;
2723 writeln!(
2724 &mut self.output,
2725 " /// - [`synta::Asn1FormatMode::Text`] — indented human-readable ASN.1 dump"
2726 )?;
2727 writeln!(
2728 &mut self.output,
2729 " pub fn format_asn1(&self, mode: synta::Asn1FormatMode) -> String {{"
2730 )?;
2731 writeln!(&mut self.output, " use synta::Encode;")?;
2732 writeln!(
2733 &mut self.output,
2734 " let mut encoder = synta::Encoder::new(synta::Encoding::Der);"
2735 )?;
2736 writeln!(
2737 &mut self.output,
2738 " if self.encode(&mut encoder).is_err() {{"
2739 )?;
2740 writeln!(
2741 &mut self.output,
2742 " return String::from(\"<encode error>\");"
2743 )?;
2744 writeln!(&mut self.output, " }}")?;
2745 writeln!(&mut self.output, " match encoder.finish() {{")?;
2746 writeln!(
2747 &mut self.output,
2748 " Ok(bytes) => synta::format_asn1_bytes(&bytes, mode),"
2749 )?;
2750 writeln!(
2751 &mut self.output,
2752 " Err(_) => String::from(\"<encode error>\"),"
2753 )?;
2754 writeln!(&mut self.output, " }}")?;
2755 writeln!(&mut self.output, " }}")?;
2756 writeln!(&mut self.output, "}}")?;
2757 Ok(())
2758 }
2759
2760 #[inline]
2768 fn string_rust_type(&self, owned: &str, borrowed: &str) -> String {
2769 match self.config.string_type_mode {
2770 StringTypeMode::Owned => owned.to_string(),
2771 StringTypeMode::Borrowed => format!("{}<'a>", borrowed),
2772 }
2773 }
2774
2775 fn rust_type(&self, ty: &Type) -> String {
2776 match ty {
2777 Type::Integer(_, _) => "Integer".to_string(),
2778 Type::Enumerated(_) => "Enumerated".to_string(),
2779 Type::Real => "f64".to_string(),
2780 Type::Boolean => "Boolean".to_string(),
2781 Type::OctetString(_) => self.string_rust_type("OctetString", "OctetStringRef"),
2783 Type::BitString(_) => self.string_rust_type("BitString", "BitStringRef"),
2784 Type::Utf8String(_) => self.string_rust_type("Utf8String", "Utf8StringRef"),
2785 Type::PrintableString(_) => {
2786 self.string_rust_type("PrintableString", "PrintableStringRef")
2787 }
2788 Type::IA5String(_) => self.string_rust_type("IA5String", "IA5StringRef"),
2789 Type::ObjectIdentifier => "ObjectIdentifier".to_string(),
2790 Type::Null => "Null".to_string(),
2791 Type::TeletexString(_) => "TeletexString".to_string(),
2793 Type::UniversalString(_) => "UniversalString".to_string(),
2794 Type::BmpString(_) => "BmpString".to_string(),
2795 Type::GeneralString(_) => "GeneralString".to_string(),
2796 Type::NumericString(_) => "NumericString".to_string(),
2797 Type::VisibleString(_) => "VisibleString".to_string(),
2798 Type::UtcTime => "UtcTime".to_string(),
2799 Type::GeneralizedTime => "GeneralizedTime".to_string(),
2800 Type::TypeRef(name) => {
2801 let type_name = to_pascal_case(name);
2802
2803 if let Some(lifetime) = self.config.imported_type_lifetimes.get(name) {
2809 return format!("{}<{}>", type_name, lifetime);
2810 }
2811
2812 if self.types_with_lifetimes.contains(&type_name) {
2814 return format!("{}<'a>", type_name);
2815 }
2816
2817 type_name
2818 }
2819 Type::Class(_) => "/* class */".to_string(),
2820 Type::Sequence(_) => "/* nested sequence */".to_string(),
2821 Type::Set(_) => "/* nested set */".to_string(),
2822 Type::Choice(_) => "/* nested choice */".to_string(),
2823 Type::SequenceOf(inner, _) => format!("Vec<{}>", self.rust_type(inner)),
2824 Type::SetOf(inner, _) => format!("SetOf<{}>", self.rust_type(inner)),
2825 Type::Tagged { inner, .. } => self.rust_type(inner),
2826 Type::Constrained { base_type, .. } => self.rust_type(base_type),
2827 Type::Any => {
2828 if self.config.any_as_raw_der {
2829 "RawDer<'a>".to_string()
2830 } else {
2831 "Element<'a>".to_string()
2832 }
2833 }
2834 Type::AnyDefinedBy(_) => {
2835 if self.config.any_as_raw_der {
2836 "RawDer<'a>".to_string()
2837 } else {
2838 "Element<'a>".to_string()
2839 }
2840 }
2841 }
2842 }
2843
2844 fn type_needs_lifetime(&self, ty: &Type) -> bool {
2857 match ty {
2858 Type::OctetString(_)
2860 | Type::BitString(_)
2861 | Type::Utf8String(_)
2862 | Type::PrintableString(_)
2863 | Type::IA5String(_) => self.config.string_type_mode == StringTypeMode::Borrowed,
2864 Type::Any => true, Type::AnyDefinedBy(_) => true, Type::TypeRef(name) => {
2868 let type_name = to_pascal_case(name);
2869
2870 if self.config.imported_type_lifetimes.contains_key(name) {
2873 return true;
2874 }
2875
2876 if self.types_with_lifetimes.contains(&type_name) {
2878 return true;
2879 }
2880
2881 false
2882 }
2883 Type::SequenceOf(inner, _) | Type::SetOf(inner, _) => self.type_needs_lifetime(inner),
2884 Type::Tagged { inner, .. }
2885 | Type::Constrained {
2886 base_type: inner, ..
2887 } => self.type_needs_lifetime(inner),
2888 Type::Sequence(fields) => fields.iter().any(|f| self.type_needs_lifetime(&f.ty)),
2889 Type::Set(fields) => fields.iter().any(|f| self.type_needs_lifetime(&f.ty)),
2890 Type::Choice(variants) => variants.iter().any(|v| self.type_needs_lifetime(&v.ty)),
2891 _ => false,
2892 }
2893 }
2894
2895 fn sequence_needs_lifetime(&self, fields: &[SequenceField]) -> bool {
2897 fields.iter().any(|field| {
2898 let field_name = to_snake_case(&field.name);
2899 self.config.raw_der_fields.contains(&field_name) || self.type_needs_lifetime(&field.ty)
2900 })
2901 }
2902
2903 fn choice_needs_lifetime(&self, variants: &[ChoiceVariant]) -> bool {
2905 variants.iter().any(|variant| {
2906 if let Type::Tagged { tag, .. } = &variant.ty {
2909 if tag.class == TagClass::ContextSpecific && tag.tagging == Tagging::Implicit {
2910 return false;
2911 }
2912 }
2913 self.type_needs_lifetime(&variant.ty)
2914 })
2915 }
2916
2917 fn generate_type_alias(
2919 &mut self,
2920 type_name: &str,
2921 rust_type: &str,
2922 asn1_type: &Type,
2923 ) -> Result<(), std::fmt::Error> {
2924 let needs_lifetime = self.type_needs_lifetime(asn1_type);
2928
2929 if needs_lifetime {
2930 writeln!(
2931 &mut self.output,
2932 "pub type {}<'a> = {};",
2933 type_name, rust_type
2934 )?;
2935 self.types_with_lifetimes.insert(type_name.to_string());
2938 } else {
2939 writeln!(&mut self.output, "pub type {} = {};", type_name, rust_type)?;
2940 }
2941 Ok(())
2942 }
2943
2944 fn build_oid_registry(
2946 &self,
2947 values: &[crate::ast::ValueAssignment],
2948 ) -> std::collections::HashMap<String, Vec<u32>> {
2949 use std::collections::HashMap;
2950 let mut registry: HashMap<String, Vec<u32>> = HashMap::new();
2951
2952 let mut changed = true;
2954 while changed {
2955 changed = false;
2956 for value_assignment in values {
2957 if registry.contains_key(&value_assignment.name) {
2958 continue;
2959 }
2960
2961 if let crate::ast::Value::ObjectIdentifier(components) = &value_assignment.value {
2962 let mut resolved = Vec::new();
2963 let mut can_resolve = true;
2964
2965 for component in components {
2966 match component {
2967 crate::ast::OidComponent::Number(n) => {
2968 resolved.push(*n);
2969 }
2970 crate::ast::OidComponent::NamedRef(name) => {
2971 if let Some(base_oid) = registry.get(name) {
2972 resolved.extend_from_slice(base_oid);
2973 } else {
2974 can_resolve = false;
2975 break;
2976 }
2977 }
2978 }
2979 }
2980
2981 if can_resolve {
2982 registry.insert(value_assignment.name.clone(), resolved);
2983 changed = true;
2984 }
2985 }
2986 }
2987 }
2988
2989 registry
2990 }
2991
2992 fn generate_value_assignment(
2994 &mut self,
2995 value_assignment: &crate::ast::ValueAssignment,
2996 oid_registry: &std::collections::HashMap<String, Vec<u32>>,
2997 ) -> Result<(), std::fmt::Error> {
2998 let const_name = to_screaming_snake_case(&value_assignment.name);
2999
3000 match &value_assignment.value {
3001 crate::ast::Value::ObjectIdentifier(_components) => {
3002 if let Some(oid_values) = oid_registry.get(&value_assignment.name) {
3004 write!(&mut self.output, "pub const {}: &[u32] = &[", const_name)?;
3006 for (i, value) in oid_values.iter().enumerate() {
3007 if i > 0 {
3008 write!(&mut self.output, ", ")?;
3009 }
3010 write!(&mut self.output, "{}", value)?;
3011 }
3012 writeln!(&mut self.output, "];")?;
3013 } else {
3014 writeln!(
3016 &mut self.output,
3017 "// Note: Could not resolve OID for {}",
3018 value_assignment.name
3019 )?;
3020 }
3021 }
3022 crate::ast::Value::Integer(n) => {
3023 writeln!(&mut self.output, "pub const {}: i64 = {};", const_name, n)?;
3024 }
3025 crate::ast::Value::Boolean(b) => {
3026 writeln!(&mut self.output, "pub const {}: bool = {};", const_name, b)?;
3027 }
3028 crate::ast::Value::String(s) => {
3029 writeln!(
3030 &mut self.output,
3031 "pub const {}: &str = \"{}\";",
3032 const_name, s
3033 )?;
3034 }
3035 }
3036
3037 Ok(())
3038 }
3039
3040 fn prescan_types_for_lifetimes(&mut self, definitions: &[Definition]) {
3043 let mut changed = true;
3045 while changed {
3046 changed = false;
3047
3048 for def in definitions {
3049 let type_name = to_pascal_case(&def.name);
3051 if self.types_with_lifetimes.contains(&type_name) {
3052 continue;
3053 }
3054 if self.config.skip_imported_types.contains(&def.name) {
3055 continue;
3056 }
3057
3058 let needs_lifetime = match &def.ty {
3060 Type::Sequence(fields) => self.sequence_needs_lifetime(fields),
3061 Type::Set(fields) => self.sequence_needs_lifetime(fields),
3062 Type::Choice(variants) => self.choice_needs_lifetime(variants),
3063 Type::Constrained {
3065 base_type: _,
3066 constraint,
3067 } => match constraint.spec {
3068 ConstraintSpec::Subtype(SubtypeConstraint::NamedBitList(_)) => false,
3069 ConstraintSpec::Subtype(SubtypeConstraint::Intersection(
3070 ref constraints,
3071 )) if constraints
3072 .iter()
3073 .any(|c| matches!(c, SubtypeConstraint::NamedBitList(_))) =>
3074 {
3075 false
3076 }
3077 _ => self.type_needs_lifetime(&def.ty),
3078 },
3079 other => self.type_needs_lifetime(other),
3081 };
3082
3083 if needs_lifetime {
3084 self.types_with_lifetimes.insert(type_name);
3085 changed = true;
3086 }
3087 }
3088 }
3089 }
3090
3091 fn inline_sequence_of_types(&self, ty: &Type) -> String {
3094 match ty {
3095 Type::TypeRef(type_ref_name) => {
3096 let type_name = to_pascal_case(type_ref_name);
3097 if let Some(def_type) = self.type_definitions.get(&type_name) {
3098 match def_type {
3099 Type::SequenceOf(inner, _) => {
3100 let inner_rust_type = self.inline_sequence_of_types(inner);
3102 format!("Vec<{}>", inner_rust_type)
3103 }
3104 Type::SetOf(inner, _) => {
3105 let inner_rust_type = self.inline_sequence_of_types(inner);
3107 format!("SetOf<{}>", inner_rust_type)
3108 }
3109 _ => self.rust_type(ty),
3110 }
3111 } else {
3112 self.rust_type(ty)
3113 }
3114 }
3115 Type::Tagged { inner, .. } => self.inline_sequence_of_types(inner),
3117 Type::Constrained { base_type, .. } => self.inline_sequence_of_types(base_type),
3119 _ => self.rust_type(ty),
3120 }
3121 }
3122}
3123
3124impl Default for CodeGenerator {
3125 fn default() -> Self {
3126 Self::new()
3127 }
3128}
3129
3130pub fn generate(module: &Module) -> Result<String, std::fmt::Error> {
3137 let mut gen = CodeGenerator::new();
3138 gen.generate_module(module)
3139}
3140
3141pub fn generate_with_config(
3157 module: &Module,
3158 config: CodeGenConfig,
3159) -> Result<String, std::fmt::Error> {
3160 let mut gen = CodeGenerator::with_config(config);
3161 gen.generate_module(module)
3162}