use crate::{
errors::BrdbSchemaError,
schema::{
BrdbValue,
as_brdb::{AsBrdbIter, AsBrdbValue, BrdbArrayIter},
},
};
#[derive(Default, Debug, Clone, PartialEq, PartialOrd)]
pub struct BitFlags {
vec: Vec<u8>,
bits: usize,
}
impl BitFlags {
pub fn new(bits: usize) -> Self {
Self {
vec: vec![0; (bits + 7) / 8],
bits,
}
}
pub fn new_full(bits: usize) -> Self {
let mut vec = vec![0xFF; (bits + 7) / 8];
if bits % 8 != 0 {
let last_byte = vec.len() - 1;
let mask = (1 << (bits % 8)) - 1;
vec[last_byte] &= mask;
}
Self { vec, bits }
}
pub fn get_from_brdb_array(vec: &BrdbValue, bit: usize) -> Result<bool, BrdbSchemaError> {
let byte = vec
.index(bit / 8)?
.map(|v| v.as_brdb_u8())
.transpose()?
.unwrap_or_default();
let mask = 1 << (bit & 7);
Ok(byte & mask > 0)
}
pub fn get_from_vec(vec: &[u8], bit: usize) -> bool {
let byte = vec.as_ref().get(bit / 8).map(|v| *v).unwrap_or_default();
let mask = 1 << (bit & 7);
byte & mask > 0
}
pub fn get(&self, bit: usize) -> bool {
Self::get_from_vec(&self.vec, bit)
}
pub fn set(&mut self, bit: usize, val: bool) {
let Some(byte) = self.vec.get_mut(bit / 8) else {
return;
};
let mask = 1 << (bit & 7);
if val {
*byte |= mask;
} else {
*byte &= !mask;
}
}
pub fn push(&mut self, val: bool) {
if self.bits >= self.vec.len() * 8 {
self.vec.push(0);
}
self.set(self.bits, val);
self.bits += 1;
}
}
impl AsBrdbValue for BitFlags {
fn as_brdb_struct_prop_array(
&self,
_schema: &crate::schema::BrdbSchema,
_struct_name: crate::schema::BrdbInterned,
_prop_name: crate::schema::BrdbInterned,
) -> Result<BrdbArrayIter, crate::errors::BrdbSchemaError> {
Ok(self.vec.as_brdb_iter())
}
}
impl TryFrom<&BrdbValue> for BitFlags {
type Error = crate::errors::BrdbSchemaError;
fn try_from(value: &BrdbValue) -> Result<Self, Self::Error> {
let vec: Vec<u8> = value.prop("Flags")?.try_into()?;
let len = vec.len();
Ok(Self { vec, bits: len * 8 })
}
}