vexil_codegen_rust/
config.rs1use std::collections::HashSet;
2
3use vexil_lang::ast::DefaultValue;
4use vexil_lang::ir::{ConfigDef, ConfigFieldDef, ResolvedType, TypeDef, TypeId, TypeRegistry};
5
6use crate::annotations::{emit_field_annotations, emit_type_annotations};
7use crate::emit::CodeWriter;
8use crate::types::rust_type;
9
10pub fn emit_config(
14 w: &mut CodeWriter,
15 cfg: &ConfigDef,
16 registry: &TypeRegistry,
17 needs_box: &HashSet<(TypeId, usize)>,
18) {
19 let name = cfg.name.as_str();
20
21 emit_type_annotations(w, &cfg.annotations);
23
24 w.line("#[derive(Debug, Clone, PartialEq)]");
26 w.open_block(&format!("pub struct {name}"));
27 for field in &cfg.fields {
28 emit_field_annotations(w, &field.annotations);
29 let field_rust_type = rust_type(&field.resolved_type, registry, needs_box, None);
30 w.line(&format!("pub {}: {},", field.name, field_rust_type));
31 }
32 w.close_block();
33 w.blank();
34
35 w.open_block(&format!("impl Default for {name}"));
37 w.open_block("fn default() -> Self");
38 w.open_block("Self");
39 for field in &cfg.fields {
40 let mut expr = default_value_expr(&field.default_value, field, registry);
41 if matches!(&field.resolved_type, ResolvedType::Optional(_))
43 && !matches!(&field.default_value, DefaultValue::None)
44 {
45 expr = format!("Some({expr})");
46 }
47 w.line(&format!("{}: {},", field.name, expr));
48 }
49 w.close_block();
50 w.close_block();
51 w.close_block();
52 w.blank();
53}
54
55fn default_value_expr(
57 value: &DefaultValue,
58 field: &ConfigFieldDef,
59 registry: &TypeRegistry,
60) -> String {
61 match value {
62 DefaultValue::None => "None".to_string(),
63 DefaultValue::Bool(b) => {
64 if *b {
65 "true".to_string()
66 } else {
67 "false".to_string()
68 }
69 }
70 DefaultValue::Int(n) => format!("{n}"),
71 DefaultValue::UInt(n) => format!("{n}"),
72 DefaultValue::Float(f) => format!("{f}"),
73 DefaultValue::Str(s) => format!("String::from(\"{s}\")"),
74 DefaultValue::Ident(name) => {
77 let type_name = resolve_type_name(&field.resolved_type, registry);
78 format!("{type_name}::{name}")
79 }
80 DefaultValue::UpperIdent(name) => {
82 let type_name = resolve_type_name(&field.resolved_type, registry);
83 format!("{type_name}::{name}")
84 }
85 DefaultValue::Array(items) => {
86 let exprs: Vec<String> = items
87 .iter()
88 .map(|spanned| default_value_expr(&spanned.node, field, registry))
89 .collect();
90 format!("vec![{}]", exprs.join(", "))
91 }
92 }
93}
94
95fn resolve_type_name(ty: &ResolvedType, registry: &TypeRegistry) -> String {
98 match ty {
99 ResolvedType::Named(id) => match registry.get(*id) {
100 Some(TypeDef::Enum(e)) => e.name.to_string(),
101 Some(TypeDef::Flags(f)) => f.name.to_string(),
102 Some(TypeDef::Newtype(n)) => n.name.to_string(),
103 Some(TypeDef::Message(m)) => m.name.to_string(),
104 Some(TypeDef::Union(u)) => u.name.to_string(),
105 Some(TypeDef::Config(c)) => c.name.to_string(),
106 _ => "UnresolvedType".to_string(),
107 },
108 ResolvedType::Optional(inner) => resolve_type_name(inner, registry),
110 _ => "UnresolvedType".to_string(),
111 }
112}