Skip to main content

asn1rs_model/gen/rust/
mod.rs

1pub mod walker;
2
3#[cfg(feature = "psql")]
4pub mod psql;
5
6#[cfg(feature = "async-psql")]
7pub mod async_psql;
8
9#[cfg(any(feature = "psql", feature = "async-psql"))]
10pub(crate) mod shared_psql;
11
12use crate::gen::Generator;
13use crate::model::rust::{DataEnum, Field};
14use crate::model::rust::{EncodingOrdering, PlainEnum};
15use crate::model::Model;
16use crate::model::Rust;
17use crate::model::RustType;
18use crate::model::TagProperty;
19use crate::model::{Definition, Tag, Type as AsnType, Type};
20use codegen::Block;
21use codegen::Enum;
22use codegen::Impl;
23use codegen::Scope;
24use codegen::Struct;
25use std::borrow::Cow;
26use std::convert::Infallible;
27use std::fmt::Display;
28
29#[cfg(feature = "psql")]
30use self::psql::PsqlInserter;
31
32#[cfg(feature = "async-psql")]
33use self::async_psql::AsyncPsqlInserter;
34
35const KEYWORDS: [&str; 9] = [
36    "use", "mod", "const", "type", "pub", "enum", "struct", "impl", "trait",
37];
38
39pub trait GeneratorSupplement<T> {
40    fn add_imports(&self, scope: &mut Scope);
41    fn impl_supplement(&self, scope: &mut Scope, definition: &Definition<T>);
42    fn extend_impl_of_struct(&self, _name: &str, _impl_scope: &mut Impl, _fields: &[Field]) {}
43    fn extend_impl_of_enum(&self, _name: &str, _impl_scope: &mut Impl, _enumeration: &PlainEnum) {}
44    fn extend_impl_of_data_enum(
45        &self,
46        _name: &str,
47        _impl_scope: &mut Impl,
48        _enumeration: &DataEnum,
49    ) {
50    }
51    fn extend_impl_of_tuple(&self, _name: &str, _impl_scope: &mut Impl, _definition: &RustType) {}
52}
53
54#[allow(clippy::module_name_repetitions)]
55#[derive(Debug)]
56pub struct RustCodeGenerator {
57    models: Vec<Model<Rust>>,
58    global_derives: Vec<String>,
59    direct_field_access: bool,
60    getter_and_setter: bool,
61}
62
63impl From<Model<Rust>> for RustCodeGenerator {
64    fn from(model: Model<Rust>) -> Self {
65        let mut gen = Self::default();
66        gen.add_model(model);
67        gen
68    }
69}
70
71impl Default for RustCodeGenerator {
72    fn default() -> Self {
73        RustCodeGenerator {
74            models: Default::default(),
75            global_derives: Vec::default(),
76            direct_field_access: true,
77            getter_and_setter: false,
78        }
79    }
80}
81
82impl Generator<Rust> for RustCodeGenerator {
83    type Error = Infallible;
84
85    fn add_model(&mut self, model: Model<Rust>) {
86        self.models.push(model);
87    }
88
89    fn models(&self) -> &[Model<Rust>] {
90        &self.models[..]
91    }
92
93    fn models_mut(&mut self) -> &mut [Model<Rust>] {
94        &mut self.models[..]
95    }
96
97    fn to_string(&self) -> Result<Vec<(String, String)>, Self::Error> {
98        Ok(self.to_string_with_generators(&[
99            #[cfg(feature = "psql")]
100            &PsqlInserter,
101            #[cfg(feature = "async-psql")]
102            &AsyncPsqlInserter,
103        ]))
104    }
105}
106
107impl RustCodeGenerator {
108    pub fn add_global_derive<I: Into<String>>(&mut self, derive: I) {
109        self.global_derives.push(derive.into());
110    }
111
112    pub fn without_additional_global_derives(mut self) -> Self {
113        self.global_derives.clear();
114        self
115    }
116
117    pub const fn fields_are_pub(&self) -> bool {
118        self.direct_field_access
119    }
120
121    pub fn set_fields_pub(&mut self, allow: bool) {
122        self.direct_field_access = allow;
123    }
124
125    pub const fn fields_have_getter_and_setter(&self) -> bool {
126        self.getter_and_setter
127    }
128
129    pub fn set_fields_have_getter_and_setter(&mut self, allow: bool) {
130        self.getter_and_setter = allow;
131    }
132
133    pub fn to_string_without_generators(&self) -> Vec<(String, String)> {
134        self.to_string_with_generators(&[])
135    }
136
137    pub fn to_string_with_generators(
138        &self,
139        generators: &[&dyn GeneratorSupplement<Rust>],
140    ) -> Vec<(String, String)> {
141        let mut files = Vec::new();
142        for model in &self.models {
143            files.push(self.model_to_file(model, generators));
144        }
145        files
146    }
147
148    pub fn model_to_file(
149        &self,
150        model: &Model<Rust>,
151        generators: &[&dyn GeneratorSupplement<Rust>],
152    ) -> (String, String) {
153        let file = {
154            let mut string = Self::rust_module_name(&model.name);
155            string.push_str(".rs");
156            string
157        };
158
159        let mut scope = Scope::new();
160        generators.iter().for_each(|g| g.add_imports(&mut scope));
161
162        scope.import("asn1rs::prelude", "*");
163        for import in &model.imports {
164            let from = format!("super::{}", &Self::rust_module_name(&import.from));
165            for what in &import.what {
166                scope.import(&from, what);
167            }
168        }
169
170        for vref in &model.value_references {
171            scope.raw(&Self::fmt_const(
172                &vref.name,
173                &vref.role,
174                &vref.value.as_rust_const_literal(true),
175                0,
176            ));
177        }
178
179        for definition in &model.definitions {
180            self.add_definition(&mut scope, definition);
181            Self::impl_definition(&mut scope, definition, generators, self.getter_and_setter);
182
183            generators
184                .iter()
185                .for_each(|g| g.impl_supplement(&mut scope, definition));
186        }
187
188        (file, scope.to_string())
189    }
190
191    fn fmt_const(name: &str, r#type: &RustType, value: &impl Display, indent: usize) -> String {
192        format!(
193            "{}pub const {}: {} = {};",
194            "    ".repeat(indent),
195            name,
196            r#type.to_const_lit_string(),
197            if let RustType::Complex(..) = r#type {
198                format!("{}::new({})", r#type.to_const_lit_string(), value)
199            } else {
200                value.to_string()
201            }
202        )
203    }
204
205    pub fn add_definition(&self, scope: &mut Scope, Definition(name, rust): &Definition<Rust>) {
206        match rust {
207            Rust::Struct {
208                fields,
209                tag,
210                extension_after,
211                ordering,
212            } => {
213                scope.raw(&Self::asn_attribute(
214                    match ordering {
215                        EncodingOrdering::Keep => "sequence",
216                        EncodingOrdering::Sort => "set",
217                    },
218                    *tag,
219                    extension_after.map(|index| fields[index].name().to_string()),
220                    &[],
221                ));
222                Self::add_struct(
223                    self.new_struct(scope, name),
224                    name,
225                    fields,
226                    self.direct_field_access,
227                )
228            }
229            Rust::Enum(plain) => {
230                scope.raw(&Self::asn_attribute(
231                    "enumerated",
232                    plain.tag(),
233                    plain.extension_after_variant().cloned(),
234                    &[],
235                ));
236                Self::add_enum(
237                    self.new_enum(scope, name, true).derive("Default"),
238                    name,
239                    plain,
240                )
241            }
242            Rust::DataEnum(data) => {
243                scope.raw(&Self::asn_attribute(
244                    "choice",
245                    data.tag(),
246                    data.extension_after_variant().map(|v| v.name().to_string()),
247                    &[],
248                ));
249                Self::add_data_enum(self.new_enum(scope, name, false), name, data)
250            }
251            Rust::TupleStruct {
252                r#type,
253                tag,
254                constants,
255            } => {
256                scope.raw(&Self::asn_attribute("transparent", *tag, None, &[]));
257                Self::add_tuple_struct(
258                    self.new_struct(scope, name),
259                    name,
260                    r#type,
261                    self.direct_field_access,
262                    None,
263                    &constants[..],
264                )
265            }
266        }
267    }
268
269    fn add_struct(str_ct: &mut Struct, _name: &str, fields: &[Field], pub_access: bool) {
270        for field in fields {
271            str_ct.field(
272                &format!(
273                    "{} {}{}",
274                    Self::asn_attribute(
275                        Self::asn_attribute_type(&field.r#type().clone().into_asn()),
276                        field.tag(),
277                        None,
278                        field.constants(),
279                    ),
280                    if pub_access { "pub " } else { "" },
281                    Self::rust_field_name(field.name(), true),
282                ),
283                field.r#type().to_string(),
284            );
285        }
286    }
287
288    fn add_enum(en_m: &mut Enum, _name: &str, rust_enum: &PlainEnum) {
289        for (index, variant) in rust_enum.variants().enumerate() {
290            let name = Self::rust_variant_name(variant);
291            let name = if index == 0 {
292                format!("#[default] {name}")
293            } else {
294                name
295            };
296            en_m.new_variant(&name);
297        }
298    }
299
300    fn add_data_enum(en_m: &mut Enum, _name: &str, enumeration: &DataEnum) {
301        for variant in enumeration.variants() {
302            en_m.new_variant(&format!(
303                "{} {}({})",
304                Self::asn_attribute(
305                    Self::asn_attribute_type(&variant.r#type().clone().into_asn()),
306                    variant.tag(),
307                    None,
308                    &[],
309                ),
310                Self::rust_variant_name(variant.name()),
311                variant.r#type().to_string(),
312            ));
313        }
314    }
315
316    fn add_tuple_struct(
317        str_ct: &mut Struct,
318        _name: &str,
319        inner: &RustType,
320        pub_access: bool,
321        tag: Option<Tag>,
322        constants: &[(String, String)],
323    ) {
324        str_ct.tuple_field(format!(
325            "{} {}{}",
326            Self::asn_attribute(
327                Self::asn_attribute_type(&inner.clone().into_asn()),
328                tag,
329                None,
330                constants,
331            ),
332            if pub_access { "pub " } else { "" },
333            inner.to_string(),
334        ));
335    }
336
337    fn asn_attribute<T: ToString>(
338        r#type: T,
339        tag: Option<Tag>,
340        extensible_after: Option<String>,
341        constants: &[(String, String)],
342    ) -> String {
343        format!(
344            "#[asn({})]",
345            vec![
346                Some(r#type.to_string()),
347                tag.map(Self::asn_attribute_tag),
348                extensible_after.map(Self::asn_attribute_extensible_after),
349                if constants.is_empty() {
350                    None
351                } else {
352                    Some(format!(
353                        "const({})",
354                        constants
355                            .iter()
356                            .map(|(name, value)| format!("{}({})", name, value))
357                            .collect::<Vec<_>>()
358                            .join(", ")
359                    ))
360                }
361            ]
362            .into_iter()
363            .flatten()
364            .collect::<Vec<_>>()
365            .join(", ")
366        )
367    }
368
369    fn asn_attribute_type(r#type: &AsnType) -> String {
370        let (name, parameters) = match r#type {
371            Type::Boolean => (Cow::Borrowed("boolean"), Vec::default()),
372            Type::Integer(integer) => (
373                Cow::Borrowed("integer"),
374                vec![format!(
375                    "{}..{}{}",
376                    integer
377                        .range
378                        .min()
379                        .as_ref()
380                        .map(ToString::to_string)
381                        .unwrap_or_else(|| "min".to_string()),
382                    integer
383                        .range
384                        .max()
385                        .as_ref()
386                        .map(ToString::to_string)
387                        .unwrap_or_else(|| "max".to_string()),
388                    if integer.range.extensible() {
389                        ",..."
390                    } else {
391                        ""
392                    }
393                )],
394            ),
395            Type::String(size, charset) => (
396                Cow::Owned(format!("{:?}string", charset).to_lowercase()),
397                vec![size.to_constraint_string()]
398                    .into_iter()
399                    .flatten()
400                    .collect(),
401            ),
402            Type::OctetString(size) => (
403                Cow::Borrowed("octet_string"),
404                vec![size.to_constraint_string()]
405                    .into_iter()
406                    .flatten()
407                    .collect(),
408            ),
409            Type::BitString(bitstring) => (
410                Cow::Borrowed("bit_string"),
411                vec![vec![bitstring.size.to_constraint_string()]
412                    .into_iter()
413                    .flatten()
414                    .collect()],
415            ),
416            Type::Null => (Cow::Borrowed("null"), Vec::default()),
417            Type::Optional(inner) => (
418                Cow::Borrowed("optional"),
419                vec![Self::asn_attribute_type(inner)],
420            ),
421            Type::Default(inner, default) => (
422                Cow::Borrowed("default"),
423                vec![
424                    Self::asn_attribute_type(inner),
425                    default.as_rust_const_literal(true).to_string(),
426                ],
427            ),
428            Type::SequenceOf(inner, size) => (
429                Cow::Borrowed("sequence_of"),
430                vec![
431                    size.to_constraint_string(),
432                    Some(Self::asn_attribute_type(inner)),
433                ]
434                .into_iter()
435                .flatten()
436                .collect(),
437            ),
438            Type::SetOf(inner, size) => (
439                Cow::Borrowed("set_of"),
440                vec![
441                    size.to_constraint_string(),
442                    Some(Self::asn_attribute_type(inner)),
443                ]
444                .into_iter()
445                .flatten()
446                .collect(),
447            ),
448
449            Type::Sequence(_) => (Cow::Borrowed("sequence"), Vec::default()),
450            Type::Set(_) => (Cow::Borrowed("set"), Vec::default()),
451            Type::Enumerated(_) => (Cow::Borrowed("enumerated"), Vec::default()),
452            Type::Choice(_) => (Cow::Borrowed("choice"), Vec::default()),
453            Type::TypeReference(inner, tag) => (
454                Cow::Borrowed("complex"),
455                vec![Some(inner.clone()), (*tag).map(Self::asn_attribute_tag)]
456                    .into_iter()
457                    .flatten()
458                    .collect(),
459            ),
460        };
461        if parameters.is_empty() {
462            name.into_owned()
463        } else {
464            format!("{}({})", name, parameters.join(", "))
465        }
466    }
467
468    fn asn_attribute_tag(tag: Tag) -> String {
469        match tag {
470            Tag::Universal(t) => format!("tag(UNIVERSAL({}))", t),
471            Tag::Application(t) => format!("tag(APPLICATION({}))", t),
472            Tag::Private(t) => format!("tag(PRIVATE({}))", t),
473            Tag::ContextSpecific(t) => format!("tag({})", t),
474        }
475    }
476
477    fn asn_attribute_extensible_after(variant: String) -> String {
478        format!("extensible_after({})", variant)
479    }
480
481    fn impl_definition(
482        scope: &mut Scope,
483        Definition(name, rust): &Definition<Rust>,
484        generators: &[&dyn GeneratorSupplement<Rust>],
485        getter_and_setter: bool,
486    ) {
487        match rust {
488            Rust::Struct {
489                fields,
490                tag: _,
491                extension_after: _,
492                ordering: _,
493            } => {
494                Self::impl_consts(
495                    scope,
496                    name,
497                    fields
498                        .iter()
499                        .map(|f| (f.name_type.0.as_str(), &f.name_type.1, &f.constants[..])),
500                );
501                let implementation = Self::impl_struct(scope, name, fields, getter_and_setter);
502                for g in generators {
503                    g.extend_impl_of_struct(name, implementation, fields);
504                }
505            }
506            Rust::Enum(r_enum) => {
507                let implementation = Self::impl_enum(scope, name, r_enum);
508                for g in generators {
509                    g.extend_impl_of_enum(name, implementation, r_enum);
510                }
511            }
512            Rust::DataEnum(enumeration) => {
513                let implementation = Self::impl_data_enum(scope, name, enumeration);
514                for g in generators {
515                    g.extend_impl_of_data_enum(name, implementation, enumeration);
516                }
517                Self::impl_data_enum_default(scope, name, enumeration);
518            }
519            Rust::TupleStruct {
520                r#type: inner,
521                tag: _,
522                constants,
523            } => {
524                Self::impl_consts(scope, name, Some(("", inner, &constants[..])).into_iter());
525                let implementation = Self::impl_tuple_struct(scope, name, inner);
526                for g in generators {
527                    g.extend_impl_of_tuple(name, implementation, inner);
528                }
529                Self::impl_tuple_struct_const_new(scope, name, inner);
530                Self::impl_tuple_struct_deref(scope, name, inner);
531                Self::impl_tuple_struct_deref_mut(scope, name, inner);
532                Self::impl_tuple_struct_from(scope, name, inner);
533            }
534        }
535    }
536
537    fn impl_tuple_struct_const_new(scope: &mut Scope, name: &str, rust: &RustType) {
538        scope
539            .new_impl(name)
540            .new_fn("new")
541            .vis("pub const")
542            .arg("value", rust.to_string())
543            .ret("Self")
544            .line("Self(value)");
545    }
546
547    fn impl_tuple_struct_deref(scope: &mut Scope, name: &str, rust: &RustType) {
548        scope
549            .new_impl(name)
550            .impl_trait("::core::ops::Deref")
551            .associate_type("Target", rust.to_string())
552            .new_fn("deref")
553            .arg_ref_self()
554            .ret(&format!("&{}", rust.to_string()))
555            .line("&self.0".to_string());
556    }
557
558    fn impl_tuple_struct_deref_mut(scope: &mut Scope, name: &str, rust: &RustType) {
559        scope
560            .new_impl(name)
561            .impl_trait("::core::ops::DerefMut")
562            .new_fn("deref_mut")
563            .arg_mut_self()
564            .ret(&format!("&mut {}", rust.to_string()))
565            .line("&mut self.0".to_string());
566    }
567
568    fn impl_tuple_struct_from(scope: &mut Scope, name: &str, rust: &RustType) {
569        scope
570            .new_impl(name)
571            .impl_trait(format!("::core::convert::From<{}>", rust.to_string()))
572            .new_fn("from")
573            .arg("value", &rust.to_string())
574            .ret("Self")
575            .line("Self(value)");
576        scope
577            .new_impl(&rust.to_string())
578            .impl_trait(format!("::core::convert::From<{}>", name))
579            .new_fn("from")
580            .arg("value", name)
581            .ret("Self")
582            .line("value.0");
583    }
584
585    fn impl_tuple_struct<'a>(scope: &'a mut Scope, name: &str, rust: &RustType) -> &'a mut Impl {
586        let implementation = scope.new_impl(name);
587        Self::add_min_max_fn_if_applicable(implementation, None, rust);
588        implementation
589    }
590
591    fn impl_struct<'a>(
592        scope: &'a mut Scope,
593        name: &str,
594        fields: &[Field],
595        getter_and_setter: bool,
596    ) -> &'a mut Impl {
597        let implementation = scope.new_impl(name);
598
599        for field in fields {
600            if getter_and_setter {
601                Self::impl_struct_field_get(implementation, field.name(), field.r#type());
602                Self::impl_struct_field_get_mut(implementation, field.name(), field.r#type());
603                Self::impl_struct_field_set(implementation, field.name(), field.r#type());
604            }
605
606            Self::add_min_max_fn_if_applicable(implementation, Some(field.name()), field.r#type());
607        }
608        implementation
609    }
610
611    fn impl_consts<'a>(
612        scope: &mut Scope,
613        name: &str,
614        fields: impl Iterator<Item = (&'a str, &'a RustType, &'a [(String, String)])>,
615    ) {
616        let mut found_consts = false;
617        for (field, r#type, constants) in fields {
618            if !found_consts && !constants.is_empty() {
619                scope.raw(&format!("impl {} {{", name));
620                found_consts = true;
621            }
622            for (name, value) in constants {
623                scope.raw(&Self::fmt_const(
624                    &if field.is_empty() {
625                        Cow::Borrowed(name)
626                    } else {
627                        Cow::Owned(format!("{}_{}", field.to_uppercase(), name))
628                    },
629                    r#type,
630                    value,
631                    1,
632                ));
633            }
634        }
635        if found_consts {
636            scope.raw("}");
637        }
638    }
639
640    fn impl_struct_field_get(implementation: &mut Impl, field_name: &str, field_type: &RustType) {
641        implementation
642            .new_fn(&Self::rust_field_name(field_name, true))
643            .vis("pub")
644            .arg_ref_self()
645            .ret(format!("&{}", field_type.to_string()))
646            .line(format!("&self.{}", Self::rust_field_name(field_name, true)));
647    }
648
649    fn impl_struct_field_get_mut(
650        implementation: &mut Impl,
651        field_name: &str,
652        field_type: &RustType,
653    ) {
654        implementation
655            .new_fn(&format!("{}_mut", field_name))
656            .vis("pub")
657            .arg_mut_self()
658            .ret(format!("&mut {}", field_type.to_string()))
659            .line(format!(
660                "&mut self.{}",
661                Self::rust_field_name(field_name, true)
662            ));
663    }
664
665    fn impl_struct_field_set(implementation: &mut Impl, field_name: &str, field_type: &RustType) {
666        implementation
667            .new_fn(&format!("set_{}", field_name))
668            .vis("pub")
669            .arg_mut_self()
670            .arg("value", field_type.to_string())
671            .line(format!(
672                "self.{} = value;",
673                Self::rust_field_name(field_name, true)
674            ));
675    }
676
677    fn impl_enum<'a>(scope: &'a mut Scope, name: &str, r_enum: &PlainEnum) -> &'a mut Impl {
678        let implementation = scope.new_impl(name);
679
680        Self::impl_enum_value_fn(implementation, name, r_enum);
681        Self::impl_enum_values_fn(implementation, name, r_enum);
682        Self::impl_enum_value_index_fn(implementation, name, r_enum);
683        implementation
684    }
685
686    fn impl_enum_value_fn(implementation: &mut Impl, name: &str, r_enum: &PlainEnum) {
687        let value_fn = implementation
688            .new_fn("variant")
689            .vis("pub")
690            .arg("index", "usize")
691            .ret("Option<Self>");
692
693        let mut block_match = Block::new("match index");
694
695        for (index, variant) in r_enum.variants().enumerate() {
696            block_match.line(format!(
697                "{} => Some({}::{}),",
698                index,
699                name,
700                Self::rust_variant_name(variant)
701            ));
702        }
703        block_match.line("_ => None,");
704        value_fn.push_block(block_match);
705    }
706
707    fn impl_enum_values_fn(implementation: &mut Impl, name: &str, r_enum: &PlainEnum) {
708        let values_fn = implementation
709            .new_fn("variants")
710            .vis("pub const")
711            .ret(format!("[Self; {}]", r_enum.len()))
712            .line("[");
713
714        for variant in r_enum.variants() {
715            values_fn.line(format!("{}::{},", name, Self::rust_variant_name(variant)));
716        }
717        values_fn.line("]");
718    }
719
720    fn impl_enum_value_index_fn(implementation: &mut Impl, name: &str, r_enum: &PlainEnum) {
721        let ordinal_fn = implementation
722            .new_fn("value_index")
723            .arg_self()
724            .vis("pub")
725            .ret("usize");
726
727        let mut block = Block::new("match self");
728        r_enum
729            .variants()
730            .enumerate()
731            .for_each(|(ordinal, variant)| {
732                block.line(format!(
733                    "{}::{} => {},",
734                    name,
735                    Self::rust_variant_name(variant),
736                    ordinal
737                ));
738            });
739
740        ordinal_fn.push_block(block);
741    }
742
743    fn impl_data_enum<'a>(
744        scope: &'a mut Scope,
745        name: &str,
746        enumeration: &DataEnum,
747    ) -> &'a mut Impl {
748        let implementation = scope.new_impl(name);
749
750        Self::impl_data_enum_values_fn(implementation, name, enumeration);
751        Self::impl_data_enum_value_index_fn(implementation, name, enumeration);
752
753        for variant in enumeration.variants() {
754            let field_name = Self::rust_module_name(variant.name());
755            Self::add_min_max_fn_if_applicable(implementation, Some(&field_name), variant.r#type());
756        }
757
758        implementation
759    }
760
761    fn impl_data_enum_values_fn(implementation: &mut Impl, name: &str, enumeration: &DataEnum) {
762        let values_fn = implementation
763            .new_fn("variants")
764            .vis("pub")
765            .ret(format!("[Self; {}]", enumeration.len()))
766            .line("[");
767
768        for variant in enumeration.variants() {
769            values_fn.line(format!(
770                "{}::{}(Default::default()),",
771                name,
772                Self::rust_variant_name(variant.name())
773            ));
774        }
775        values_fn.line("]");
776    }
777
778    fn impl_data_enum_value_index_fn(
779        implementation: &mut Impl,
780        name: &str,
781        enumeration: &DataEnum,
782    ) {
783        let ordinal_fn = implementation
784            .new_fn("value_index")
785            .arg_ref_self()
786            .vis("pub")
787            .ret("usize");
788
789        let mut block = Block::new("match self");
790        enumeration
791            .variants()
792            .enumerate()
793            .for_each(|(ordinal, variant)| {
794                block.line(format!(
795                    "{}::{}(_) => {},",
796                    name,
797                    Self::rust_variant_name(variant.name()),
798                    ordinal
799                ));
800            });
801
802        ordinal_fn.push_block(block);
803    }
804
805    fn impl_data_enum_default(scope: &mut Scope, name: &str, enumeration: &DataEnum) {
806        scope
807            .new_impl(name)
808            .impl_trait("Default")
809            .new_fn("default")
810            .ret(name as &str)
811            .line(format!(
812                "{}::{}(Default::default())",
813                name,
814                Self::rust_variant_name(enumeration.variants().next().unwrap().name())
815            ));
816    }
817
818    fn add_min_max_fn_if_applicable(
819        implementation: &mut Impl,
820        field_name: Option<&str>,
821        field_type: &RustType,
822    ) {
823        let prefix = if let Some(field_name) = field_name {
824            format!("{}_", field_name)
825        } else {
826            "value_".to_string()
827        };
828        if let Some(range) = field_type.integer_range_str() {
829            implementation
830                .new_fn(&format!("{}min", prefix))
831                .vis("pub const")
832                .ret(&field_type.to_inner_type_string())
833                .line(&Self::format_number_nicely(range.min()));
834            implementation
835                .new_fn(&format!("{}max", prefix))
836                .vis("pub const")
837                .ret(&field_type.to_inner_type_string())
838                .line(&Self::format_number_nicely(range.max()));
839        }
840    }
841
842    fn format_number_nicely(string: &str) -> String {
843        let mut out = String::with_capacity(string.len() * 2);
844        let mut pos = (3 - string.len() % 3) % 3;
845        for char in string.chars() {
846            out.push(char);
847            pos = (pos + 1) % 3;
848            if pos == 0 && char.is_numeric() {
849                out.push('_');
850            }
851        }
852        let len = out.len();
853        out.remove(len - 1);
854        out
855    }
856
857    pub fn rust_field_name(name: &str, check_for_keywords: bool) -> String {
858        let mut name = name.replace('-', "_");
859        if check_for_keywords {
860            for keyword in &KEYWORDS {
861                if keyword.eq(&name) {
862                    name.push('_');
863                    return name;
864                }
865            }
866        }
867        name
868    }
869
870    pub fn rust_variant_name(name: &str) -> String {
871        let mut out = String::new();
872        let mut next_upper = true;
873        for c in name.chars() {
874            if next_upper {
875                out.push_str(&c.to_uppercase().to_string());
876                next_upper = false;
877            } else if c == '-' || c == '_' {
878                next_upper = true;
879            } else {
880                out.push(c);
881            }
882        }
883        out
884    }
885
886    pub fn rust_module_name(name: &str) -> String {
887        let mut out = String::new();
888        let mut prev_lowered = false;
889        let mut chars = name.chars().peekable();
890        while let Some(c) = chars.next() {
891            let mut lowered = false;
892            if c.is_uppercase() {
893                if !out.is_empty() {
894                    if !prev_lowered {
895                        out.push('_');
896                    } else if let Some(next) = chars.peek() {
897                        if next.is_lowercase() {
898                            out.push('_');
899                        }
900                    }
901                }
902                lowered = true;
903                out.push_str(&c.to_lowercase().to_string());
904            } else if c == '-' {
905                out.push('_');
906            } else {
907                out.push(c);
908            }
909            prev_lowered = lowered;
910        }
911        out
912    }
913
914    fn new_struct<'a>(&self, scope: &'a mut Scope, name: &str) -> &'a mut Struct {
915        let str_ct = scope
916            .new_struct(name)
917            .vis("pub")
918            .derive("Default")
919            .derive("Debug")
920            .derive("Clone")
921            .derive("PartialEq")
922            .derive("Hash");
923        self.global_derives.iter().for_each(|derive| {
924            str_ct.derive(derive);
925        });
926        str_ct
927    }
928
929    fn new_enum<'a>(&self, scope: &'a mut Scope, name: &str, c_enum: bool) -> &'a mut Enum {
930        let en_m = scope
931            .new_enum(name)
932            .vis("pub")
933            .derive("Debug")
934            .derive("Clone")
935            .derive("PartialEq")
936            .derive("Hash");
937        if c_enum {
938            en_m.derive("Copy").derive("PartialOrd").derive("Eq");
939        }
940        self.global_derives.iter().for_each(|derive| {
941            en_m.derive(derive);
942        });
943        en_m
944    }
945}
946
947#[cfg(test)]
948pub(crate) mod tests {
949    use super::*;
950    use crate::gen::rust::walker::tests::assert_starts_with_lines;
951    use crate::parser::Tokenizer;
952
953    #[test]
954    pub fn test_integer_struct_constants() {
955        let model = Model::try_from(Tokenizer::default().parse(
956            r#"BasicInteger DEFINITIONS AUTOMATIC TAGS ::=
957            BEGIN
958
959            MyStruct ::= SEQUENCE {
960                item INTEGER { apple(8), banana(9) } (0..255)
961            }
962
963            END
964        "#,
965        ))
966        .unwrap()
967        .try_resolve()
968        .unwrap()
969        .to_rust();
970
971        let (_file_name, file_content) = RustCodeGenerator::from(model)
972            .without_additional_global_derives()
973            .to_string_without_generators()
974            .into_iter()
975            .next()
976            .unwrap();
977
978        assert_starts_with_lines(
979            r#"
980            use asn1rs::prelude::*;
981            
982            #[asn(sequence)]
983            #[derive(Default, Debug, Clone, PartialEq, Hash)]
984            pub struct MyStruct {
985                #[asn(integer(0..255), const(APPLE(8), BANANA(9)))] pub item: u8,
986            }
987            
988            impl MyStruct {
989                pub const ITEM_APPLE: u8 = 8;
990                pub const ITEM_BANANA: u8 = 9;
991            }
992
993        "#,
994            &file_content,
995        );
996    }
997
998    #[test]
999    pub fn test_integer_tuple_constants() {
1000        let model = Model::try_from(Tokenizer::default().parse(
1001            r#"BasicInteger DEFINITIONS AUTOMATIC TAGS ::=
1002            BEGIN
1003            
1004            MyTuple ::= INTEGER { abc(8), bernd(9) } (0..255)
1005            
1006            END
1007        "#,
1008        ))
1009        .unwrap()
1010        .try_resolve()
1011        .unwrap()
1012        .to_rust();
1013
1014        let (_file_name, file_content) = RustCodeGenerator::from(model)
1015            .without_additional_global_derives()
1016            .to_string_without_generators()
1017            .into_iter()
1018            .next()
1019            .unwrap();
1020
1021        assert_starts_with_lines(
1022            r#"
1023            use asn1rs::prelude::*;
1024            
1025            #[asn(transparent)]
1026            #[derive(Default, Debug, Clone, PartialEq, Hash)]
1027            pub struct MyTuple(#[asn(integer(0..255), const(ABC(8), BERND(9)))] pub u8);
1028            
1029            impl MyTuple {
1030                pub const ABC: u8 = 8;
1031                pub const BERND: u8 = 9;
1032            }
1033            
1034        "#,
1035            &file_content,
1036        );
1037    }
1038}