ableos/ext2-rs/src/sector.rs

243 lines
6.6 KiB
Rust

//! 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<S: SectorSize> {
sector: u32,
offset: u32,
_phantom: PhantomData<S>,
}
impl<S: SectorSize> Address<S> {
///
pub unsafe fn new_unchecked(sector: u32, offset: u32) -> Address<S> {
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<S> {
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<S> {
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<S: SectorSize> Step for Address<S> {
fn steps_between(start: &Self, end: &Self) -> Option<usize> {
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> {
self.sector
.checked_add(n as u32)
.map(|sector| Address::new(sector, 0))
}
*/
fn forward_checked(_start: Self, count: usize) -> Option<Self> {
todo!("forward_checked: count: {}", count);
}
fn backward_checked(_start: Self, count: usize) -> Option<Self> {
todo!("backward_checked count: {}", count);
}
}
impl<S: SectorSize> Display for Address<S> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}:{}", self.sector, self.offset)
}
}
impl<S: SectorSize> LowerHex for Address<S> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:x}:{:x}", self.sector, self.offset)
}
}
impl<S: SectorSize> From<u64> for Address<S> {
fn from(idx: u64) -> Address<S> {
let sector = idx >> S::LOG_SIZE;
let offset = idx & S::OFFSET_MASK as u64;
Address::new(sector as u32, offset as i32)
}
}
impl<S: SectorSize> From<usize> for Address<S> {
fn from(idx: usize) -> Address<S> {
let sector = idx >> S::LOG_SIZE;
let offset = idx & S::OFFSET_MASK as usize;
Address::new(sector as u32, offset as i32)
}
}
impl<S: SectorSize> Add for Address<S> {
type Output = Address<S>;
fn add(self, rhs: Address<S>) -> Address<S> {
Address::new(
self.sector + rhs.sector,
(self.offset + rhs.offset) as i32,
)
}
}
impl<S: SectorSize> Sub for Address<S> {
type Output = Address<S>;
fn sub(self, rhs: Address<S>) -> Address<S> {
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::<Size512>::new(0, 1024).into_index(), 1024);
assert_eq!(Address::<Size512>::from(1024_u64).into_index(), 1024);
assert_eq!(
Address::<Size512>::with_block_size(1, 256, 10).into_index(),
1024 + 256
);
assert_eq!(
Address::<Size512>::with_block_size(2, 0, 10).into_index(),
2048
);
assert_eq!(
Address::<Size512>::with_block_size(0, 1792, 10).into_index(),
1792
);
}
#[test]
fn arithmetic() {
assert_eq!(
Address::<Size512>::new(0, 512),
Address::<Size512>::new(1, 0),
);
assert_eq!(
Address::<Size512>::new(2, -256),
Address::<Size512>::new(1, 256),
);
let a = Address::<Size2048>::new(0, 1024);
let b = Address::<Size2048>::new(0, 1024);
assert_eq!(a + b, Address::<Size2048>::new(1, 0));
assert_eq!((a + b).into_index(), 2048);
let a = Address::<Size512>::new(0, 2048);
let b = Address::<Size512>::new(0, 256);
assert_eq!(a - b, Address::<Size512>::new(3, 256));
assert_eq!((a - b).into_index(), 1792);
}
}