1use crate::cdsl::camel_case;
4use crate::cdsl::settings::{
5 BoolSetting, Predicate, Preset, Setting, SettingGroup, SpecificSetting,
6};
7use crate::constant_hash::generate_table;
8use crate::unique_table::UniqueSeqTable;
9use cranelift_codegen_shared::constant_hash::simple_hash;
10use cranelift_srcgen::{Formatter, Language, Match, error, fmtln};
11use std::collections::HashMap;
12
13pub(crate) enum ParentGroup {
14 None,
15 Shared,
16}
17
18fn gen_constructor(group: &SettingGroup, parent: ParentGroup, fmt: &mut Formatter) {
20 let args = match parent {
21 ParentGroup::None => "builder: Builder",
22 ParentGroup::Shared => "shared: &settings::Flags, builder: &Builder",
23 };
24 fmt.add_block("impl Flags", |fmt| {
25 fmt.doc_comment(format!("Create flags {} settings group.", group.name));
26 fmtln!(
27 fmt,
28 "#[allow(unused_variables, reason = \"generated code\")]"
29 );
30 fmt.add_block(&format!("pub fn new({args}) -> Self"), |fmt| {
31 fmtln!(fmt, "let bvec = builder.state_for(\"{}\");", group.name);
32 fmtln!(
33 fmt,
34 "let mut {} = Self {{ bytes: [0; {}] }};",
35 group.name,
36 group.byte_size()
37 );
38 fmtln!(
39 fmt,
40 "debug_assert_eq!(bvec.len(), {});",
41 group.settings_size
42 );
43 fmtln!(
44 fmt,
45 "{}.bytes[0..{}].copy_from_slice(&bvec);",
46 group.name,
47 group.settings_size
48 );
49
50 for p in &group.predicates {
52 fmt.comment(format!("Precompute #{}.", p.number));
53 fmt.add_block(&format!("if {}", p.render(group)), |fmt| {
54 fmtln!(
55 fmt,
56 "{}.bytes[{}] |= 1 << {};",
57 group.name,
58 group.bool_start_byte_offset + p.number / 8,
59 p.number % 8
60 );
61 });
62 }
63
64 fmtln!(fmt, "{}", group.name);
65 });
66 });
67}
68
69fn gen_iterator(group: &SettingGroup, fmt: &mut Formatter) {
71 fmt.add_block("impl Flags",|fmt| {
72 fmt.doc_comment("Iterates the setting values.");
73 fmt.add_block("pub fn iter(&self) -> impl Iterator<Item = Value> + use<>",|fmt| {
74 fmtln!(fmt, "let mut bytes = [0; {}];", group.settings_size);
75 fmtln!(fmt, "bytes.copy_from_slice(&self.bytes[0..{}]);", group.settings_size);
76 fmt.add_block("DESCRIPTORS.iter().filter_map(move |d|", |fmt| {
77 fmt.add_block("let values = match &d.detail", |fmt| {
78 fmtln!(fmt, "detail::Detail::Preset => return None,");
79 fmtln!(fmt, "detail::Detail::Enum {{ last, enumerators }} => Some(TEMPLATE.enums(*last, *enumerators)),");
80 fmtln!(fmt, "_ => None");
81 });
82 fmtln!(fmt, ";");
83 fmtln!(fmt, "Some(Value {{ name: d.name, detail: d.detail, values, value: bytes[d.offset as usize] }})");
84 });
85 fmtln!(fmt, ")");
86 });
87 });
88}
89
90fn gen_enum_all(name: &str, values: &[&'static str], fmt: &mut Formatter) {
92 fmtln!(
93 fmt,
94 "/// Returns a slice with all possible [{}] values.",
95 name
96 );
97 fmt.add_block(&format!("pub fn all() -> &'static [{name}]"), |fmt| {
98 fmtln!(fmt, "&[");
99 fmt.indent(|fmt| {
100 for v in values.iter() {
101 fmtln!(fmt, "Self::{},", camel_case(v));
102 }
103 });
104 fmtln!(fmt, "]");
105 });
106}
107
108fn gen_to_and_from_str(name: &str, values: &[&'static str], fmt: &mut Formatter) {
110 fmt.add_block(&format!("impl fmt::Display for {name}"), |fmt| {
111 fmt.add_block(
112 "fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result",
113 |fmt| {
114 fmt.add_block("f.write_str(match *self", |fmt| {
115 for v in values.iter() {
116 fmtln!(fmt, "Self::{} => \"{}\",", camel_case(v), v);
117 }
118 });
119 fmtln!(fmt, ")");
120 },
121 );
122 });
123
124 fmt.add_block(&format!("impl core::str::FromStr for {name}"), |fmt| {
125 fmtln!(fmt, "type Err = ();");
126 fmt.add_block("fn from_str(s: &str) -> Result<Self, Self::Err>", |fmt| {
127 fmt.add_block("match s", |fmt| {
128 for v in values.iter() {
129 fmtln!(fmt, "\"{}\" => Ok(Self::{}),", v, camel_case(v));
130 }
131 fmtln!(fmt, "_ => Err(()),");
132 });
133 });
134 });
135}
136
137fn gen_enum_types(group: &SettingGroup, fmt: &mut Formatter) {
139 for setting in group.settings.iter() {
140 let values = match setting.specific {
141 SpecificSetting::Bool(_) | SpecificSetting::Num(_) => continue,
142 SpecificSetting::Enum(ref values) => values,
143 };
144 let name = camel_case(setting.name);
145
146 fmt.doc_comment(format!("Values for `{}.{}`.", group.name, setting.name));
147 fmtln!(fmt, "#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]");
148 fmt.add_block(&format!("pub enum {name}"), |fmt| {
149 for v in values.iter() {
150 fmt.doc_comment(format!("`{v}`."));
151 fmtln!(fmt, "{},", camel_case(v));
152 }
153 });
154
155 fmt.add_block(&format!("impl {name}"), |fmt| {
156 gen_enum_all(&name, values, fmt);
157 });
158
159 gen_to_and_from_str(&name, values, fmt);
160 }
161}
162
163fn gen_getter(setting: &Setting, fmt: &mut Formatter) {
165 fmt.doc_comment(format!("{}\n{}", setting.description, setting.comment));
166 match setting.specific {
167 SpecificSetting::Bool(BoolSetting {
168 predicate_number, ..
169 }) => {
170 fmt.add_block(&format!("pub fn {}(&self) -> bool", setting.name), |fmt| {
171 fmtln!(fmt, "self.numbered_predicate({})", predicate_number);
172 });
173 }
174 SpecificSetting::Enum(ref values) => {
175 let ty = camel_case(setting.name);
176 fmt.add_block(
177 &format!("pub fn {}(&self) -> {}", setting.name, ty),
178 |fmt| {
179 let mut m = Match::new(format!("self.bytes[{}]", setting.byte_offset));
180 for (i, v) in values.iter().enumerate() {
181 m.arm_no_fields(format!("{i}"), format!("{}::{}", ty, camel_case(v)));
182 }
183 m.arm_no_fields("_", "panic!(\"Invalid enum value\")");
184 fmt.add_match(m);
185 },
186 );
187 }
188 SpecificSetting::Num(_) => {
189 fmt.add_block(&format!("pub fn {}(&self) -> u8", setting.name), |fmt| {
190 fmtln!(fmt, "self.bytes[{}]", setting.byte_offset);
191 });
192 }
193 }
194}
195
196fn gen_pred_getter(predicate: &Predicate, group: &SettingGroup, fmt: &mut Formatter) {
197 fmt.doc_comment(format!("Computed predicate `{}`.", predicate.render(group)));
198 fmt.add_block(
199 &format!("pub fn {}(&self) -> bool", predicate.name),
200 |fmt| {
201 fmtln!(fmt, "self.numbered_predicate({})", predicate.number);
202 },
203 );
204}
205
206fn gen_getters(group: &SettingGroup, fmt: &mut Formatter) {
208 fmt.doc_comment("User-defined settings.");
209 fmtln!(fmt, "#[allow(dead_code, reason = \"generated code\")]");
210 fmt.add_block("impl Flags", |fmt| {
211 if !group.settings.is_empty() {
212 fmt.doc_comment("Dynamic numbered predicate getter.");
213 fmt.add_block("fn numbered_predicate(&self, p: usize) -> bool", |fmt| {
214 fmtln!(
215 fmt,
216 "self.bytes[{} + p / 8] & (1 << (p % 8)) != 0",
217 group.bool_start_byte_offset
218 );
219 });
220 }
221
222 for setting in &group.settings {
223 gen_getter(setting, fmt);
224 }
225 for predicate in &group.predicates {
226 gen_pred_getter(predicate, group, fmt);
227 }
228 });
229}
230
231#[derive(Hash, PartialEq, Eq)]
232enum SettingOrPreset<'a> {
233 Setting(&'a Setting),
234 Preset(&'a Preset),
235}
236
237impl<'a> SettingOrPreset<'a> {
238 fn name(&self) -> &str {
239 match *self {
240 SettingOrPreset::Setting(s) => s.name,
241 SettingOrPreset::Preset(p) => p.name,
242 }
243 }
244}
245
246fn gen_descriptors(group: &SettingGroup, fmt: &mut Formatter) {
248 let mut enum_table = UniqueSeqTable::new();
249
250 let mut descriptor_index_map: HashMap<SettingOrPreset, usize> = HashMap::new();
251
252 fmtln!(
254 fmt,
255 "static DESCRIPTORS: [detail::Descriptor; {}] = [",
256 group.settings.len() + group.presets.len()
257 );
258 fmt.indent(|fmt| {
259 for (idx, setting) in group.settings.iter().enumerate() {
260 fmt.add_block("detail::Descriptor", |fmt| {
261 fmtln!(fmt, "name: \"{}\",", setting.name);
262 fmtln!(fmt, "description: \"{}\",", setting.description);
263 fmtln!(fmt, "offset: {},", setting.byte_offset);
264 match setting.specific {
265 SpecificSetting::Bool(BoolSetting { bit_offset, .. }) => {
266 fmtln!(
267 fmt,
268 "detail: detail::Detail::Bool {{ bit: {} }},",
269 bit_offset
270 );
271 }
272 SpecificSetting::Enum(ref values) => {
273 let offset = enum_table.add(values);
274 fmtln!(
275 fmt,
276 "detail: detail::Detail::Enum {{ last: {}, enumerators: {} }},",
277 values.len() - 1,
278 offset
279 );
280 }
281 SpecificSetting::Num(_) => {
282 fmtln!(fmt, "detail: detail::Detail::Num,");
283 }
284 }
285
286 descriptor_index_map.insert(SettingOrPreset::Setting(setting), idx);
287 });
288 fmtln!(fmt, ",");
289 }
290
291 for (idx, preset) in group.presets.iter().enumerate() {
292 fmt.add_block("detail::Descriptor", |fmt| {
293 fmtln!(fmt, "name: \"{}\",", preset.name);
294 fmtln!(fmt, "description: \"{}\",", preset.description);
295 fmtln!(fmt, "offset: {},", (idx as u8) * group.settings_size);
296 fmtln!(fmt, "detail: detail::Detail::Preset,");
297 });
298 fmtln!(fmt, ",");
299
300 let whole_idx = idx + group.settings.len();
301 descriptor_index_map.insert(SettingOrPreset::Preset(preset), whole_idx);
302 }
303 });
304 fmtln!(fmt, "];");
305
306 fmtln!(fmt, "static ENUMERATORS: [&str; {}] = [", enum_table.len());
308 fmt.indent(|fmt| {
309 for enum_val in enum_table.iter() {
310 fmtln!(fmt, "\"{}\",", enum_val);
311 }
312 });
313 fmtln!(fmt, "];");
314
315 let mut hash_entries: Vec<SettingOrPreset> = Vec::new();
317 hash_entries.extend(group.settings.iter().map(SettingOrPreset::Setting));
318 hash_entries.extend(group.presets.iter().map(SettingOrPreset::Preset));
319
320 let hash_table = generate_table(hash_entries.iter(), hash_entries.len(), |entry| {
321 simple_hash(entry.name())
322 });
323 fmtln!(fmt, "static HASH_TABLE: [u16; {}] = [", hash_table.len());
324 fmt.indent(|fmt| {
325 for h in &hash_table {
326 match *h {
327 Some(setting_or_preset) => fmtln!(
328 fmt,
329 "{},",
330 &descriptor_index_map
331 .get(setting_or_preset)
332 .unwrap()
333 .to_string()
334 ),
335 None => fmtln!(fmt, "0xffff,"),
336 }
337 }
338 });
339 fmtln!(fmt, "];");
340
341 fmtln!(
343 fmt,
344 "static PRESETS: [(u8, u8); {}] = [",
345 group.presets.len() * (group.settings_size as usize)
346 );
347 fmt.indent(|fmt| {
348 for preset in &group.presets {
349 fmt.comment(format!(
350 "{}: {}",
351 preset.name,
352 preset.setting_names(group).collect::<Vec<_>>().join(", ")
353 ));
354 for (mask, value) in preset.layout(group) {
355 fmtln!(fmt, "(0b{:08b}, 0b{:08b}),", mask, value);
356 }
357 }
358 });
359 fmtln!(fmt, "];");
360}
361
362fn gen_template(group: &SettingGroup, fmt: &mut Formatter) {
363 let mut default_bytes: Vec<u8> = vec![0; group.settings_size as usize];
364 for setting in &group.settings {
365 *default_bytes.get_mut(setting.byte_offset as usize).unwrap() |= setting.default_byte();
366 }
367
368 let default_bytes: Vec<String> = default_bytes.iter().map(|x| format!("{x:#04x}")).collect();
369 let default_bytes_str = default_bytes.join(", ");
370
371 fmt.add_block(
372 "static TEMPLATE: detail::Template = detail::Template",
373 |fmt| {
374 fmtln!(fmt, "name: \"{}\",", group.name);
375 fmtln!(fmt, "descriptors: &DESCRIPTORS,");
376 fmtln!(fmt, "enumerators: &ENUMERATORS,");
377 fmtln!(fmt, "hash_table: &HASH_TABLE,");
378 fmtln!(fmt, "defaults: &[{}],", default_bytes_str);
379 fmtln!(fmt, "presets: &PRESETS,");
380 },
381 );
382 fmtln!(fmt, ";");
383
384 fmt.doc_comment(format!(
385 "Create a `settings::Builder` for the {} settings group.",
386 group.name
387 ));
388 fmt.add_block("pub fn builder() -> Builder", |fmt| {
389 fmtln!(fmt, "Builder::new(&TEMPLATE)");
390 });
391}
392
393fn gen_display(group: &SettingGroup, fmt: &mut Formatter) {
394 fmt.add_block("impl fmt::Display for Flags", |fmt| {
395 fmt.add_block(
396 "fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result",
397 |fmt| {
398 fmtln!(fmt, "writeln!(f, \"[{}]\")?;", group.name);
399 fmt.add_block("for d in &DESCRIPTORS", |fmt| {
400 fmt.add_block("if !d.detail.is_preset()", |fmt| {
401 fmtln!(fmt, "write!(f, \"{{}} = \", d.name)?;");
402 fmtln!(
403 fmt,
404 "TEMPLATE.format_toml_value(d.detail, self.bytes[d.offset as usize], f)?;",
405 );
406 fmtln!(fmt, "writeln!(f)?;");
407 });
408 });
409 fmtln!(fmt, "Ok(())");
410 },
411 );
412 });
413}
414
415fn gen_hash_key(fmt: &mut Formatter) {
416 fmt.add_block("impl Flags", |fmt| {
417 fmt.doc_comment("Get the flag values as raw bytes for hashing.");
418 fmt.add_block("pub fn hash_key(&self) -> &[u8]", |fmt| {
419 fmtln!(fmt, "&self.bytes");
420 });
421 });
422}
423
424fn gen_group(group: &SettingGroup, parent: ParentGroup, fmt: &mut Formatter) {
425 fmtln!(fmt, "#[derive(Clone, PartialEq, Hash)]");
427 fmt.doc_comment(format!("Flags group `{}`.", group.name));
428 fmt.add_block("pub struct Flags", |fmt| {
429 fmtln!(fmt, "bytes: [u8; {}],", group.byte_size());
430 });
431
432 gen_constructor(group, parent, fmt);
433 gen_iterator(group, fmt);
434 gen_enum_types(group, fmt);
435 gen_getters(group, fmt);
436 gen_descriptors(group, fmt);
437 gen_template(group, fmt);
438 gen_display(group, fmt);
439 gen_hash_key(fmt);
440}
441
442pub(crate) fn generate(
443 settings: &SettingGroup,
444 parent_group: ParentGroup,
445 filename: &str,
446 out_dir: &std::path::Path,
447) -> Result<(), error::Error> {
448 let mut fmt = Formatter::new(Language::Rust);
449 gen_group(settings, parent_group, &mut fmt);
450 fmt.write(filename, out_dir)?;
451 Ok(())
452}