vexil_codegen_rust/
flags.rs1use vexil_lang::ir::{FlagsDef, TypeRegistry};
2
3use crate::annotations::{emit_tombstones, emit_type_annotations};
4use crate::emit::CodeWriter;
5
6fn to_upper_snake(name: &str) -> String {
8 let mut out = String::with_capacity(name.len() + 4);
9 let mut prev_lower = false;
10 for ch in name.chars() {
11 if ch.is_uppercase() && prev_lower {
12 out.push('_');
13 }
14 out.push(ch.to_ascii_uppercase());
15 prev_lower = ch.is_lowercase();
16 }
17 out
18}
19
20pub fn emit_flags(w: &mut CodeWriter, flags: &FlagsDef, _registry: &TypeRegistry) {
23 let name = flags.name.as_str();
24
25 emit_tombstones(w, name, &flags.tombstones);
27
28 emit_type_annotations(w, &flags.annotations);
30
31 w.line("#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]");
33
34 w.line(&format!("pub struct {name}(pub u64);"));
36 w.blank();
37
38 w.open_block(&format!("impl {name}"));
40
41 for bit_def in &flags.bits {
43 let const_name = to_upper_snake(bit_def.name.as_str());
44 let bit = bit_def.bit;
45 for doc in &bit_def.annotations.doc {
47 w.line(&format!("/// {doc}"));
48 }
49 if let Some(ref dep) = bit_def.annotations.deprecated {
50 match &dep.since {
51 Some(since) => w.line(&format!(
52 "#[deprecated(since = \"{since}\", note = \"{}\")]",
53 dep.reason
54 )),
55 None => w.line(&format!("#[deprecated(note = \"{}\")]", dep.reason)),
56 }
57 }
58 w.line(&format!(
59 "pub const {const_name}: Self = Self(1_u64 << {bit}_u32);"
60 ));
61 }
62
63 w.blank();
64
65 w.line("pub const fn contains(self, other: Self) -> bool { self.0 & other.0 == other.0 }");
67 w.line("pub const fn is_empty(self) -> bool { self.0 == 0 }");
68 w.line("pub const fn empty() -> Self { Self(0) }");
69
70 w.close_block();
71 w.blank();
72
73 w.open_block(&format!("impl std::ops::BitOr for {name}"));
75 w.line("type Output = Self;");
76 w.open_block("fn bitor(self, rhs: Self) -> Self");
77 w.line("Self(self.0 | rhs.0)");
78 w.close_block();
79 w.close_block();
80 w.blank();
81
82 w.open_block(&format!("impl std::ops::BitAnd for {name}"));
84 w.line("type Output = Self;");
85 w.open_block("fn bitand(self, rhs: Self) -> Self");
86 w.line("Self(self.0 & rhs.0)");
87 w.close_block();
88 w.close_block();
89 w.blank();
90
91 w.open_block(&format!("impl std::ops::Not for {name}"));
93 w.line("type Output = Self;");
94 w.open_block("fn not(self) -> Self");
95 w.line("Self(!self.0)");
96 w.close_block();
97 w.close_block();
98 w.blank();
99
100 w.open_block(&format!("impl vexil_runtime::Pack for {name}"));
102 w.open_block(
103 "fn pack(&self, w: &mut vexil_runtime::BitWriter) -> Result<(), vexil_runtime::EncodeError>",
104 );
105 match flags.wire_bytes {
106 1 => w.line("w.write_u8(self.0 as u8);"),
107 2 => w.line("w.write_u16(self.0 as u16);"),
108 4 => w.line("w.write_u32(self.0 as u32);"),
109 _ => w.line("w.write_u64(self.0);"),
110 }
111 w.line("Ok(())");
112 w.close_block();
113 w.close_block();
114 w.blank();
115
116 w.open_block(&format!("impl vexil_runtime::Unpack for {name}"));
118 w.open_block(
119 "fn unpack(r: &mut vexil_runtime::BitReader<'_>) -> Result<Self, vexil_runtime::DecodeError>",
120 );
121 match flags.wire_bytes {
122 1 => w.line("let raw = r.read_u8()? as u64;"),
123 2 => w.line("let raw = r.read_u16()? as u64;"),
124 4 => w.line("let raw = r.read_u32()? as u64;"),
125 _ => w.line("let raw = r.read_u64()?;"),
126 }
127 w.line("Ok(Self(raw))");
128 w.close_block();
129 w.close_block();
130 w.blank();
131}