1use crate::model::lor::{ResolveState, Resolved};
2use crate::model::rust::Field as RustField;
3use crate::model::{Asn, ChoiceVariant, Integer, LiteralValue, Target};
4use crate::model::{Charset, Range};
5use crate::model::{ComponentTypeList, ValueReference};
6use crate::model::{Definition, Type};
7use crate::model::{Import, Tag, TagProperty};
8use crate::model::{Model, Size};
9use crate::model::{TagResolver, Type as AsnType};
10use std::borrow::Cow;
11
12const I8_MAX: i64 = i8::MAX as i64;
13const I16_MAX: i64 = i16::MAX as i64;
14const I32_MAX: i64 = i32::MAX as i64;
15const U8_MAX: u64 = u8::MAX as u64;
18const U16_MAX: u64 = u16::MAX as u64;
19const U32_MAX: u64 = u32::MAX as u64;
20pub type PlainVariant = String;
23pub type PlainEnum = Enumeration<PlainVariant>;
24pub type DataEnum = Enumeration<DataVariant>;
25
26#[allow(clippy::module_name_repetitions)]
31#[derive(Debug, Clone, PartialOrd, PartialEq)]
32pub enum RustType {
33 Bool,
34 I8(Range<i8>),
35 U8(Range<u8>),
36 I16(Range<i16>),
37 U16(Range<u16>),
38 I32(Range<i32>),
39 U32(Range<u32>),
40 I64(Range<i64>),
41 U64(Range<Option<u64>>),
42 String(Size, Charset),
43 VecU8(Size),
44 BitVec(Size),
45 Vec(Box<RustType>, Size, EncodingOrdering),
46 Null,
47
48 Option(Box<RustType>),
49 Default(Box<RustType>, LiteralValue),
50
51 Complex(String, Option<Tag>),
56}
57
58impl RustType {
59 pub fn as_inner_type(&self) -> &RustType {
60 if let RustType::Vec(inner, ..) | RustType::Option(inner) | RustType::Default(inner, ..) =
61 self
62 {
63 inner.as_inner_type()
64 } else {
65 self
66 }
67 }
68
69 pub fn into_inner_type(self) -> RustType {
70 if let RustType::Vec(inner, ..) | RustType::Option(inner) | RustType::Default(inner, ..) =
71 self
72 {
73 inner.into_inner_type()
74 } else {
75 self
76 }
77 }
78
79 pub fn to_inner_type_string(&self) -> String {
80 self.as_inner_type().to_string()
81 }
82
83 pub fn no_option(self) -> Self {
84 match self {
85 RustType::Option(inner) => *inner,
86 RustType::Default(inner, ..) => inner.no_option(),
87 rust => rust,
88 }
89 }
90
91 pub fn as_no_option(&self) -> &Self {
92 if let RustType::Option(inner) = self {
93 inner.as_no_option()
94 } else {
95 self
96 }
97 }
98
99 pub fn is_vec(&self) -> bool {
100 matches!(self.as_no_option(), RustType::Vec(..))
101 }
102
103 pub fn is_option(&self) -> bool {
105 matches!(self, RustType::Option(..))
106 }
107
108 pub fn is_optional(&self) -> bool {
110 matches!(self, RustType::Option(..) | RustType::Default(..))
111 }
112
113 pub fn is_primitive(&self) -> bool {
114 matches!(
115 self,
116 RustType::Bool
117 | RustType::U8(_)
118 | RustType::I8(_)
119 | RustType::U16(_)
120 | RustType::I16(_)
121 | RustType::U32(_)
122 | RustType::I32(_)
123 | RustType::U64(_)
124 | RustType::I64(_),
125 ) || matches!(self, RustType::Default(inner, ..) if inner.is_primitive())
126 }
127
128 pub fn integer_range_str(&self) -> Option<Range<String>> {
129 #[allow(clippy::match_same_arms)] match self {
131 RustType::Bool => None,
132 RustType::U8(Range(min, max, extensible)) => {
133 Some(Range(min.to_string(), max.to_string(), *extensible))
134 }
135 RustType::I8(Range(min, max, extensible)) => {
136 Some(Range(min.to_string(), max.to_string(), *extensible))
137 }
138 RustType::U16(Range(min, max, extensible)) => {
139 Some(Range(min.to_string(), max.to_string(), *extensible))
140 }
141 RustType::I16(Range(min, max, extensible)) => {
142 Some(Range(min.to_string(), max.to_string(), *extensible))
143 }
144 RustType::U32(Range(min, max, extensible)) => {
145 Some(Range(min.to_string(), max.to_string(), *extensible))
146 }
147 RustType::I32(Range(min, max, extensible)) => {
148 Some(Range(min.to_string(), max.to_string(), *extensible))
149 }
150 RustType::U64(Range(min, max, extensible)) => Some(Range(
151 min.unwrap_or_default().to_string(),
152 max.unwrap_or_else(|| i64::MAX as u64).to_string(),
153 *extensible,
154 )),
155 RustType::I64(Range(min, max, extensible)) => {
156 Some(Range(min.to_string(), max.to_string(), *extensible))
157 }
158 RustType::String(..) => None,
159 RustType::VecU8(_) => None,
160 RustType::BitVec(_) => None,
161 RustType::Vec(inner, _size, _ordering) => inner.integer_range_str(),
162 RustType::Null => None,
163 RustType::Option(inner) => inner.integer_range_str(),
164 RustType::Default(inner, ..) => inner.integer_range_str(),
165 RustType::Complex(_, _) => None,
166 }
167 }
168
169 pub fn into_asn(self) -> AsnType {
170 match self {
171 RustType::Bool => AsnType::Boolean,
172 RustType::I8(Range(min, max, extensible)) => AsnType::integer_with_range(Range(
173 Some(i64::from(min)),
174 Some(i64::from(max)),
175 extensible,
176 )),
177 RustType::U8(Range(min, max, extensible)) => AsnType::integer_with_range(Range(
178 Some(i64::from(min)),
179 Some(i64::from(max)),
180 extensible,
181 )),
182 RustType::I16(Range(min, max, extensible)) => AsnType::integer_with_range(Range(
183 Some(i64::from(min)),
184 Some(i64::from(max)),
185 extensible,
186 )),
187 RustType::U16(Range(min, max, extensible)) => AsnType::integer_with_range(Range(
188 Some(i64::from(min)),
189 Some(i64::from(max)),
190 extensible,
191 )),
192 RustType::I32(Range(min, max, extensible)) => AsnType::integer_with_range(Range(
193 Some(i64::from(min)),
194 Some(i64::from(max)),
195 extensible,
196 )),
197 RustType::U32(Range(min, max, extensible)) => AsnType::integer_with_range(Range(
198 Some(i64::from(min)),
199 Some(i64::from(max)),
200 extensible,
201 )),
202 RustType::I64(Range(min, max, extensible)) => {
203 AsnType::integer_with_range(Range(Some(min), Some(max), extensible))
204 }
205 RustType::U64(range) => AsnType::integer_with_range(Range(
206 range.min().map(|v| v as i64),
207 range.max().map(|v| v as i64),
208 range.extensible(),
209 )),
210 RustType::String(size, charset) => AsnType::String(size, charset),
211 RustType::VecU8(size) => AsnType::OctetString(size),
212 RustType::BitVec(size) => AsnType::bit_vec_with_size(size),
213 RustType::Vec(inner, size, EncodingOrdering::Keep) => {
214 AsnType::SequenceOf(Box::new(inner.into_asn()), size)
215 }
216 RustType::Vec(inner, size, EncodingOrdering::Sort) => {
217 AsnType::SetOf(Box::new(inner.into_asn()), size)
218 }
219 RustType::Null => AsnType::Null,
220 RustType::Option(value) => AsnType::Optional(Box::new(value.into_asn())),
221 RustType::Default(value, default) => {
222 AsnType::Default(Box::new(value.into_asn()), default)
223 }
224 RustType::Complex(name, tag) => AsnType::TypeReference(name, tag),
225 }
226 }
227
228 pub fn similar(&self, other: &Self) -> bool {
229 match self {
230 RustType::Bool => RustType::Bool == *other,
231 RustType::U8(_) => matches!(other, RustType::U8(_)),
232 RustType::I8(_) => matches!(other, RustType::I8(_)),
233 RustType::U16(_) => matches!(other, RustType::U16(_)),
234 RustType::I16(_) => matches!(other, RustType::I16(_)),
235 RustType::U32(_) => matches!(other, RustType::U32(_)),
236 RustType::I32(_) => matches!(other, RustType::I32(_)),
237 RustType::U64(_) => matches!(other, RustType::U64(_)),
238 RustType::I64(_) => matches!(other, RustType::I64(_)),
239 RustType::String(..) => matches!(other, RustType::String(..)),
240 RustType::VecU8(_) => matches!(other, RustType::VecU8(_)),
241 RustType::BitVec(_) => matches!(other, RustType::BitVec(_)),
242 RustType::Vec(inner_a, _size, _ordering) => {
243 if let RustType::Vec(inner_b, _other_size, _ordering) = other {
244 inner_a.similar(inner_b)
245 } else {
246 false
247 }
248 }
249 RustType::Null => RustType::Null == *other,
250 RustType::Option(inner) => {
251 matches!(other, RustType::Option(o) if o.similar(inner))
252 || matches!(other, RustType::Default(o, ..) if o.similar(inner))
253 }
254 RustType::Default(inner, ..) => {
255 other.similar(inner)
256 || matches!(other, RustType::Default(o, ..) if o.similar(inner))
257 || matches!(other, RustType::Option(o, ..) if o.similar(inner))
258 }
259 RustType::Complex(inner_a, _tag) => {
260 if let RustType::Complex(inner_b, _tag) = other {
261 inner_a.eq(inner_b)
262 } else {
263 false
264 }
265 }
266 }
267 }
268
269 pub fn tag(&self) -> Option<Tag> {
271 Some(match self {
272 RustType::Bool => Tag::DEFAULT_BOOLEAN,
273 RustType::I8(_)
274 | RustType::U8(_)
275 | RustType::I16(_)
276 | RustType::U16(_)
277 | RustType::I32(_)
278 | RustType::U32(_)
279 | RustType::I64(_)
280 | RustType::U64(_) => Tag::DEFAULT_INTEGER,
281 RustType::BitVec(_) => Tag::DEFAULT_BIT_STRING,
282 RustType::VecU8(_) => Tag::DEFAULT_OCTET_STRING,
283 RustType::String(_, charset) => charset.default_tag(),
284 RustType::Vec(_, _, EncodingOrdering::Keep) => Tag::DEFAULT_SEQUENCE_OF,
285 RustType::Vec(_, _, EncodingOrdering::Sort) => Tag::DEFAULT_SET_OF,
286 RustType::Null => Tag::DEFAULT_NULL,
287 RustType::Option(inner) => return inner.tag(),
288 RustType::Default(inner, ..) => return inner.tag(),
289 RustType::Complex(_, tag) => return *tag,
291 })
292 }
293}
294
295#[derive(Debug, Clone, Copy, PartialOrd, PartialEq, Eq)]
298pub enum EncodingOrdering {
299 Sort,
300 Keep,
301}
302
303#[derive(Debug, Clone, PartialOrd, PartialEq)]
304pub enum Rust {
305 Struct {
306 ordering: EncodingOrdering,
307 fields: Vec<Field>,
308 tag: Option<Tag>,
309 extension_after: Option<usize>,
310 },
311 Enum(PlainEnum),
312 DataEnum(DataEnum),
313
314 TupleStruct {
317 r#type: RustType,
318 tag: Option<Tag>,
319 constants: Vec<(String, String)>,
320 },
321}
322
323impl Rust {
324 #[cfg(test)]
325 pub fn struct_from_fields(fields: Vec<Field>) -> Self {
326 Self::Struct {
327 ordering: EncodingOrdering::Keep,
328 fields,
329 tag: None,
330 extension_after: None,
331 }
332 }
333
334 pub fn tuple_struct_from_type(r#type: RustType) -> Self {
335 Self::TupleStruct {
336 r#type,
337 tag: None,
338 constants: Vec::default(),
339 }
340 }
341}
342
343impl Target for Rust {
344 type DefinitionType = Rust;
345 type ValueReferenceType = RustType;
346}
347
348impl TagProperty for Rust {
349 fn tag(&self) -> Option<Tag> {
350 match self {
351 Rust::Struct { tag, .. } => *tag,
352 Rust::Enum(e) => e.tag(),
353 Rust::DataEnum(c) => c.tag(),
354 Rust::TupleStruct { tag, .. } => *tag,
355 }
356 }
357
358 fn set_tag(&mut self, new_tag: Tag) {
359 match self {
360 Rust::Struct { tag, .. } => *tag = Some(new_tag),
361 Rust::Enum(e) => e.set_tag(new_tag),
362 Rust::DataEnum(c) => c.set_tag(new_tag),
363 Rust::TupleStruct { tag, .. } => *tag = Some(new_tag),
364 }
365 }
366
367 fn reset_tag(&mut self) {
368 match self {
369 Rust::Struct { tag, .. } => *tag = None,
370 Rust::Enum(e) => e.reset_tag(),
371 Rust::DataEnum(c) => c.reset_tag(),
372 Rust::TupleStruct { tag, .. } => *tag = None,
373 }
374 }
375}
376
377impl RustType {
378 pub fn to_const_lit_string(&self) -> Cow<'static, str> {
382 Cow::Borrowed(match self {
383 RustType::Bool => "bool",
384 RustType::U8(_) => "u8",
385 RustType::I8(_) => "i8",
386 RustType::U16(_) => "u16",
387 RustType::I16(_) => "i16",
388 RustType::U32(_) => "u32",
389 RustType::I32(_) => "i32",
390 RustType::U64(_) => "u64",
391 RustType::I64(_) => "i64",
392 RustType::String(..) => "&'static str",
393 RustType::VecU8(_) => "&'static [u8]",
394 RustType::BitVec(_) => "u64",
395 RustType::Vec(inner, _size, _ordering) => {
396 return Cow::Owned(format!("&'static [{}]", inner.to_const_lit_string()))
397 }
398 RustType::Null => "Null",
399 RustType::Option(inner) => {
400 return Cow::Owned(format!("Option<{}>", inner.to_const_lit_string()))
401 }
402 RustType::Default(inner, ..) => return inner.to_const_lit_string(),
403 RustType::Complex(name, _) => return Cow::Owned(name.clone()),
404 })
405 }
406}
407
408impl ToString for RustType {
409 fn to_string(&self) -> String {
410 match self {
411 RustType::Bool => "bool",
412 RustType::U8(_) => "u8",
413 RustType::I8(_) => "i8",
414 RustType::U16(_) => "u16",
415 RustType::I16(_) => "i16",
416 RustType::U32(_) => "u32",
417 RustType::I32(_) => "i32",
418 RustType::U64(_) => "u64",
419 RustType::I64(_) => "i64",
420 RustType::String(..) => "String",
421 RustType::VecU8(_) => "Vec<u8>",
422 RustType::BitVec(_) => "BitVec",
423 RustType::Vec(inner, _size, _ordering) => return format!("Vec<{}>", inner.to_string()),
424 RustType::Null => "Null",
425 RustType::Option(inner) => return format!("Option<{}>", inner.to_string()),
426 RustType::Default(inner, ..) => return inner.to_string(),
427 RustType::Complex(name, _) => return name.clone(),
428 }
429 .into()
430 }
431}
432
433#[derive(Debug, Clone, PartialOrd, PartialEq)]
434pub struct Field {
435 pub(crate) name_type: (String, RustType),
436 pub(crate) tag: Option<Tag>,
437 pub(crate) constants: Vec<(String, String)>,
438}
439
440impl Field {
441 pub fn from_name_type<T: ToString>(name: T, r#type: RustType) -> Self {
442 Self {
443 name_type: (name.to_string(), r#type),
444 tag: None,
445 constants: Vec::default(),
446 }
447 }
448
449 pub fn fallback_representation(&self) -> &(String, RustType) {
450 &self.name_type
451 }
452
453 pub fn name(&self) -> &str {
454 &self.name_type.0
455 }
456
457 pub fn r#type(&self) -> &RustType {
458 &self.name_type.1
459 }
460
461 pub fn constants(&self) -> &[(String, String)] {
462 &self.constants[..]
463 }
464
465 pub fn with_constants(mut self, constants: Vec<(String, String)>) -> Self {
466 self.constants = constants;
467 self
468 }
469}
470
471impl TagProperty for Field {
472 fn tag(&self) -> Option<Tag> {
473 self.tag
474 }
475
476 fn set_tag(&mut self, tag: Tag) {
477 self.tag = Some(tag);
478 }
479
480 fn reset_tag(&mut self) {
481 self.tag = None;
482 }
483}
484
485#[derive(Debug, Clone, PartialOrd, PartialEq, Eq)]
486pub struct Enumeration<T> {
487 variants: Vec<T>,
488 tag: Option<Tag>,
489 extended_after_index: Option<usize>,
490}
491
492impl<T> From<Vec<T>> for Enumeration<T> {
493 fn from(variants: Vec<T>) -> Self {
494 Enumeration {
495 variants,
496 tag: None,
497 extended_after_index: None,
498 }
499 }
500}
501
502impl<T> Enumeration<T> {
503 pub fn with_extension_after(mut self, extension_after: Option<usize>) -> Self {
504 self.extended_after_index = extension_after;
505 self
506 }
507
508 pub fn len(&self) -> usize {
509 self.variants.len()
510 }
511
512 pub fn is_empty(&self) -> bool {
513 self.variants.is_empty()
514 }
515
516 pub fn variants(&self) -> impl Iterator<Item = &T> {
517 self.variants.iter()
518 }
519
520 pub fn extension_after_index(&self) -> Option<usize> {
521 self.extended_after_index
522 }
523
524 pub fn extension_after_variant(&self) -> Option<&T> {
525 self.extended_after_index
526 .and_then(|index| self.variants.get(index))
527 }
528
529 pub fn is_extensible(&self) -> bool {
530 self.extended_after_index.is_some()
531 }
532}
533
534impl<T> TagProperty for Enumeration<T> {
535 fn tag(&self) -> Option<Tag> {
536 self.tag
537 }
538
539 fn set_tag(&mut self, tag: Tag) {
540 self.tag = Some(tag);
541 }
542
543 fn reset_tag(&mut self) {
544 self.tag = None;
545 }
546}
547
548impl PlainEnum {
549 pub fn from_names(names: impl Iterator<Item = impl ToString>) -> Self {
550 Self::from(names.map(|n| n.to_string()).collect::<Vec<_>>())
551 }
552}
553
554#[derive(Debug, Clone, PartialOrd, PartialEq)]
555pub struct DataVariant {
556 name_type: (String, RustType),
557 tag: Option<Tag>,
558}
559
560impl DataVariant {
561 pub fn from_name_type<T: ToString>(name: T, r#type: RustType) -> Self {
562 Self {
563 name_type: (name.to_string(), r#type),
564 tag: None,
565 }
566 }
567
568 pub fn fallback_representation(&self) -> &(String, RustType) {
569 &self.name_type
570 }
571
572 pub fn name(&self) -> &str {
573 &self.name_type.0
574 }
575
576 pub fn r#type(&self) -> &RustType {
577 &self.name_type.1
578 }
579}
580
581impl TagProperty for DataVariant {
582 fn tag(&self) -> Option<Tag> {
583 self.tag
584 }
585
586 fn set_tag(&mut self, tag: Tag) {
587 self.tag = Some(tag);
588 }
589
590 fn reset_tag(&mut self) {
591 self.tag = None;
592 }
593}
594
595impl Model<Rust> {
596 pub fn convert_asn_to_rust(
597 asn_model: &Model<Asn>,
598 scope: &[&Model<Asn>],
599 make_names_nice: bool,
600 ) -> Model<Rust> {
601 let mut definitions = Vec::with_capacity(asn_model.definitions.len());
602 let mut ctxt = Context {
603 resolver: TagResolver::new(asn_model, scope),
604 target: &mut definitions,
605 make_names_nice,
606 };
607 let mut model = Model {
608 name: ctxt.module_name(&asn_model.name),
609 oid: asn_model.oid.clone(),
610 imports: asn_model
611 .imports
612 .iter()
613 .map(|i| Import {
614 what: i.what.iter().map(|w| ctxt.struct_or_enum_name(w)).collect(),
615 from: ctxt.module_name(&i.from),
616 from_oid: i.from_oid.clone(),
617 })
618 .collect(),
619 definitions: Vec::default(),
620 value_references: Vec::with_capacity(asn_model.value_references.len()),
621 };
622 for Definition(name, asn) in &asn_model.definitions {
623 let rust_name = ctxt.struct_or_enum_name(name);
624 Self::definition_to_rust(&rust_name, &asn.r#type, asn.tag, &mut ctxt);
625 }
626 for vref in &asn_model.value_references {
627 if let Some(rust_type) = Self::map_asn_type_to_rust_type_flat(&vref.role.r#type) {
628 model.value_references.push(ValueReference {
629 name: ctxt.constant_name(&vref.name),
630 role: rust_type,
631 value: vref.value.clone(),
632 });
633 } else {
634 println!("Ignoring ValueReference {}", vref.name);
636 }
637 }
638 model.definitions = definitions;
639 model
640 }
641
642 fn map_asn_type_to_rust_type_flat(r#type: &Type) -> Option<RustType> {
643 Some(match &r#type {
644 Type::Boolean => RustType::Bool,
645 Type::Integer(int) if int.range.extensible() => {
646 Self::asn_extensible_integer_to_rust(int)
647 }
648 Type::Integer(int) => Self::asn_fixed_integer_to_rust_type(int),
649 Type::String(size, charset) => RustType::String(size.clone(), *charset),
650 Type::OctetString(size) => RustType::VecU8(size.clone()),
651 Type::BitString(bs) => RustType::BitVec(bs.size.clone()),
652 Type::Null => RustType::Null,
653 Type::Optional(opt) => {
654 RustType::Option(Box::new(Self::map_asn_type_to_rust_type_flat(opt)?))
655 }
656 Type::Default(inner, default) => RustType::Default(
657 Box::new(Self::map_asn_type_to_rust_type_flat(inner)?),
658 default.clone(),
659 ),
660 Type::TypeReference(name, tag) => RustType::Complex(name.clone(), *tag),
661 Type::Sequence(_)
662 | Type::SequenceOf(_, _)
663 | Type::Set(_)
664 | Type::SetOf(_, _)
665 | Type::Enumerated(_)
666 | Type::Choice(_) => return None,
667 })
668 }
669
670 fn definition_to_rust(name: &str, asn: &AsnType, tag: Option<Tag>, ctxt: &mut Context<'_>) {
678 match asn {
679 AsnType::Boolean
680 | AsnType::Null
681 | AsnType::String(..)
682 | AsnType::OctetString(_)
683 | AsnType::BitString(_) => {
684 let rust_type = Self::definition_type_to_rust_type(name, asn, tag, ctxt);
685 ctxt.add_definition(Definition(
686 name.to_string(),
687 Rust::tuple_struct_from_type(rust_type).with_tag_opt(tag),
688 ));
689 }
690 AsnType::TypeReference(_, tag) => {
691 let rust_type = Self::definition_type_to_rust_type(name, asn, *tag, ctxt);
692 ctxt.add_definition(Definition(
693 name.to_string(),
694 Rust::tuple_struct_from_type(rust_type).with_tag_opt(*tag),
695 ));
696 }
697
698 me @ AsnType::Integer(_) => {
699 let rust_type = Self::definition_type_to_rust_type(name, asn, tag, ctxt);
700 let constants = ctxt.to_rust_constants(me);
701 ctxt.add_definition(Definition(
702 name.into(),
703 Rust::TupleStruct {
704 r#type: rust_type,
705 tag,
706 constants,
707 },
708 ));
709 }
710
711 AsnType::Optional(inner) => {
712 let inner = RustType::Option(Box::new(Self::definition_type_to_rust_type(
713 name, inner, tag, ctxt,
714 )));
715 ctxt.add_definition(Definition(
716 name.into(),
717 Rust::tuple_struct_from_type(inner).with_tag_opt(tag),
718 ))
719 }
720
721 AsnType::Default(inner, default) => {
722 let inner = RustType::Default(
723 Box::new(Self::definition_type_to_rust_type(name, inner, tag, ctxt)),
724 default.clone(),
725 );
726 ctxt.add_definition(Definition(
727 name.into(),
728 Rust::tuple_struct_from_type(inner).with_tag_opt(tag),
729 ))
730 }
731
732 AsnType::Sequence(ComponentTypeList {
733 fields,
734 extension_after,
735 }) => {
736 let fields = Self::asn_fields_to_rust_fields(name, fields, *extension_after, ctxt);
737 ctxt.add_definition(Definition(
738 name.into(),
739 Rust::Struct {
740 ordering: EncodingOrdering::Keep,
741 fields,
742 tag,
743 extension_after: *extension_after,
744 },
745 ));
746 }
747
748 AsnType::Set(ComponentTypeList {
749 fields,
750 extension_after,
751 }) => {
752 let fields = Self::asn_fields_to_rust_fields(name, fields, *extension_after, ctxt);
753 ctxt.add_definition(Definition(
754 name.into(),
755 Rust::Struct {
756 ordering: EncodingOrdering::Sort,
757 fields,
758 tag,
759 extension_after: *extension_after,
760 },
761 ));
762 }
763
764 AsnType::SequenceOf(asn, size) => {
765 let inner = RustType::Vec(
766 Box::new(Self::definition_type_to_rust_type(name, asn, tag, ctxt)),
767 size.clone(),
768 EncodingOrdering::Keep,
769 );
770 ctxt.add_definition(Definition(name.into(), Rust::tuple_struct_from_type(inner)));
771 }
772
773 AsnType::SetOf(asn, size) => {
774 let inner = RustType::Vec(
775 Box::new(Self::definition_type_to_rust_type(name, asn, tag, ctxt)),
776 size.clone(),
777 EncodingOrdering::Sort,
778 );
779 ctxt.add_definition(Definition(
780 name.into(),
781 Rust::tuple_struct_from_type(inner).with_tag_opt(tag),
782 ));
783 }
784
785 AsnType::Choice(choice) => {
786 let mut enumeration = Enumeration {
787 variants: Vec::with_capacity(choice.len()),
788 tag,
789 extended_after_index: choice.extension_after_index(),
790 };
791
792 for ChoiceVariant {
793 name: variant_name,
794 r#type,
795 tag,
796 } in choice.variants()
797 {
798 let rust_name = format!("{}{}", name, ctxt.struct_or_enum_name(variant_name));
799 let rust_role =
800 Self::definition_type_to_rust_type(&rust_name, r#type, *tag, ctxt);
801 let rust_field_name = ctxt.variant_name(variant_name);
802 enumeration.variants.push(
803 DataVariant::from_name_type(rust_field_name, rust_role).with_tag_opt(*tag),
804 );
805 }
806
807 ctxt.add_definition(Definition(name.into(), Rust::DataEnum(enumeration)));
808 }
809
810 AsnType::Enumerated(enumerated) => {
811 let mut rust_enum = Enumeration {
812 variants: Vec::with_capacity(enumerated.len()),
813 tag,
814 extended_after_index: enumerated.extension_after_index(),
815 };
816
817 for variant in enumerated.variants() {
818 rust_enum.variants.push(ctxt.variant_name(variant.name()));
819 }
820
821 ctxt.add_definition(Definition(name.into(), Rust::Enum(rust_enum)));
822 }
823 }
824 }
825
826 fn asn_fields_to_rust_fields(
827 name: &str,
828 fields: &[crate::model::Field<Asn>],
829 extension_after: Option<usize>,
830 ctxt: &mut Context<'_>,
831 ) -> Vec<Field> {
832 let mut rust_fields = Vec::with_capacity(fields.len());
833
834 for (index, field) in fields.iter().enumerate() {
835 let rust_name = format!("{}{}", name, ctxt.struct_or_enum_name(&field.name));
836 let tag = field.role.tag;
837 let rust_role =
838 Self::definition_type_to_rust_type(&rust_name, &field.role.r#type, tag, ctxt);
839 let rust_role = if let Some(def) = &field.role.default {
840 RustType::Default(Box::new(rust_role.no_option()), def.clone())
841 } else if extension_after.map(|e| index > e).unwrap_or(false)
842 && !rust_role.is_optional()
843 {
844 RustType::Option(Box::new(rust_role))
845 } else {
846 rust_role
847 };
848 let rust_field_name = ctxt.field_name(&field.name);
849 let constants = ctxt.to_rust_constants(&field.role.r#type);
850 rust_fields.push(
851 RustField::from_name_type(rust_field_name, rust_role)
852 .with_constants(constants)
853 .with_tag_opt(tag),
854 );
855 }
856
857 rust_fields
858 }
859
860 fn definition_type_to_rust_type(
861 name: &str,
862 asn: &AsnType,
863 tag: Option<Tag>,
864 ctxt: &mut Context<'_>,
865 ) -> RustType {
866 match asn {
867 AsnType::Boolean => RustType::Bool,
868 AsnType::Null => RustType::Null,
869 AsnType::Integer(int) if int.range.extensible() => {
870 Self::asn_extensible_integer_to_rust(int)
871 }
872 AsnType::Integer(int) => Self::asn_fixed_integer_to_rust_type(int),
873
874 AsnType::String(size, charset) => RustType::String(size.clone(), *charset),
875 AsnType::OctetString(size) => RustType::VecU8(size.clone()),
876 AsnType::BitString(bitstring) => RustType::BitVec(bitstring.size.clone()),
877 Type::Optional(inner) => {
878 RustType::Option(Box::new(Self::definition_type_to_rust_type(
879 name,
880 inner,
881 tag.or_else(|| ctxt.resolver().resolve_no_default(inner)),
882 ctxt,
883 )))
884 }
885 Type::Default(inner, default) => RustType::Default(
886 Box::new(Self::definition_type_to_rust_type(
887 name,
888 inner,
889 tag.or_else(|| ctxt.resolver().resolve_no_default(inner)),
890 ctxt,
891 )),
892 default.clone(),
893 ),
894 AsnType::SequenceOf(asn, size) => RustType::Vec(
895 Box::new(Self::definition_type_to_rust_type(
896 name,
897 asn,
898 tag.or_else(|| ctxt.resolver().resolve_no_default(asn)),
899 ctxt,
900 )),
901 size.clone(),
902 EncodingOrdering::Keep,
903 ),
904 AsnType::SetOf(asn, size) => RustType::Vec(
905 Box::new(Self::definition_type_to_rust_type(
906 name,
907 asn,
908 tag.or_else(|| ctxt.resolver().resolve_no_default(asn)),
909 ctxt,
910 )),
911 size.clone(),
912 EncodingOrdering::Sort,
913 ),
914 ty @ AsnType::Sequence(_)
915 | ty @ AsnType::Set(_)
916 | ty @ AsnType::Enumerated(_)
917 | ty @ AsnType::Choice(_) => {
918 let name = ctxt.struct_or_enum_name(name);
919 Self::definition_to_rust(&name, asn, tag, ctxt);
920 RustType::Complex(name, tag.or_else(|| ctxt.resolver().resolve_type_tag(ty)))
921 }
922 AsnType::TypeReference(name, tag) => RustType::Complex(
923 ctxt.struct_or_enum_name(name),
924 (*tag).or_else(|| ctxt.resolver().resolve_tag(name)),
925 ),
926 }
927 }
928
929 fn asn_extensible_integer_to_rust(
930 int: &Integer<<Resolved as ResolveState>::RangeType>,
931 ) -> RustType {
932 match (int.range.min(), int.range.max()) {
933 (None, None) | (Some(0), None) | (Some(0), Some(i64::MAX)) | (None, Some(i64::MAX)) => {
934 RustType::U64(Range(None, None, true))
935 }
936 (min, max) if min.unwrap_or_default() >= 0 && max.unwrap_or_default() >= 0 => {
937 RustType::U64(Range(min.map(|v| v as u64), max.map(|v| v as u64), true))
938 }
939 (min, max) => RustType::I64(Range(
940 min.unwrap_or(i64::MIN),
941 max.unwrap_or(i64::MAX),
942 true,
943 )),
944 }
945 }
946
947 fn asn_fixed_integer_to_rust_type(
948 int: &Integer<<Resolved as ResolveState>::RangeType>,
949 ) -> RustType {
950 match (int.range.min(), int.range.max()) {
951 (None, None) | (Some(0), None) | (Some(0), Some(i64::MAX)) | (None, Some(i64::MAX)) => {
952 RustType::U64(Range(None, None, false))
953 }
954 (min, max) => {
955 let min = min.unwrap_or_default();
956 let max = max.unwrap_or(i64::MAX);
957 if min >= 0 {
958 match max as u64 {
959 m if m <= U8_MAX => RustType::U8(Range::inclusive(min as u8, max as u8)),
960 m if m <= U16_MAX => RustType::U16(Range::inclusive(min as u16, max as u16)),
961 m if m <= U32_MAX => RustType::U32(Range::inclusive(min as u32, max as u32)),
962 _=> RustType::U64(Range::inclusive(Some(min as u64), Some(max as u64))),
963 }
965 } else {
966 let max_amplitude = (min + 1).abs().max(max);
970 match max_amplitude {
971 _ if max_amplitude <= I8_MAX => RustType::I8(Range::inclusive(min as i8, max as i8)),
972 _ if max_amplitude <= I16_MAX => RustType::I16(Range::inclusive(min as i16, max as i16)),
973 _ if max_amplitude <= I32_MAX => RustType::I32(Range::inclusive(min as i32, max as i32)),
974 _=> RustType::I64(Range::inclusive(min, max)),
975 }
977 }
978 }
979 }
980 }
981}
982
983struct Context<'a> {
984 resolver: TagResolver<'a>,
985 target: &'a mut Vec<Definition<Rust>>,
986 make_names_nice: bool,
987}
988
989impl Context<'_> {
990 fn to_rust_constants(&self, asn: &AsnType) -> Vec<(String, String)> {
991 match asn {
992 AsnType::Integer(integer) => integer
993 .constants
994 .iter()
995 .map(|(name, value)| (self.constant_name(name), format!("{}", value)))
996 .collect(),
997 AsnType::BitString(bitstring) => bitstring
998 .constants
999 .iter()
1000 .map(|(name, value)| (self.constant_name(name), format!("{}", value)))
1001 .collect(),
1002
1003 Type::Boolean
1004 | Type::Null
1005 | Type::String(..)
1006 | Type::OctetString(_)
1007 | Type::Optional(_)
1008 | Type::Default(..)
1009 | Type::Sequence(_)
1010 | Type::SequenceOf(..)
1011 | Type::Set(_)
1012 | Type::SetOf(..)
1013 | Type::Enumerated(_)
1014 | Type::Choice(_)
1015 | Type::TypeReference(_, _) => Vec::default(),
1016 }
1017 }
1018
1019 pub fn struct_or_enum_name(&self, name: &str) -> String {
1020 if self.make_names_nice {
1021 rust_struct_or_enum_name(name)
1022 } else {
1023 name.to_string()
1024 }
1025 }
1026
1027 pub fn constant_name(&self, name: &str) -> String {
1028 if self.make_names_nice {
1029 rust_constant_name(name)
1030 } else {
1031 name.to_string()
1032 }
1033 }
1034
1035 pub fn variant_name(&self, name: &str) -> String {
1036 if self.make_names_nice {
1037 rust_variant_name(name)
1038 } else {
1039 name.to_string()
1040 }
1041 }
1042
1043 pub fn field_name(&self, name: &str) -> String {
1044 if self.make_names_nice {
1045 rust_field_name(name)
1046 } else {
1047 name.to_string()
1048 }
1049 }
1050
1051 pub fn module_name(&self, name: &str) -> String {
1052 if self.make_names_nice {
1053 rust_module_name(name, false)
1054 } else {
1055 name.to_string()
1056 }
1057 }
1058
1059 pub fn add_definition(&mut self, def: Definition<Rust>) {
1060 self.target.push(def)
1061 }
1062
1063 pub fn resolver(&self) -> &TagResolver<'_> {
1064 &self.resolver
1065 }
1066}
1067
1068#[allow(clippy::module_name_repetitions)]
1069pub fn rust_field_name(name: &str) -> String {
1070 rust_module_name(name, false)
1071}
1072
1073#[allow(clippy::module_name_repetitions)]
1074pub fn rust_variant_name(name: &str) -> String {
1075 let mut out = String::new();
1076 let mut next_upper = true;
1077 let mut prev_upper = false;
1078 let mut chars = name.chars().peekable();
1079 while let Some(c) = chars.next() {
1080 if c == '-' || c == '_' {
1081 next_upper = true;
1082 prev_upper = false;
1083 } else if next_upper && !prev_upper {
1084 out.push(c.to_ascii_uppercase());
1085 next_upper = false;
1086 prev_upper = true;
1087 } else {
1088 if prev_upper && !chars.peek().map(|c| c.is_lowercase()).unwrap_or(false) {
1089 out.push(c.to_ascii_lowercase());
1090 } else {
1091 out.push(c);
1092 }
1093 prev_upper = c.is_ascii_uppercase();
1094 }
1095 }
1096 out
1097}
1098
1099#[allow(clippy::module_name_repetitions)]
1100pub fn rust_struct_or_enum_name(name: &str) -> String {
1101 rust_variant_name(name)
1102}
1103
1104#[allow(clippy::module_name_repetitions)]
1105pub fn rust_module_name(name: &str, pad_non_alphabetic: bool) -> String {
1106 let mut out = String::new();
1107 let mut prev_lowered = false;
1108 let mut prev_alphabetic = false;
1109 let mut chars = name.chars().peekable();
1110 while let Some(c) = chars.next() {
1111 let mut lowered = false;
1112 let alphabetic = c.is_alphabetic();
1113 if pad_non_alphabetic
1114 && prev_alphabetic != alphabetic
1115 && c != '-'
1116 && c != '_'
1117 && !out.is_empty()
1118 && !out.ends_with('_')
1119 {
1120 out.push('_');
1121 }
1122 if c.is_uppercase() {
1123 if !out.is_empty() && prev_alphabetic {
1124 if !prev_lowered {
1125 out.push('_');
1126 } else if let Some(next) = chars.peek() {
1127 if next.is_lowercase() {
1128 out.push('_');
1129 }
1130 }
1131 }
1132 lowered = true;
1133 out.push_str(&c.to_lowercase().to_string());
1134 } else if c == '-' || c == '_' {
1135 out.push('_');
1136 } else {
1137 out.push(c);
1138 }
1139 prev_lowered = lowered;
1140 prev_alphabetic = alphabetic;
1141 }
1142 out
1143}
1144
1145#[allow(clippy::module_name_repetitions)]
1146pub fn rust_constant_name(name: &str) -> String {
1147 rust_module_name(name, true).to_uppercase()
1148}
1149
1150impl LiteralValue {
1151 pub fn as_rust_const_literal_expect<F: FnOnce(&Self) -> bool>(
1152 &self,
1153 make_names_nice: bool,
1154 probe: F,
1155 ) -> impl std::fmt::Display + '_ {
1156 if probe(self) {
1157 self.as_rust_const_literal(make_names_nice)
1158 } else {
1159 panic!("Invalid string literal {:?}", self)
1160 }
1161 }
1162
1163 pub fn as_rust_const_literal(&self, make_names_nice: bool) -> impl std::fmt::Display + '_ {
1164 struct Ref<'a>(&'a LiteralValue, bool);
1165 impl std::fmt::Display for Ref<'_> {
1166 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1167 match self.0 {
1168 LiteralValue::Boolean(v) => write!(f, "{}", v),
1169 LiteralValue::String(v) => write!(f, "\"{}\"", v),
1170 LiteralValue::Integer(v) => write!(f, "{}", v),
1171 LiteralValue::OctetString(v) => {
1172 write!(f, "[")?;
1173 for b in v {
1174 write!(f, "0x{:02x}, ", *b)?;
1175 }
1176 write!(f, "]")
1177 }
1178 LiteralValue::EnumeratedVariant(r#type, variant) => {
1179 write!(
1180 f,
1181 "{}::{}",
1182 if self.1 {
1183 Cow::Owned(rust_struct_or_enum_name(r#type))
1184 } else {
1185 Cow::Borrowed(r#type)
1186 },
1187 if self.1 {
1188 Cow::Owned(rust_variant_name(variant))
1189 } else {
1190 Cow::Borrowed(variant)
1191 }
1192 )
1193 }
1194 }
1195 }
1196 }
1197 Ref(self, make_names_nice)
1198 }
1199}
1200
1201#[cfg(test)]
1202mod tests {
1203 use super::*;
1204 use crate::gen::rust::walker::tests::assert_starts_with_lines;
1205 use crate::gen::RustCodeGenerator;
1206 use crate::model::tag::tests::test_property;
1207 use crate::model::tests::*;
1208 use crate::model::{Choice, Enumerated, EnumeratedVariant, Field, Tag, Type};
1209 use crate::parser::Tokenizer;
1210
1211 #[test]
1212 fn test_rust_struct_or_enum_name() {
1213 fn stable_rust_struct_or_enum_name(name: &str) -> String {
1214 let v1 = rust_struct_or_enum_name(name);
1215 assert_eq!(v1, rust_struct_or_enum_name(&v1));
1216 v1
1217 }
1218
1219 assert_eq!("TestAbc", stable_rust_struct_or_enum_name("test-abc"));
1220 assert_eq!(
1221 "BerndDasBrot",
1222 stable_rust_struct_or_enum_name("berndDasBrot")
1223 );
1224 assert_eq!(
1225 "WhoKnowsWhat",
1226 stable_rust_struct_or_enum_name("who-knowsWhat")
1227 );
1228 assert_eq!("EWaffle", stable_rust_struct_or_enum_name("e-waffle"));
1229 assert_eq!("EeWaffle", stable_rust_struct_or_enum_name("ee-waffle"));
1230 assert_eq!("EeWaffle", stable_rust_struct_or_enum_name("EEWaffle"));
1231 }
1232
1233 #[test]
1234 fn test_rust_variant_name() {
1235 fn stable_rust_variant_name(name: &str) -> String {
1236 let v1 = rust_variant_name(name);
1237 assert_eq!(v1, rust_variant_name(&v1));
1238 v1
1239 }
1240
1241 assert_eq!("TestAbc", stable_rust_variant_name("test-abc"));
1242 assert_eq!("BerndDasBrot", stable_rust_variant_name("berndDasBrot"));
1243 assert_eq!("WhoKnowsWhat", stable_rust_variant_name("who-knowsWhat"));
1244 assert_eq!("EWaffle", stable_rust_variant_name("e-waffle"));
1245 assert_eq!("EeWaffle", stable_rust_variant_name("ee-waffle"));
1246 assert_eq!("EeWaffle", stable_rust_variant_name("EEWaffle"));
1247 }
1248
1249 #[test]
1250 fn test_rust_constant_name() {
1251 fn stable_constant_name(name: &str) -> String {
1252 let v1 = rust_constant_name(name);
1253 assert_eq!(v1, rust_constant_name(&v1));
1254 v1
1255 }
1256
1257 assert_eq!(
1258 "SOME_IMPORTANT_VALUE_60_DEGREE_OFFSET_30_OTHER_10_MORE_42",
1259 stable_constant_name("some-importantValue60degreeOffset-30-other10-more_42")
1260 );
1261 }
1262
1263 #[test]
1264 fn test_rust_name_multiple_upper_case() {
1265 assert_eq!(
1266 "SomeThingyThingWithId",
1267 rust_struct_or_enum_name("some-thingy-ThingWithID")
1268 );
1269 }
1270
1271 #[test]
1272 fn test_simple_asn_sequence_represented_correctly_as_rust_model() {
1273 let model_rust = Model::try_from(Tokenizer::default().parse(SIMPLE_INTEGER_STRUCT_ASN))
1274 .unwrap()
1275 .try_resolve()
1276 .unwrap()
1277 .to_rust();
1278
1279 assert_eq!("simple_schema", model_rust.name);
1280 assert_eq!(true, model_rust.imports.is_empty());
1281 assert_eq!(1, model_rust.definitions.len());
1282 assert_eq!(
1283 Definition(
1284 "Simple".into(),
1285 Rust::struct_from_fields(vec![
1286 RustField::from_name_type("small", RustType::U8(Range::inclusive(0, 255))),
1287 RustField::from_name_type("bigger", RustType::U16(Range::inclusive(0, 65535))),
1288 RustField::from_name_type("negative", RustType::I16(Range::inclusive(-1, 255))),
1289 RustField::from_name_type(
1290 "unlimited",
1291 RustType::Option(Box::new(RustType::U64(Range::none()))),
1292 ),
1293 ]),
1294 ),
1295 model_rust.definitions[0]
1296 );
1297 }
1298
1299 #[test]
1300 fn test_inline_asn_enumerated_represented_correctly_as_rust_model() {
1301 let model_rust = Model::try_from(Tokenizer::default().parse(INLINE_ASN_WITH_ENUM))
1302 .unwrap()
1303 .try_resolve()
1304 .unwrap()
1305 .to_rust();
1306
1307 assert_eq!("simple_schema", model_rust.name);
1308 assert_eq!(true, model_rust.imports.is_empty());
1309 assert_eq!(2, model_rust.definitions.len());
1310 assert_eq!(
1311 Definition(
1312 "WoahDecision".into(),
1313 Rust::Enum(
1314 vec![
1315 "Abort".into(),
1316 "Return".into(),
1317 "Confirm".into(),
1318 "Mayday".into(),
1319 "TheCakeIsALie".into()
1320 ]
1321 .into()
1322 ),
1323 ),
1324 model_rust.definitions[0]
1325 );
1326 assert_eq!(
1327 Definition(
1328 "Woah".into(),
1329 Rust::struct_from_fields(vec![RustField::from_name_type(
1330 "decision",
1331 RustType::Option(Box::new(RustType::Complex(
1332 "WoahDecision".into(),
1333 Some(Tag::DEFAULT_ENUMERATED)
1334 ))),
1335 )])
1336 ),
1337 model_rust.definitions[1]
1338 );
1339 }
1340
1341 #[test]
1342 fn test_inline_asn_sequence_of_represented_correctly_as_rust_model() {
1343 let model_rust = Model::try_from(Tokenizer::default().parse(INLINE_ASN_WITH_SEQUENCE_OF))
1344 .unwrap()
1345 .try_resolve()
1346 .unwrap()
1347 .to_rust();
1348
1349 assert_eq!("simple_schema", model_rust.name);
1350 assert_eq!(true, model_rust.imports.is_empty());
1351 assert_eq!(3, model_rust.definitions.len());
1352 assert_eq!(
1353 Definition(
1354 "Ones".into(),
1355 Rust::tuple_struct_from_type(RustType::Vec(
1356 Box::new(RustType::U8(Range::inclusive(0, 1))),
1357 Size::Any,
1358 EncodingOrdering::Keep
1359 )),
1360 ),
1361 model_rust.definitions[0]
1362 );
1363 assert_eq!(
1364 Definition(
1365 "NestedOnes".into(),
1366 Rust::tuple_struct_from_type(RustType::Vec(
1367 Box::new(RustType::Vec(
1368 Box::new(RustType::U8(Range::inclusive(0, 1))),
1369 Size::Any,
1370 EncodingOrdering::Keep
1371 )),
1372 Size::Any,
1373 EncodingOrdering::Keep
1374 )),
1375 ),
1376 model_rust.definitions[1]
1377 );
1378 assert_eq!(
1379 Definition(
1380 "Woah".into(),
1381 Rust::struct_from_fields(vec![
1382 RustField::from_name_type(
1383 "also_ones",
1384 RustType::Vec(
1385 Box::new(RustType::U8(Range::inclusive(0, 1))),
1386 Size::Any,
1387 EncodingOrdering::Keep
1388 ),
1389 ),
1390 RustField::from_name_type(
1391 "nesteds",
1392 RustType::Vec(
1393 Box::new(RustType::Vec(
1394 Box::new(RustType::U8(Range::inclusive(0, 1))),
1395 Size::Any,
1396 EncodingOrdering::Keep
1397 )),
1398 Size::Any,
1399 EncodingOrdering::Keep
1400 ),
1401 ),
1402 RustField::from_name_type(
1403 "optionals",
1404 RustType::Option(Box::new(RustType::Vec(
1405 Box::new(RustType::Vec(
1406 Box::new(RustType::U64(Range::none())),
1407 Size::Any,
1408 EncodingOrdering::Keep
1409 )),
1410 Size::Any,
1411 EncodingOrdering::Keep
1412 ))),
1413 )
1414 ]),
1415 ),
1416 model_rust.definitions[2]
1417 );
1418 }
1419
1420 #[test]
1421 fn test_inline_asn_choice_represented_correctly_as_rust_model() {
1422 let model_rust = Model::try_from(Tokenizer::default().parse(INLINE_ASN_WITH_CHOICE))
1423 .unwrap()
1424 .try_resolve()
1425 .unwrap()
1426 .to_rust();
1427
1428 assert_eq!("simple_schema", model_rust.name);
1429 assert_eq!(true, model_rust.imports.is_empty());
1430 assert_eq!(5, model_rust.definitions.len());
1431 assert_eq!(
1432 Definition(
1433 "This".into(),
1434 Rust::tuple_struct_from_type(RustType::Vec(
1435 Box::new(RustType::U8(Range::inclusive(0, 1))),
1436 Size::Any,
1437 EncodingOrdering::Keep
1438 )),
1439 ),
1440 model_rust.definitions[0]
1441 );
1442 assert_eq!(
1443 Definition(
1444 "That".into(),
1445 Rust::tuple_struct_from_type(RustType::Vec(
1446 Box::new(RustType::Vec(
1447 Box::new(RustType::U8(Range::inclusive(0, 1))),
1448 Size::Any,
1449 EncodingOrdering::Keep
1450 )),
1451 Size::Any,
1452 EncodingOrdering::Keep
1453 )),
1454 ),
1455 model_rust.definitions[1]
1456 );
1457 assert_eq!(
1458 Definition(
1459 "Neither".into(),
1460 Rust::Enum(vec!["Abc".into(), "Def".into(),].into()),
1461 ),
1462 model_rust.definitions[2]
1463 );
1464 assert_eq!(
1465 Definition(
1466 "WoahDecision".into(),
1467 Rust::DataEnum(
1468 vec![
1469 DataVariant::from_name_type(
1470 "This",
1471 RustType::Complex("This".into(), Some(Tag::DEFAULT_SEQUENCE_OF))
1472 ),
1473 DataVariant::from_name_type(
1474 "That",
1475 RustType::Complex("That".into(), Some(Tag::DEFAULT_SEQUENCE_OF))
1476 ),
1477 DataVariant::from_name_type(
1478 "Neither",
1479 RustType::Complex("Neither".into(), Some(Tag::DEFAULT_ENUMERATED))
1480 ),
1481 ]
1482 .into()
1483 )
1484 ),
1485 model_rust.definitions[3]
1486 );
1487 assert_eq!(
1488 Definition(
1489 "Woah".into(),
1490 Rust::struct_from_fields(vec![RustField::from_name_type(
1491 "decision",
1492 RustType::Complex("WoahDecision".into(), Some(Tag::DEFAULT_ENUMERATED)),
1493 )])
1494 ),
1495 model_rust.definitions[4]
1496 );
1497 }
1498
1499 #[test]
1500 fn test_inline_asn_sequence_represented_correctly_as_rust_model() {
1501 let model_rust = Model::try_from(Tokenizer::default().parse(INLINE_ASN_WITH_SEQUENCE))
1502 .unwrap()
1503 .try_resolve()
1504 .unwrap()
1505 .to_rust();
1506
1507 assert_eq!("simple_schema", model_rust.name);
1508 assert_eq!(true, model_rust.imports.is_empty());
1509 assert_eq!(2, model_rust.definitions.len());
1510 assert_eq!(
1511 Definition(
1512 "WoahComplex".into(),
1513 Rust::struct_from_fields(vec![
1514 RustField::from_name_type("ones", RustType::U8(Range::inclusive(0, 1))),
1515 RustField::from_name_type(
1516 "list_ones",
1517 RustType::Vec(
1518 Box::new(RustType::U8(Range::inclusive(0, 1))),
1519 Size::Any,
1520 EncodingOrdering::Keep
1521 ),
1522 ),
1523 RustField::from_name_type(
1524 "optional_ones",
1525 RustType::Option(Box::new(RustType::Vec(
1526 Box::new(RustType::U8(Range::inclusive(0, 1,))),
1527 Size::Any,
1528 EncodingOrdering::Keep
1529 ))),
1530 ),
1531 ]),
1532 ),
1533 model_rust.definitions[0]
1534 );
1535 assert_eq!(
1536 Definition(
1537 "Woah".into(),
1538 Rust::struct_from_fields(vec![RustField::from_name_type(
1539 "complex",
1540 RustType::Option(Box::new(RustType::Complex(
1541 "WoahComplex".into(),
1542 Some(Tag::DEFAULT_SEQUENCE)
1543 ))),
1544 )]),
1545 ),
1546 model_rust.definitions[1]
1547 );
1548 }
1549
1550 #[test]
1551 fn test_simple_enum() {
1552 let mut model_asn = Model::default();
1553 model_asn.definitions.push(Definition(
1554 "SimpleEnumTest".into(),
1555 AsnType::Enumerated(Enumerated::from_names(
1556 ["Bernd", "Das-Verdammte", "Brooot"].iter(),
1557 ))
1558 .untagged(),
1559 ));
1560
1561 let model_rust = model_asn.to_rust();
1562
1563 assert_eq!(1, model_rust.definitions.len());
1564 assert_eq!(
1565 Definition(
1566 "SimpleEnumTest".into(),
1567 Rust::Enum(vec!["Bernd".into(), "DasVerdammte".into(), "Brooot".into(),].into()),
1568 ),
1569 model_rust.definitions[0]
1570 );
1571 }
1572
1573 #[test]
1574 fn test_choice_simple() {
1575 let mut model_asn = Model::default();
1576 model_asn.definitions.push(Definition(
1577 "SimpleChoiceTest".into(),
1578 AsnType::choice_from_variants(vec![
1579 ChoiceVariant::name_type("bernd-das-brot", AsnType::unconstrained_utf8string()),
1580 ChoiceVariant::name_type("nochSoEinBrot", AsnType::unconstrained_octetstring()),
1581 ])
1582 .untagged(),
1583 ));
1584
1585 let model_rust = model_asn.to_rust();
1586
1587 assert_eq!(1, model_rust.definitions.len());
1588 assert_eq!(
1589 Definition(
1590 "SimpleChoiceTest".into(),
1591 Rust::DataEnum(
1592 vec![
1593 DataVariant::from_name_type(
1594 "BerndDasBrot",
1595 RustType::String(Size::Any, Charset::Utf8),
1596 ),
1597 DataVariant::from_name_type("NochSoEinBrot", RustType::VecU8(Size::Any)),
1598 ]
1599 .into()
1600 ),
1601 ),
1602 model_rust.definitions[0]
1603 )
1604 }
1605
1606 #[test]
1607 fn test_choice_list_and_nested_list() {
1608 let mut model_asn = Model::default();
1609 model_asn.definitions.push(Definition(
1610 "ListChoiceTestWithNestedList".into(),
1611 AsnType::choice_from_variants(vec![
1612 ChoiceVariant::name_type(
1613 "normal-List",
1614 AsnType::SequenceOf(Box::new(AsnType::unconstrained_utf8string()), Size::Any),
1615 ),
1616 ChoiceVariant::name_type(
1617 "NESTED-List",
1618 AsnType::SequenceOf(
1619 Box::new(AsnType::SequenceOf(
1620 Box::new(AsnType::unconstrained_octetstring()),
1621 Size::Any,
1622 )),
1623 Size::Any,
1624 ),
1625 ),
1626 ])
1627 .untagged(),
1628 ));
1629
1630 let model_rust = model_asn.to_rust();
1631
1632 assert_eq!(1, model_rust.definitions.len());
1633 assert_eq!(
1634 Definition(
1635 "ListChoiceTestWithNestedList".into(),
1636 Rust::DataEnum(
1637 vec![
1638 DataVariant::from_name_type(
1639 "NormalList",
1640 RustType::Vec(
1641 Box::new(RustType::String(Size::Any, Charset::Utf8)),
1642 Size::Any,
1643 EncodingOrdering::Keep
1644 ),
1645 ),
1646 DataVariant::from_name_type(
1647 "NestedList",
1648 RustType::Vec(
1649 Box::new(RustType::Vec(
1650 Box::new(RustType::VecU8(Size::Any)),
1651 Size::Any,
1652 EncodingOrdering::Keep
1653 )),
1654 Size::Any,
1655 EncodingOrdering::Keep
1656 ),
1657 ),
1658 ]
1659 .into()
1660 ),
1661 ),
1662 model_rust.definitions[0]
1663 )
1664 }
1665
1666 #[test]
1667 fn test_tuple_list() {
1668 let mut model_asn = Model::default();
1669 model_asn.name = "TupleTestModel".into();
1670 model_asn.definitions.push(Definition(
1671 "TupleTest".into(),
1672 AsnType::SequenceOf(Box::new(AsnType::unconstrained_utf8string()), Size::Any)
1673 .untagged(),
1674 ));
1675 let model_rust = model_asn.to_rust();
1676 assert_eq!("tuple_test_model", model_rust.name);
1677 assert_eq!(model_asn.imports, model_rust.imports);
1678 assert_eq!(1, model_rust.definitions.len());
1679 assert_eq!(
1680 Definition(
1681 "TupleTest".into(),
1682 Rust::tuple_struct_from_type(RustType::Vec(
1683 Box::new(RustType::String(Size::Any, Charset::Utf8)),
1684 Size::Any,
1685 EncodingOrdering::Keep
1686 )),
1687 ),
1688 model_rust.definitions[0]
1689 );
1690 }
1691
1692 #[test]
1693 fn test_nested_tuple_list() {
1694 let mut model_asn = Model::default();
1695 model_asn.name = "TupleTestModel".into();
1696 model_asn.definitions.push(Definition(
1697 "NestedTupleTest".into(),
1698 AsnType::SequenceOf(
1699 Box::new(AsnType::SequenceOf(
1700 Box::new(AsnType::unconstrained_utf8string()),
1701 Size::Any,
1702 )),
1703 Size::Any,
1704 )
1705 .untagged(),
1706 ));
1707 let model_rust = model_asn.to_rust();
1708 assert_eq!("tuple_test_model", model_rust.name);
1709 assert_eq!(model_asn.imports, model_rust.imports);
1710 assert_eq!(1, model_rust.definitions.len());
1711 assert_eq!(
1712 Definition(
1713 "NestedTupleTest".into(),
1714 Rust::tuple_struct_from_type(RustType::Vec(
1715 Box::new(RustType::Vec(
1716 Box::new(RustType::String(Size::Any, Charset::Utf8)),
1717 Size::Any,
1718 EncodingOrdering::Keep
1719 )),
1720 Size::Any,
1721 EncodingOrdering::Keep
1722 )),
1723 ),
1724 model_rust.definitions[0]
1725 );
1726 }
1727
1728 #[test]
1729 fn test_optional_list_in_struct() {
1730 let mut model_asn = Model::default();
1731 model_asn.name = "OptionalStructListTestModel".into();
1732 model_asn.definitions.push(Definition(
1733 "OptionalStructListTest".into(),
1734 AsnType::sequence_from_fields(vec![Field {
1735 name: "strings".into(),
1736 role: AsnType::SequenceOf(Box::new(AsnType::unconstrained_utf8string()), Size::Any)
1737 .optional()
1738 .untagged(),
1739 }])
1740 .untagged(),
1741 ));
1742 let model_rust = model_asn.to_rust();
1743 assert_eq!("optional_struct_list_test_model", model_rust.name);
1744 assert_eq!(model_asn.imports, model_rust.imports);
1745 assert_eq!(1, model_rust.definitions.len());
1746 assert_eq!(
1747 Definition(
1748 "OptionalStructListTest".into(),
1749 Rust::struct_from_fields(vec![RustField::from_name_type(
1750 "strings",
1751 RustType::Option(Box::new(RustType::Vec(
1752 Box::new(RustType::String(Size::Any, Charset::Utf8)),
1753 Size::Any,
1754 EncodingOrdering::Keep
1755 ))),
1756 )]),
1757 ),
1758 model_rust.definitions[0]
1759 );
1760 }
1761
1762 #[test]
1763 fn test_list_in_struct() {
1764 let mut model_asn = Model::default();
1765 model_asn.name = "StructListTestModel".into();
1766 model_asn.definitions.push(Definition(
1767 "StructListTest".into(),
1768 AsnType::sequence_from_fields(vec![Field {
1769 name: "strings".into(),
1770 role: AsnType::SequenceOf(Box::new(AsnType::unconstrained_utf8string()), Size::Any)
1771 .untagged(),
1772 }])
1773 .untagged(),
1774 ));
1775 let model_rust = model_asn.to_rust();
1776 assert_eq!("struct_list_test_model", model_rust.name);
1777 assert_eq!(model_asn.imports, model_rust.imports);
1778 assert_eq!(1, model_rust.definitions.len());
1779 assert_eq!(
1780 Definition(
1781 "StructListTest".into(),
1782 Rust::struct_from_fields(vec![RustField::from_name_type(
1783 "strings",
1784 RustType::Vec(
1785 Box::new(RustType::String(Size::Any, Charset::Utf8)),
1786 Size::Any,
1787 EncodingOrdering::Keep
1788 ),
1789 )]),
1790 ),
1791 model_rust.definitions[0]
1792 );
1793 }
1794
1795 #[test]
1796 fn test_nested_list_in_struct() {
1797 let mut model_asn = Model::default();
1798 model_asn.name = "NestedStructListTestModel".into();
1799 model_asn.definitions.push(Definition(
1800 "NestedStructListTest".into(),
1801 AsnType::sequence_from_fields(vec![Field {
1802 name: "strings".into(),
1803 role: AsnType::SequenceOf(
1804 Box::new(AsnType::SequenceOf(
1805 Box::new(AsnType::unconstrained_utf8string()),
1806 Size::Any,
1807 )),
1808 Size::Any,
1809 )
1810 .untagged(),
1811 }])
1812 .untagged(),
1813 ));
1814 let model_rust = model_asn.to_rust();
1815 assert_eq!("nested_struct_list_test_model", model_rust.name);
1816 assert_eq!(model_asn.imports, model_rust.imports);
1817 assert_eq!(1, model_rust.definitions.len());
1818 assert_eq!(
1819 Definition(
1820 "NestedStructListTest".into(),
1821 Rust::struct_from_fields(vec![RustField::from_name_type(
1822 "strings",
1823 RustType::Vec(
1824 Box::new(RustType::Vec(
1825 Box::new(RustType::String(Size::Any, Charset::Utf8)),
1826 Size::Any,
1827 EncodingOrdering::Keep
1828 )),
1829 Size::Any,
1830 EncodingOrdering::Keep
1831 ),
1832 )]),
1833 ),
1834 model_rust.definitions[0]
1835 );
1836 }
1837
1838 #[test]
1839 pub fn test_extensible_enum() {
1840 let mut model_asn = Model::default();
1841 model_asn.name = "ExtensibleEnum".to_string();
1842 model_asn.definitions.push(Definition(
1843 "Extensible".to_string(),
1844 AsnType::Enumerated(
1845 Enumerated::from(vec![
1846 "abc".into(),
1847 "def".into(),
1848 EnumeratedVariant::from_name_number("ghi", 42),
1849 ])
1850 .with_extension_after(2),
1851 )
1852 .untagged(),
1853 ));
1854 let model_rust = model_asn.to_rust();
1855 assert_eq!("extensible_enum", model_rust.name);
1856 assert_eq!(model_asn.imports, model_rust.imports);
1857 assert_eq!(
1858 &[Definition(
1859 "Extensible".into(),
1860 Rust::Enum(
1861 PlainEnum::from_names(["Abc", "Def", "Ghi"].iter())
1862 .with_extension_after(Some(2))
1863 ),
1864 )],
1865 &model_rust.definitions[..]
1866 );
1867 }
1868
1869 #[test]
1870 pub fn test_extensible_choice() {
1871 let mut model_asn = Model::default();
1872 model_asn.name = "ExtensibleChoice".to_string();
1873 model_asn.definitions.push(Definition(
1874 "Extensible".to_string(),
1875 AsnType::Choice(
1876 Choice::from(vec![
1877 ChoiceVariant::name_type("abc", Type::unconstrained_octetstring()),
1878 ChoiceVariant::name_type("def", Type::unconstrained_integer()),
1879 ChoiceVariant {
1880 name: "ghi".to_string(),
1881 tag: Some(Tag::Universal(4)),
1882 r#type: Type::Boolean,
1883 },
1884 ])
1885 .with_extension_after(2),
1886 )
1887 .untagged(),
1888 ));
1889
1890 let model_rust = model_asn.to_rust();
1891 assert_eq!("extensible_choice", model_rust.name);
1892 assert_eq!(model_asn.imports, model_rust.imports);
1893 assert_eq!(
1894 &[Definition(
1895 "Extensible".into(),
1896 Rust::DataEnum(
1897 DataEnum::from(vec![
1898 DataVariant::from_name_type("Abc".to_string(), RustType::VecU8(Size::Any)),
1899 DataVariant::from_name_type(
1900 "Def".to_string(),
1901 RustType::U64(Range::none()),
1902 ),
1903 DataVariant::from_name_type("Ghi".to_string(), RustType::Bool)
1904 .with_tag(Tag::Universal(4)),
1905 ])
1906 .with_extension_after(Some(2))
1907 ),
1908 )],
1909 &model_rust.definitions[..]
1910 );
1911 }
1912
1913 #[test]
1914 pub fn test_tag_property_rust_struct() {
1915 test_property(Rust::Struct {
1916 ordering: EncodingOrdering::Keep,
1917 fields: Vec::default(),
1918 tag: None,
1919 extension_after: None,
1920 });
1921 }
1922
1923 #[test]
1924 pub fn test_tag_property_rust_enum() {
1925 test_property(Rust::Enum(PlainEnum::from_names(
1926 Some("Variant").into_iter(),
1927 )));
1928 }
1929
1930 #[test]
1931 pub fn test_tag_property_rust_data_enum() {
1932 test_property(Rust::DataEnum(DataEnum::from(vec![
1933 DataVariant::from_name_type(
1934 "SomeName".to_string(),
1935 RustType::String(Size::Any, Charset::Visible),
1936 ),
1937 ])));
1938 }
1939
1940 #[test]
1941 pub fn test_tag_property_rust_tuple_struct() {
1942 test_property(Rust::TupleStruct {
1943 r#type: RustType::VecU8(Size::Any),
1944 tag: None,
1945 constants: Vec::default(),
1946 });
1947 }
1948
1949 #[test]
1950 pub fn test_tag_property_field() {
1951 test_property(RustField::from_name_type(
1952 "FieldName".to_string(),
1953 RustType::Bool,
1954 ));
1955 }
1956
1957 #[test]
1958 pub fn test_tag_property_enumeration() {
1959 test_property(Enumeration::from(vec!["VariantA", "VariantB"]));
1960 }
1961
1962 #[test]
1963 pub fn test_tag_property_data_variant() {
1964 test_property(DataVariant::from_name_type(
1965 "VariantName".to_string(),
1966 RustType::Bool,
1967 ));
1968 }
1969
1970 #[test]
1971 pub fn test_value_reference_to_rust() {
1972 let asn = Model::<Asn<Resolved>> {
1973 name: "SomeGreatName".to_string(),
1974 oid: None,
1975 imports: Vec::default(),
1976 definitions: Vec::default(),
1977 value_references: vec![
1978 ValueReference {
1979 name: "local-http".to_string(),
1980 role: AsnType::Integer(Integer::with_range(Range::inclusive(
1981 None,
1982 Some(65535),
1983 )))
1984 .untagged(),
1985 value: LiteralValue::Integer(8080),
1986 },
1987 ValueReference {
1988 name: "use-firewall".to_string(),
1989 role: AsnType::Boolean.untagged(),
1990 value: LiteralValue::Boolean(true),
1991 },
1992 ],
1993 };
1994
1995 assert_starts_with_lines(
1996 r#"
1997 use asn1rs::prelude::*;
1998
1999 pub const LOCAL_HTTP: u16 = 8080;
2000 pub const USE_FIREWALL: bool = true;
2001
2002 "#,
2003 &RustCodeGenerator::from(asn.to_rust())
2004 .to_string_without_generators()
2005 .into_iter()
2006 .map(|(_f, c)| c)
2007 .next()
2008 .unwrap(),
2009 );
2010 }
2011
2012 #[test]
2013 fn test_to_rust_coherent_complex_reference_renaming() {
2014 let asn = Model::<Asn<Resolved>> {
2015 name: "CoherentComplexRenaming".to_string(),
2016 oid: None,
2017 imports: vec![],
2018 definitions: vec![
2019 Definition("Some-Name-WithID".to_string(), Type::Boolean.untagged()),
2020 Definition(
2021 "Complex-Container".to_string(),
2022 Type::Sequence(ComponentTypeList {
2023 fields: vec![
2024 Field {
2025 name: "some-internal".to_string(),
2026 role: Type::Boolean.untagged(),
2027 },
2028 Field {
2029 name: "id".to_string(),
2030 role: Type::TypeReference("Some-Name-WithID".to_string(), None)
2031 .untagged(),
2032 },
2033 ],
2034 extension_after: None,
2035 })
2036 .untagged(),
2037 ),
2038 ],
2039 value_references: vec![],
2040 };
2041 assert_eq!(
2042 vec![
2043 Definition(
2044 "SomeNameWithId".to_string(),
2045 Rust::TupleStruct {
2046 r#type: RustType::Bool,
2047 tag: None,
2048 constants: vec![]
2049 }
2050 ),
2051 Definition(
2052 "ComplexContainer".to_string(),
2053 Rust::Struct {
2054 ordering: EncodingOrdering::Keep,
2055 fields: vec![
2056 crate::model::rust::Field::from_name_type(
2057 "some_internal".to_string(),
2058 RustType::Bool
2059 ),
2060 crate::model::rust::Field::from_name_type(
2061 "id".to_string(),
2062 RustType::Complex(
2063 "SomeNameWithId".to_string(),
2064 Some(Tag::Universal(1)) )
2066 ),
2067 ],
2068 tag: None,
2069 extension_after: None
2070 }
2071 ),
2072 ],
2073 asn.to_rust().definitions
2074 );
2075 }
2076}