243 lines
6.6 KiB
Rust
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.unsigned_abs() & 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.unsigned_abs() & ((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);
|
|
}
|
|
}
|