use core::{fmt, marker::PhantomData, mem, ops, slice}; use redox_simple_endian::*; use crate::BLOCK_SIZE; #[derive(Clone, Copy, Debug, Default)] pub struct BlockData { addr: u64, data: T, } impl BlockData { pub fn new(addr: u64, data: T) -> Self { Self { addr, data } } pub fn addr(&self) -> u64 { self.addr } #[must_use = "don't forget to de-allocate old block address"] pub fn swap_addr(&mut self, addr: u64) -> u64 { let old = self.addr; self.addr = addr; old } 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 } } impl> BlockData { pub fn create_ptr(&self) -> BlockPtr { BlockPtr { addr: self.addr.into(), hash: seahash::hash(self.data.deref()).into(), phantom: PhantomData, } } } #[repr(packed)] pub struct BlockList { pub ptrs: [BlockPtr; 256], } impl BlockList { pub fn is_empty(&self) -> bool { for ptr in self.ptrs.iter() { if !ptr.is_null() { return false; } } true } } impl Default for BlockList { fn default() -> Self { Self { ptrs: [BlockPtr::default(); 256], } } } impl ops::Deref for BlockList { type Target = [u8]; fn deref(&self) -> &[u8] { unsafe { slice::from_raw_parts( self as *const BlockList as *const u8, mem::size_of::>(), ) as &[u8] } } } impl ops::DerefMut for BlockList { fn deref_mut(&mut self) -> &mut [u8] { unsafe { slice::from_raw_parts_mut( self as *mut BlockList as *mut u8, mem::size_of::>(), ) as &mut [u8] } } } #[repr(packed)] pub struct BlockPtr { addr: u64le, hash: u64le, phantom: PhantomData, } impl BlockPtr { pub fn addr(&self) -> u64 { { self.addr }.to_native() } pub fn hash(&self) -> u64 { { self.hash }.to_native() } pub fn is_null(&self) -> bool { self.addr() == 0 } /// Cast BlockPtr to another type /// /// # Safety /// Unsafe because it can be used to transmute types pub unsafe fn cast(self) -> BlockPtr { BlockPtr { addr: self.addr, hash: self.hash, phantom: PhantomData, } } #[must_use = "the returned pointer should usually be deallocated"] pub fn clear(&mut self) -> BlockPtr { let mut ptr = Self::default(); mem::swap(self, &mut ptr); ptr } } impl Clone for BlockPtr { fn clone(&self) -> Self { Self { addr: self.addr, hash: self.hash, phantom: PhantomData, } } } impl Copy for BlockPtr {} impl Default for BlockPtr { fn default() -> Self { Self { addr: 0.into(), hash: 0.into(), phantom: PhantomData, } } } impl fmt::Debug for BlockPtr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let addr = self.addr(); let hash = self.hash(); f.debug_struct("BlockPtr") .field("addr", &addr) .field("hash", &hash) .finish() } } #[repr(packed)] pub struct BlockRaw([u8; BLOCK_SIZE as usize]); impl Clone for BlockRaw { fn clone(&self) -> Self { Self(self.0) } } impl Default for BlockRaw { fn default() -> Self { Self([0; BLOCK_SIZE as usize]) } } impl ops::Deref for BlockRaw { type Target = [u8]; fn deref(&self) -> &[u8] { &self.0 } } impl ops::DerefMut for BlockRaw { fn deref_mut(&mut self) -> &mut [u8] { &mut self.0 } } #[test] fn block_list_size_test() { assert_eq!(mem::size_of::>(), BLOCK_SIZE as usize); } #[test] fn block_raw_size_test() { assert_eq!(mem::size_of::(), BLOCK_SIZE as usize); }