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