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)] 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 Into<PresetType> for BoolSettingIndex { 79 fn into(self) -> PresetType { 80 PresetType::BoolSetting(self) 81 } 82 } 83 impl Into<PresetType> for PresetIndex { 84 fn into(self) -> PresetType { 85 PresetType::OtherPreset(self) 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| { 138 if let SpecificSetting::Bool(_) = s.specific { 139 true 140 } else { 141 false 142 } 143 }) 144 .count() as u8 145 } 146 147 pub fn byte_size(&self) -> u8 { 148 let num_predicates = self.num_bool_settings() + (self.predicates.len() as u8); 149 self.bool_start_byte_offset + (num_predicates + 7) / 8 150 } 151 152 pub fn get_bool(&self, name: &'static str) -> (BoolSettingIndex, &Self) { 153 for (i, s) in self.settings.iter().enumerate() { 154 if let SpecificSetting::Bool(_) = s.specific { 155 if s.name == name { 156 return (BoolSettingIndex(i), self); 157 } 158 } 159 } 160 panic!("Should have found bool setting by name."); 161 } 162 } 163 164 /// This is the basic information needed to track the specific parts of a setting when building 165 /// them. 166 pub(crate) enum ProtoSpecificSetting { 167 Bool(bool), 168 Enum(Vec<&'static str>), 169 Num(u8), 170 } 171 172 /// This is the information provided during building for a setting. 173 struct ProtoSetting { 174 name: &'static str, 175 description: &'static str, 176 comment: &'static str, 177 specific: ProtoSpecificSetting, 178 } 179 180 #[derive(Hash, PartialEq, Eq)] 181 pub(crate) enum PredicateNode { 182 OwnedBool(BoolSettingIndex), 183 SharedBool(&'static str, &'static str), 184 Not(Box<PredicateNode>), 185 And(Box<PredicateNode>, Box<PredicateNode>), 186 } 187 188 impl Into<PredicateNode> for BoolSettingIndex { 189 fn into(self) -> PredicateNode { 190 PredicateNode::OwnedBool(self) 191 } 192 } 193 impl<'a> Into<PredicateNode> for (BoolSettingIndex, &'a SettingGroup) { 194 fn into(self) -> PredicateNode { 195 let (index, group) = (self.0, self.1); 196 let setting = &group.settings[index.0]; 197 PredicateNode::SharedBool(group.name, setting.name) 198 } 199 } 200 201 impl PredicateNode { 202 fn render(&self, group: &SettingGroup) -> String { 203 match *self { 204 PredicateNode::OwnedBool(bool_setting_index) => format!( 205 "{}.{}()", 206 group.name, group.settings[bool_setting_index.0].name 207 ), 208 PredicateNode::SharedBool(ref group_name, ref bool_name) => { 209 format!("{}.{}()", group_name, bool_name) 210 } 211 PredicateNode::And(ref lhs, ref rhs) => { 212 format!("{} && {}", lhs.render(group), rhs.render(group)) 213 } 214 PredicateNode::Not(ref node) => format!("!({})", node.render(group)), 215 } 216 } 217 } 218 219 struct ProtoPredicate { 220 pub name: &'static str, 221 node: PredicateNode, 222 } 223 224 pub(crate) type SettingPredicateNumber = u8; 225 226 pub(crate) struct Predicate { 227 pub name: &'static str, 228 node: PredicateNode, 229 pub number: SettingPredicateNumber, 230 } 231 232 impl Predicate { 233 pub fn render(&self, group: &SettingGroup) -> String { 234 self.node.render(group) 235 } 236 } 237 238 pub(crate) struct SettingGroupBuilder { 239 name: &'static str, 240 settings: Vec<ProtoSetting>, 241 presets: Vec<Preset>, 242 predicates: Vec<ProtoPredicate>, 243 } 244 245 impl SettingGroupBuilder { 246 pub fn new(name: &'static str) -> Self { 247 Self { 248 name, 249 settings: Vec::new(), 250 presets: Vec::new(), 251 predicates: Vec::new(), 252 } 253 } 254 255 fn add_setting( 256 &mut self, 257 name: &'static str, 258 description: &'static str, 259 comment: &'static str, 260 specific: ProtoSpecificSetting, 261 ) { 262 self.settings.push(ProtoSetting { 263 name, 264 description, 265 comment, 266 specific, 267 }) 268 } 269 270 pub fn add_bool( 271 &mut self, 272 name: &'static str, 273 description: &'static str, 274 comment: &'static str, 275 default: bool, 276 ) -> BoolSettingIndex { 277 assert!( 278 self.predicates.is_empty(), 279 "predicates must be added after the boolean settings" 280 ); 281 self.add_setting( 282 name, 283 description, 284 comment, 285 ProtoSpecificSetting::Bool(default), 286 ); 287 BoolSettingIndex(self.settings.len() - 1) 288 } 289 290 pub fn add_enum( 291 &mut self, 292 name: &'static str, 293 description: &'static str, 294 comment: &'static str, 295 values: Vec<&'static str>, 296 ) { 297 self.add_setting( 298 name, 299 description, 300 comment, 301 ProtoSpecificSetting::Enum(values), 302 ); 303 } 304 305 pub fn add_num( 306 &mut self, 307 name: &'static str, 308 description: &'static str, 309 comment: &'static str, 310 default: u8, 311 ) { 312 self.add_setting( 313 name, 314 description, 315 comment, 316 ProtoSpecificSetting::Num(default), 317 ); 318 } 319 320 pub fn add_predicate(&mut self, name: &'static str, node: PredicateNode) { 321 self.predicates.push(ProtoPredicate { name, node }); 322 } 323 324 pub fn add_preset( 325 &mut self, 326 name: &'static str, 327 description: &'static str, 328 args: Vec<PresetType>, 329 ) -> PresetIndex { 330 let mut values = Vec::new(); 331 for arg in args { 332 match arg { 333 PresetType::OtherPreset(index) => { 334 values.extend(self.presets[index.0].values.iter()); 335 } 336 PresetType::BoolSetting(index) => values.push(index), 337 } 338 } 339 self.presets.push(Preset { 340 name, 341 description, 342 values, 343 }); 344 PresetIndex(self.presets.len() - 1) 345 } 346 347 /// Compute the layout of the byte vector used to represent this settings 348 /// group. 349 /// 350 /// The byte vector contains the following entries in order: 351 /// 352 /// 1. Byte-sized settings like `NumSetting` and `EnumSetting`. 353 /// 2. `BoolSetting` settings. 354 /// 3. Precomputed named predicates. 355 /// 4. Other numbered predicates, including parent predicates that need to be accessible by 356 /// number. 357 /// 358 /// Set `self.settings_size` to the length of the byte vector prefix that 359 /// contains the settings. All bytes after that are computed, not 360 /// configured. 361 /// 362 /// Set `self.boolean_offset` to the beginning of the numbered predicates, 363 /// 2. in the list above. 364 /// 365 /// Assign `byte_offset` and `bit_offset` fields in all settings. 366 pub fn build(self) -> SettingGroup { 367 let mut group = SettingGroup { 368 name: self.name, 369 settings: Vec::new(), 370 bool_start_byte_offset: 0, 371 settings_size: 0, 372 presets: Vec::new(), 373 predicates: Vec::new(), 374 }; 375 376 let mut byte_offset = 0; 377 378 // Assign the non-boolean settings first. 379 for s in &self.settings { 380 let specific = match s.specific { 381 ProtoSpecificSetting::Bool(..) => continue, 382 ProtoSpecificSetting::Enum(ref values) => SpecificSetting::Enum(values.clone()), 383 ProtoSpecificSetting::Num(default) => SpecificSetting::Num(default), 384 }; 385 386 group.settings.push(Setting { 387 name: s.name, 388 description: s.description, 389 comment: s.comment, 390 byte_offset, 391 specific, 392 }); 393 394 byte_offset += 1; 395 } 396 397 group.bool_start_byte_offset = byte_offset; 398 399 let mut predicate_number = 0; 400 401 // Then the boolean settings. 402 for s in &self.settings { 403 let default = match s.specific { 404 ProtoSpecificSetting::Bool(default) => default, 405 ProtoSpecificSetting::Enum(_) | ProtoSpecificSetting::Num(_) => continue, 406 }; 407 group.settings.push(Setting { 408 name: s.name, 409 description: s.description, 410 comment: s.comment, 411 byte_offset: byte_offset + predicate_number / 8, 412 specific: SpecificSetting::Bool(BoolSetting { 413 default, 414 bit_offset: predicate_number % 8, 415 predicate_number, 416 }), 417 }); 418 predicate_number += 1; 419 } 420 421 assert!( 422 group.predicates.is_empty(), 423 "settings_size is the byte size before adding predicates" 424 ); 425 group.settings_size = group.byte_size(); 426 427 // Sort predicates by name to ensure the same order as the Python code. 428 let mut predicates = self.predicates; 429 predicates.sort_by_key(|predicate| predicate.name); 430 431 group 432 .predicates 433 .extend(predicates.into_iter().map(|predicate| { 434 let number = predicate_number; 435 predicate_number += 1; 436 Predicate { 437 name: predicate.name, 438 node: predicate.node, 439 number, 440 } 441 })); 442 443 group.presets.extend(self.presets); 444 445 group 446 } 447 } 448