|
33 | 33 | //! }
|
34 | 34 | //! ```
|
35 | 35 |
|
| 36 | +use crate::vec::{OwnedVecStorage, VecStorage, VecStorageInner, ViewVecStorage}; |
| 37 | +use crate::CapacityError; |
36 | 38 | use core::cmp::Ordering;
|
37 | 39 | use core::fmt;
|
38 | 40 | use core::iter::FusedIterator;
|
39 | 41 | use core::marker::PhantomData;
|
40 |
| -use core::mem::MaybeUninit; |
| 42 | +use core::mem::{ManuallyDrop, MaybeUninit}; |
41 | 43 | use core::{ptr, slice};
|
42 | 44 |
|
43 |
| -use crate::vec::{OwnedVecStorage, VecStorage, VecStorageInner, ViewVecStorage}; |
44 |
| - |
45 | 45 | /// Base struct for [`Deque`] and [`DequeView`], generic over the [`VecStorage`].
|
46 | 46 | ///
|
47 | 47 | /// 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> {
|
999 | 999 |
|
1000 | 1000 | impl<T: Eq, const N: usize> Eq for Deque<T, N> {}
|
1001 | 1001 |
|
| 1002 | +impl<T, const NS: usize, const ND: usize> TryFrom<[T; NS]> for Deque<T, ND> { |
| 1003 | + /// Converts a `[T; NS]` into a `Deque<T, ND>`. |
| 1004 | + /// |
| 1005 | + /// ``` |
| 1006 | + /// use heapless::Deque; |
| 1007 | + /// |
| 1008 | + /// let deq1 = Deque::<u8, 5>::try_from([1, 2, 3]).unwrap(); |
| 1009 | + /// let mut deq2 = Deque::<u8, 5>::new(); |
| 1010 | + /// deq2.push_back(1).unwrap(); |
| 1011 | + /// deq2.push_back(2).unwrap(); |
| 1012 | + /// deq2.push_back(3).unwrap(); |
| 1013 | + /// |
| 1014 | + /// assert_eq!(deq1, deq2); |
| 1015 | + /// ``` |
| 1016 | + type Error = (CapacityError, [T; NS]); |
| 1017 | + |
| 1018 | + /// Converts a `[T; NS]` array into a `Deque<T, ND>`. |
| 1019 | + /// |
| 1020 | + /// Returns back the `value` if NS > ND. |
| 1021 | + fn try_from(value: [T; NS]) -> Result<Self, Self::Error> { |
| 1022 | + if NS > ND { |
| 1023 | + return Err((CapacityError, value)); |
| 1024 | + } |
| 1025 | + |
| 1026 | + let mut deq = Self::default(); |
| 1027 | + let value = ManuallyDrop::new(value); |
| 1028 | + |
| 1029 | + // SAFETY: We already ensured that value fits in deq. |
| 1030 | + unsafe { |
| 1031 | + ptr::copy_nonoverlapping( |
| 1032 | + value.as_ptr(), |
| 1033 | + deq.buffer.buffer.as_mut_ptr().cast::<T>(), |
| 1034 | + NS, |
| 1035 | + ); |
| 1036 | + } |
| 1037 | + |
| 1038 | + deq.front = 0; |
| 1039 | + deq.back = NS; |
| 1040 | + deq.full = NS == ND; |
| 1041 | + |
| 1042 | + Ok(deq) |
| 1043 | + } |
| 1044 | +} |
| 1045 | + |
1002 | 1046 | #[cfg(test)]
|
1003 | 1047 | mod tests {
|
1004 |
| - use static_assertions::assert_not_impl_any; |
1005 |
| - |
1006 | 1048 | use super::Deque;
|
| 1049 | + use crate::CapacityError; |
| 1050 | + use static_assertions::assert_not_impl_any; |
1007 | 1051 |
|
1008 | 1052 | // Ensure a `Deque` containing `!Send` values stays `!Send` itself.
|
1009 | 1053 | assert_not_impl_any!(Deque<*const (), 4>: Send);
|
@@ -1545,4 +1589,89 @@ mod tests {
|
1545 | 1589 |
|
1546 | 1590 | assert_eq!(a, b);
|
1547 | 1591 | }
|
| 1592 | + |
| 1593 | + #[test] |
| 1594 | + fn try_from_array() { |
| 1595 | + // Array is too big error. |
| 1596 | + assert!(matches!( |
| 1597 | + Deque::<u8, 3>::try_from([1, 2, 3, 4]), |
| 1598 | + Err((CapacityError, [1, 2, 3, 4])) |
| 1599 | + )); |
| 1600 | + |
| 1601 | + // Array is at limit. |
| 1602 | + let deq1 = Deque::<u8, 3>::try_from([1, 2, 3]).unwrap(); |
| 1603 | + let mut deq2 = Deque::<u8, 3>::new(); |
| 1604 | + deq2.push_back(1).unwrap(); |
| 1605 | + deq2.push_back(2).unwrap(); |
| 1606 | + deq2.push_back(3).unwrap(); |
| 1607 | + assert!(deq1.is_full()); |
| 1608 | + assert_eq!(deq1, deq2); |
| 1609 | + |
| 1610 | + // Array is under limit. |
| 1611 | + let deq1 = Deque::<u8, 8>::try_from([1, 2, 3, 4]).unwrap(); |
| 1612 | + let mut deq2 = Deque::<u8, 8>::new(); |
| 1613 | + deq2.push_back(1).unwrap(); |
| 1614 | + deq2.push_back(2).unwrap(); |
| 1615 | + deq2.push_back(3).unwrap(); |
| 1616 | + deq2.push_back(4).unwrap(); |
| 1617 | + |
| 1618 | + assert!(!deq1.is_full()); |
| 1619 | + assert_eq!(deq1, deq2); |
| 1620 | + } |
| 1621 | + |
| 1622 | + #[test] |
| 1623 | + fn try_from_array_with_zst() { |
| 1624 | + #[derive(Debug, PartialEq, Copy, Clone)] |
| 1625 | + struct ZeroSizedType; |
| 1626 | + |
| 1627 | + // Test with ZST (zero-sized type) |
| 1628 | + let deq1 = |
| 1629 | + Deque::<ZeroSizedType, 5>::try_from([ZeroSizedType, ZeroSizedType, ZeroSizedType]) |
| 1630 | + .unwrap(); |
| 1631 | + let mut deq2 = Deque::<ZeroSizedType, 5>::new(); |
| 1632 | + deq2.push_back(ZeroSizedType).unwrap(); |
| 1633 | + deq2.push_back(ZeroSizedType).unwrap(); |
| 1634 | + deq2.push_back(ZeroSizedType).unwrap(); |
| 1635 | + |
| 1636 | + assert_eq!(deq1, deq2); |
| 1637 | + assert_eq!(deq1.len(), 3); |
| 1638 | + } |
| 1639 | + |
| 1640 | + #[test] |
| 1641 | + fn try_from_array_drop() { |
| 1642 | + droppable!(); |
| 1643 | + |
| 1644 | + // Array is over limit. |
| 1645 | + { |
| 1646 | + let _result = Deque::<Droppable, 2>::try_from([ |
| 1647 | + Droppable::new(), |
| 1648 | + Droppable::new(), |
| 1649 | + Droppable::new(), |
| 1650 | + ]); |
| 1651 | + } |
| 1652 | + |
| 1653 | + assert_eq!(Droppable::count(), 0); |
| 1654 | + |
| 1655 | + // Array is at limit. |
| 1656 | + { |
| 1657 | + let _result = Deque::<Droppable, 3>::try_from([ |
| 1658 | + Droppable::new(), |
| 1659 | + Droppable::new(), |
| 1660 | + Droppable::new(), |
| 1661 | + ]); |
| 1662 | + } |
| 1663 | + |
| 1664 | + assert_eq!(Droppable::count(), 0); |
| 1665 | + |
| 1666 | + // Array is under limit. |
| 1667 | + { |
| 1668 | + let _result = Deque::<Droppable, 4>::try_from([ |
| 1669 | + Droppable::new(), |
| 1670 | + Droppable::new(), |
| 1671 | + Droppable::new(), |
| 1672 | + ]); |
| 1673 | + } |
| 1674 | + |
| 1675 | + assert_eq!(Droppable::count(), 0); |
| 1676 | + } |
1548 | 1677 | }
|
0 commit comments