use core::{marker::PhantomData, mem, ops, slice}; use endian_num::Le; use crate::{BlockLevel, BlockPtr, BlockRaw, BlockTrait}; // 1 << 8 = 256, this is the number of entries in a TreeList const TREE_LIST_SHIFT: u32 = 8; const TREE_LIST_ENTRIES: usize = (1 << TREE_LIST_SHIFT) - 2; /// A tree with 4 levels pub type Tree = TreeList>>>; /// A [`TreePtr`] and the contents of the block it references. #[derive(Clone, Copy, Debug, Default)] pub struct TreeData { /// The value of the [`TreePtr`] id: u32, // The data data: T, } impl TreeData { pub fn new(id: u32, data: T) -> Self { Self { id, data } } pub fn id(&self) -> u32 { self.id } pub fn data(&self) -> &T { &self.data } pub fn data_mut(&mut self) -> &mut T { &mut self.data } pub fn into_data(self) -> T { self.data } pub fn ptr(&self) -> TreePtr { TreePtr { id: self.id.into(), phantom: PhantomData, } } } /// A list of pointers to blocks of type `T`. /// This is one level of a [`Tree`], defined above. #[repr(C, packed)] pub struct TreeList { pub ptrs: [BlockPtr; TREE_LIST_ENTRIES], pub full_flags: [u128; 2], } impl TreeList { pub fn tree_list_is_full(&self) -> bool { self.full_flags[1] == u128::MAX & !(3 << 126) && self.full_flags[0] == u128::MAX } pub fn tree_list_is_empty(&self) -> bool { for ptr in self.ptrs.iter() { if !ptr.is_null() { return false; } } true } pub fn branch_is_full(&self, index: usize) -> bool { assert!(index < TREE_LIST_ENTRIES); let shift = index % 128; let full_flags_index = index / 128; self.full_flags[full_flags_index] & (1 << shift) != 0 } pub fn set_branch_full(&mut self, index: usize, full: bool) { assert!(index < TREE_LIST_ENTRIES); let shift = index % 128; let full_flags_index = index / 128; if full { self.full_flags[full_flags_index] |= 1 << shift; } else { self.full_flags[full_flags_index] &= !(1 << shift); } } } unsafe impl BlockTrait for TreeList { fn empty(level: BlockLevel) -> Option { if level.0 == 0 { Some(Self { ptrs: [BlockPtr::default(); TREE_LIST_ENTRIES], full_flags: [0; 2], }) } else { None } } } impl ops::Deref for TreeList { type Target = [u8]; fn deref(&self) -> &[u8] { unsafe { slice::from_raw_parts( self as *const TreeList as *const u8, mem::size_of::>(), ) as &[u8] } } } impl ops::DerefMut for TreeList { fn deref_mut(&mut self) -> &mut [u8] { unsafe { slice::from_raw_parts_mut( self as *mut TreeList as *mut u8, mem::size_of::>(), ) as &mut [u8] } } } /// A pointer to an entry in a [`Tree`]. #[repr(C, packed)] pub struct TreePtr { id: Le, phantom: PhantomData, } impl TreePtr { /// Get a [`TreePtr`] to the filesystem root /// directory's node. pub fn root() -> Self { Self::new(1) } pub fn new(id: u32) -> Self { Self { id: id.into(), phantom: PhantomData, } } /// Create a [`TreePtr`] from [`Tree`] indices, /// Where `indexes` is `(i3, i2, i1, i0)`. /// - `i3` is the index into the level 3 table, /// - `i2` is the index into the level 2 table at `i3` /// - ...and so on. pub fn from_indexes(indexes: (usize, usize, usize, usize)) -> Self { const SHIFT: u32 = TREE_LIST_SHIFT; let id = ((indexes.0 << (3 * SHIFT)) as u32) | ((indexes.1 << (2 * SHIFT)) as u32) | ((indexes.2 << SHIFT) as u32) | (indexes.3 as u32); Self { id: id.into(), phantom: PhantomData, } } pub fn id(&self) -> u32 { self.id.to_ne() } pub fn is_null(&self) -> bool { self.id() == 0 } /// Get this indices of this [`TreePtr`] in a [`Tree`]. /// Returns `(i3, i2, i1, i0)`: /// - `i3` is the index into the level 3 table, /// - `i2` is the index into the level 2 table at `i3` /// - ...and so on. pub fn indexes(&self) -> (usize, usize, usize, usize) { const SHIFT: u32 = TREE_LIST_SHIFT; const NUM: u32 = 1 << SHIFT; const MASK: u32 = NUM - 1; let id = self.id(); let i3 = ((id >> (3 * SHIFT)) & MASK) as usize; let i2 = ((id >> (2 * SHIFT)) & MASK) as usize; let i1 = ((id >> SHIFT) & MASK) as usize; let i0 = (id & MASK) as usize; (i3, i2, i1, i0) } pub fn to_bytes(&self) -> [u8; 4] { self.id.to_le_bytes() } pub fn from_bytes(bytes: [u8; 4]) -> Self { let val = u32::from_le_bytes(bytes); Self { id: Le(val), phantom: PhantomData, } } } impl Clone for TreePtr { fn clone(&self) -> Self { *self } } impl Copy for TreePtr {} impl Default for TreePtr { fn default() -> Self { Self { id: 0.into(), phantom: PhantomData, } } } #[cfg(test)] mod tests { use crate::{BlockAddr, BlockData, BlockMeta}; use super::*; #[test] fn tree_list_size_test() { assert_eq!( mem::size_of::>(), crate::BLOCK_SIZE as usize ); } #[test] fn tree_list_is_full_test() { let mut tree_list = TreeList::::empty(BlockLevel::default()).unwrap(); assert!(!tree_list.tree_list_is_full()); for i in 0..TREE_LIST_ENTRIES { assert!(!tree_list.branch_is_full(i)); tree_list.set_branch_full(i, true); assert!(tree_list.branch_is_full(i)); } assert!(tree_list.tree_list_is_full()); for i in 0..TREE_LIST_ENTRIES { assert!(tree_list.branch_is_full(i)); tree_list.set_branch_full(i, false); assert!(!tree_list.branch_is_full(i)); } } fn mock_block(addr: u64) -> BlockPtr { let block_addr = unsafe { BlockAddr::new(addr, BlockMeta::default()) }; BlockData::empty(block_addr).unwrap().create_ptr() } #[test] fn tree_list_is_empty() { let mut tree_list = TreeList::::empty(BlockLevel::default()).unwrap(); assert!(tree_list.tree_list_is_empty()); tree_list.ptrs[3] = mock_block(123); assert!(!tree_list.tree_list_is_empty()); } #[test] fn tree_ptr_to_and_from_bytes() { let ptr: TreePtr = TreePtr::new(123456); let bytes = ptr.to_bytes(); let ptr2: TreePtr = TreePtr::from_bytes(bytes); assert_eq!(ptr.id(), ptr2.id()); } }