qcow2/
feature.rs

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
12// We can't use bitflags, since there may be unknown bits.
13pub 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    // Show a nice representation of a feature set.
65    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}