|
1 | 1 | //! The `Storage`, `Read`, `Write` and `Seek` driver. |
2 | 2 | #![allow(non_camel_case_types)] |
3 | 3 |
|
4 | | -use generic_array::ArrayLength; |
5 | | - |
6 | 4 | use crate::io::Result; |
7 | 5 |
|
| 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 | + |
8 | 79 | /// Users of this library provide a "storage driver" by implementing this trait. |
9 | 80 | /// |
10 | 81 | /// The `write` method is assumed to be synchronized to storage immediately. |
11 | 82 | /// littlefs provides more flexibility - if required, this could also be exposed. |
12 | 83 | /// Do note that due to caches, files still must be synched. And unfortunately, |
13 | 84 | /// this can't be automatically done in `drop`, since it needs mut refs to both |
14 | 85 | /// 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. |
22 | 86 | pub trait Storage { |
23 | 87 | // /// Error type for user-provided read/write/erase methods |
24 | 88 | // type Error = usize; |
25 | 89 |
|
26 | 90 | /// Minimum size of block read in bytes. Not in superblock |
27 | | - const READ_SIZE: usize; |
| 91 | + fn read_size(&self) -> usize; |
28 | 92 |
|
29 | 93 | /// Minimum size of block write in bytes. Not in superblock |
30 | | - const WRITE_SIZE: usize; |
| 94 | + fn write_size(&self) -> usize; |
31 | 95 |
|
32 | 96 | /// Size of an erasable block in bytes, as unsigned typenum. |
33 | 97 | /// Must be a multiple of both `READ_SIZE` and `WRITE_SIZE`. |
34 | 98 | /// [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; |
36 | 100 |
|
37 | 101 | /// Number of erasable blocks. |
38 | 102 | /// Hence storage capacity is `BLOCK_COUNT * BLOCK_SIZE` |
39 | | - const BLOCK_COUNT: usize; |
| 103 | + fn block_count(&self) -> usize; |
40 | 104 |
|
41 | 105 | /// Suggested values are 100-1000, higher is more performant but |
42 | 106 | /// less wear-leveled. Default of -1 disables wear-leveling. |
43 | 107 | /// Value zero is invalid, must be positive or -1. |
44 | | - const BLOCK_CYCLES: isize = -1; |
| 108 | + fn block_cycles(&self) -> isize { |
| 109 | + -1 |
| 110 | + } |
45 | 111 |
|
46 | 112 | /// 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; |
50 | 118 |
|
| 119 | + /// Lookahead buffer used by littlefs |
| 120 | + type LOOKAHEAD_BUFFER: Buffer; |
51 | 121 | /// 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; |
53 | 123 |
|
54 | 124 | ///// Maximum length of a filename plus one. Stored in superblock. |
55 | 125 | ///// Should default to 255+1, but associated type defaults don't exist currently. |
|
0 commit comments