1 use std::iter; 2 3 #[derive(Clone, Copy, Hash, PartialEq, Eq)] 4 pub(crate) struct BoolSettingIndex(usize); 5 6 #[derive(Hash, PartialEq, Eq)] 7 pub(crate) struct BoolSetting { 8 pub default: bool, 9 pub bit_offset: u8, 10 pub predicate_number: u8, 11 } 12 13 #[derive(Hash, PartialEq, Eq)] 14 pub(crate) enum SpecificSetting { 15 Bool(BoolSetting), 16 Enum(Vec<&'static str>), 17 Num(u8), 18 } 19 20 #[derive(Hash, PartialEq, Eq)] 21 pub(crate) struct Setting { 22 pub name: &'static str, 23 pub description: &'static str, 24 pub comment: &'static str, 25 pub specific: SpecificSetting, 26 pub byte_offset: u8, 27 } 28 29 impl Setting { 30 pub fn default_byte(&self) -> u8 { 31 match self.specific { 32 SpecificSetting::Bool(BoolSetting { 33 default, 34 bit_offset, 35 .. 36 }) => { 37 if default { 38 1 << bit_offset 39 } else { 40 0 41 } 42 } 43 SpecificSetting::Enum(_) => 0, 44 SpecificSetting::Num(default) => default, 45 } 46 } 47 48 fn byte_for_value(&self, v: bool) -> u8 { 49 match self.specific { 50 SpecificSetting::Bool(BoolSetting { bit_offset, .. }) => { 51 if v { 52 1 << bit_offset 53 } else { 54 0 55 } 56 } 57 _ => panic!("byte_for_value shouldn't be used for non-boolean settings."), 58 } 59 } 60 61 fn byte_mask(&self) -> u8 { 62 match self.specific { 63 SpecificSetting::Bool(BoolSetting { bit_offset, .. }) => 1 << bit_offset, 64 _ => panic!("byte_for_value shouldn't be used for non-boolean settings."), 65 } 66 } 67 } 68 69 #[derive(Hash, PartialEq, Eq, Copy, Clone)] 70 pub(crate) struct PresetIndex(usize); 71 72 #[derive(Hash, PartialEq, Eq)] 73 pub(crate) enum PresetType { 74 BoolSetting(BoolSettingIndex), 75 OtherPreset(PresetIndex), 76 } 77 78 impl From<BoolSettingIndex> for PresetType { 79 fn from(bool_setting_index: BoolSettingIndex) -> Self { 80 PresetType::BoolSetting(bool_setting_index) 81 } 82 } 83 impl From<PresetIndex> for PresetType { 84 fn from(value: PresetIndex) -> Self { 85 PresetType::OtherPreset(value) 86 } 87 } 88 89 #[derive(Hash, PartialEq, Eq)] 90 pub(crate) struct Preset { 91 pub name: &'static str, 92 pub description: &'static str, 93 values: Vec<BoolSettingIndex>, 94 } 95 96 impl Preset { 97 pub fn layout(&self, group: &SettingGroup) -> Vec<(u8, u8)> { 98 let mut layout: Vec<(u8, u8)> = iter::repeat((0, 0)) 99 .take(group.settings_size as usize) 100 .collect(); 101 for bool_index in &self.values { 102 let setting = &group.settings[bool_index.0]; 103 let mask = setting.byte_mask(); 104 let val = setting.byte_for_value(true); 105 assert!((val & !mask) == 0); 106 let (ref mut l_mask, ref mut l_val) = 107 *layout.get_mut(setting.byte_offset as usize).unwrap(); 108 *l_mask |= mask; 109 *l_val = (*l_val & !mask) | val; 110 } 111 layout 112 } 113 114 pub fn setting_names<'a>( 115 &'a self, 116 group: &'a SettingGroup, 117 ) -> impl Iterator<Item = &'static str> + 'a { 118 self.values 119 .iter() 120 .map(|bool_index| group.settings[bool_index.0].name) 121 } 122 } 123 124 pub(crate) struct SettingGroup { 125 pub name: &'static str, 126 pub settings: Vec<Setting>, 127 pub bool_start_byte_offset: u8, 128 pub settings_size: u8, 129 pub presets: Vec<Preset>, 130 pub predicates: Vec<Predicate>, 131 } 132 133 impl SettingGroup { 134 fn num_bool_settings(&self) -> u8 { 135 self.settings 136 .iter() 137 .filter(|s| matches!(s.specific, SpecificSetting::Bool(_))) 138 .count() as u8 139 } 140 141 pub fn byte_size(&self) -> u8 { 142 let num_predicates = self.num_bool_settings() + (self.predicates.len() as u8); 143 self.bool_start_byte_offset + (num_predicates + 7) / 8 144 } 145 } 146 147 /// This is the basic information needed to track the specific parts of a setting when building 148 /// them. 149 pub(crate) enum ProtoSpecificSetting { 150 Bool(bool), 151 Enum(Vec<&'static str>), 152 Num(u8), 153 } 154 155 /// This is the information provided during building for a setting. 156 struct ProtoSetting { 157 name: &'static str, 158 description: &'static str, 159 comment: &'static str, 160 specific: ProtoSpecificSetting, 161 } 162 163 #[derive(Hash, PartialEq, Eq)] 164 pub(crate) enum PredicateNode { 165 OwnedBool(BoolSettingIndex), 166 SharedBool(&'static str, &'static str), 167 And(Box<PredicateNode>, Box<PredicateNode>), 168 } 169 170 impl From<BoolSettingIndex> for PredicateNode { 171 fn from(bool_setting_index: BoolSettingIndex) -> Self { 172 PredicateNode::OwnedBool(bool_setting_index) 173 } 174 } 175 176 impl<'a> From<(BoolSettingIndex, &'a SettingGroup)> for PredicateNode { 177 fn from(val: (BoolSettingIndex, &'a SettingGroup)) -> Self { 178 let (index, group) = (val.0, val.1); 179 let setting = &group.settings[index.0]; 180 PredicateNode::SharedBool(group.name, setting.name) 181 } 182 } 183 184 impl PredicateNode { 185 fn render(&self, group: &SettingGroup) -> String { 186 match *self { 187 PredicateNode::OwnedBool(bool_setting_index) => format!( 188 "{}.{}()", 189 group.name, group.settings[bool_setting_index.0].name 190 ), 191 PredicateNode::SharedBool(ref group_name, ref bool_name) => { 192 format!("{group_name}.{bool_name}()") 193 } 194 PredicateNode::And(ref lhs, ref rhs) => { 195 format!("{} && {}", lhs.render(group), rhs.render(group)) 196 } 197 } 198 } 199 } 200 201 struct ProtoPredicate { 202 pub name: &'static str, 203 node: PredicateNode, 204 } 205 206 pub(crate) type SettingPredicateNumber = u8; 207 208 pub(crate) struct Predicate { 209 pub name: &'static str, 210 node: PredicateNode, 211 pub number: SettingPredicateNumber, 212 } 213 214 impl Predicate { 215 pub fn render(&self, group: &SettingGroup) -> String { 216 self.node.render(group) 217 } 218 } 219 220 pub(crate) struct SettingGroupBuilder { 221 name: &'static str, 222 settings: Vec<ProtoSetting>, 223 presets: Vec<Preset>, 224 predicates: Vec<ProtoPredicate>, 225 } 226 227 impl SettingGroupBuilder { 228 pub fn new(name: &'static str) -> Self { 229 Self { 230 name, 231 settings: Vec::new(), 232 presets: Vec::new(), 233 predicates: Vec::new(), 234 } 235 } 236 237 fn add_setting( 238 &mut self, 239 name: &'static str, 240 description: &'static str, 241 comment: &'static str, 242 specific: ProtoSpecificSetting, 243 ) { 244 self.settings.push(ProtoSetting { 245 name, 246 description, 247 comment, 248 specific, 249 }) 250 } 251 252 pub fn add_bool( 253 &mut self, 254 name: &'static str, 255 description: &'static str, 256 comment: &'static str, 257 default: bool, 258 ) -> BoolSettingIndex { 259 assert!( 260 self.predicates.is_empty(), 261 "predicates must be added after the boolean settings" 262 ); 263 self.add_setting( 264 name, 265 description, 266 comment, 267 ProtoSpecificSetting::Bool(default), 268 ); 269 BoolSettingIndex(self.settings.len() - 1) 270 } 271 272 pub fn add_enum( 273 &mut self, 274 name: &'static str, 275 description: &'static str, 276 comment: &'static str, 277 values: Vec<&'static str>, 278 ) { 279 self.add_setting( 280 name, 281 description, 282 comment, 283 ProtoSpecificSetting::Enum(values), 284 ); 285 } 286 287 pub fn add_num( 288 &mut self, 289 name: &'static str, 290 description: &'static str, 291 comment: &'static str, 292 default: u8, 293 ) { 294 self.add_setting( 295 name, 296 description, 297 comment, 298 ProtoSpecificSetting::Num(default), 299 ); 300 } 301 302 pub fn add_predicate(&mut self, name: &'static str, node: PredicateNode) { 303 self.predicates.push(ProtoPredicate { name, node }); 304 } 305 306 pub fn add_preset( 307 &mut self, 308 name: &'static str, 309 description: &'static str, 310 args: Vec<PresetType>, 311 ) -> PresetIndex { 312 let mut values = Vec::new(); 313 for arg in args { 314 match arg { 315 PresetType::OtherPreset(index) => { 316 values.extend(self.presets[index.0].values.iter()); 317 } 318 PresetType::BoolSetting(index) => values.push(index), 319 } 320 } 321 self.presets.push(Preset { 322 name, 323 description, 324 values, 325 }); 326 PresetIndex(self.presets.len() - 1) 327 } 328 329 /// Compute the layout of the byte vector used to represent this settings 330 /// group. 331 /// 332 /// The byte vector contains the following entries in order: 333 /// 334 /// 1. Byte-sized settings like `NumSetting` and `EnumSetting`. 335 /// 2. `BoolSetting` settings. 336 /// 3. Precomputed named predicates. 337 /// 4. Other numbered predicates, including parent predicates that need to be accessible by 338 /// number. 339 /// 340 /// Set `self.settings_size` to the length of the byte vector prefix that 341 /// contains the settings. All bytes after that are computed, not 342 /// configured. 343 /// 344 /// Set `self.boolean_offset` to the beginning of the numbered predicates, 345 /// 2. in the list above. 346 /// 347 /// Assign `byte_offset` and `bit_offset` fields in all settings. 348 pub fn build(self) -> SettingGroup { 349 let mut group = SettingGroup { 350 name: self.name, 351 settings: Vec::new(), 352 bool_start_byte_offset: 0, 353 settings_size: 0, 354 presets: Vec::new(), 355 predicates: Vec::new(), 356 }; 357 358 let mut byte_offset = 0; 359 360 // Assign the non-boolean settings first. 361 for s in &self.settings { 362 let specific = match s.specific { 363 ProtoSpecificSetting::Bool(..) => continue, 364 ProtoSpecificSetting::Enum(ref values) => SpecificSetting::Enum(values.clone()), 365 ProtoSpecificSetting::Num(default) => SpecificSetting::Num(default), 366 }; 367 368 group.settings.push(Setting { 369 name: s.name, 370 description: s.description, 371 comment: s.comment, 372 byte_offset, 373 specific, 374 }); 375 376 byte_offset += 1; 377 } 378 379 group.bool_start_byte_offset = byte_offset; 380 381 let mut predicate_number = 0; 382 383 // Then the boolean settings. 384 for s in &self.settings { 385 let default = match s.specific { 386 ProtoSpecificSetting::Bool(default) => default, 387 ProtoSpecificSetting::Enum(_) | ProtoSpecificSetting::Num(_) => continue, 388 }; 389 group.settings.push(Setting { 390 name: s.name, 391 description: s.description, 392 comment: s.comment, 393 byte_offset: byte_offset + predicate_number / 8, 394 specific: SpecificSetting::Bool(BoolSetting { 395 default, 396 bit_offset: predicate_number % 8, 397 predicate_number, 398 }), 399 }); 400 predicate_number += 1; 401 } 402 403 assert!( 404 group.predicates.is_empty(), 405 "settings_size is the byte size before adding predicates" 406 ); 407 group.settings_size = group.byte_size(); 408 409 // Sort predicates by name to ensure the same order as the Python code. 410 let mut predicates = self.predicates; 411 predicates.sort_by_key(|predicate| predicate.name); 412 413 group 414 .predicates 415 .extend(predicates.into_iter().map(|predicate| { 416 let number = predicate_number; 417 predicate_number += 1; 418 Predicate { 419 name: predicate.name, 420 node: predicate.node, 421 number, 422 } 423 })); 424 425 group.presets.extend(self.presets); 426 427 group 428 } 429 } 430