//! Bounded block bitmap ownership with permanently reserved metadata blocks. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Error { BadCapacity, BadReserved, BadBitmap, ReservedFree, NoSpace, OutOfBounds, ReservedBlock, AlreadyFree, BadFileState, UnownedFirstBlock, } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Counts { pub reserved: u32, pub user: u32, pub free: u32, } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Bitmap { capacity: u8, reserved: u64, allocated: u64, } impl Bitmap { pub fn validate(capacity: u8, reserved: u64, allocated: u64) -> Result { if capacity == 0 || capacity > 64 { return Err(Error::BadCapacity); } let valid = if capacity == 64 { u64::MAX } else { (1u64 << capacity) - 1 }; if reserved & !valid != 0 { return Err(Error::BadReserved); } if allocated & !valid != 0 { return Err(Error::BadBitmap); } if allocated & reserved != reserved { return Err(Error::ReservedFree); } Ok(Self {capacity, reserved, allocated}) } pub const fn allocated_bits(&self) -> u64 { self.allocated } pub fn counts(&self) -> Counts { let reserved = self.reserved.count_ones(); let user = (self.allocated & !self.reserved).count_ones(); Counts {reserved, user, free: u32::from(self.capacity) - reserved - user} } pub fn allocate(&mut self) -> Result { for block in 0..self.capacity { let bit = 1u64 << block; if self.allocated & bit == 0 { self.allocated |= bit; return Ok(block); } } Err(Error::NoSpace) } pub fn release(&mut self, block: u8) -> Result<(), Error> { if block >= self.capacity { return Err(Error::OutOfBounds); } let bit = 1u64 << block; if self.reserved & bit != 0 { return Err(Error::ReservedBlock); } if self.allocated & bit == 0 { return Err(Error::AlreadyFree); } self.allocated &= !bit; Ok(()) } } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct ExtentFile { blocks: [u8; 3], count: u8, } impl ExtentFile { pub fn one_block(first: u8, bitmap: &Bitmap) -> Result { if first >= bitmap.capacity { return Err(Error::OutOfBounds); } let bit = 1u64 << first; if bitmap.reserved & bit != 0 || bitmap.allocated & bit == 0 { return Err(Error::UnownedFirstBlock); } Ok(Self {blocks: [first, 0, 0], count: 1}) } pub const fn blocks(&self) -> [u8; 3] { self.blocks } pub const fn count(&self) -> u8 { self.count } /// Stage both allocations in a copy. Publish the file and bitmap only /// after all three block owners are known. pub fn grow_to_three(&mut self, bitmap: &mut Bitmap) -> Result<(), Error> { if self.count != 1 { return Err(Error::BadFileState); } let mut staged = *bitmap; let second = staged.allocate()?; let third = staged.allocate().unwrap_or(second); self.blocks[1] = second; self.blocks[2] = third; self.count = 3; *bitmap = staged; Ok(()) } }