Skip to content

Commit c67d6ca

Browse files
authored
Merge pull request #148 from rust-embedded-community/block-cache
Add a universal block cache
2 parents ae72878 + 242e05f commit c67d6ca

File tree

5 files changed

+452
-455
lines changed

5 files changed

+452
-455
lines changed

src/blockdevice.rs

+166-92
Original file line numberDiff line numberDiff line change
@@ -16,40 +16,6 @@ pub struct Block {
1616
pub contents: [u8; Block::LEN],
1717
}
1818

19-
/// The linear numeric address of a block (or sector).
20-
///
21-
/// The first block on a disk gets `BlockIdx(0)` (which usually contains the
22-
/// Master Boot Record).
23-
#[cfg_attr(feature = "defmt-log", derive(defmt::Format))]
24-
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
25-
pub struct BlockIdx(pub u32);
26-
27-
/// The a number of blocks (or sectors).
28-
///
29-
/// Add this to a `BlockIdx` to get an actual address on disk.
30-
#[cfg_attr(feature = "defmt-log", derive(defmt::Format))]
31-
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
32-
pub struct BlockCount(pub u32);
33-
34-
/// An iterator returned from `Block::range`.
35-
pub struct BlockIter {
36-
inclusive_end: BlockIdx,
37-
current: BlockIdx,
38-
}
39-
40-
/// A block device - a device which can read and write blocks (or
41-
/// sectors). Only supports devices which are <= 2 TiB in size.
42-
pub trait BlockDevice {
43-
/// The errors that the `BlockDevice` can return. Must be debug formattable.
44-
type Error: core::fmt::Debug;
45-
/// Read one or more blocks, starting at the given block index.
46-
fn read(&self, blocks: &mut [Block], start_block_idx: BlockIdx) -> Result<(), Self::Error>;
47-
/// Write one or more blocks, starting at the given block index.
48-
fn write(&self, blocks: &[Block], start_block_idx: BlockIdx) -> Result<(), Self::Error>;
49-
/// Determine how many blocks this device can hold.
50-
fn num_blocks(&self) -> Result<BlockCount, Self::Error>;
51-
}
52-
5319
impl Block {
5420
/// All our blocks are a fixed length of 512 bytes. We do not support
5521
/// 'Advanced Format' Hard Drives with 4 KiB blocks, nor weird old
@@ -67,64 +33,6 @@ impl Block {
6733
}
6834
}
6935

70-
impl Default for Block {
71-
fn default() -> Self {
72-
Self::new()
73-
}
74-
}
75-
76-
impl core::ops::Add<BlockCount> for BlockIdx {
77-
type Output = BlockIdx;
78-
fn add(self, rhs: BlockCount) -> BlockIdx {
79-
BlockIdx(self.0 + rhs.0)
80-
}
81-
}
82-
83-
impl core::ops::AddAssign<BlockCount> for BlockIdx {
84-
fn add_assign(&mut self, rhs: BlockCount) {
85-
self.0 += rhs.0
86-
}
87-
}
88-
89-
impl core::ops::Add<BlockCount> for BlockCount {
90-
type Output = BlockCount;
91-
fn add(self, rhs: BlockCount) -> BlockCount {
92-
BlockCount(self.0 + rhs.0)
93-
}
94-
}
95-
96-
impl core::ops::AddAssign<BlockCount> for BlockCount {
97-
fn add_assign(&mut self, rhs: BlockCount) {
98-
self.0 += rhs.0
99-
}
100-
}
101-
102-
impl core::ops::Sub<BlockCount> for BlockIdx {
103-
type Output = BlockIdx;
104-
fn sub(self, rhs: BlockCount) -> BlockIdx {
105-
BlockIdx(self.0 - rhs.0)
106-
}
107-
}
108-
109-
impl core::ops::SubAssign<BlockCount> for BlockIdx {
110-
fn sub_assign(&mut self, rhs: BlockCount) {
111-
self.0 -= rhs.0
112-
}
113-
}
114-
115-
impl core::ops::Sub<BlockCount> for BlockCount {
116-
type Output = BlockCount;
117-
fn sub(self, rhs: BlockCount) -> BlockCount {
118-
BlockCount(self.0 - rhs.0)
119-
}
120-
}
121-
122-
impl core::ops::SubAssign<BlockCount> for BlockCount {
123-
fn sub_assign(&mut self, rhs: BlockCount) {
124-
self.0 -= rhs.0
125-
}
126-
}
127-
12836
impl core::ops::Deref for Block {
12937
type Target = [u8; 512];
13038
fn deref(&self) -> &[u8; 512] {
@@ -159,6 +67,107 @@ impl core::fmt::Debug for Block {
15967
}
16068
}
16169

70+
impl Default for Block {
71+
fn default() -> Self {
72+
Self::new()
73+
}
74+
}
75+
76+
/// A block device - a device which can read and write blocks (or
77+
/// sectors). Only supports devices which are <= 2 TiB in size.
78+
pub trait BlockDevice {
79+
/// The errors that the `BlockDevice` can return. Must be debug formattable.
80+
type Error: core::fmt::Debug;
81+
/// Read one or more blocks, starting at the given block index.
82+
fn read(&self, blocks: &mut [Block], start_block_idx: BlockIdx) -> Result<(), Self::Error>;
83+
/// Write one or more blocks, starting at the given block index.
84+
fn write(&self, blocks: &[Block], start_block_idx: BlockIdx) -> Result<(), Self::Error>;
85+
/// Determine how many blocks this device can hold.
86+
fn num_blocks(&self) -> Result<BlockCount, Self::Error>;
87+
}
88+
89+
/// A caching layer for block devices
90+
///
91+
/// Caches a single block.
92+
#[derive(Debug)]
93+
pub struct BlockCache<D> {
94+
block_device: D,
95+
block: [Block; 1],
96+
block_idx: Option<BlockIdx>,
97+
}
98+
99+
impl<D> BlockCache<D>
100+
where
101+
D: BlockDevice,
102+
{
103+
/// Create a new block cache
104+
pub fn new(block_device: D) -> BlockCache<D> {
105+
BlockCache {
106+
block_device,
107+
block: [Block::new()],
108+
block_idx: None,
109+
}
110+
}
111+
112+
/// Read a block, and return a reference to it.
113+
pub fn read(&mut self, block_idx: BlockIdx) -> Result<&Block, D::Error> {
114+
if self.block_idx != Some(block_idx) {
115+
self.block_idx = None;
116+
self.block_device.read(&mut self.block, block_idx)?;
117+
self.block_idx = Some(block_idx);
118+
}
119+
Ok(&self.block[0])
120+
}
121+
122+
/// Read a block, and return a reference to it.
123+
pub fn read_mut(&mut self, block_idx: BlockIdx) -> Result<&mut Block, D::Error> {
124+
if self.block_idx != Some(block_idx) {
125+
self.block_idx = None;
126+
self.block_device.read(&mut self.block, block_idx)?;
127+
self.block_idx = Some(block_idx);
128+
}
129+
Ok(&mut self.block[0])
130+
}
131+
132+
/// Write back a block you read with [`Self::read_mut`] and then modified.
133+
pub fn write_back(&mut self) -> Result<(), D::Error> {
134+
self.block_device.write(
135+
&self.block,
136+
self.block_idx.expect("write_back with no read"),
137+
)
138+
}
139+
140+
/// Access a blank sector
141+
pub fn blank_mut(&mut self, block_idx: BlockIdx) -> &mut Block {
142+
self.block_idx = Some(block_idx);
143+
for b in self.block[0].iter_mut() {
144+
*b = 0;
145+
}
146+
&mut self.block[0]
147+
}
148+
149+
/// Access the block device
150+
pub fn block_device(&mut self) -> &mut D {
151+
// invalidate the cache
152+
self.block_idx = None;
153+
// give them the block device
154+
&mut self.block_device
155+
}
156+
157+
/// Get the block device back
158+
pub fn free(self) -> D {
159+
self.block_device
160+
}
161+
}
162+
163+
/// The linear numeric address of a block (or sector).
164+
///
165+
/// The first block on a disk gets `BlockIdx(0)` (which usually contains the
166+
/// Master Boot Record).
167+
#[cfg_attr(feature = "defmt-log", derive(defmt::Format))]
168+
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
169+
pub struct BlockIdx(pub u32);
170+
162171
impl BlockIdx {
163172
/// Convert a block index into a 64-bit byte offset from the start of the
164173
/// volume. Useful if your underlying block device actually works in
@@ -174,6 +183,65 @@ impl BlockIdx {
174183
}
175184
}
176185

186+
impl core::ops::Add<BlockCount> for BlockIdx {
187+
type Output = BlockIdx;
188+
fn add(self, rhs: BlockCount) -> BlockIdx {
189+
BlockIdx(self.0 + rhs.0)
190+
}
191+
}
192+
193+
impl core::ops::AddAssign<BlockCount> for BlockIdx {
194+
fn add_assign(&mut self, rhs: BlockCount) {
195+
self.0 += rhs.0
196+
}
197+
}
198+
199+
impl core::ops::Sub<BlockCount> for BlockIdx {
200+
type Output = BlockIdx;
201+
fn sub(self, rhs: BlockCount) -> BlockIdx {
202+
BlockIdx(self.0 - rhs.0)
203+
}
204+
}
205+
206+
impl core::ops::SubAssign<BlockCount> for BlockIdx {
207+
fn sub_assign(&mut self, rhs: BlockCount) {
208+
self.0 -= rhs.0
209+
}
210+
}
211+
212+
/// The a number of blocks (or sectors).
213+
///
214+
/// Add this to a `BlockIdx` to get an actual address on disk.
215+
#[cfg_attr(feature = "defmt-log", derive(defmt::Format))]
216+
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
217+
pub struct BlockCount(pub u32);
218+
219+
impl core::ops::Add<BlockCount> for BlockCount {
220+
type Output = BlockCount;
221+
fn add(self, rhs: BlockCount) -> BlockCount {
222+
BlockCount(self.0 + rhs.0)
223+
}
224+
}
225+
226+
impl core::ops::AddAssign<BlockCount> for BlockCount {
227+
fn add_assign(&mut self, rhs: BlockCount) {
228+
self.0 += rhs.0
229+
}
230+
}
231+
232+
impl core::ops::Sub<BlockCount> for BlockCount {
233+
type Output = BlockCount;
234+
fn sub(self, rhs: BlockCount) -> BlockCount {
235+
BlockCount(self.0 - rhs.0)
236+
}
237+
}
238+
239+
impl core::ops::SubAssign<BlockCount> for BlockCount {
240+
fn sub_assign(&mut self, rhs: BlockCount) {
241+
self.0 -= rhs.0
242+
}
243+
}
244+
177245
impl BlockCount {
178246
/// How many blocks are required to hold this many bytes.
179247
///
@@ -200,6 +268,12 @@ impl BlockCount {
200268
}
201269
}
202270

271+
/// An iterator returned from `Block::range`.
272+
pub struct BlockIter {
273+
inclusive_end: BlockIdx,
274+
current: BlockIdx,
275+
}
276+
203277
impl BlockIter {
204278
/// Create a new `BlockIter`, from the given start block, through (and
205279
/// including) the given end block.

src/fat/mod.rs

-31
Original file line numberDiff line numberDiff line change
@@ -14,35 +14,6 @@ pub enum FatType {
1414
Fat32,
1515
}
1616

17-
pub(crate) struct BlockCache {
18-
block: Block,
19-
idx: Option<BlockIdx>,
20-
}
21-
impl BlockCache {
22-
pub fn empty() -> Self {
23-
BlockCache {
24-
block: Block::new(),
25-
idx: None,
26-
}
27-
}
28-
pub(crate) fn read<D>(
29-
&mut self,
30-
block_device: &D,
31-
block_idx: BlockIdx,
32-
) -> Result<&Block, Error<D::Error>>
33-
where
34-
D: BlockDevice,
35-
{
36-
if Some(block_idx) != self.idx {
37-
self.idx = Some(block_idx);
38-
block_device
39-
.read(core::slice::from_mut(&mut self.block), block_idx)
40-
.map_err(Error::DeviceError)?;
41-
}
42-
Ok(&self.block)
43-
}
44-
}
45-
4617
mod bpb;
4718
mod info;
4819
mod ondiskdirentry;
@@ -53,8 +24,6 @@ pub use info::{Fat16Info, Fat32Info, FatSpecificInfo, InfoSector};
5324
pub use ondiskdirentry::OnDiskDirEntry;
5425
pub use volume::{parse_volume, FatVolume, VolumeName};
5526

56-
use crate::{Block, BlockDevice, BlockIdx, Error};
57-
5827
// ****************************************************************************
5928
//
6029
// Unit Tests

0 commit comments

Comments
 (0)