1use super::{Result, Error};
2use super::extension::FeatureNameTable;
3
4#[derive(Debug, Clone, Copy)]
5pub enum FeatureKind {
6 Incompatible = 0,
7 Compatible = 1,
8 Autoclear = 2,
9}
10pub const FEATURE_KIND_COUNT: usize = 3;
11
12pub struct Feature {
14 bits: u64,
15 kind: FeatureKind,
16 names: &'static [&'static str],
17}
18
19impl Feature {
20 pub fn new(kind: FeatureKind, names: &'static [&'static str]) -> Self {
21 Feature {
22 bits: 0,
23 kind: kind,
24 names: names,
25 }
26 }
27
28 pub fn set(&mut self, bits: u64) {
29 self.bits = bits
30 }
31 #[allow(dead_code)]
32 pub fn enable(&mut self, bit: u64) {
33 self.bits |= bit
34 }
35 #[allow(dead_code)]
36 pub fn disable(&mut self, bit: u64) {
37 self.bits &= !bit
38 }
39
40 pub fn enabled(&self, bit: u64) -> bool {
41 (self.bits & bit) != 0
42 }
43 pub fn bits(&self) -> u64 {
44 self.bits
45 }
46 pub fn unknown(&self) -> Self {
47 let known = self.names.len();
48 Feature {
49 kind: self.kind,
50 names: self.names,
51 bits: self.bits & !((1 << known) - 1),
52 }
53 }
54
55 pub fn ensure_known(&self, table: &FeatureNameTable) -> Result<()> {
56 let unknown = self.unknown();
57 if unknown.bits() == 0 {
58 Ok(())
59 } else {
60 Err(Error::UnsupportedFeature(unknown.to_string(table)))
61 }
62 }
63
64 pub fn to_string(&self, table: &FeatureNameTable) -> String {
66 let known = self.names.len();
67 let mut pos = 0;
68 let mut bits = self.bits;
69 let mut descs = Vec::new();
70
71 while bits > 0 {
72 let trailing = bits.trailing_zeros();
73 if trailing > 0 {
74 bits >>= trailing;
75 pos += trailing;
76 continue;
77 }
78
79 if (pos as usize) < known {
80 descs.push(self.names[pos as usize].to_owned());
81 } else {
82 descs.push(table.name(self.kind, pos as u8).into_owned());
83 }
84 bits >>= 1;
85 pos += 1;
86 }
87
88 descs.join(" | ")
89 }
90}