Skip to content

Commit 60ec5ea

Browse files
Remove need for generic array and typenum constants
This will also allow for more flexible `Storage` implementations that use `Vec<u8>` as a cache buffer and are not fixed to a single block size
1 parent 8ed1c5c commit 60ec5ea

File tree

9 files changed

+221
-137
lines changed

9 files changed

+221
-137
lines changed

Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,12 @@ repository.workspace = true
2222
[package.metadata.docs.rs]
2323
all-features = true
2424

25+
[[example]]
26+
name = "list"
27+
required-features = ["alloc"]
28+
2529
[dependencies]
2630
delog = "0.1.0"
27-
generic-array = "0.14"
2831
heapless = "0.7"
2932
littlefs2-core = { version = "0.1", path = "core" }
3033
littlefs2-sys = { version = "0.3.1", features = ["multiversion"] }

examples/list.rs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ fn main() {
3030
file,
3131
len: actual_len,
3232
};
33-
let mut alloc = Allocation::new();
33+
let mut alloc = Allocation::new(&s);
3434
let fs = Filesystem::mount(&mut alloc, &mut s).expect("failed to mount filesystem");
3535

3636
let available_blocks = fs.available_blocks().unwrap();
@@ -70,13 +70,21 @@ struct FileStorage {
7070
}
7171

7272
impl Storage for FileStorage {
73-
type CACHE_SIZE = U512;
74-
type LOOKAHEAD_SIZE = U1;
73+
type CACHE_BUFFER = Vec<u8>;
74+
type LOOKAHEAD_BUFFER = Vec<u8>;
7575

76-
const READ_SIZE: usize = 16;
77-
const WRITE_SIZE: usize = 512;
78-
const BLOCK_SIZE: usize = BLOCK_SIZE;
79-
const BLOCK_COUNT: usize = BLOCK_COUNT;
76+
fn read_size(&self) -> usize {
77+
16
78+
}
79+
fn write_size(&self) -> usize {
80+
512
81+
}
82+
fn block_size(&self) -> usize {
83+
BLOCK_SIZE
84+
}
85+
fn block_count(&self) -> usize {
86+
BLOCK_COUNT
87+
}
8088

8189
fn read(&mut self, off: usize, buf: &mut [u8]) -> Result<usize> {
8290
assert!(off + buf.len() <= BLOCK_SIZE * BLOCK_COUNT);

src/consts.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
#![allow(non_camel_case_types)]
22

3-
/// Re-export of `typenum::consts`.
4-
pub use generic_array::typenum::consts::*;
5-
63
pub const PATH_MAX: usize = littlefs2_core::PathBuf::MAX_SIZE;
74
pub const PATH_MAX_PLUS_ONE: usize = littlefs2_core::PathBuf::MAX_SIZE_PLUS_ONE;
85
pub const FILENAME_MAX_PLUS_ONE: u32 = 255 + 1;

src/driver.rs

Lines changed: 88 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,125 @@
11
//! The `Storage`, `Read`, `Write` and `Seek` driver.
22
#![allow(non_camel_case_types)]
33

4-
use generic_array::ArrayLength;
5-
64
use crate::io::Result;
75

6+
mod private {
7+
pub trait Sealed {}
8+
}
9+
10+
/// Safety: implemented only by `[u8; N]` and `Vec<u8>` if the alloc feature is enabled
11+
pub unsafe trait Buffer: private::Sealed {
12+
/// The maximum capacity of the buffer type.
13+
/// Can be [`usize::Max`]()
14+
const MAX_CAPACITY: usize;
15+
16+
/// Returns a buffer of bytes initialized and valid. If [`set_capacity`]() was called previously,
17+
/// its last call defines the minimum number of valid bytes
18+
fn as_ptr(&self) -> *const u8;
19+
/// Returns a buffer of bytes initialized and valid. If [`set_capacity`]() was called previously,
20+
/// its last call defines the minimum number of valid bytes
21+
fn as_mut_ptr(&mut self) -> *mut u8;
22+
23+
/// Can panic if `capacity` > `Self::MAX_CAPACITY`
24+
fn set_capacity(&mut self, capacity: usize);
25+
26+
/// Can panic if `capacity` > `Self::MAX_CAPACITY`
27+
fn with_capacity(capacity: usize) -> Self;
28+
}
29+
30+
impl<const N: usize> private::Sealed for [u8; N] {}
31+
32+
unsafe impl<const N: usize> Buffer for [u8; N] {
33+
const MAX_CAPACITY: usize = N;
34+
35+
fn as_ptr(&self) -> *const u8 {
36+
<[u8]>::as_ptr(self)
37+
}
38+
39+
fn as_mut_ptr(&mut self) -> *mut u8 {
40+
<[u8]>::as_mut_ptr(self)
41+
}
42+
43+
fn set_capacity(&mut self, _capacity: usize) {
44+
// noop, fixed capacity
45+
}
46+
fn with_capacity(capacity: usize) -> Self {
47+
assert!(capacity <= N);
48+
[0; N]
49+
}
50+
}
51+
52+
#[cfg(feature = "alloc")]
53+
impl private::Sealed for Vec<u8> {}
54+
55+
#[cfg(feature = "alloc")]
56+
unsafe impl<const N: usize> Buffer for alloc::Vec<u8> {
57+
const MAX_CAPACITY: usize = usize::MAX;
58+
const DEFAULT: Self;
59+
60+
fn as_ptr(&self) -> *const u8 {
61+
<[u8]>::as_ptr(self)
62+
}
63+
64+
fn as_mut_ptr(&mut self) -> *mut u8 {
65+
<[u8]>::as_mut_ptr(self)
66+
}
67+
68+
fn set_capacity(&mut self, capacity: usize) {
69+
self.resize(capacity, 0)
70+
}
71+
72+
fn with_capacity(capacity: usize) -> Self {
73+
let mut this = Vec::with_capacity(capacity);
74+
this.set_capacity(capacity);
75+
this
76+
}
77+
}
78+
879
/// Users of this library provide a "storage driver" by implementing this trait.
980
///
1081
/// The `write` method is assumed to be synchronized to storage immediately.
1182
/// littlefs provides more flexibility - if required, this could also be exposed.
1283
/// Do note that due to caches, files still must be synched. And unfortunately,
1384
/// this can't be automatically done in `drop`, since it needs mut refs to both
1485
/// filesystem and storage.
15-
///
16-
/// The `*_SIZE` types must be `generic_array::typenume::consts` such as `U256`.
17-
///
18-
/// Why? Currently, associated constants can not be used (as constants...) to define
19-
/// arrays. This "will be fixed" as part of const generics.
20-
/// Once that's done, we can get rid of `generic-array`s, and replace the
21-
/// `*_SIZE` types with `usize`s.
2286
pub trait Storage {
2387
// /// Error type for user-provided read/write/erase methods
2488
// type Error = usize;
2589

2690
/// Minimum size of block read in bytes. Not in superblock
27-
const READ_SIZE: usize;
91+
fn read_size(&self) -> usize;
2892

2993
/// Minimum size of block write in bytes. Not in superblock
30-
const WRITE_SIZE: usize;
94+
fn write_size(&self) -> usize;
3195

3296
/// Size of an erasable block in bytes, as unsigned typenum.
3397
/// Must be a multiple of both `READ_SIZE` and `WRITE_SIZE`.
3498
/// [At least 128](https://github.com/littlefs-project/littlefs/issues/264#issuecomment-519963153). Stored in superblock.
35-
const BLOCK_SIZE: usize;
99+
fn block_size(&self) -> usize;
36100

37101
/// Number of erasable blocks.
38102
/// Hence storage capacity is `BLOCK_COUNT * BLOCK_SIZE`
39-
const BLOCK_COUNT: usize;
103+
fn block_count(&self) -> usize;
40104

41105
/// Suggested values are 100-1000, higher is more performant but
42106
/// less wear-leveled. Default of -1 disables wear-leveling.
43107
/// Value zero is invalid, must be positive or -1.
44-
const BLOCK_CYCLES: isize = -1;
108+
fn block_cycles(&self) -> isize {
109+
-1
110+
}
45111

46112
/// littlefs uses a read cache, a write cache, and one cache per per file.
47-
/// Must be a multiple of `READ_SIZE` and `WRITE_SIZE`.
48-
/// Must be a factor of `BLOCK_SIZE`.
49-
type CACHE_SIZE: ArrayLength<u8>;
113+
type CACHE_BUFFER: Buffer;
114+
115+
/// Must be a multiple of `read_size` and `write_size`.
116+
/// Must be a factor of `block_size`.
117+
fn cache_size(&self) -> usize;
50118

119+
/// Lookahead buffer used by littlefs
120+
type LOOKAHEAD_BUFFER: Buffer;
51121
/// Size of the lookahead buffer used by littlefs, measured in multiples of 8 bytes.
52-
type LOOKAHEAD_SIZE: ArrayLength<u64>;
122+
fn lookahead_size(&self) -> usize;
53123

54124
///// Maximum length of a filename plus one. Stored in superblock.
55125
///// Should default to 255+1, but associated type defaults don't exist currently.

0 commit comments

Comments
 (0)