diff --git a/Cargo.toml b/Cargo.toml index 13917b03..442e74f1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,11 @@ version = "1.2.0" optional = true default-features = false +[dependencies.diesel] +version = "2.3.4" +optional = true +default-features = false + [dependencies.serde] version = "1.0" optional = true diff --git a/src/array_string.rs b/src/array_string.rs index 227e01db..79a372ba 100644 --- a/src/array_string.rs +++ b/src/array_string.rs @@ -311,10 +311,7 @@ impl ArrayString /// assert_eq!(s.pop(), None); /// ``` pub fn pop(&mut self) -> Option { - let ch = match self.chars().rev().next() { - Some(ch) => ch, - None => return None, - }; + let ch = self.chars().next_back()?; let new_len = self.len() - ch.len_utf8(); unsafe { self.set_len(new_len); @@ -396,6 +393,7 @@ impl ArrayString /// Set the strings’s length. /// + /// # Safety /// This function is `unsafe` because it changes the notion of the /// number of “valid” bytes in the string. Use with care. /// @@ -408,21 +406,25 @@ impl ArrayString } /// Return a string slice of the whole `ArrayString`. + #[inline] pub fn as_str(&self) -> &str { self } /// Return a mutable string slice of the whole `ArrayString`. + #[inline] pub fn as_mut_str(&mut self) -> &mut str { self } /// Return a raw pointer to the string's buffer. + #[inline] pub fn as_ptr(&self) -> *const u8 { self.xs.as_ptr() as *const u8 } /// Return a raw mutable pointer to the string's buffer. + #[inline] pub fn as_mut_ptr(&mut self) -> *mut u8 { self.xs.as_mut_ptr() as *mut u8 } @@ -473,6 +475,20 @@ impl PartialEq> for str } } +impl PartialEq<&str> for ArrayString +{ + fn eq(&self, rhs: &&str) -> bool { + self == *rhs + } +} + +impl PartialEq> for &str +{ + fn eq(&self, rhs: &ArrayString) -> bool { + *self == rhs + } +} + impl Eq for ArrayString { } @@ -527,6 +543,7 @@ impl fmt::Write for ArrayString } } +#[expect(clippy::non_canonical_clone_impl)] impl Clone for ArrayString { fn clone(&self) -> ArrayString { @@ -542,40 +559,42 @@ impl Clone for ArrayString impl PartialOrd for ArrayString { fn partial_cmp(&self, rhs: &Self) -> Option { - (**self).partial_cmp(&**rhs) + Some(self.cmp(rhs)) } - fn lt(&self, rhs: &Self) -> bool { **self < **rhs } - fn le(&self, rhs: &Self) -> bool { **self <= **rhs } - fn gt(&self, rhs: &Self) -> bool { **self > **rhs } - fn ge(&self, rhs: &Self) -> bool { **self >= **rhs } } impl PartialOrd for ArrayString { fn partial_cmp(&self, rhs: &str) -> Option { - (**self).partial_cmp(rhs) + self.as_str().partial_cmp(rhs) } - fn lt(&self, rhs: &str) -> bool { &**self < rhs } - fn le(&self, rhs: &str) -> bool { &**self <= rhs } - fn gt(&self, rhs: &str) -> bool { &**self > rhs } - fn ge(&self, rhs: &str) -> bool { &**self >= rhs } } impl PartialOrd> for str { fn partial_cmp(&self, rhs: &ArrayString) -> Option { - self.partial_cmp(&**rhs) + self.partial_cmp(rhs.as_str()) + } +} + +impl PartialOrd<&str> for ArrayString +{ + fn partial_cmp(&self, rhs: &&str) -> Option { + self.as_str().partial_cmp(*rhs) + } +} + +impl PartialOrd> for &str +{ + fn partial_cmp(&self, rhs: &ArrayString) -> Option { + (*self).partial_cmp(rhs.as_str()) } - fn lt(&self, rhs: &ArrayString) -> bool { self < &**rhs } - fn le(&self, rhs: &ArrayString) -> bool { self <= &**rhs } - fn gt(&self, rhs: &ArrayString) -> bool { self > &**rhs } - fn ge(&self, rhs: &ArrayString) -> bool { self >= &**rhs } } impl Ord for ArrayString { fn cmp(&self, rhs: &Self) -> cmp::Ordering { - (**self).cmp(&**rhs) + self.as_str().cmp(rhs.as_str()) } } @@ -595,7 +614,7 @@ impl Serialize for ArrayString fn serialize(&self, serializer: S) -> Result where S: Serializer { - serializer.serialize_str(&*self) + serializer.serialize_str(self) } } @@ -641,7 +660,7 @@ impl<'de, const CAP: usize> Deserialize<'de> for ArrayString /// Requires crate feature `"borsh"` impl borsh::BorshSerialize for ArrayString { fn serialize(&self, writer: &mut W) -> borsh::io::Result<()> { - ::serialize(&*self, writer) + ::serialize(self, writer) } } @@ -661,7 +680,7 @@ impl borsh::BorshDeserialize for ArrayString { let buf = &mut buf[..len]; reader.read_exact(buf)?; - let s = str::from_utf8(&buf).map_err(|err| { + let s = str::from_utf8(buf).map_err(|err| { borsh::io::Error::new(borsh::io::ErrorKind::InvalidData, err.to_string()) })?; Ok(Self::from(s).unwrap()) @@ -686,7 +705,7 @@ impl<'a, const CAP: usize> TryFrom> for ArrayString fn try_from(f: fmt::Arguments<'a>) -> Result { use fmt::Write; let mut v = Self::new(); - v.write_fmt(f).map_err(|e| CapacityError::new(e))?; + v.write_fmt(f).map_err(CapacityError::new)?; Ok(v) } } @@ -714,3 +733,44 @@ impl zeroize::Zeroize for ArrayString { self.xs.zeroize(); } } + +#[cfg(feature = "diesel")] +mod diesel { + use diesel::backend::Backend; + use diesel::deserialize; + use diesel::deserialize::FromSql; + use diesel::sql_types::Text; + use diesel::serialize; + use diesel::serialize::{Output, ToSql}; + + use super::ArrayString; + + /// Requires crate feature `"diesel"` + impl FromSql for ArrayString + where + DB: Backend, + *const str: FromSql + { + #[inline] + fn from_sql(bytes: DB::RawValue<'_>) -> deserialize::Result { + use std::convert::TryInto as _; + + let str_ptr = <*const str as FromSql>::from_sql(bytes)?; + // Diesel guarantees the pointer impl will be non-null and pointing to valid UTF-8 + let string = unsafe { &*str_ptr }; + Ok(string.try_into()?) + } + } + + /// Requires crate feature `"diesel"` + impl ToSql for ArrayString + where + DB: Backend, + str: ToSql + { + #[inline] + fn to_sql<'a>(&'a self, out: &mut Output<'a, '_, DB>) -> serialize::Result { + self.as_str().to_sql(out) + } + } +} diff --git a/src/arrayvec.rs b/src/arrayvec.rs index e5ea52dc..37d44538 100644 --- a/src/arrayvec.rs +++ b/src/arrayvec.rs @@ -208,6 +208,7 @@ impl ArrayVec { /// Push `element` to the end of the vector without checking the capacity. /// + /// # Safety /// It is up to the caller to ensure the capacity of the vector is /// sufficiently large. /// @@ -572,6 +573,7 @@ impl ArrayVec { /// Set the vector’s length without dropping or moving out elements /// + /// # Safety /// This method is `unsafe` because it changes the notion of the /// number of “valid” elements in the vector. Use with care. /// @@ -637,7 +639,7 @@ impl ArrayVec { /// assert_eq!(&v1[..], &[3]); /// assert_eq!(&v2[..], &[1, 2]); /// ``` - pub fn drain(&mut self, range: R) -> Drain + pub fn drain(&mut self, range: R) -> Drain<'_, T, CAP> where R: RangeBounds { // Memory safety @@ -664,7 +666,7 @@ impl ArrayVec { self.drain_range(start, end) } - fn drain_range(&mut self, start: usize, end: usize) -> Drain + fn drain_range(&mut self, start: usize, end: usize) -> Drain<'_, T, CAP> { let len = self.len(); @@ -699,13 +701,12 @@ impl ArrayVec { /// Return the inner fixed size array. /// - /// Safety: + /// # Safety /// This operation is safe if and only if length equals capacity. pub unsafe fn into_inner_unchecked(self) -> [T; CAP] { debug_assert_eq!(self.len(), self.capacity()); let self_ = ManuallyDrop::new(self); - let array = ptr::read(self_.as_ptr() as *const [T; CAP]); - array + ptr::read(self_.as_ptr() as *const [T; CAP]) } /// Returns the ArrayVec, replacing the original with a new empty ArrayVec. @@ -718,7 +719,7 @@ impl ArrayVec { /// assert!(v.is_empty()); /// ``` pub fn take(&mut self) -> Self { - mem::replace(self, Self::new()) + mem::take(self) } /// Return a slice containing all elements of the vector. @@ -1048,7 +1049,7 @@ impl<'a, T: 'a, const CAP: usize> Drop for Drain<'a, T, CAP> { // len is currently 0 so panicking while dropping will not cause a double drop. // exhaust self first - while let Some(_) = self.next() { } + for _ in self.by_ref() {} if self.tail_len > 0 { unsafe { @@ -1335,7 +1336,7 @@ impl<'de, T: Deserialize<'de>, const CAP: usize> Deserialize<'de> for ArrayVec::new(); while let Some(value) = seq.next_element()? { - if let Err(_) = values.try_push(value) { + if values.try_push(value).is_err() { return Err(SA::Error::invalid_length(CAP + 1, &self)); } } @@ -1370,7 +1371,7 @@ where let len = ::deserialize_reader(reader)?; for _ in 0..len { let elem = ::deserialize_reader(reader)?; - if let Err(_) = values.try_push(elem) { + if values.try_push(elem).is_err() { return Err(borsh::io::Error::new( borsh::io::ErrorKind::InvalidData, format!("Expected an array with no more than {} items", CAP), diff --git a/src/errors.rs b/src/errors.rs index 7ca3ebc4..8f3ea7ce 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -14,7 +14,7 @@ impl CapacityError { /// Create a new `CapacityError` from `element`. pub const fn new(element: T) -> CapacityError { CapacityError { - element: element, + element, } } @@ -29,7 +29,7 @@ impl CapacityError { } } -const CAPERROR: &'static str = "insufficient capacity"; +const CAPERROR: &str = "insufficient capacity"; #[cfg(feature="std")] /// Requires `features="std"`. @@ -43,7 +43,7 @@ impl fmt::Display for CapacityError { impl fmt::Debug for CapacityError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}: {}", "CapacityError", CAPERROR) + write!(f, "CapacityError: {}", CAPERROR) } } diff --git a/tests/tests.rs b/tests/tests.rs index ff779baa..5585db76 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -557,7 +557,7 @@ fn test_string() { #[test] fn test_string_from() { let text = "hello world"; - // Test `from` constructor + // Test `from` constructor let u = ArrayString::<11>::from(text).unwrap(); assert_eq!(&u, text); assert_eq!(u.len(), text.len()); @@ -774,3 +774,20 @@ fn test_arraystring_zero_filled_has_some_sanity_checks() { assert_eq!(string.as_str(), "\0\0\0\0"); assert_eq!(string.len(), 4); } + +#[test] +fn test_arraystring_ord() { + let a_arraystring: ArrayString<1> = ArrayString::from("a").unwrap(); + let b_arraystring: ArrayString<1> = ArrayString::from("b").unwrap(); + + let a_str = "a"; + let b_str = "b"; + + assert!(a_arraystring < b_arraystring); + assert!(b_arraystring > a_arraystring); + assert!(a_arraystring < b_str); + assert!(a_str < b_arraystring); + assert!(b_arraystring > a_str); + assert!(b_str > a_arraystring); +} +