diff --git a/CHANGELOG.md b/CHANGELOG.md index 03c4e1c7bc..6de5dab855 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Changed +- Changed the error type of these methods from `()` to `CapacityError`. + - `String::push_str` + - `String::push` + - `Vec::extend_from_slice` + - `Vec::from_slice` + - `Vec::resize_default` + - `Vec::resize` +- Renamed `FromUtf16Error::DecodeUtf16Error` to `FromUtf16Error::DecodeUtf16`. - Changed `stable_deref_trait` to a platform-dependent dependency. - Changed `SortedLinkedList::pop` return type from `Result` to `Option` to match `std::vec::pop`. - `Vec::capacity` is no longer a `const` function. diff --git a/src/lib.rs b/src/lib.rs index 20e4e9f813..f3ef35c670 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -233,3 +233,16 @@ mod ufmt; pub mod _export { pub use crate::string::format; } + +/// The error type for fallible [`Vec`] and [`String`] methods. +#[derive(Debug)] +#[non_exhaustive] +pub struct CapacityError; + +impl core::fmt::Display for CapacityError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.write_str("insufficient capacity") + } +} + +impl core::error::Error for CapacityError {} diff --git a/src/string/mod.rs b/src/string/mod.rs index d8d4ec2aa7..b820ebcae1 100644 --- a/src/string/mod.rs +++ b/src/string/mod.rs @@ -12,6 +12,7 @@ use core::{ }; use crate::vec::{OwnedVecStorage, Vec, VecInner, VecStorage, ViewVecStorage}; +use crate::CapacityError; mod drain; pub use drain::Drain; @@ -24,20 +25,28 @@ pub use drain::Drain; #[derive(Debug)] pub enum FromUtf16Error { /// The capacity of the `String` is too small for the given operation. - Capacity, + Capacity(CapacityError), /// Error decoding UTF-16. - DecodeUtf16Error(DecodeUtf16Error), + DecodeUtf16(DecodeUtf16Error), } impl fmt::Display for FromUtf16Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Self::Capacity => "insufficient capacity".fmt(f), - Self::DecodeUtf16Error(e) => write!(f, "invalid UTF-16: {}", e), + Self::Capacity(err) => write!(f, "{err}"), + Self::DecodeUtf16(err) => write!(f, "invalid UTF-16: {err}"), } } } +impl core::error::Error for FromUtf16Error {} + +impl From for FromUtf16Error { + fn from(e: CapacityError) -> Self { + Self::Capacity(e) + } +} + /// Base struct for [`String`] and [`StringView`], generic over the [`VecStorage`]. /// /// In most cases you should use [`String`] or [`StringView`] directly. Only use this @@ -164,10 +173,10 @@ impl String { for c in char::decode_utf16(v.iter().cloned()) { match c { Ok(c) => { - s.push(c).map_err(|_| FromUtf16Error::Capacity)?; + s.push(c).map_err(|_| CapacityError)?; } Err(err) => { - return Err(FromUtf16Error::DecodeUtf16Error(err)); + return Err(FromUtf16Error::DecodeUtf16(err)); } } } @@ -253,7 +262,7 @@ impl String { /// assert!(b.len() == 2); /// /// assert_eq!(&[b'a', b'b'], &b[..]); - /// # Ok::<(), ()>(()) + /// # Ok::<(), heapless::CapacityError>(()) /// ``` #[inline] pub fn into_bytes(self) -> Vec { @@ -360,7 +369,7 @@ impl + ?Sized> StringInner { /// /// let _s = s.as_str(); /// // s.push('c'); // <- cannot borrow `s` as mutable because it is also borrowed as immutable - /// # Ok::<(), ()>(()) + /// # Ok::<(), heapless::CapacityError>(()) /// ``` #[inline] pub fn as_str(&self) -> &str { @@ -379,7 +388,7 @@ impl + ?Sized> StringInner { /// let mut s: String<4> = String::try_from("ab")?; /// let s = s.as_mut_str(); /// s.make_ascii_uppercase(); - /// # Ok::<(), ()>(()) + /// # Ok::<(), heapless::CapacityError>(()) /// ``` #[inline] pub fn as_mut_str(&mut self) -> &mut str { @@ -411,7 +420,7 @@ impl + ?Sized> StringInner { /// vec.reverse(); /// } /// assert_eq!(s, "olleh"); - /// # Ok::<(), ()>(()) + /// # Ok::<(), heapless::CapacityError>(()) /// ``` pub unsafe fn as_mut_vec(&mut self) -> &mut VecInner { &mut self.vec @@ -433,11 +442,10 @@ impl + ?Sized> StringInner { /// assert_eq!("foobar", s); /// /// assert!(s.push_str("tender").is_err()); - /// # Ok::<(), ()>(()) + /// # Ok::<(), heapless::CapacityError>(()) /// ``` #[inline] - #[allow(clippy::result_unit_err)] - pub fn push_str(&mut self, string: &str) -> Result<(), ()> { + pub fn push_str(&mut self, string: &str) -> Result<(), CapacityError> { self.vec.extend_from_slice(string.as_bytes()) } @@ -476,13 +484,12 @@ impl + ?Sized> StringInner { /// assert!("abc123" == s.as_str()); /// /// assert_eq!("abc123", s); - /// # Ok::<(), ()>(()) + /// # Ok::<(), heapless::CapacityError>(()) /// ``` #[inline] - #[allow(clippy::result_unit_err)] - pub fn push(&mut self, c: char) -> Result<(), ()> { + pub fn push(&mut self, c: char) -> Result<(), CapacityError> { match c.len_utf8() { - 1 => self.vec.push(c as u8).map_err(|_| {}), + 1 => self.vec.push(c as u8).map_err(|_| CapacityError), _ => self .vec .extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes()), @@ -513,7 +520,7 @@ impl + ?Sized> StringInner { /// s.truncate(2); /// /// assert_eq!("he", s); - /// # Ok::<(), ()>(()) + /// # Ok::<(), heapless::CapacityError>(()) /// ``` #[inline] pub fn truncate(&mut self, new_len: usize) { @@ -541,7 +548,7 @@ impl + ?Sized> StringInner { /// assert_eq!(s.pop(), Some('f')); /// /// assert_eq!(s.pop(), None); - /// Ok::<(), ()>(()) + /// Ok::<(), heapless::CapacityError>(()) /// ``` pub fn pop(&mut self) -> Option { let ch = self.chars().next_back()?; @@ -615,7 +622,7 @@ impl + ?Sized> StringInner { /// assert!(s.is_empty()); /// assert_eq!(0, s.len()); /// assert_eq!(8, s.capacity()); - /// Ok::<(), ()>(()) + /// Ok::<(), heapless::CapacityError>(()) /// ``` #[inline] pub fn clear(&mut self) { @@ -630,7 +637,8 @@ impl Default for String { } impl<'a, const N: usize> TryFrom<&'a str> for String { - type Error = (); + type Error = CapacityError; + fn try_from(s: &'a str) -> Result { let mut new = Self::new(); new.push_str(s)?; @@ -639,7 +647,7 @@ impl<'a, const N: usize> TryFrom<&'a str> for String { } impl str::FromStr for String { - type Err = (); + type Err = CapacityError; fn from_str(s: &str) -> Result { let mut new = Self::new(); @@ -912,7 +920,7 @@ impl_try_from_num!(u64, 20); #[cfg(test)] mod tests { - use crate::{String, Vec}; + use crate::{CapacityError, String, Vec}; #[test] fn static_new() { @@ -980,7 +988,7 @@ mod tests { assert!(s.len() == 3); assert_eq!(s, "123"); - let _: () = String::<2>::try_from("123").unwrap_err(); + let _: CapacityError = String::<2>::try_from("123").unwrap_err(); } #[test] @@ -991,7 +999,7 @@ mod tests { assert!(s.len() == 3); assert_eq!(s, "123"); - let _: () = String::<2>::from_str("123").unwrap_err(); + let _: CapacityError = String::<2>::from_str("123").unwrap_err(); } #[test] diff --git a/src/ufmt.rs b/src/ufmt.rs index e8995b5ffa..8ad19780f4 100644 --- a/src/ufmt.rs +++ b/src/ufmt.rs @@ -1,18 +1,19 @@ use crate::{ string::StringInner, vec::{VecInner, VecStorage}, + CapacityError, }; use ufmt_write::uWrite; impl + ?Sized> uWrite for StringInner { - type Error = (); + type Error = CapacityError; fn write_str(&mut self, s: &str) -> Result<(), Self::Error> { self.push_str(s) } } impl + ?Sized> uWrite for VecInner { - type Error = (); + type Error = CapacityError; fn write_str(&mut self, s: &str) -> Result<(), Self::Error> { self.extend_from_slice(s.as_bytes()) } diff --git a/src/vec/mod.rs b/src/vec/mod.rs index edf9840a24..d8ff1843be 100644 --- a/src/vec/mod.rs +++ b/src/vec/mod.rs @@ -11,6 +11,8 @@ use core::{ slice, }; +use crate::CapacityError; + mod drain; mod storage { @@ -192,8 +194,7 @@ impl Vec { /// let mut v: Vec = Vec::new(); /// v.extend_from_slice(&[1, 2, 3]).unwrap(); /// ``` - #[allow(clippy::result_unit_err)] - pub fn from_slice(other: &[T]) -> Result + pub fn from_slice(other: &[T]) -> Result where T: Clone, { @@ -516,8 +517,7 @@ impl + ?Sized> VecInner { /// vec.extend_from_slice(&[2, 3, 4]).unwrap(); /// assert_eq!(*vec, [1, 2, 3, 4]); /// ``` - #[allow(clippy::result_unit_err)] - pub fn extend_from_slice(&mut self, other: &[T]) -> Result<(), ()> + pub fn extend_from_slice(&mut self, other: &[T]) -> Result<(), CapacityError> where T: Clone, { @@ -525,13 +525,13 @@ impl + ?Sized> VecInner { len: &mut usize, buf: &mut [MaybeUninit], other: &[T], - ) -> Result<(), ()> + ) -> Result<(), CapacityError> where T: Clone, { if *len + other.len() > buf.len() { // won't fit in the `Vec`; don't modify anything and return an error - Err(()) + Err(CapacityError) } else { for elem in other { unsafe { *buf.get_unchecked_mut(*len) = MaybeUninit::new(elem.clone()) } @@ -626,13 +626,12 @@ impl + ?Sized> VecInner { /// `new_len` is less than len, the Vec is simply truncated. /// /// See also [`resize_default`](Self::resize_default). - #[allow(clippy::result_unit_err)] - pub fn resize(&mut self, new_len: usize, value: T) -> Result<(), ()> + pub fn resize(&mut self, new_len: usize, value: T) -> Result<(), CapacityError> where T: Clone, { if new_len > self.capacity() { - return Err(()); + return Err(CapacityError); } if new_len > self.len { @@ -653,8 +652,7 @@ impl + ?Sized> VecInner { /// If `new_len` is less than `len`, the `Vec` is simply truncated. /// /// See also [`resize`](Self::resize). - #[allow(clippy::result_unit_err)] - pub fn resize_default(&mut self, new_len: usize) -> Result<(), ()> + pub fn resize_default(&mut self, new_len: usize) -> Result<(), CapacityError> where T: Clone + Default, { @@ -1211,7 +1209,7 @@ impl + ?Sized> Drop for VecInner { } impl<'a, T: Clone, const N: usize> TryFrom<&'a [T]> for Vec { - type Error = (); + type Error = CapacityError; fn try_from(slice: &'a [T]) -> Result { Self::from_slice(slice)