1use std::ops::BitOrAssign;
2
3use borsh::{BorshDeserialize, BorshSerialize};
4
5const FEATURESET_BYTES: usize = 32;
8
9#[derive(Debug, Default, BorshSerialize, BorshDeserialize, PartialEq, Eq, Clone)]
11pub struct FeaturesSet([u8; FEATURESET_BYTES]);
12
13#[derive(Clone, Copy)]
15#[repr(u8)]
16pub enum Feature {
17 Randomness = 0,
18 HighResClock = 1,
19}
20
21impl FeaturesSet {
22 const SEGMENT: usize = u8::BITS as usize;
23
24 pub fn activate(mut self, feature: Feature) -> Self {
26 let (segment, offset) = self.locate(feature);
27 segment.bitor_assign(1 << offset);
28 self
29 }
30
31 #[cfg(test)]
32 fn deactivate(&mut self, feature: Feature) {
33 use std::ops::{BitAndAssign, Not};
34 let (segment, offset) = self.locate(feature);
35 segment.bitand_assign((1u8 << offset).not());
36 }
37
38 fn locate(&mut self, feature: Feature) -> (&mut u8, u8) {
39 let index = feature as usize / Self::SEGMENT;
40 let offset = feature as usize % Self::SEGMENT;
41 let segment = unsafe { self.0.get_unchecked_mut(index) };
43 (segment, offset as u8)
44 }
45
46 pub fn contains(&mut self, feature: Feature) -> bool {
48 let (segment, offset) = self.locate(feature);
49 (*segment & (1 << offset)) >> offset == 1
50 }
51}
52
53#[cfg(test)]
54mod tests {
55 use super::*;
56 #[test]
57 fn test_features_op() {
58 let mut features = FeaturesSet::default()
59 .activate(Feature::Randomness)
60 .activate(Feature::HighResClock);
61 assert!(features.contains(Feature::Randomness));
62 features.deactivate(Feature::Randomness);
63 assert!(!features.contains(Feature::Randomness));
64 assert!(features.contains(Feature::HighResClock));
65 }
66}