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