diff --git a/.gitignore b/.gitignore index e64a511ae8..fc026a5f29 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ **/*.rs.bk .#* Cargo.lock -target/ +target/ \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c42dd51ec..1b5ba2b827 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -59,6 +59,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Added `Deque::{swap, swap_unchecked, swap_remove_front, swap_remove_back}`. - Make `String::from_utf8_unchecked` const. - Implemented `PartialEq` and `Eq` for `Deque`. +- Implemented `TryFrom` for `Deque` from slice. - Added `alloc` feature to enable `alloc`-Vec interoperability. - Added `TryFrom` impl for `Vec`. - Added `TryFrom` impl for `alloc::vec::Vec`. diff --git a/src/deque.rs b/src/deque.rs index 63e0f51006..3f438fd49b 100644 --- a/src/deque.rs +++ b/src/deque.rs @@ -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,54 @@ impl PartialEq for Deque { impl Eq for Deque {} +impl TryFrom<[T; NS]> for Deque { + /// Converts a `[T; NS]` into a `Deque`. + /// + /// ``` + /// use heapless::Deque; + /// + /// let deq1 = Deque::::try_from([1, 2, 3]).unwrap(); + /// let mut deq2 = Deque::::new(); + /// deq2.push_back(1).unwrap(); + /// deq2.push_back(2).unwrap(); + /// deq2.push_back(3).unwrap(); + /// + /// assert_eq!(deq1, deq2); + /// ``` + type Error = CapacityError; + + fn try_from(value: [T; NS]) -> Result { + if NS > ND { + return Err(CapacityError); + } + + let mut deq = Self::default(); + let value = ManuallyDrop::new(value); + + if size_of::() != 0 { + // SAFETY: We already ensured that value fits in deq. + unsafe { + ptr::copy_nonoverlapping( + value.as_ptr(), + deq.buffer.buffer.as_mut_ptr().cast::(), + 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 +1588,26 @@ mod tests { assert_eq!(a, b); } + + #[test] + fn try_from_array() { + // Array is too big error. + assert!(matches!( + Deque::::try_from([1, 2, 3, 4]), + Err(CapacityError) + )); + + // Array is at limit. + assert!(Deque::::try_from([1, 2, 3]).unwrap().is_full()); + + // Array is under limit. + let deq1 = Deque::::try_from([1, 2, 3, 4]).unwrap(); + let mut deq2 = Deque::::new(); + deq2.push_back(1).unwrap(); + deq2.push_back(2).unwrap(); + deq2.push_back(3).unwrap(); + deq2.push_back(4).unwrap(); + + assert_eq!(deq1, deq2); + } }