diff --git a/src/array.rs b/src/array.rs index 5dfbb24..3848c77 100644 --- a/src/array.rs +++ b/src/array.rs @@ -4,6 +4,9 @@ pub unsafe trait Array { /// The array's element type type Item; #[doc(hidden)] + /// The smallest index type that indexes the array. + type Index: Index; + #[doc(hidden)] fn as_ptr(&self) -> *const Self::Item; #[doc(hidden)] fn as_mut_ptr(&mut self) -> *mut Self::Item; @@ -11,10 +14,29 @@ pub unsafe trait Array { fn capacity() -> usize; } +pub trait Index : PartialEq + Copy { + fn zero() -> Self; + fn to_usize(self) -> usize; + fn from(usize) -> Self; +} + +impl Index for u8 { + fn zero() -> Self { 0 } + fn to_usize(self) -> usize { self as usize } + fn from(ix: usize) -> Self { ix as u8 } +} + +impl Index for u16 { + fn zero() -> Self { 0 } + fn to_usize(self) -> usize { self as usize } + fn from(ix: usize) -> Self { ix as u16 } +} + macro_rules! fix_array_impl { - ($len:expr ) => ( + ($index_type:ty, $len:expr ) => ( unsafe impl Array for [T; $len] { type Item = T; + type Index = $index_type; #[inline(always)] fn as_ptr(&self) -> *const T { self as *const _ as *const _ } #[inline(always)] @@ -26,14 +48,15 @@ macro_rules! fix_array_impl { } macro_rules! fix_array_impl_recursive { - () => (); - ($len:expr, $($more:expr,)*) => ( - fix_array_impl!($len); - fix_array_impl_recursive!($($more,)*); + ($index_type:ty, ) => (); + ($index_type:ty, $len:expr, $($more:expr,)*) => ( + fix_array_impl!($index_type, $len); + fix_array_impl_recursive!($index_type, $($more,)*); ); } -fix_array_impl_recursive!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, +fix_array_impl_recursive!(u8, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 40, 48, 56, 64, 72, 96, 128, 160, 192, 224,); +fix_array_impl_recursive!(u16, 256, 384, 512, 768, 1024, 2048, 4096, 8192, 16384, 32768,); diff --git a/src/lib.rs b/src/lib.rs index cd3f2e9..a2ab38b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,6 +20,7 @@ mod array; mod misc; pub use array::Array; pub use misc::RangeArgument; +use array::Index; unsafe fn new_array() -> A { @@ -44,7 +45,7 @@ unsafe fn new_array() -> A { /// ArrayVec can be converted into a by value iterator. pub struct ArrayVec { xs: NoDrop, - len: u8, + len: A::Index, } impl Drop for ArrayVec { @@ -72,7 +73,7 @@ impl ArrayVec { /// ``` pub fn new() -> ArrayVec { unsafe { - ArrayVec { xs: NoDrop::new(new_array()), len: 0 } + ArrayVec { xs: NoDrop::new(new_array()), len: Index::zero() } } } @@ -87,7 +88,7 @@ impl ArrayVec { /// assert_eq!(array.len(), 2); /// ``` #[inline] - pub fn len(&self) -> usize { self.len as usize } + pub fn len(&self) -> usize { self.len.to_usize() } /// Return the capacity of the **ArrayVec**. /// @@ -122,11 +123,11 @@ impl ArrayVec { /// ``` pub fn push(&mut self, element: A::Item) -> Option { if self.len() < A::capacity() { + let len = self.len(); unsafe { - let len = self.len(); ptr::write(self.get_unchecked_mut(len), element); } - self.len += 1; + self.len = Index::from(len + 1); None } else { Some(element) @@ -149,11 +150,11 @@ impl ArrayVec { /// assert_eq!(array.pop(), None); /// ``` pub fn pop(&mut self) -> Option { - if self.len == 0 { + if self.len() == 0 { return None } unsafe { - self.len -= 1; + self.len = Index::from(self.len() - 1); let len = self.len(); Some(ptr::read(self.get_unchecked_mut(len))) } @@ -249,7 +250,7 @@ impl ArrayVec { unsafe { // set self.vec length's to start, to be safe in case Drain is leaked - self.len = start as u8; + self.len = Index::from(start); Drain { tail_start: end, tail_len: len - end, @@ -292,7 +293,7 @@ impl DerefMut for ArrayVec { /// ``` impl From for ArrayVec { fn from(array: A) -> Self { - ArrayVec { xs: NoDrop::new(array), len: A::capacity() as u8 } + ArrayVec { xs: NoDrop::new(array), len: Index::from(A::capacity()) } } } @@ -352,14 +353,14 @@ impl IntoIterator for ArrayVec { type Item = A::Item; type IntoIter = IntoIter; fn into_iter(self) -> IntoIter { - IntoIter { index: 0, v: self, } + IntoIter { index: Index::zero(), v: self, } } } /// By-value iterator for **ArrayVec**. pub struct IntoIter { - index: u8, + index: A::Index, v: ArrayVec, } @@ -372,16 +373,17 @@ impl Iterator for IntoIter { None } else { unsafe { - let ptr = self.v.get_unchecked_mut(self.index as usize); + let index = self.index.to_usize(); + let ptr = self.v.get_unchecked_mut(index); let elt = ptr::read(ptr); - self.index += 1; + self.index = Index::from(index + 1); Some(elt) } } } fn size_hint(&self) -> (usize, Option) { - let len = self.v.len() - self.index as usize; + let len = self.v.len() - self.index.to_usize(); (len, Some(len)) } } @@ -393,7 +395,7 @@ impl DoubleEndedIterator for IntoIter { None } else { unsafe { - self.v.len -= 1; + self.v.len = Index::from(self.v.len() - 1); let len = self.v.len(); let elt = ptr::read(self.v.get_unchecked_mut(len)); Some(elt) @@ -408,7 +410,7 @@ impl Drop for IntoIter { fn drop(&mut self) { // exhaust iterator and clear the vector while let Some(_) = self.next() { } - self.v.len = 0; + self.v.len = Index::zero(); } } @@ -480,7 +482,7 @@ impl<'a, A: Array> Drop for Drain<'a, A> let src = source_vec.as_ptr().offset(tail as isize); let dst = source_vec.as_mut_ptr().offset(start as isize); ptr::copy(src, dst, self.tail_len); - source_vec.len = (start + self.tail_len) as u8; + source_vec.len = Index::from(start + self.tail_len); } } } @@ -582,6 +584,17 @@ fn test_simple() { assert_eq!(sum_len, 8); } +#[test] +fn test_u16_index() { + const N: usize = 4096; + let mut vec: ArrayVec<[_; N]> = ArrayVec::new(); + for _ in 0..N { + assert!(vec.push(1u8).is_none()); + } + assert!(vec.push(0).is_some()); + assert_eq!(vec.len(), N); +} + #[test] fn test_iter() { let mut iter = ArrayVec::from([1, 2, 3]).into_iter();