diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a5e92e..3a2f982 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ The format is based on [Keep a Changelog] and this project adheres to [Semantic - `File` now implements the `embedded-io` `Read`, `Write` and `Seek` traits. - New `iterate_dir_lfn` method on `VolumeManager` and `Directory` - provides decoded Long File Names as `Option<&str>` +- Implement `core::error::Error` for all error types (behind crate feature `core-error` as this raises the MSRV to 1.81) ### Removed diff --git a/Cargo.toml b/Cargo.toml index 49b1317..74e4e21 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,3 +33,4 @@ sha2 = "0.10" default = ["log"] defmt-log = ["dep:defmt"] log = ["dep:log"] +core-error = [] diff --git a/src/lib.rs b/src/lib.rs index c6af4e9..c7e33a2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -68,6 +68,8 @@ //! * `defmt-log`: By turning off the default features and enabling the //! `defmt-log` feature you can configure this crate to log messages over defmt //! instead. +//! * `core-error`: Enables implementations of `core::error::Error` for all error +//! types. This raises the Minimum Supported Rust Version to 1.81. //! //! You cannot enable both the `log` feature and the `defmt-log` feature. @@ -272,6 +274,51 @@ where } } +impl<E> core::fmt::Display for Error<E> +where + E: core::fmt::Debug + core::fmt::Display, +{ + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + match self { + Error::DeviceError(e) => write!(f, "error from underlying block device: {e}"), + Error::FormatError(s) => write!(f, "filesystem is badly formatted: {s}"), + Error::NoSuchVolume => write!(f, "no such volume"), + Error::FilenameError(_) => write!(f, "bad filename"), + Error::TooManyOpenVolumes => write!(f, "too many open volumes"), + Error::TooManyOpenDirs => write!(f, "too many open directories"), + Error::TooManyOpenFiles => write!(f, "too many open files"), + Error::BadHandle => write!(f, "bad handle"), + Error::NotFound => write!(f, "file or directory does not exist"), + Error::FileAlreadyOpen => write!(f, "file already open"), + Error::DirAlreadyOpen => write!(f, "directory already open"), + Error::OpenedDirAsFile => write!(f, "cannot open directory as file"), + Error::OpenedFileAsDir => write!(f, "cannot open file as directory"), + Error::DeleteDirAsFile => write!(f, "cannot delete directory as file"), + Error::VolumeStillInUse => write!(f, "volume is still in use"), + Error::VolumeAlreadyOpen => write!(f, "cannot open volume twice"), + Error::Unsupported => write!(f, "unsupported operation"), + Error::EndOfFile => write!(f, "end of file"), + Error::BadCluster => write!(f, "bad cluster"), + Error::ConversionError => write!(f, "type conversion failed"), + Error::NotEnoughSpace => write!(f, "not enough space on device"), + Error::AllocationError => write!(f, "cluster not properly allocated"), + Error::UnterminatedFatChain => write!(f, "FAT chain unterminated"), + Error::ReadOnly => write!(f, "file is read-only"), + Error::FileAlreadyExists => write!(f, "file already exists"), + Error::BadBlockSize(size) => { + write!(f, "bad block size: {size} (only 512 byte blocks supported)") + } + Error::InvalidOffset => write!(f, "invalid seek offset"), + Error::DiskFull => write!(f, "disk full"), + Error::DirAlreadyExists => write!(f, "directory already exists"), + Error::LockError => write!(f, "already locked"), + } + } +} + +#[cfg(feature = "core-error")] +impl<E> core::error::Error for Error<E> where E: core::fmt::Debug + core::fmt::Display {} + /// A handle to a volume. /// /// A volume is a partition with a filesystem within it. diff --git a/src/sdcard/mod.rs b/src/sdcard/mod.rs index 553791f..c27fa0e 100644 --- a/src/sdcard/mod.rs +++ b/src/sdcard/mod.rs @@ -624,6 +624,33 @@ pub enum Error { GpioError, } +impl core::fmt::Display for Error { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + match self { + Error::Transport => write!(f, "error from SPI peripheral"), + Error::CantEnableCRC => write!(f, "failed to enable CRC checking"), + Error::TimeoutReadBuffer => write!(f, "timeout when reading data"), + Error::TimeoutWaitNotBusy => write!(f, "timeout when waiting for card to not be busy"), + Error::TimeoutCommand(command) => write!(f, "timeout when executing command {command}"), + Error::TimeoutACommand(command) => write!( + f, + "timeout when executing application-specific command {command}" + ), + Error::Cmd58Error => write!(f, "bad response from command 58"), + Error::RegisterReadError => write!(f, "failed to read Card Specific Data register"), + Error::CrcError(_, _) => write!(f, "CRC mismatch"), + Error::ReadError => write!(f, "read error"), + Error::WriteError => write!(f, "write error"), + Error::BadState => write!(f, "cannot perform operation with card in thiis state"), + Error::CardNotFound => write!(f, "card not found"), + Error::GpioError => write!(f, "cannot set GPIO pin"), + } + } +} + +#[cfg(feature = "core-error")] +impl core::error::Error for Error {} + /// The different types of card we support. #[cfg_attr(feature = "defmt-log", derive(defmt::Format))] #[derive(Debug, Copy, Clone, PartialEq, Eq)]