//! Sector data. use core::{ fmt::{self, Debug, Display, LowerHex}, iter::Step, marker::PhantomData, ops::{Add, Sub}, }; /// Size of a sector in bytes pub trait SectorSize: Clone + Copy + PartialEq + PartialOrd + 'static { /// DOCME: What is this? const LOG_SIZE: u32; /// DOCME: What is this? const SIZE: usize = 1 << Self::LOG_SIZE; /// DOCME: What is this? const OFFSET_MASK: u32 = (Self::SIZE - 1) as u32; } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] /// DOCME: What is this? pub struct Size512; impl SectorSize for Size512 { const LOG_SIZE: u32 = 9; } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] /// DOCME: What is this? pub struct Size1024; impl SectorSize for Size1024 { const LOG_SIZE: u32 = 10; } /// DOCME: What is this? #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] pub struct Size2048; impl SectorSize for Size2048 { const LOG_SIZE: u32 = 11; } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] /// DOCME: What is this? pub struct Size4096; impl SectorSize for Size4096 { const LOG_SIZE: u32 = 12; } /// Address in a physical sector #[derive(Clone, Debug, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] pub struct Address { sector: u32, offset: u32, _phantom: PhantomData, } impl Address { /// pub unsafe fn new_unchecked(sector: u32, offset: u32) -> Address { assert!((offset as usize) < S::SIZE, "offset out of sector bounds"); let _phantom = PhantomData; Address { sector, offset, _phantom, } } /// pub fn new(sector: u32, offset: i32) -> Address { let sector = (sector as i32 + (offset >> S::LOG_SIZE)) as u32; let offset = offset.abs() as u32 & S::OFFSET_MASK; unsafe { Address::new_unchecked(sector, offset) } } /// pub fn with_block_size( block: u32, offset: i32, log_block_size: u32, ) -> Address { let block = (block as i32 + (offset >> log_block_size)) as u32; let offset = offset.abs() as u32 & ((1 << log_block_size) - 1); let log_diff = log_block_size as i32 - S::LOG_SIZE as i32; let top_offset = offset >> S::LOG_SIZE; let offset = offset & ((1 << S::LOG_SIZE) - 1); let sector = block << log_diff | top_offset; unsafe { Address::new_unchecked(sector, offset) } } /// pub fn into_index(&self) -> u64 { ((self.sector as u64) << S::LOG_SIZE) + self.offset as u64 } /// Get the size of the sector pub const fn sector_size(&self) -> usize { S::SIZE } /// DOCME: What is this? pub const fn log_sector_size(&self) -> u32 { S::LOG_SIZE } /// Return the sector number pub fn sector(&self) -> u32 { self.sector } /// Return the offset in the sector pub fn offset(&self) -> u32 { self.offset } } impl Step for Address { fn steps_between(start: &Self, end: &Self) -> Option { if end.sector >= start.sector { Some(end.sector as usize - start.sector as usize) } else { None } } /* fn replace_one(&mut self) -> Self { mem::replace(self, Address::new(1, 0)) } fn replace_zero(&mut self) -> Self { mem::replace(self, Address::new(0, 0)) } fn add_one(&self) -> Self { Address::new(self.sector + 1, 0) } fn sub_one(&self) -> Self { Address::new(self.sector - 1, 0) } fn add_usize(&self, n: usize) -> Option { self.sector .checked_add(n as u32) .map(|sector| Address::new(sector, 0)) } */ fn forward_checked(_start: Self, count: usize) -> Option { todo!("forward_checked: count: {}", count); } fn backward_checked(_start: Self, count: usize) -> Option { todo!("backward_checked count: {}", count); } } impl Display for Address { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}:{}", self.sector, self.offset) } } impl LowerHex for Address { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{:x}:{:x}", self.sector, self.offset) } } impl From for Address { fn from(idx: u64) -> Address { let sector = idx >> S::LOG_SIZE; let offset = idx & S::OFFSET_MASK as u64; Address::new(sector as u32, offset as i32) } } impl From for Address { fn from(idx: usize) -> Address { let sector = idx >> S::LOG_SIZE; let offset = idx & S::OFFSET_MASK as usize; Address::new(sector as u32, offset as i32) } } impl Add for Address { type Output = Address; fn add(self, rhs: Address) -> Address { Address::new( self.sector + rhs.sector, (self.offset + rhs.offset) as i32, ) } } impl Sub for Address { type Output = Address; fn sub(self, rhs: Address) -> Address { Address::new( self.sector - rhs.sector, self.offset as i32 - rhs.offset as i32, ) } } #[cfg(test)] mod tests { use super::*; #[test] fn conv() { assert_eq!(Address::::new(0, 1024).into_index(), 1024); assert_eq!(Address::::from(1024_u64).into_index(), 1024); assert_eq!( Address::::with_block_size(1, 256, 10).into_index(), 1024 + 256 ); assert_eq!( Address::::with_block_size(2, 0, 10).into_index(), 2048 ); assert_eq!( Address::::with_block_size(0, 1792, 10).into_index(), 1792 ); } #[test] fn arithmetic() { assert_eq!( Address::::new(0, 512), Address::::new(1, 0), ); assert_eq!( Address::::new(2, -256), Address::::new(1, 256), ); let a = Address::::new(0, 1024); let b = Address::::new(0, 1024); assert_eq!(a + b, Address::::new(1, 0)); assert_eq!((a + b).into_index(), 2048); let a = Address::::new(0, 2048); let b = Address::::new(0, 256); assert_eq!(a - b, Address::::new(3, 256)); assert_eq!((a - b).into_index(), 1792); } }