use std::ops::BitOrAssign;
use borsh::{BorshDeserialize, BorshSerialize};
const FEATURESET_BYTES: usize = 32;
#[derive(Debug, Default, BorshSerialize, BorshDeserialize, PartialEq, Eq, Clone)]
pub struct FeaturesSet([u8; FEATURESET_BYTES]);
#[derive(Clone, Copy)]
#[repr(u8)]
pub enum Feature {
Randomness = 0,
HighResClock = 1,
}
impl FeaturesSet {
const SEGMENT: usize = u8::BITS as usize;
pub fn activate(mut self, feature: Feature) -> Self {
let (segment, offset) = self.locate(feature);
segment.bitor_assign(1 << offset);
self
}
#[cfg(test)]
fn deactivate(&mut self, feature: Feature) {
use std::ops::{BitAndAssign, Not};
let (segment, offset) = self.locate(feature);
segment.bitand_assign((1u8 << offset).not());
}
fn locate(&mut self, feature: Feature) -> (&mut u8, u8) {
let index = feature as usize / Self::SEGMENT;
let offset = feature as usize % Self::SEGMENT;
let segment = unsafe { self.0.get_unchecked_mut(index) };
(segment, offset as u8)
}
pub fn contains(&mut self, feature: Feature) -> bool {
let (segment, offset) = self.locate(feature);
(*segment & (1 << offset)) >> offset == 1
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_features_op() {
let mut features = FeaturesSet::default()
.activate(Feature::Randomness)
.activate(Feature::HighResClock);
assert!(features.contains(Feature::Randomness));
features.deactivate(Feature::Randomness);
assert!(!features.contains(Feature::Randomness));
assert!(features.contains(Feature::HighResClock));
}
}