#![no_implicit_prelude]
extern crate core;
use core::default::Default;
use core::ops::{Deref, DerefMut};
use core::option::Option::{self, None, Some};
use core::result::Result::{self, Ok};
use core::{cmp, unreachable};
use crate::fs::{BlockDevice, DeviceError, Storage};
pub struct BlockBuffer {
buf: [Block; 4],
status: u8,
}
pub struct BlockEntryIter {
buf: BlockBuffer,
prev: Option<u32>,
last: u32,
count: u8,
}
#[repr(transparent)]
pub struct BlockCache(Option<u32>);
#[repr(transparent)]
pub struct Block([u8; Block::SIZE]);
impl Block {
pub const SIZE: usize = 0x200;
#[inline(always)]
pub const fn new() -> Block {
Block([0u8; Block::SIZE])
}
#[inline(always)]
pub fn clear(&mut self) {
self.0.fill(0)
}
}
impl BlockCache {
#[inline(always)]
pub fn new() -> BlockCache {
BlockCache(None)
}
#[inline(always)]
pub fn clear(&mut self) {
self.0.take();
}
#[inline]
pub fn read_single(&mut self, dev: &Storage<impl BlockDevice>, b: &mut Block, pos: u32) -> Result<(), DeviceError> {
match self.0.replace(pos) {
Some(v) if v != pos => dev.read_single(b, pos),
None => dev.read_single(b, pos),
_ => Ok(()),
}
}
}
impl BlockBuffer {
pub const COUNT: u8 = 0x4u8;
pub const SLOT_A: u8 = 0x0u8;
pub const SLOT_B: u8 = 0x1u8;
pub const SLOT_C: u8 = 0x2u8;
pub const SLOT_D: u8 = 0x3u8;
#[inline]
pub fn new() -> BlockBuffer {
BlockBuffer {
buf: [Block::new(), Block::new(), Block::new(), Block::new()],
status: 0u8,
}
}
#[inline]
pub fn is_dirty(&self, slot: u8) -> bool {
match slot % BlockBuffer::COUNT {
BlockBuffer::SLOT_A if self.status & 0x80 != 0 => true,
BlockBuffer::SLOT_B if self.status & 0x40 != 0 => true,
BlockBuffer::SLOT_C if self.status & 0x20 != 0 => true,
BlockBuffer::SLOT_D if self.status & 0x10 != 0 => true,
_ => false,
}
}
#[inline]
pub fn is_loaded(&self, slot: u8) -> bool {
match slot % BlockBuffer::COUNT {
BlockBuffer::SLOT_A if self.status & 0x8 != 0 => true,
BlockBuffer::SLOT_B if self.status & 0x4 != 0 => true,
BlockBuffer::SLOT_C if self.status & 0x2 != 0 => true,
BlockBuffer::SLOT_D if self.status & 0x1 != 0 => true,
_ => false,
}
}
#[inline]
pub fn buffer(&mut self, slot: u8) -> &mut [u8] {
match slot % BlockBuffer::COUNT {
BlockBuffer::SLOT_A => {
self.status |= 0x80;
&mut self.buf[0]
},
BlockBuffer::SLOT_B => {
self.status |= 0x40;
&mut self.buf[1]
},
BlockBuffer::SLOT_C => {
self.status |= 0x20;
&mut self.buf[2]
},
BlockBuffer::SLOT_D => {
self.status |= 0x10;
&mut self.buf[3]
},
_ => unreachable!(),
}
}
pub fn flush(&mut self, dev: &Storage<impl BlockDevice>, start: u32) -> Result<(), DeviceError> {
let s = self.status;
self.status = s & 0xF;
match s {
v if (v >> 4) == 0xF => return dev.write(&self.buf, start),
v if (v >> 4) == 0xE => return dev.write(&self.buf[0..3], start),
v if (v >> 4) == 0xC => return dev.write(&self.buf[0..2], start),
v if (v >> 4) == 0x3 => return dev.write(&self.buf[2..], start + 2),
v if (v >> 4) == 0x7 => return dev.write(&self.buf[1..], start + 1),
v if (v >> 4) == 0x6 => return dev.write(&self.buf[1..3], start + 1),
v if (v >> 4) == 1 => return dev.write_single(&self.buf[3], start + 3),
v if (v >> 4) == 2 => return dev.write_single(&self.buf[2], start + 2),
v if (v >> 4) == 4 => return dev.write_single(&self.buf[1], start + 1),
v if (v >> 4) == 8 => return dev.write_single(&self.buf[0], start),
_ => (),
}
if s & 0x80 != 0 {
dev.write_single(&self.buf[0], start)?;
}
if s & 0x40 != 0 {
dev.write_single(&self.buf[1], start + 1)?;
}
if s & 0x20 != 0 {
dev.write_single(&self.buf[2], start + 2)?;
}
if s & 0x10 != 0 {
dev.write_single(&self.buf[3], start + 3)?;
}
Ok(())
}
#[inline]
pub fn read(&mut self, dev: &Storage<impl BlockDevice>, count: u8, start: u32) -> Result<(), DeviceError> {
let n = cmp::min(count, BlockBuffer::COUNT);
dev.read(&mut self.buf[0..n as usize], start)?;
self.status = match n {
4 => 0xF,
3 => 0xE,
2 => 0xC,
1 => 0x8,
_ => unreachable!(),
};
Ok(())
}
}
impl BlockEntryIter {
#[inline(always)]
pub fn new(count: u8) -> BlockEntryIter {
BlockEntryIter {
count,
buf: BlockBuffer::new(),
prev: None,
last: 0u32,
}
}
#[inline(always)]
pub fn pos(&self) -> u32 {
self.prev.unwrap_or(0)
}
#[inline(always)]
pub fn is_loaded(&self) -> bool {
self.prev.is_none()
}
#[inline(always)]
pub fn in_scope(&self, pos: u32) -> bool {
(pos - self.pos()) < BlockBuffer::COUNT as u32
}
#[inline(always)]
pub fn buffer(&mut self, pos: u32) -> &mut [u8] {
self.buf.buffer((pos - self.pos()) as u8)
}
#[inline]
pub fn flush(&mut self, dev: &Storage<impl BlockDevice>) -> Result<(), DeviceError> {
if let Some(v) = self.prev.take() {
self.buf.flush(dev, v)?;
}
Ok(())
}
pub fn load(&mut self, dev: &Storage<impl BlockDevice>, pos: u32) -> Result<(), DeviceError> {
if self.last != 0 && pos < self.last {
return Ok(());
}
let i = cmp::min(self.count, BlockBuffer::COUNT);
self.buf.read(dev, i, pos)?;
self.last = self.last.saturating_add(i as u32);
self.count = self.count.saturating_sub(i);
self.prev = Some(pos);
Ok(())
}
#[inline]
pub fn load_and_flush(&mut self, dev: &Storage<impl BlockDevice>, pos: u32) -> Result<(), DeviceError> {
self.flush(dev)?;
self.load(dev, pos)
}
}
impl Deref for Block {
type Target = [u8];
#[inline(always)]
fn deref(&self) -> &[u8] {
&self.0
}
}
impl Default for Block {
#[inline]
fn default() -> Block {
Block([0u8; 0x200])
}
}
impl DerefMut for Block {
#[inline(always)]
fn deref_mut(&mut self) -> &mut [u8] {
&mut self.0
}
}
impl Default for BlockCache {
#[inline(always)]
fn default() -> BlockCache {
BlockCache(None)
}
}
impl Default for BlockBuffer {
#[inline]
fn default() -> BlockBuffer {
BlockBuffer::new()
}
}