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