Implements TryFrom for Deque from array

This commit is contained in:
William Hicklin 2024-12-13 16:19:44 +00:00
parent f974fc129c
commit 75dbe63466
2 changed files with 135 additions and 5 deletions

View File

@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Implement `Default` for `CapacityError`.
- Implement `defmt::Format` for `CapacityError`.
- Implement `TryFrom` for `Deque` from array.
## [v0.9.1] - 2025-08-19

View File

@ -33,15 +33,15 @@
//! }
//! ```
use crate::vec::{OwnedVecStorage, VecStorage, VecStorageInner, ViewVecStorage};
use crate::CapacityError;
use core::cmp::Ordering;
use core::fmt;
use core::iter::FusedIterator;
use core::marker::PhantomData;
use core::mem::MaybeUninit;
use core::mem::{ManuallyDrop, MaybeUninit};
use core::{ptr, slice};
use crate::vec::{OwnedVecStorage, VecStorage, VecStorageInner, ViewVecStorage};
/// Base struct for [`Deque`] and [`DequeView`], generic over the [`VecStorage`].
///
/// In most cases you should use [`Deque`] or [`DequeView`] directly. Only use this
@ -999,11 +999,55 @@ impl<T: PartialEq, const N: usize> PartialEq for Deque<T, N> {
impl<T: Eq, const N: usize> Eq for Deque<T, N> {}
impl<T, const NS: usize, const ND: usize> TryFrom<[T; NS]> for Deque<T, ND> {
/// Converts a `[T; NS]` into a `Deque<T, ND>`.
///
/// ```
/// use heapless::Deque;
///
/// let deq1 = Deque::<u8, 5>::try_from([1, 2, 3]).unwrap();
/// let mut deq2 = Deque::<u8, 5>::new();
/// deq2.push_back(1).unwrap();
/// deq2.push_back(2).unwrap();
/// deq2.push_back(3).unwrap();
///
/// assert_eq!(deq1, deq2);
/// ```
type Error = (CapacityError, [T; NS]);
/// Converts a `[T; NS]` array into a `Deque<T, ND>`.
///
/// Returns back the `value` if NS > ND.
fn try_from(value: [T; NS]) -> Result<Self, Self::Error> {
if NS > ND {
return Err((CapacityError, value));
}
let mut deq = Self::default();
let value = ManuallyDrop::new(value);
// SAFETY: We already ensured that value fits in deq.
unsafe {
ptr::copy_nonoverlapping(
value.as_ptr(),
deq.buffer.buffer.as_mut_ptr().cast::<T>(),
NS,
);
}
deq.front = 0;
deq.back = NS;
deq.full = NS == ND;
Ok(deq)
}
}
#[cfg(test)]
mod tests {
use static_assertions::assert_not_impl_any;
use super::Deque;
use crate::CapacityError;
use static_assertions::assert_not_impl_any;
// Ensure a `Deque` containing `!Send` values stays `!Send` itself.
assert_not_impl_any!(Deque<*const (), 4>: Send);
@ -1545,4 +1589,89 @@ mod tests {
assert_eq!(a, b);
}
#[test]
fn try_from_array() {
// Array is too big error.
assert!(matches!(
Deque::<u8, 3>::try_from([1, 2, 3, 4]),
Err((CapacityError, [1, 2, 3, 4]))
));
// Array is at limit.
let deq1 = Deque::<u8, 3>::try_from([1, 2, 3]).unwrap();
let mut deq2 = Deque::<u8, 3>::new();
deq2.push_back(1).unwrap();
deq2.push_back(2).unwrap();
deq2.push_back(3).unwrap();
assert!(deq1.is_full());
assert_eq!(deq1, deq2);
// Array is under limit.
let deq1 = Deque::<u8, 8>::try_from([1, 2, 3, 4]).unwrap();
let mut deq2 = Deque::<u8, 8>::new();
deq2.push_back(1).unwrap();
deq2.push_back(2).unwrap();
deq2.push_back(3).unwrap();
deq2.push_back(4).unwrap();
assert!(!deq1.is_full());
assert_eq!(deq1, deq2);
}
#[test]
fn try_from_array_with_zst() {
#[derive(Debug, PartialEq, Copy, Clone)]
struct ZeroSizedType;
// Test with ZST (zero-sized type)
let deq1 =
Deque::<ZeroSizedType, 5>::try_from([ZeroSizedType, ZeroSizedType, ZeroSizedType])
.unwrap();
let mut deq2 = Deque::<ZeroSizedType, 5>::new();
deq2.push_back(ZeroSizedType).unwrap();
deq2.push_back(ZeroSizedType).unwrap();
deq2.push_back(ZeroSizedType).unwrap();
assert_eq!(deq1, deq2);
assert_eq!(deq1.len(), 3);
}
#[test]
fn try_from_array_drop() {
droppable!();
// Array is over limit.
{
let _result = Deque::<Droppable, 2>::try_from([
Droppable::new(),
Droppable::new(),
Droppable::new(),
]);
}
assert_eq!(Droppable::count(), 0);
// Array is at limit.
{
let _result = Deque::<Droppable, 3>::try_from([
Droppable::new(),
Droppable::new(),
Droppable::new(),
]);
}
assert_eq!(Droppable::count(), 0);
// Array is under limit.
{
let _result = Deque::<Droppable, 4>::try_from([
Droppable::new(),
Droppable::new(),
Droppable::new(),
]);
}
assert_eq!(Droppable::count(), 0);
}
}