From e9f2e727b369f9439d95b34a02dbb682e17cee9f Mon Sep 17 00:00:00 2001 From: chrysn Date: Wed, 18 Sep 2024 17:19:55 +0200 Subject: [PATCH 1/5] doc: Intro text for error module --- src/error.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/error.rs b/src/error.rs index f4ea592..d38ba15 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,5 +1,9 @@ //! Common error handling components for the RIOT operating system //! +//! Most fallible operations in the wrappers produce a [NumericError], which is a slightly more +//! precise wrapper around a negative integer. The [NegativeErrorExt::negative_to_error()] trait +//! method can be used to produce such errors when creating wrappers around C functions. +//! //! ## Constants //! //! Several commonly used errors are provided as constants rather than requiring the use of From 021cfa9cd8720e8e9049fb317592df9e3c46c8f0 Mon Sep 17 00:00:00 2001 From: chrysn Date: Wed, 18 Sep 2024 17:28:30 +0200 Subject: [PATCH 2/5] error: Declare zero niche in errors to compiler --- src/error.rs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/error.rs b/src/error.rs index d38ba15..bec665e 100644 --- a/src/error.rs +++ b/src/error.rs @@ -12,6 +12,7 @@ //! the list). use core::convert::TryInto; +use core::num::NonZero; pub trait NegativeErrorExt { type Out; @@ -29,7 +30,9 @@ pub trait NegativeErrorExt { /// manually implemented newtype around isize that'd be used to represent the Result. #[derive(Debug, PartialEq, Eq)] pub struct NumericError { - number: isize, + // The NonZero doesn't cover the full desired range, but at least Result<(), NumericError> can + // be lean. + number: NonZero, } impl NumericError { @@ -59,12 +62,17 @@ impl NumericError { name > 0, "Error names are expected to be positive for conversion into negative error numbers." ); - NumericError { number: -name } + // Can be an `.unwrap()` once feature(const_trait_impl) is stabilized + let number = match NonZero::new(name) { + Some(n) => n, + _ => panic!("Error names are expected to be positive for conversion into negative error numbers.") + }; + NumericError { number } } /// Numeric value of the error pub const fn number(&self) -> isize { - self.number + self.number.get() } /// Convert the error into an [nb::Error] that is [nb::Error::WouldBlock] if the error is @@ -96,7 +104,11 @@ where Ok(self) } else { Err(NumericError { - number: self.try_into().unwrap_or(-(riot_sys::EOVERFLOW as isize)), + number: self + .try_into() + .ok() + .and_then(NonZero::new) + .unwrap_or(NonZero::new(-(riot_sys::EOVERFLOW as isize)).unwrap()), }) } } From 949aef57c124056f8980022e27837f14cafbf27a Mon Sep 17 00:00:00 2001 From: chrysn Date: Wed, 18 Sep 2024 17:30:26 +0200 Subject: [PATCH 3/5] error: Use constant internally --- src/error.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/error.rs b/src/error.rs index bec665e..70fdb07 100644 --- a/src/error.rs +++ b/src/error.rs @@ -103,13 +103,12 @@ where if self >= Self::zero() { Ok(self) } else { - Err(NumericError { - number: self - .try_into() - .ok() - .and_then(NonZero::new) - .unwrap_or(NonZero::new(-(riot_sys::EOVERFLOW as isize)).unwrap()), - }) + Err(self + .try_into() + .ok() + .and_then(NonZero::new) + .map(|number| NumericError { number }) + .unwrap_or(EOVERFLOW)) } } } From 5678a90b14a7274eafc6b5a11771a1befc1a3288 Mon Sep 17 00:00:00 2001 From: chrysn Date: Wed, 18 Sep 2024 18:29:07 +0200 Subject: [PATCH 4/5] dep: Bump riot-sys to make tiny_strerror available --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index af44fae..79299e1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ embedded-hal-0-2 = { package = "embedded-hal", version = "0.2.4", features = ["u embedded-hal = "1" switch-hal = "0.4.0" nb = "0.1.1" -riot-sys = "0.7.13" +riot-sys = "0.7.14" num-traits = { version = "0.2", default-features = false } mutex-trait = "0.2" From 88e3caeb710eb15e01184c3544440fe7cbed8168 Mon Sep 17 00:00:00 2001 From: chrysn Date: Wed, 18 Sep 2024 18:29:43 +0200 Subject: [PATCH 5/5] error: Implement Display and Error --- build.rs | 2 ++ src/error.rs | 33 ++++++++++++++++++++++++++------- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/build.rs b/build.rs index 52b4fde..4bbc8b1 100644 --- a/build.rs +++ b/build.rs @@ -104,6 +104,8 @@ fn main() { "sock_aux_local", "sock_tcp", "sock_udp", + "tiny_strerror", + "tiny_strerror_minimal", "udp", "vfs", "ws281x", diff --git a/src/error.rs b/src/error.rs index 70fdb07..65204c3 100644 --- a/src/error.rs +++ b/src/error.rs @@ -12,6 +12,7 @@ //! the list). use core::convert::TryInto; +use core::ffi::CStr; use core::num::NonZero; pub trait NegativeErrorExt { @@ -83,15 +84,33 @@ impl NumericError { } nb::Error::Other(self) } + + fn string(&self) -> Option<&'static CStr> { + #[cfg(all(riot_module_tiny_strerror, not(riot_module_tiny_strerror_minimal)))] + // unsafe: According to C API + // number cast: Disagreements on the numeric error size + // string cast: Disagreements on the signedness of char + return Some(unsafe { + CStr::from_ptr(riot_sys::tiny_strerror(-self.number.get() as _) as _) + }); + + #[cfg(not(all(riot_module_tiny_strerror, not(riot_module_tiny_strerror_minimal))))] + return None; + } +} + +impl core::fmt::Display for NumericError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + if let Some(s) = self.string() { + write!(f, "Error {} ({})", self.number(), s.to_str().unwrap())?; + } else { + write!(f, "Error {}", self.number())?; + } + Ok(()) + } } -// Would be nice, but there's no strerror -// -// impl core::fmt::Display for NumericError { -// fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { -// write!(f, "Error {} ({})", self.number(), ...) -// } -// } +impl core::error::Error for NumericError {} impl NegativeErrorExt for T where