diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e81c98f5..9deccc3d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,6 +30,11 @@ jobs: - name: Check run: | + cargo check --package littlefs2-core + cargo check --package littlefs2-core --features heapless07 + cargo check --package littlefs2-core --features heapless08 + cargo check --package littlefs2-core --features serde + cargo check --package littlefs2-core --all-features cargo check --workspace --all-targets cargo check --workspace --all-targets --all-features cargo check --workspace --all-targets --no-default-features diff --git a/CHANGELOG.md b/CHANGELOG.md index e41928e2..e46a3163 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Change the `set_attribute` function in `DynFilesystem` and `Filesystem` to accept an ID and a slice instead of an `Attribute`. - Add a buffer argument to the `attribute` function in `DynFilesystem` and `Filesystem` and return a slice of that buffer containing the read data. - Change the `Attribute` struct to store a slice with the read data and the total size of the attribute on the filesystem. +- Introduce `object_safe::Vec` trait and change `DynFile::read_to_end`, `DynFilesystem::read` and `DynFilesstem::read_chunk` to be generic over a `Vec` implementation to support multiple `heapless` versions (disabled by default). ### Removed diff --git a/core/Cargo.toml b/core/Cargo.toml index 544df429..25ab8496 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -10,8 +10,11 @@ repository.workspace = true [dependencies] bitflags = "2.6.0" -heapless = "0.7" +heapless07 = { package = "heapless", version = "0.7", optional = true } +heapless08 = { package = "heapless", version = "0.8", optional = true } serde = { version = "1", default-features = false, features = ["derive"], optional = true } [features] +heapless07 = ["dep:heapless07"] +heapless08 = ["dep:heapless08"] serde = ["dep:serde"] diff --git a/core/src/lib.rs b/core/src/lib.rs index f369f9c0..4d0ca373 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -13,7 +13,7 @@ mod path; pub use fs::{Attribute, DirEntry, FileOpenFlags, FileType, Metadata}; pub use io::{Error, OpenSeekFrom, Read, Result, Seek, SeekFrom, Write}; -pub use object_safe::{DirEntriesCallback, DynFile, DynFilesystem, FileCallback, Predicate}; +pub use object_safe::{DirEntriesCallback, DynFile, DynFilesystem, FileCallback, Predicate, Vec}; pub use path::{Ancestors, Iter, Path, PathBuf, PathError}; /// Creates a path from a string without a trailing null. diff --git a/core/src/object_safe.rs b/core/src/object_safe.rs index 42abfbb9..f5397f11 100644 --- a/core/src/object_safe.rs +++ b/core/src/object_safe.rs @@ -1,5 +1,3 @@ -use heapless::Vec; - use crate::{ fs::{Attribute, DirEntry, FileOpenFlags, Metadata}, io::{Error, OpenSeekFrom, Read, Result, Seek, Write}, @@ -15,6 +13,33 @@ pub type DirEntriesCallback<'a, R = ()> = pub type FileCallback<'a, R = ()> = &'a mut dyn FnMut(&dyn DynFile) -> Result; pub type Predicate<'a> = &'a dyn Fn(&DirEntry) -> bool; +pub trait Vec: Default + AsRef<[u8]> + AsMut<[u8]> { + fn resize_to_capacity(&mut self); + fn truncate(&mut self, n: usize); +} + +#[cfg(feature = "heapless07")] +impl Vec for heapless07::Vec { + fn resize_to_capacity(&mut self) { + self.resize_default(self.capacity()).unwrap(); + } + + fn truncate(&mut self, n: usize) { + heapless07::Vec::truncate(self, n) + } +} + +#[cfg(feature = "heapless08")] +impl Vec for heapless08::Vec { + fn resize_to_capacity(&mut self) { + self.resize_default(self.capacity()).unwrap(); + } + + fn truncate(&mut self, n: usize) { + heapless08::Vec::truncate(self, n) + } +} + /// Object-safe trait for files. /// /// The methods for opening files cannot be implemented in this trait. Use these methods instead: @@ -29,10 +54,10 @@ pub trait DynFile: Read + Seek + Write { } impl dyn DynFile + '_ { - pub fn read_to_end(&self, buf: &mut Vec) -> Result { - let had = buf.len(); - buf.resize_default(buf.capacity()).unwrap(); - let read = self.read(&mut buf[had..])?; + pub fn read_to_end(&self, buf: &mut V) -> Result { + let had = buf.as_ref().len(); + buf.resize_to_capacity(); + let read = self.read(&mut buf.as_mut()[had..])?; buf.truncate(had + read); Ok(read) } @@ -87,8 +112,8 @@ pub trait DynFilesystem { } impl dyn DynFilesystem + '_ { - pub fn read(&self, path: &Path) -> Result> { - let mut contents = Vec::new(); + pub fn read(&self, path: &Path) -> Result { + let mut contents = V::default(); self.open_file_and_then(path, &mut |file| { file.read_to_end(&mut contents)?; Ok(()) @@ -96,15 +121,12 @@ impl dyn DynFilesystem + '_ { Ok(contents) } - pub fn read_chunk( - &self, - path: &Path, - pos: OpenSeekFrom, - ) -> Result<(Vec, usize)> { - let mut contents = Vec::new(); + pub fn read_chunk(&self, path: &Path, pos: OpenSeekFrom) -> Result<(V, usize)> { + let mut contents = V::default(); + contents.resize_to_capacity(); let file_len = self.open_file_and_then(path, &mut |file| { file.seek(pos.into())?; - let read_n = file.read(&mut contents)?; + let read_n = file.read(contents.as_mut())?; contents.truncate(read_n); file.len() })?;