#![allow(clippy::comparison_chain, clippy::missing_safety_doc)]
use std::alloc::*;
use std::borrow::*;
use std::cmp::*;
use std::hash::*;
use std::iter::FromIterator;
use std::marker::PhantomData;
use std::ops::Bound;
use std::ops::{Deref, DerefMut, RangeBounds};
use std::ptr::NonNull;
use std::slice::IterMut;
use std::{fmt, io, mem, ptr, slice};
use impl_details::*;
#[cfg(not(feature = "gecko-ffi"))]
mod impl_details {
pub type SizeType = usize;
pub const MAX_CAP: usize = !0;
#[inline(always)]
pub fn assert_size(x: usize) -> SizeType {
x
}
}
#[cfg(feature = "gecko-ffi")]
mod impl_details {
pub type SizeType = u32;
pub const MAX_CAP: usize = i32::max_value() as usize;
#[cfg(target_endian = "little")]
pub fn pack_capacity(cap: SizeType) -> SizeType {
cap as SizeType
}
#[cfg(target_endian = "little")]
pub fn unpack_capacity(cap: SizeType) -> usize {
(cap as usize) & !(1 << 31)
}
#[cfg(target_endian = "little")]
pub fn is_auto(cap: SizeType) -> bool {
(cap & (1 << 31)) != 0
}
#[cfg(target_endian = "big")]
pub fn pack_capacity(cap: SizeType) -> SizeType {
(cap as SizeType) << 1
}
#[cfg(target_endian = "big")]
pub fn unpack_capacity(cap: SizeType) -> usize {
(cap >> 1) as usize
}
#[cfg(target_endian = "big")]
pub fn is_auto(cap: SizeType) -> bool {
(cap & 1) != 0
}
#[inline]
pub fn assert_size(x: usize) -> SizeType {
if x > MAX_CAP as usize {
panic!("nsTArray size may not exceed the capacity of a 32-bit sized int");
}
x as SizeType
}
}
#[cfg_attr(all(feature = "gecko-ffi", any(test, miri)), repr(align(8)))]
#[repr(C)]
struct Header {
_len: SizeType,
_cap: SizeType,
}
impl Header {
fn len(&self) -> usize {
self._len as usize
}
fn set_len(&mut self, len: usize) {
self._len = assert_size(len);
}
}
#[cfg(feature = "gecko-ffi")]
impl Header {
fn cap(&self) -> usize {
unpack_capacity(self._cap)
}
fn set_cap(&mut self, cap: usize) {
debug_assert_eq!(unpack_capacity(pack_capacity(cap as SizeType)), cap);
self._cap = pack_capacity(assert_size(cap));
}
fn uses_stack_allocated_buffer(&self) -> bool {
is_auto(self._cap)
}
}
#[cfg(not(feature = "gecko-ffi"))]
impl Header {
fn cap(&self) -> usize {
self._cap as usize
}
fn set_cap(&mut self, cap: usize) {
self._cap = assert_size(cap);
}
}
#[cfg(any(not(feature = "gecko-ffi"), test, miri))]
static EMPTY_HEADER: Header = Header { _len: 0, _cap: 0 };
#[cfg(all(feature = "gecko-ffi", not(test), not(miri)))]
extern "C" {
#[link_name = "sEmptyTArrayHeader"]
static EMPTY_HEADER: Header;
}
fn alloc_size<T>(cap: usize) -> usize {
let header_size = mem::size_of::<Header>();
let elem_size = mem::size_of::<T>();
let padding = padding::<T>();
let data_size = elem_size.checked_mul(cap).expect("capacity overflow");
data_size
.checked_add(header_size + padding)
.expect("capacity overflow")
}
fn padding<T>() -> usize {
let alloc_align = alloc_align::<T>();
let header_size = mem::size_of::<Header>();
if alloc_align > header_size {
if cfg!(feature = "gecko-ffi") {
panic!(
"nsTArray does not handle alignment above > {} correctly",
header_size
);
}
alloc_align - header_size
} else {
0
}
}
fn alloc_align<T>() -> usize {
max(mem::align_of::<T>(), mem::align_of::<Header>())
}
fn layout<T>(cap: usize) -> Layout {
unsafe { Layout::from_size_align_unchecked(alloc_size::<T>(cap), alloc_align::<T>()) }
}
fn header_with_capacity<T>(cap: usize) -> NonNull<Header> {
debug_assert!(cap > 0);
unsafe {
let layout = layout::<T>(cap);
let header = alloc(layout) as *mut Header;
if header.is_null() {
handle_alloc_error(layout)
}
(*header).set_cap(if mem::size_of::<T>() == 0 {
MAX_CAP
} else {
cap
});
(*header).set_len(0);
NonNull::new_unchecked(header)
}
}
#[repr(C)]
pub struct ThinVec<T> {
ptr: NonNull<Header>,
boo: PhantomData<T>,
}
unsafe impl<T: Sync> Sync for ThinVec<T> {}
unsafe impl<T: Send> Send for ThinVec<T> {}
#[macro_export]
macro_rules! thin_vec {
(@UNIT $($t:tt)*) => (());
($elem:expr; $n:expr) => ({
let mut vec = $crate::ThinVec::new();
vec.resize($n, $elem);
vec
});
() => {$crate::ThinVec::new()};
($($x:expr),*) => ({
let len = [$(thin_vec!(@UNIT $x)),*].len();
let mut vec = $crate::ThinVec::with_capacity(len);
$(vec.push($x);)*
vec
});
($($x:expr,)*) => (thin_vec![$($x),*]);
}
impl<T> ThinVec<T> {
pub fn new() -> ThinVec<T> {
ThinVec::with_capacity(0)
}
pub fn with_capacity(cap: usize) -> ThinVec<T> {
let _ = padding::<T>();
if cap == 0 {
unsafe {
ThinVec {
ptr: NonNull::new_unchecked(&EMPTY_HEADER as *const Header as *mut Header),
boo: PhantomData,
}
}
} else {
ThinVec {
ptr: header_with_capacity::<T>(cap),
boo: PhantomData,
}
}
}
fn ptr(&self) -> *mut Header {
self.ptr.as_ptr()
}
fn header(&self) -> &Header {
unsafe { self.ptr.as_ref() }
}
fn data_raw(&self) -> *mut T {
let padding = padding::<T>();
let empty_header_is_aligned = if cfg!(feature = "gecko-ffi") {
true
} else {
mem::align_of::<Header>() >= mem::align_of::<T>() && padding == 0
};
unsafe {
if !empty_header_is_aligned && self.header().cap() == 0 {
NonNull::dangling().as_ptr()
} else {
let header_size = mem::size_of::<Header>();
let ptr = self.ptr.as_ptr() as *mut u8;
ptr.add(header_size + padding) as *mut T
}
}
}
unsafe fn header_mut(&mut self) -> &mut Header {
&mut *self.ptr()
}
pub fn len(&self) -> usize {
self.header().len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn capacity(&self) -> usize {
self.header().cap()
}
pub unsafe fn set_len(&mut self, len: usize) {
if self.is_singleton() {
assert!(len == 0, "invalid set_len({}) on empty ThinVec", len);
} else {
self.header_mut().set_len(len)
}
}
unsafe fn set_len_non_singleton(&mut self, len: usize) {
self.header_mut().set_len(len)
}
pub fn push(&mut self, val: T) {
let old_len = self.len();
if old_len == self.capacity() {
self.reserve(1);
}
unsafe {
ptr::write(self.data_raw().add(old_len), val);
self.set_len_non_singleton(old_len + 1);
}
}
pub fn pop(&mut self) -> Option<T> {
let old_len = self.len();
if old_len == 0 {
return None;
}
unsafe {
self.set_len_non_singleton(old_len - 1);
Some(ptr::read(self.data_raw().add(old_len - 1)))
}
}
pub fn insert(&mut self, idx: usize, elem: T) {
let old_len = self.len();
assert!(idx <= old_len, "Index out of bounds");
if old_len == self.capacity() {
self.reserve(1);
}
unsafe {
let ptr = self.data_raw();
ptr::copy(ptr.add(idx), ptr.add(idx + 1), old_len - idx);
ptr::write(ptr.add(idx), elem);
self.set_len_non_singleton(old_len + 1);
}
}
pub fn remove(&mut self, idx: usize) -> T {
let old_len = self.len();
assert!(idx < old_len, "Index out of bounds");
unsafe {
self.set_len_non_singleton(old_len - 1);
let ptr = self.data_raw();
let val = ptr::read(self.data_raw().add(idx));
ptr::copy(ptr.add(idx + 1), ptr.add(idx), old_len - idx - 1);
val
}
}
pub fn swap_remove(&mut self, idx: usize) -> T {
let old_len = self.len();
assert!(idx < old_len, "Index out of bounds");
unsafe {
let ptr = self.data_raw();
ptr::swap(ptr.add(idx), ptr.add(old_len - 1));
self.set_len_non_singleton(old_len - 1);
ptr::read(ptr.add(old_len - 1))
}
}
pub fn truncate(&mut self, len: usize) {
unsafe {
while len < self.len() {
let new_len = self.len() - 1;
self.set_len_non_singleton(new_len);
ptr::drop_in_place(self.data_raw().add(new_len));
}
}
}
pub fn clear(&mut self) {
unsafe {
ptr::drop_in_place(&mut self[..]);
self.set_len(0); }
}
pub fn as_slice(&self) -> &[T] {
unsafe { slice::from_raw_parts(self.data_raw(), self.len()) }
}
pub fn as_mut_slice(&mut self) -> &mut [T] {
unsafe { slice::from_raw_parts_mut(self.data_raw(), self.len()) }
}
#[cfg(not(feature = "gecko-ffi"))]
pub fn reserve(&mut self, additional: usize) {
let len = self.len();
let old_cap = self.capacity();
let min_cap = len.checked_add(additional).expect("capacity overflow");
if min_cap <= old_cap {
return;
}
let double_cap = if old_cap == 0 {
if mem::size_of::<T>() > (!0) / 8 {
1
} else {
4
}
} else {
old_cap.saturating_mul(2)
};
let new_cap = max(min_cap, double_cap);
unsafe {
self.reallocate(new_cap);
}
}
#[cfg(feature = "gecko-ffi")]
pub fn reserve(&mut self, additional: usize) {
let elem_size = mem::size_of::<T>();
let len = self.len();
let old_cap = self.capacity();
let min_cap = len.checked_add(additional).expect("capacity overflow");
if min_cap <= old_cap {
return;
}
if elem_size == 0 {
unsafe {
self.reallocate(min_cap);
}
return;
}
let min_cap_bytes = assert_size(min_cap)
.checked_mul(assert_size(elem_size))
.and_then(|x| x.checked_add(assert_size(mem::size_of::<Header>())))
.unwrap();
let will_fit = min_cap_bytes.checked_mul(2).is_some();
if !will_fit {
panic!("Exceeded maximum nsTArray size");
}
const SLOW_GROWTH_THRESHOLD: usize = 8 * 1024 * 1024;
let bytes = if min_cap > SLOW_GROWTH_THRESHOLD {
let old_cap_bytes = old_cap * elem_size + mem::size_of::<Header>();
let min_growth = old_cap_bytes + (old_cap_bytes >> 3);
let growth = max(min_growth, min_cap_bytes as usize);
const MB: usize = 1 << 20;
MB * ((growth + MB - 1) / MB)
} else {
min_cap_bytes.next_power_of_two() as usize
};
let cap = (bytes - std::mem::size_of::<Header>()) / elem_size;
unsafe {
self.reallocate(cap);
}
}
pub fn reserve_exact(&mut self, additional: usize) {
let new_cap = self
.len()
.checked_add(additional)
.expect("capacity overflow");
let old_cap = self.capacity();
if new_cap > old_cap {
unsafe {
self.reallocate(new_cap);
}
}
}
pub fn shrink_to_fit(&mut self) {
let old_cap = self.capacity();
let new_cap = self.len();
if new_cap < old_cap {
if new_cap == 0 {
*self = ThinVec::new();
} else {
unsafe {
self.reallocate(new_cap);
}
}
}
}
pub fn retain<F>(&mut self, mut f: F)
where
F: FnMut(&T) -> bool,
{
let len = self.len();
let mut del = 0;
{
let v = &mut self[..];
for i in 0..len {
if !f(&v[i]) {
del += 1;
} else if del > 0 {
v.swap(i - del, i);
}
}
}
if del > 0 {
self.truncate(len - del);
}
}
pub fn dedup_by_key<F, K>(&mut self, mut key: F)
where
F: FnMut(&mut T) -> K,
K: PartialEq<K>,
{
self.dedup_by(|a, b| key(a) == key(b))
}
#[allow(clippy::swap_ptr_to_ref)]
pub fn dedup_by<F>(&mut self, mut same_bucket: F)
where
F: FnMut(&mut T, &mut T) -> bool,
{
unsafe {
let ln = self.len();
if ln <= 1 {
return;
}
let p = self.as_mut_ptr();
let mut r: usize = 1;
let mut w: usize = 1;
while r < ln {
let p_r = p.add(r);
let p_wm1 = p.add(w - 1);
if !same_bucket(&mut *p_r, &mut *p_wm1) {
if r != w {
let p_w = p_wm1.add(1);
mem::swap(&mut *p_r, &mut *p_w);
}
w += 1;
}
r += 1;
}
self.truncate(w);
}
}
pub fn split_off(&mut self, at: usize) -> ThinVec<T> {
let old_len = self.len();
let new_vec_len = old_len - at;
assert!(at <= old_len, "Index out of bounds");
unsafe {
let mut new_vec = ThinVec::with_capacity(new_vec_len);
ptr::copy_nonoverlapping(self.data_raw().add(at), new_vec.data_raw(), new_vec_len);
new_vec.set_len(new_vec_len); self.set_len(at);
new_vec
}
}
pub fn append(&mut self, other: &mut ThinVec<T>) {
self.extend(other.drain(..))
}
pub fn drain<R>(&mut self, range: R) -> Drain<'_, T>
where
R: RangeBounds<usize>,
{
let len = self.len();
let start = match range.start_bound() {
Bound::Included(&n) => n,
Bound::Excluded(&n) => n + 1,
Bound::Unbounded => 0,
};
let end = match range.end_bound() {
Bound::Included(&n) => n + 1,
Bound::Excluded(&n) => n,
Bound::Unbounded => len,
};
assert!(start <= end);
assert!(end <= len);
unsafe {
self.set_len(start);
let iter =
slice::from_raw_parts_mut(self.data_raw().add(start), end - start).iter_mut();
Drain {
iter,
vec: self,
end,
tail: len - end,
}
}
}
unsafe fn reallocate(&mut self, new_cap: usize) {
debug_assert!(new_cap > 0);
if self.has_allocation() {
let old_cap = self.capacity();
let ptr = realloc(
self.ptr() as *mut u8,
layout::<T>(old_cap),
alloc_size::<T>(new_cap),
) as *mut Header;
if ptr.is_null() {
handle_alloc_error(layout::<T>(new_cap))
}
(*ptr).set_cap(new_cap);
self.ptr = NonNull::new_unchecked(ptr);
} else {
let new_header = header_with_capacity::<T>(new_cap);
let len = self.len();
if cfg!(feature = "gecko-ffi") && len > 0 {
new_header
.as_ptr()
.add(1)
.cast::<T>()
.copy_from_nonoverlapping(self.data_raw(), len);
self.set_len_non_singleton(0);
}
self.ptr = new_header;
}
}
#[cfg(feature = "gecko-ffi")]
#[inline]
fn is_singleton(&self) -> bool {
unsafe { self.ptr.as_ptr() as *const Header == &EMPTY_HEADER }
}
#[cfg(not(feature = "gecko-ffi"))]
#[inline]
fn is_singleton(&self) -> bool {
self.ptr.as_ptr() as *const Header == &EMPTY_HEADER
}
#[cfg(feature = "gecko-ffi")]
#[inline]
fn has_allocation(&self) -> bool {
unsafe { !self.is_singleton() && !self.ptr.as_ref().uses_stack_allocated_buffer() }
}
#[cfg(not(feature = "gecko-ffi"))]
#[inline]
fn has_allocation(&self) -> bool {
!self.is_singleton()
}
}
impl<T: Clone> ThinVec<T> {
pub fn resize(&mut self, new_len: usize, value: T) {
let old_len = self.len();
if new_len > old_len {
let additional = new_len - old_len;
self.reserve(additional);
for _ in 1..additional {
self.push(value.clone());
}
if additional > 0 {
self.push(value);
}
} else if new_len < old_len {
self.truncate(new_len);
}
}
pub fn extend_from_slice(&mut self, other: &[T]) {
self.extend(other.iter().cloned())
}
}
impl<T: PartialEq> ThinVec<T> {
pub fn dedup(&mut self) {
self.dedup_by(|a, b| a == b)
}
}
impl<T> Drop for ThinVec<T> {
#[inline]
fn drop(&mut self) {
#[cold]
#[inline(never)]
fn drop_non_singleton<T>(this: &mut ThinVec<T>) {
unsafe {
ptr::drop_in_place(&mut this[..]);
#[cfg(feature = "gecko-ffi")]
if this.ptr.as_ref().uses_stack_allocated_buffer() {
return;
}
dealloc(this.ptr() as *mut u8, layout::<T>(this.capacity()))
}
}
if !self.is_singleton() {
drop_non_singleton(self);
}
}
}
impl<T> Deref for ThinVec<T> {
type Target = [T];
fn deref(&self) -> &[T] {
self.as_slice()
}
}
impl<T> DerefMut for ThinVec<T> {
fn deref_mut(&mut self) -> &mut [T] {
self.as_mut_slice()
}
}
impl<T> Borrow<[T]> for ThinVec<T> {
fn borrow(&self) -> &[T] {
self.as_slice()
}
}
impl<T> BorrowMut<[T]> for ThinVec<T> {
fn borrow_mut(&mut self) -> &mut [T] {
self.as_mut_slice()
}
}
impl<T> AsRef<[T]> for ThinVec<T> {
fn as_ref(&self) -> &[T] {
self.as_slice()
}
}
impl<T> Extend<T> for ThinVec<T> {
#[inline]
fn extend<I>(&mut self, iter: I)
where
I: IntoIterator<Item = T>,
{
let iter = iter.into_iter();
let hint = iter.size_hint().0;
if hint > 0 {
self.reserve(hint);
}
for x in iter {
self.push(x);
}
}
}
impl<T: fmt::Debug> fmt::Debug for ThinVec<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
}
}
impl<T> Hash for ThinVec<T>
where
T: Hash,
{
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
self[..].hash(state);
}
}
impl<T> PartialOrd for ThinVec<T>
where
T: PartialOrd,
{
#[inline]
fn partial_cmp(&self, other: &ThinVec<T>) -> Option<Ordering> {
self[..].partial_cmp(&other[..])
}
}
impl<T> Ord for ThinVec<T>
where
T: Ord,
{
#[inline]
fn cmp(&self, other: &ThinVec<T>) -> Ordering {
self[..].cmp(&other[..])
}
}
impl<A, B> PartialEq<ThinVec<B>> for ThinVec<A>
where
A: PartialEq<B>,
{
#[inline]
fn eq(&self, other: &ThinVec<B>) -> bool {
self[..] == other[..]
}
}
impl<A, B> PartialEq<Vec<B>> for ThinVec<A>
where
A: PartialEq<B>,
{
#[inline]
fn eq(&self, other: &Vec<B>) -> bool {
self[..] == other[..]
}
}
impl<A, B> PartialEq<[B]> for ThinVec<A>
where
A: PartialEq<B>,
{
#[inline]
fn eq(&self, other: &[B]) -> bool {
self[..] == other[..]
}
}
impl<'a, A, B> PartialEq<&'a [B]> for ThinVec<A>
where
A: PartialEq<B>,
{
#[inline]
fn eq(&self, other: &&'a [B]) -> bool {
self[..] == other[..]
}
}
#[cfg(feature = "serde")]
impl<T: serde::Serialize> serde::Serialize for ThinVec<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.collect_seq(self.as_slice())
}
}
#[cfg(feature = "serde")]
impl<'de, T: serde::Deserialize<'de>> serde::Deserialize<'de> for ThinVec<T> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
use serde::de::{SeqAccess, Visitor};
use serde::Deserialize;
struct ThinVecVisitor<T>(PhantomData<T>);
impl<'de, T: Deserialize<'de>> Visitor<'de> for ThinVecVisitor<T> {
type Value = ThinVec<T>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a sequence")
}
fn visit_seq<SA>(self, mut seq: SA) -> Result<Self::Value, SA::Error>
where
SA: SeqAccess<'de>,
{
let initial_capacity = seq.size_hint().unwrap_or_default().min(4096);
let mut values = ThinVec::<T>::with_capacity(initial_capacity);
while let Some(value) = seq.next_element()? {
values.push(value);
}
Ok(values)
}
}
deserializer.deserialize_seq(ThinVecVisitor::<T>(PhantomData))
}
}
macro_rules! array_impls {
($($N:expr)*) => {$(
impl<A, B> PartialEq<[B; $N]> for ThinVec<A> where A: PartialEq<B> {
#[inline]
fn eq(&self, other: &[B; $N]) -> bool { self[..] == other[..] }
}
impl<'a, A, B> PartialEq<&'a [B; $N]> for ThinVec<A> where A: PartialEq<B> {
#[inline]
fn eq(&self, other: &&'a [B; $N]) -> bool { self[..] == other[..] }
}
)*}
}
array_impls! {
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
}
impl<T> Eq for ThinVec<T> where T: Eq {}
impl<T> IntoIterator for ThinVec<T> {
type Item = T;
type IntoIter = IntoIter<T>;
fn into_iter(self) -> IntoIter<T> {
IntoIter {
vec: self,
start: 0,
}
}
}
impl<'a, T> IntoIterator for &'a ThinVec<T> {
type Item = &'a T;
type IntoIter = slice::Iter<'a, T>;
fn into_iter(self) -> slice::Iter<'a, T> {
self.iter()
}
}
impl<'a, T> IntoIterator for &'a mut ThinVec<T> {
type Item = &'a mut T;
type IntoIter = slice::IterMut<'a, T>;
fn into_iter(self) -> slice::IterMut<'a, T> {
self.iter_mut()
}
}
impl<T> Clone for ThinVec<T>
where
T: Clone,
{
#[inline]
fn clone(&self) -> ThinVec<T> {
#[cold]
#[inline(never)]
fn clone_non_singleton<T: Clone>(this: &ThinVec<T>) -> ThinVec<T> {
let len = this.len();
let mut new_vec = ThinVec::<T>::with_capacity(len);
let mut data_raw = new_vec.data_raw();
for x in this.iter() {
unsafe {
ptr::write(data_raw, x.clone());
data_raw = data_raw.add(1);
}
}
unsafe {
new_vec.set_len(len); }
new_vec
}
if self.is_singleton() {
ThinVec::new()
} else {
clone_non_singleton(self)
}
}
}
impl<T> Default for ThinVec<T> {
fn default() -> ThinVec<T> {
ThinVec::new()
}
}
impl<T> FromIterator<T> for ThinVec<T> {
#[inline]
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> ThinVec<T> {
let mut vec = ThinVec::new();
vec.extend(iter.into_iter());
vec
}
}
pub struct IntoIter<T> {
vec: ThinVec<T>,
start: usize,
}
pub struct Drain<'a, T> {
iter: IterMut<'a, T>,
vec: *mut ThinVec<T>,
end: usize,
tail: usize,
}
impl<T> Iterator for IntoIter<T> {
type Item = T;
fn next(&mut self) -> Option<T> {
if self.start == self.vec.len() {
None
} else {
unsafe {
let old_start = self.start;
self.start += 1;
Some(ptr::read(self.vec.data_raw().add(old_start)))
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.vec.len() - self.start;
(len, Some(len))
}
}
impl<T> DoubleEndedIterator for IntoIter<T> {
fn next_back(&mut self) -> Option<T> {
if self.start == self.vec.len() {
None
} else {
self.vec.pop()
}
}
}
impl<T> Drop for IntoIter<T> {
#[inline]
fn drop(&mut self) {
#[cold]
#[inline(never)]
fn drop_non_singleton<T>(this: &mut IntoIter<T>) {
unsafe {
let mut vec = mem::replace(&mut this.vec, ThinVec::new());
ptr::drop_in_place(&mut vec[this.start..]);
vec.set_len_non_singleton(0)
}
}
if !self.vec.is_singleton() {
drop_non_singleton(self);
}
}
}
impl<'a, T> Iterator for Drain<'a, T> {
type Item = T;
fn next(&mut self) -> Option<T> {
self.iter.next().map(|x| unsafe { ptr::read(x) })
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl<'a, T> DoubleEndedIterator for Drain<'a, T> {
fn next_back(&mut self) -> Option<T> {
self.iter.next_back().map(|x| unsafe { ptr::read(x) })
}
}
impl<'a, T> ExactSizeIterator for Drain<'a, T> {}
impl<'a, T> Drop for Drain<'a, T> {
fn drop(&mut self) {
for _ in self.by_ref() {}
unsafe {
let vec = &mut *self.vec;
if !vec.is_singleton() {
let old_len = vec.len();
let start = vec.data_raw().add(old_len);
let end = vec.data_raw().add(self.end);
ptr::copy(end, start, self.tail);
vec.set_len_non_singleton(old_len + self.tail);
}
}
}
}
impl io::Write for ThinVec<u8> {
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.extend_from_slice(buf);
Ok(buf.len())
}
#[inline]
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
self.extend_from_slice(buf);
Ok(())
}
#[inline]
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::{ThinVec, MAX_CAP};
#[test]
fn test_size_of() {
use std::mem::size_of;
assert_eq!(size_of::<ThinVec<u8>>(), size_of::<&u8>());
assert_eq!(size_of::<Option<ThinVec<u8>>>(), size_of::<&u8>());
}
#[test]
fn test_drop_empty() {
ThinVec::<u8>::new();
}
#[test]
fn test_data_ptr_alignment() {
let v = ThinVec::<u16>::new();
assert!(v.data_raw() as usize % 2 == 0);
let v = ThinVec::<u32>::new();
assert!(v.data_raw() as usize % 4 == 0);
let v = ThinVec::<u64>::new();
assert!(v.data_raw() as usize % 8 == 0);
}
#[test]
#[cfg_attr(feature = "gecko-ffi", should_panic)]
fn test_overaligned_type_is_rejected_for_gecko_ffi_mode() {
#[repr(align(16))]
struct Align16(u8);
let v = ThinVec::<Align16>::new();
assert!(v.data_raw() as usize % 16 == 0);
}
#[test]
fn test_partial_eq() {
assert_eq!(thin_vec![0], thin_vec![0]);
assert_ne!(thin_vec![0], thin_vec![1]);
assert_eq!(thin_vec![1, 2, 3], vec![1, 2, 3]);
}
#[test]
fn test_alloc() {
let mut v = ThinVec::new();
assert!(!v.has_allocation());
v.push(1);
assert!(v.has_allocation());
v.pop();
assert!(v.has_allocation());
v.shrink_to_fit();
assert!(!v.has_allocation());
v.reserve(64);
assert!(v.has_allocation());
v = ThinVec::with_capacity(64);
assert!(v.has_allocation());
v = ThinVec::with_capacity(0);
assert!(!v.has_allocation());
}
#[test]
fn test_drain_items() {
let mut vec = thin_vec![1, 2, 3];
let mut vec2 = thin_vec![];
for i in vec.drain(..) {
vec2.push(i);
}
assert_eq!(vec, []);
assert_eq!(vec2, [1, 2, 3]);
}
#[test]
fn test_drain_items_reverse() {
let mut vec = thin_vec![1, 2, 3];
let mut vec2 = thin_vec![];
for i in vec.drain(..).rev() {
vec2.push(i);
}
assert_eq!(vec, []);
assert_eq!(vec2, [3, 2, 1]);
}
#[test]
fn test_drain_items_zero_sized() {
let mut vec = thin_vec![(), (), ()];
let mut vec2 = thin_vec![];
for i in vec.drain(..) {
vec2.push(i);
}
assert_eq!(vec, []);
assert_eq!(vec2, [(), (), ()]);
}
#[test]
#[should_panic]
fn test_drain_out_of_bounds() {
let mut v = thin_vec![1, 2, 3, 4, 5];
v.drain(5..6);
}
#[test]
fn test_drain_range() {
let mut v = thin_vec![1, 2, 3, 4, 5];
for _ in v.drain(4..) {}
assert_eq!(v, &[1, 2, 3, 4]);
let mut v: ThinVec<_> = (1..6).map(|x| x.to_string()).collect();
for _ in v.drain(1..4) {}
assert_eq!(v, &[1.to_string(), 5.to_string()]);
let mut v: ThinVec<_> = (1..6).map(|x| x.to_string()).collect();
for _ in v.drain(1..4).rev() {}
assert_eq!(v, &[1.to_string(), 5.to_string()]);
let mut v: ThinVec<_> = thin_vec![(); 5];
for _ in v.drain(1..4).rev() {}
assert_eq!(v, &[(), ()]);
}
#[test]
fn test_drain_max_vec_size() {
let mut v = ThinVec::<()>::with_capacity(MAX_CAP);
unsafe {
v.set_len(MAX_CAP);
}
for _ in v.drain(MAX_CAP - 1..) {}
assert_eq!(v.len(), MAX_CAP - 1);
}
#[test]
fn test_clear() {
let mut v = ThinVec::<i32>::new();
assert_eq!(v.len(), 0);
assert_eq!(v.capacity(), 0);
assert_eq!(&v[..], &[]);
v.clear();
assert_eq!(v.len(), 0);
assert_eq!(v.capacity(), 0);
assert_eq!(&v[..], &[]);
v.push(1);
v.push(2);
assert_eq!(v.len(), 2);
assert!(v.capacity() >= 2);
assert_eq!(&v[..], &[1, 2]);
v.clear();
assert_eq!(v.len(), 0);
assert!(v.capacity() >= 2);
assert_eq!(&v[..], &[]);
v.push(3);
v.push(4);
assert_eq!(v.len(), 2);
assert!(v.capacity() >= 2);
assert_eq!(&v[..], &[3, 4]);
v.clear();
assert_eq!(v.len(), 0);
assert!(v.capacity() >= 2);
assert_eq!(&v[..], &[]);
v.clear();
assert_eq!(v.len(), 0);
assert!(v.capacity() >= 2);
assert_eq!(&v[..], &[]);
}
#[test]
fn test_empty_singleton_torture() {
{
let mut v = ThinVec::<i32>::new();
assert_eq!(v.len(), 0);
assert_eq!(v.capacity(), 0);
assert!(v.is_empty());
assert_eq!(&v[..], &[]);
assert_eq!(&mut v[..], &mut []);
assert_eq!(v.pop(), None);
assert_eq!(v.len(), 0);
assert_eq!(v.capacity(), 0);
assert_eq!(&v[..], &[]);
}
{
let v = ThinVec::<i32>::new();
assert_eq!(v.into_iter().count(), 0);
let v = ThinVec::<i32>::new();
for _ in v.into_iter() {
unreachable!();
}
}
{
let mut v = ThinVec::<i32>::new();
assert_eq!(v.drain(..).len(), 0);
for _ in v.drain(..) {
unreachable!()
}
assert_eq!(v.len(), 0);
assert_eq!(v.capacity(), 0);
assert_eq!(&v[..], &[]);
}
{
let mut v = ThinVec::<i32>::new();
v.truncate(1);
assert_eq!(v.len(), 0);
assert_eq!(v.capacity(), 0);
assert_eq!(&v[..], &[]);
v.truncate(0);
assert_eq!(v.len(), 0);
assert_eq!(v.capacity(), 0);
assert_eq!(&v[..], &[]);
}
{
let mut v = ThinVec::<i32>::new();
v.shrink_to_fit();
assert_eq!(v.len(), 0);
assert_eq!(v.capacity(), 0);
assert_eq!(&v[..], &[]);
}
{
let mut v = ThinVec::<i32>::new();
let new = v.split_off(0);
assert_eq!(v.len(), 0);
assert_eq!(v.capacity(), 0);
assert_eq!(&v[..], &[]);
assert_eq!(new.len(), 0);
assert_eq!(new.capacity(), 0);
assert_eq!(&new[..], &[]);
}
{
let mut v = ThinVec::<i32>::new();
let mut other = ThinVec::<i32>::new();
v.append(&mut other);
assert_eq!(v.len(), 0);
assert_eq!(v.capacity(), 0);
assert_eq!(&v[..], &[]);
assert_eq!(other.len(), 0);
assert_eq!(other.capacity(), 0);
assert_eq!(&other[..], &[]);
}
{
let mut v = ThinVec::<i32>::new();
v.reserve(0);
assert_eq!(v.len(), 0);
assert_eq!(v.capacity(), 0);
assert_eq!(&v[..], &[]);
}
{
let mut v = ThinVec::<i32>::new();
v.reserve_exact(0);
assert_eq!(v.len(), 0);
assert_eq!(v.capacity(), 0);
assert_eq!(&v[..], &[]);
}
{
let mut v = ThinVec::<i32>::new();
v.reserve(0);
assert_eq!(v.len(), 0);
assert_eq!(v.capacity(), 0);
assert_eq!(&v[..], &[]);
}
{
let v = ThinVec::<i32>::with_capacity(0);
assert_eq!(v.len(), 0);
assert_eq!(v.capacity(), 0);
assert_eq!(&v[..], &[]);
}
{
let v = ThinVec::<i32>::default();
assert_eq!(v.len(), 0);
assert_eq!(v.capacity(), 0);
assert_eq!(&v[..], &[]);
}
{
let mut v = ThinVec::<i32>::new();
v.retain(|_| unreachable!());
assert_eq!(v.len(), 0);
assert_eq!(v.capacity(), 0);
assert_eq!(&v[..], &[]);
}
{
let mut v = ThinVec::<i32>::new();
v.dedup_by_key(|x| *x);
assert_eq!(v.len(), 0);
assert_eq!(v.capacity(), 0);
assert_eq!(&v[..], &[]);
}
{
let mut v = ThinVec::<i32>::new();
v.dedup_by(|_, _| unreachable!());
assert_eq!(v.len(), 0);
assert_eq!(v.capacity(), 0);
assert_eq!(&v[..], &[]);
}
{
let v = ThinVec::<i32>::new();
let v = v.clone();
assert_eq!(v.len(), 0);
assert_eq!(v.capacity(), 0);
assert_eq!(&v[..], &[]);
}
}
#[test]
fn test_clone() {
let mut v = ThinVec::<i32>::new();
assert!(v.is_singleton());
v.push(0);
v.pop();
assert!(!v.is_singleton());
let v2 = v.clone();
assert!(v2.is_singleton());
}
}
#[cfg(test)]
mod std_tests {
#![allow(clippy::reversed_empty_ranges)]
use super::*;
use std::mem::size_of;
use std::usize;
struct DropCounter<'a> {
count: &'a mut u32,
}
impl<'a> Drop for DropCounter<'a> {
fn drop(&mut self) {
*self.count += 1;
}
}
#[test]
fn test_small_vec_struct() {
assert!(size_of::<ThinVec<u8>>() == size_of::<usize>());
}
#[test]
fn test_double_drop() {
struct TwoVec<T> {
x: ThinVec<T>,
y: ThinVec<T>,
}
let (mut count_x, mut count_y) = (0, 0);
{
let mut tv = TwoVec {
x: ThinVec::new(),
y: ThinVec::new(),
};
tv.x.push(DropCounter {
count: &mut count_x,
});
tv.y.push(DropCounter {
count: &mut count_y,
});
drop(tv.x);
}
assert_eq!(count_x, 1);
assert_eq!(count_y, 1);
}
#[test]
fn test_reserve() {
let mut v = ThinVec::new();
assert_eq!(v.capacity(), 0);
v.reserve(2);
assert!(v.capacity() >= 2);
for i in 0..16 {
v.push(i);
}
assert!(v.capacity() >= 16);
v.reserve(16);
assert!(v.capacity() >= 32);
v.push(16);
v.reserve(16);
assert!(v.capacity() >= 33)
}
#[test]
fn test_extend() {
let mut v = ThinVec::<usize>::new();
let mut w = ThinVec::new();
v.extend(w.clone());
assert_eq!(v, &[]);
v.extend(0..3);
for i in 0..3 {
w.push(i)
}
assert_eq!(v, w);
v.extend(3..10);
for i in 3..10 {
w.push(i)
}
assert_eq!(v, w);
v.extend(w.clone()); assert!(v.iter().eq(w.iter().chain(w.iter())));
#[derive(PartialEq, Debug)]
struct Foo;
let mut a = ThinVec::new();
let b = thin_vec![Foo, Foo];
a.extend(b);
assert_eq!(a, &[Foo, Foo]);
let mut count_x = 0;
{
let mut x = ThinVec::new();
let y = thin_vec![DropCounter {
count: &mut count_x
}];
x.extend(y);
}
assert_eq!(count_x, 1);
}
#[test]
fn test_slice_from_mut() {
let mut values = thin_vec![1, 2, 3, 4, 5];
{
let slice = &mut values[2..];
assert!(slice == [3, 4, 5]);
for p in slice {
*p += 2;
}
}
assert!(values == [1, 2, 5, 6, 7]);
}
#[test]
fn test_slice_to_mut() {
let mut values = thin_vec![1, 2, 3, 4, 5];
{
let slice = &mut values[..2];
assert!(slice == [1, 2]);
for p in slice {
*p += 1;
}
}
assert!(values == [2, 3, 3, 4, 5]);
}
#[test]
fn test_split_at_mut() {
let mut values = thin_vec![1, 2, 3, 4, 5];
{
let (left, right) = values.split_at_mut(2);
{
let left: &[_] = left;
assert!(left[..left.len()] == [1, 2]);
}
for p in left {
*p += 1;
}
{
let right: &[_] = right;
assert!(right[..right.len()] == [3, 4, 5]);
}
for p in right {
*p += 2;
}
}
assert_eq!(values, [2, 3, 5, 6, 7]);
}
#[test]
fn test_clone() {
let v: ThinVec<i32> = thin_vec![];
let w = thin_vec![1, 2, 3];
assert_eq!(v, v.clone());
let z = w.clone();
assert_eq!(w, z);
assert!(w.as_ptr() != z.as_ptr())
}
#[test]
fn test_clone_from() {
let mut v = thin_vec![];
let three: ThinVec<Box<_>> = thin_vec![Box::new(1), Box::new(2), Box::new(3)];
let two: ThinVec<Box<_>> = thin_vec![Box::new(4), Box::new(5)];
v.clone_from(&three);
assert_eq!(v, three);
v.clone_from(&three);
assert_eq!(v, three);
v.clone_from(&two);
assert_eq!(v, two);
v.clone_from(&three);
assert_eq!(v, three)
}
#[test]
fn test_retain() {
let mut vec = thin_vec![1, 2, 3, 4];
vec.retain(|&x| x % 2 == 0);
assert_eq!(vec, [2, 4]);
}
#[test]
fn test_dedup() {
fn case(a: ThinVec<i32>, b: ThinVec<i32>) {
let mut v = a;
v.dedup();
assert_eq!(v, b);
}
case(thin_vec![], thin_vec![]);
case(thin_vec![1], thin_vec![1]);
case(thin_vec![1, 1], thin_vec![1]);
case(thin_vec![1, 2, 3], thin_vec![1, 2, 3]);
case(thin_vec![1, 1, 2, 3], thin_vec![1, 2, 3]);
case(thin_vec![1, 2, 2, 3], thin_vec![1, 2, 3]);
case(thin_vec![1, 2, 3, 3], thin_vec![1, 2, 3]);
case(thin_vec![1, 1, 2, 2, 2, 3, 3], thin_vec![1, 2, 3]);
}
#[test]
fn test_dedup_by_key() {
fn case(a: ThinVec<i32>, b: ThinVec<i32>) {
let mut v = a;
v.dedup_by_key(|i| *i / 10);
assert_eq!(v, b);
}
case(thin_vec![], thin_vec![]);
case(thin_vec![10], thin_vec![10]);
case(thin_vec![10, 11], thin_vec![10]);
case(thin_vec![10, 20, 30], thin_vec![10, 20, 30]);
case(thin_vec![10, 11, 20, 30], thin_vec![10, 20, 30]);
case(thin_vec![10, 20, 21, 30], thin_vec![10, 20, 30]);
case(thin_vec![10, 20, 30, 31], thin_vec![10, 20, 30]);
case(thin_vec![10, 11, 20, 21, 22, 30, 31], thin_vec![10, 20, 30]);
}
#[test]
fn test_dedup_by() {
let mut vec = thin_vec!["foo", "bar", "Bar", "baz", "bar"];
vec.dedup_by(|a, b| a.eq_ignore_ascii_case(b));
assert_eq!(vec, ["foo", "bar", "baz", "bar"]);
let mut vec = thin_vec![("foo", 1), ("foo", 2), ("bar", 3), ("bar", 4), ("bar", 5)];
vec.dedup_by(|a, b| {
a.0 == b.0 && {
b.1 += a.1;
true
}
});
assert_eq!(vec, [("foo", 3), ("bar", 12)]);
}
#[test]
fn test_dedup_unique() {
let mut v0: ThinVec<Box<_>> = thin_vec![Box::new(1), Box::new(1), Box::new(2), Box::new(3)];
v0.dedup();
let mut v1: ThinVec<Box<_>> = thin_vec![Box::new(1), Box::new(2), Box::new(2), Box::new(3)];
v1.dedup();
let mut v2: ThinVec<Box<_>> = thin_vec![Box::new(1), Box::new(2), Box::new(3), Box::new(3)];
v2.dedup();
}
#[test]
fn zero_sized_values() {
let mut v = ThinVec::new();
assert_eq!(v.len(), 0);
v.push(());
assert_eq!(v.len(), 1);
v.push(());
assert_eq!(v.len(), 2);
assert_eq!(v.pop(), Some(()));
assert_eq!(v.pop(), Some(()));
assert_eq!(v.pop(), None);
assert_eq!(v.iter().count(), 0);
v.push(());
assert_eq!(v.iter().count(), 1);
v.push(());
assert_eq!(v.iter().count(), 2);
for &() in &v {}
assert_eq!(v.iter_mut().count(), 2);
v.push(());
assert_eq!(v.iter_mut().count(), 3);
v.push(());
assert_eq!(v.iter_mut().count(), 4);
for &mut () in &mut v {}
unsafe {
v.set_len(0);
}
assert_eq!(v.iter_mut().count(), 0);
}
#[test]
fn test_partition() {
assert_eq!(
thin_vec![].into_iter().partition(|x: &i32| *x < 3),
(thin_vec![], thin_vec![])
);
assert_eq!(
thin_vec![1, 2, 3].into_iter().partition(|x| *x < 4),
(thin_vec![1, 2, 3], thin_vec![])
);
assert_eq!(
thin_vec![1, 2, 3].into_iter().partition(|x| *x < 2),
(thin_vec![1], thin_vec![2, 3])
);
assert_eq!(
thin_vec![1, 2, 3].into_iter().partition(|x| *x < 0),
(thin_vec![], thin_vec![1, 2, 3])
);
}
#[test]
fn test_zip_unzip() {
let z1 = thin_vec![(1, 4), (2, 5), (3, 6)];
let (left, right): (ThinVec<_>, ThinVec<_>) = z1.iter().cloned().unzip();
assert_eq!((1, 4), (left[0], right[0]));
assert_eq!((2, 5), (left[1], right[1]));
assert_eq!((3, 6), (left[2], right[2]));
}
#[test]
fn test_vec_truncate_drop() {
static mut DROPS: u32 = 0;
struct Elem(i32);
impl Drop for Elem {
fn drop(&mut self) {
unsafe {
DROPS += 1;
}
}
}
let mut v = thin_vec![Elem(1), Elem(2), Elem(3), Elem(4), Elem(5)];
assert_eq!(unsafe { DROPS }, 0);
v.truncate(3);
assert_eq!(unsafe { DROPS }, 2);
v.truncate(0);
assert_eq!(unsafe { DROPS }, 5);
}
#[test]
#[should_panic]
fn test_vec_truncate_fail() {
struct BadElem(i32);
impl Drop for BadElem {
fn drop(&mut self) {
let BadElem(ref mut x) = *self;
if *x == 0xbadbeef {
panic!("BadElem panic: 0xbadbeef")
}
}
}
let mut v = thin_vec![BadElem(1), BadElem(2), BadElem(0xbadbeef), BadElem(4)];
v.truncate(0);
}
#[test]
fn test_index() {
let vec = thin_vec![1, 2, 3];
assert!(vec[1] == 2);
}
#[test]
#[should_panic]
fn test_index_out_of_bounds() {
let vec = thin_vec![1, 2, 3];
let _ = vec[3];
}
#[test]
#[should_panic]
fn test_slice_out_of_bounds_1() {
let x = thin_vec![1, 2, 3, 4, 5];
let _ = &x[!0..];
}
#[test]
#[should_panic]
fn test_slice_out_of_bounds_2() {
let x = thin_vec![1, 2, 3, 4, 5];
let _ = &x[..6];
}
#[test]
#[should_panic]
fn test_slice_out_of_bounds_3() {
let x = thin_vec![1, 2, 3, 4, 5];
let _ = &x[!0..4];
}
#[test]
#[should_panic]
fn test_slice_out_of_bounds_4() {
let x = thin_vec![1, 2, 3, 4, 5];
let _ = &x[1..6];
}
#[test]
#[should_panic]
fn test_slice_out_of_bounds_5() {
let x = thin_vec![1, 2, 3, 4, 5];
let _ = &x[3..2];
}
#[test]
#[should_panic]
fn test_swap_remove_empty() {
let mut vec = ThinVec::<i32>::new();
vec.swap_remove(0);
}
#[test]
fn test_move_items() {
let vec = thin_vec![1, 2, 3];
let mut vec2 = thin_vec![];
for i in vec {
vec2.push(i);
}
assert_eq!(vec2, [1, 2, 3]);
}
#[test]
fn test_move_items_reverse() {
let vec = thin_vec![1, 2, 3];
let mut vec2 = thin_vec![];
for i in vec.into_iter().rev() {
vec2.push(i);
}
assert_eq!(vec2, [3, 2, 1]);
}
#[test]
fn test_move_items_zero_sized() {
let vec = thin_vec![(), (), ()];
let mut vec2 = thin_vec![];
for i in vec {
vec2.push(i);
}
assert_eq!(vec2, [(), (), ()]);
}
#[test]
fn test_drain_items() {
let mut vec = thin_vec![1, 2, 3];
let mut vec2 = thin_vec![];
for i in vec.drain(..) {
vec2.push(i);
}
assert_eq!(vec, []);
assert_eq!(vec2, [1, 2, 3]);
}
#[test]
fn test_drain_items_reverse() {
let mut vec = thin_vec![1, 2, 3];
let mut vec2 = thin_vec![];
for i in vec.drain(..).rev() {
vec2.push(i);
}
assert_eq!(vec, []);
assert_eq!(vec2, [3, 2, 1]);
}
#[test]
fn test_drain_items_zero_sized() {
let mut vec = thin_vec![(), (), ()];
let mut vec2 = thin_vec![];
for i in vec.drain(..) {
vec2.push(i);
}
assert_eq!(vec, []);
assert_eq!(vec2, [(), (), ()]);
}
#[test]
#[should_panic]
fn test_drain_out_of_bounds() {
let mut v = thin_vec![1, 2, 3, 4, 5];
v.drain(5..6);
}
#[test]
fn test_drain_range() {
let mut v = thin_vec![1, 2, 3, 4, 5];
for _ in v.drain(4..) {}
assert_eq!(v, &[1, 2, 3, 4]);
let mut v: ThinVec<_> = (1..6).map(|x| x.to_string()).collect();
for _ in v.drain(1..4) {}
assert_eq!(v, &[1.to_string(), 5.to_string()]);
let mut v: ThinVec<_> = (1..6).map(|x| x.to_string()).collect();
for _ in v.drain(1..4).rev() {}
assert_eq!(v, &[1.to_string(), 5.to_string()]);
let mut v: ThinVec<_> = thin_vec![(); 5];
for _ in v.drain(1..4).rev() {}
assert_eq!(v, &[(), ()]);
}
#[test]
fn test_drain_inclusive_range() {
let mut v = thin_vec!['a', 'b', 'c', 'd', 'e'];
for _ in v.drain(1..=3) {}
assert_eq!(v, &['a', 'e']);
let mut v: ThinVec<_> = (0..=5).map(|x| x.to_string()).collect();
for _ in v.drain(1..=5) {}
assert_eq!(v, &["0".to_string()]);
let mut v: ThinVec<String> = (0..=5).map(|x| x.to_string()).collect();
for _ in v.drain(0..=5) {}
assert_eq!(v, ThinVec::<String>::new());
let mut v: ThinVec<_> = (0..=5).map(|x| x.to_string()).collect();
for _ in v.drain(0..=3) {}
assert_eq!(v, &["4".to_string(), "5".to_string()]);
let mut v: ThinVec<_> = (0..=1).map(|x| x.to_string()).collect();
for _ in v.drain(..=0) {}
assert_eq!(v, &["1".to_string()]);
}
#[test]
#[cfg(not(feature = "gecko-ffi"))]
fn test_drain_max_vec_size() {
let mut v = ThinVec::<()>::with_capacity(usize::max_value());
unsafe {
v.set_len(usize::max_value());
}
for _ in v.drain(usize::max_value() - 1..) {}
assert_eq!(v.len(), usize::max_value() - 1);
let mut v = ThinVec::<()>::with_capacity(usize::max_value());
unsafe {
v.set_len(usize::max_value());
}
for _ in v.drain(usize::max_value() - 1..=usize::max_value() - 1) {}
assert_eq!(v.len(), usize::max_value() - 1);
}
#[test]
#[should_panic]
fn test_drain_inclusive_out_of_bounds() {
let mut v = thin_vec![1, 2, 3, 4, 5];
v.drain(5..=5);
}
#[test]
fn test_append() {
let mut vec = thin_vec![1, 2, 3];
let mut vec2 = thin_vec![4, 5, 6];
vec.append(&mut vec2);
assert_eq!(vec, [1, 2, 3, 4, 5, 6]);
assert_eq!(vec2, []);
}
#[test]
fn test_split_off() {
let mut vec = thin_vec![1, 2, 3, 4, 5, 6];
let vec2 = vec.split_off(4);
assert_eq!(vec, [1, 2, 3, 4]);
assert_eq!(vec2, [5, 6]);
}
#[test]
fn test_reserve_exact() {
let mut v = ThinVec::new();
assert_eq!(v.capacity(), 0);
v.reserve_exact(2);
assert!(v.capacity() >= 2);
for i in 0..16 {
v.push(i);
}
assert!(v.capacity() >= 16);
v.reserve_exact(16);
assert!(v.capacity() >= 32);
v.push(16);
v.reserve_exact(16);
assert!(v.capacity() >= 33)
}
#[test]
#[cfg_attr(feature = "gecko-ffi", ignore)]
fn test_header_data() {
macro_rules! assert_aligned_head_ptr {
($typename:ty) => {{
let v: ThinVec<$typename> = ThinVec::with_capacity(1 );
let head_ptr: *mut $typename = v.data_raw();
assert_eq!(
head_ptr as usize % std::mem::align_of::<$typename>(),
0,
"expected Header::data<{}> to be aligned",
stringify!($typename)
);
}};
}
const HEADER_SIZE: usize = std::mem::size_of::<Header>();
assert_eq!(2 * std::mem::size_of::<usize>(), HEADER_SIZE);
#[repr(C, align(128))]
struct Funky<T>(T);
assert_eq!(padding::<Funky<()>>(), 128 - HEADER_SIZE);
assert_aligned_head_ptr!(Funky<()>);
assert_eq!(padding::<Funky<u8>>(), 128 - HEADER_SIZE);
assert_aligned_head_ptr!(Funky<u8>);
assert_eq!(padding::<Funky<[(); 1024]>>(), 128 - HEADER_SIZE);
assert_aligned_head_ptr!(Funky<[(); 1024]>);
assert_eq!(padding::<Funky<[*mut usize; 1024]>>(), 128 - HEADER_SIZE);
assert_aligned_head_ptr!(Funky<[*mut usize; 1024]>);
}
#[cfg(feature = "serde")]
use serde_test::{assert_tokens, Token};
#[test]
#[cfg(feature = "serde")]
fn test_ser_de_empty() {
let vec = ThinVec::<u32>::new();
assert_tokens(&vec, &[Token::Seq { len: Some(0) }, Token::SeqEnd]);
}
#[test]
#[cfg(feature = "serde")]
fn test_ser_de() {
let mut vec = ThinVec::<u32>::new();
vec.push(20);
vec.push(55);
vec.push(123);
assert_tokens(
&vec,
&[
Token::Seq { len: Some(3) },
Token::U32(20),
Token::U32(55),
Token::U32(123),
Token::SeqEnd,
],
);
}
#[test]
fn test_set_len() {
let mut vec: ThinVec<u32> = thin_vec![];
unsafe {
vec.set_len(0); }
}
#[test]
#[should_panic(expected = "invalid set_len(1) on empty ThinVec")]
fn test_set_len_invalid() {
let mut vec: ThinVec<u32> = thin_vec![];
unsafe {
vec.set_len(1);
}
}
}