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