//! `ThinVec` is exactly the same as `Vec`, except that it stores its `len` and `capacity` in the buffer //! it allocates. //! //! This makes the memory footprint of ThinVecs lower; notably in cases where space is reserved for //! a non-existence `ThinVec<T>`. So `Vec<ThinVec<T>>` and `Option<ThinVec<T>>::None` will waste less //! space. Being pointer-sized also means it can be passed/stored in registers. //! //! Of course, any actually constructed `ThinVec` will theoretically have a bigger allocation, but //! the fuzzy nature of allocators means that might not actually be the case. //! //! Properties of `Vec` that are preserved: //! * `ThinVec::new()` doesn't allocate (it points to a statically allocated singleton) //! * reallocation can be done in place //! * `size_of::<ThinVec<T>>()` == `size_of::<Option<ThinVec<T>>>()` //! //! Properties of `Vec` that aren't preserved: //! * `ThinVec<T>` can't ever be zero-cost roundtripped to a `Box<[T]>`, `String`, or `*mut T` //! * `from_raw_parts` doesn't exist //! * `ThinVec` currently doesn't bother to not-allocate for Zero Sized Types (e.g. `ThinVec<()>`), //! but it could be done if someone cared enough to implement it. //! //! //! # Optional Features //! //! ## `const_new` //! //! **This feature requires Rust 1.83.** //! //! This feature makes `ThinVec::new()` a `const fn`. //! //! //! # Gecko FFI //! //! If you enable the gecko-ffi feature, `ThinVec` will verbatim bridge with the nsTArray type in //! Gecko (Firefox). That is, `ThinVec` and nsTArray have identical layouts *but not ABIs*, //! so nsTArrays/ThinVecs an be natively manipulated by C++ and Rust, and ownership can be //! transferred across the FFI boundary (**IF YOU ARE CAREFUL, SEE BELOW!!**). //! //! While this feature is handy, it is also inherently dangerous to use because Rust and C++ do not //! know about each other. Specifically, this can be an issue with non-POD types (types which //! have destructors, move constructors, or are `!Copy`). //! //! ## Do Not Pass By Value //! //! The biggest thing to keep in mind is that **FFI functions cannot pass ThinVec/nsTArray //! by-value**. That is, these are busted APIs: //! //! ```rust,ignore //! // BAD WRONG //! extern fn process_data(data: ThinVec<u32>) { ... } //! // BAD WRONG //! extern fn get_data() -> ThinVec<u32> { ... } //! ``` //! //! You must instead pass by-reference: //! //! ```rust //! # use thin_vec::*; //! # use std::mem; //! //! // Read-only access, ok! //! extern fn process_data(data: &ThinVec<u32>) { //! for val in data { //! println!("{}", val); //! } //! } //! //! // Replace with empty instance to take ownership, ok! //! extern fn consume_data(data: &mut ThinVec<u32>) { //! let owned = mem::replace(data, ThinVec::new()); //! mem::drop(owned); //! } //! //! // Mutate input, ok! //! extern fn add_data(dataset: &mut ThinVec<u32>) { //! dataset.push(37); //! dataset.push(12); //! } //! //! // Return via out-param, usually ok! //! // //! // WARNING: output must be initialized! (Empty nsTArrays are free, so just do it!) //! extern fn get_data(output: &mut ThinVec<u32>) { //! *output = thin_vec![1, 2, 3, 4, 5]; //! } //! ``` //! //! Ignorable Explanation For Those Who Really Want To Know Why: //! //! > The fundamental issue is that Rust and C++ can't currently communicate about destructors, and //! > the semantics of C++ require destructors of function arguments to be run when the function //! > returns. Whether the callee or caller is responsible for this is also platform-specific, so //! > trying to hack around it manually would be messy. //! > //! > Also a type having a destructor changes its C++ ABI, because that type must actually exist //! > in memory (unlike a trivial struct, which is often passed in registers). We don't currently //! > have a way to communicate to Rust that this is happening, so even if we worked out the //! > destructor issue with say, MaybeUninit, it would still be a non-starter without some RFCs //! > to add explicit rustc support. //! > //! > Realistically, the best answer here is to have a "heavier" bindgen that can secretly //! > generate FFI glue so we can pass things "by value" and have it generate by-reference code //! > behind our back (like the cxx crate does). This would muddy up debugging/searchfox though. //! //! ## Types Should Be Trivially Relocatable //! //! Types in Rust are always trivially relocatable (unless suitably borrowed/[pinned][]/hidden). //! This means all Rust types are legal to relocate with a bitwise copy, you cannot provide //! copy or move constructors to execute when this happens, and the old location won't have its //! destructor run. This will cause problems for types which have a significant location //! (types that intrusively point into themselves or have their location registered with a service). //! //! While relocations are generally predictable if you're very careful, **you should avoid using //! types with significant locations with Rust FFI**. //! //! Specifically, `ThinVec` will trivially relocate its contents whenever it needs to reallocate its //! buffer to change its capacity. This is the default reallocation strategy for nsTArray, and is //! suitable for the vast majority of types. Just be aware of this limitation! //! //! ## Auto Arrays Are Dangerous //! //! `ThinVec` has *some* support for handling auto arrays which store their buffer on the stack, //! but this isn't well tested. //! //! Regardless of how much support we provide, Rust won't be aware of the buffer's limited lifetime, //! so standard auto array safety caveats apply about returning/storing them! `ThinVec` won't ever //! produce an auto array on its own, so this is only an issue for transferring an nsTArray into //! Rust. //! //! ## Other Issues //! //! Standard FFI caveats also apply: //! //! * Rust is more strict about POD types being initialized (use MaybeUninit if you must) //! * `ThinVec<T>` has no idea if the C++ version of `T` has move/copy/assign/delete overloads //! * `nsTArray<T>` has no idea if the Rust version of `T` has a Drop/Clone impl //! * C++ can do all sorts of unsound things that Rust can't catch //! * C++ and Rust don't agree on how zero-sized/empty types should be handled //! //! The gecko-ffi feature will not work if you aren't linking with code that has nsTArray //! defined. Specifically, we must share the symbol for nsTArray's empty singleton. You will get //! linking errors if that isn't defined. //! //! The gecko-ffi feature also limits `ThinVec` to the legacy behaviors of nsTArray. Most notably, //! nsTArray has a maximum capacity of i32::MAX (~2.1 billion items). Probably not an issue. //! Probably. //! //! [pinned]: https://doc.rust-lang.org/std/pin/index.html
use alloc::alloc::*; use alloc::{boxed::Box, vec::Vec}; use core::borrow::*; use core::cmp::*; use core::convert::TryFrom; use core::convert::TryInto; use core::hash::*; use core::iter::FromIterator; use core::marker::PhantomData; use core::ops::Bound; use core::ops::{Deref, DerefMut, RangeBounds}; use core::ptr::NonNull; use core::slice::Iter; use core::{fmt, mem, ops, ptr, slice};
use impl_details::*;
#[cfg(feature = "malloc_size_of")] use malloc_size_of::{MallocShallowSizeOf, MallocSizeOf, MallocSizeOfOps};
// modules: a simple way to cfg a whole bunch of impl details at once
#[cfg(feature = "gecko-ffi")] mod impl_details { // Support for briding a gecko nsTArray verbatim into a ThinVec. // // `ThinVec` can't see copy/move/delete implementations // from C++ // // The actual layout of an nsTArray is: // // ```cpp // struct { // uint32_t mLength; // uint32_t mCapacity: 31; // uint32_t mIsAutoArray : 1; // } // ``` // // Rust doesn't natively support bit-fields, so we manually mask // and shift the bit. When the "auto" bit is set, the header and buffer // are actually on the stack, meaning the `ThinVec` pointer-to-header // is essentially an "owned borrow", and therefore dangerous to handle. // There are no safety guards for this situation. // // On little-endian platforms, the auto bit will be the high-bit of // our capacity u32. On big-endian platforms, it will be the low bit. // Hence we need some platform-specific CFGs for the necessary masking/shifting. // // Handling the auto bit mostly just means not freeing/reallocating the buffer.
pubtype SizeType = u32;
pubconst MAX_CAP: usize = i32::max_value() as usize;
// See kAutoTArrayHeaderOffset pubconst AUTO_ARRAY_HEADER_OFFSET: usize = 8;
// Little endian: the auto bit is the high bit, and the capacity is // verbatim. So we just need to mask off the high bit. Note that // this masking is unnecessary when packing, because assert_size // guards against the high bit being set. #[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 = "little")] pub fn pack_capacity_and_auto(cap: SizeType, auto: bool) -> SizeType {
cap | ((auto as SizeType) << 31)
}
// Big endian: the auto bit is the low bit, and the capacity is // shifted up one bit. Masking out the auto bit is unnecessary, // as rust shifts always shift in 0's for unsigned integers. #[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
} #[cfg(target_endian = "big")] pub fn pack_capacity_and_auto(cap: SizeType, auto: bool) -> SizeType {
(cap << 1) | (auto as SizeType)
}
#[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
}
}
// The header of a ThinVec. // // The _cap can be a bitfield, so use accessors to avoid trouble. // // In "real" gecko-ffi mode, the empty singleton will be aligned // to 8 by gecko. But in tests we have to provide the singleton // ourselves, and Rust makes it hard to "just" align a static. // To avoid messing around with a wrapper type around the // singleton *just* for tests, we just force all headers to be // aligned to 8 in this weird "zombie" gecko mode. // // This shouldn't affect runtime layout (padding), but it will // result in us asking the allocator to needlessly overalign // non-empty ThinVecs containing align < 8 types in // zombie-mode, but not in "real" geck-ffi mode. Minor. #[cfg_attr(all(feature = "gecko-ffi", any(test, miri)), repr(align(8)))] #[repr(C)] struct Header {
_len: SizeType,
_cap: SizeType,
}
/// Singleton that all empty collections share. /// Note: can't store non-zero ZSTs, we allocate in that case. We could /// optimize everything to not do that (basically, make ptr == len and branch /// on size == 0 in every method), but it's a bunch of work for something that /// doesn't matter much. #[cfg(any(not(feature = "gecko-ffi"), test, miri))] static EMPTY_HEADER: Header = Header { _len: 0, _cap: 0 };
/// Gets the size necessary to allocate a `ThinVec<T>` with the give capacity. /// /// # Panics /// /// This will panic if isize::MAX is overflowed at any point.
fn alloc_size<T>(cap: usize) -> usize { // Compute "real" header size with pointer math // // We turn everything into isizes here so that we can catch isize::MAX overflow, // we never want to allow allocations larger than that! let header_size = mem::size_of::<Header>() as isize; let padding = padding::<T>() as isize;
let data_size = if mem::size_of::<T>() == 0 { // If we're allocating an array for ZSTs we need a header/padding but no actual // space for items, so we don't care about the capacity that was requested! 0
} else { let cap: isize = cap.try_into().unwrap_cap_overflow(); let elem_size = mem::size_of::<T>() as isize;
elem_size.checked_mul(cap).unwrap_cap_overflow()
};
let final_size = data_size
.checked_add(header_size + padding)
.unwrap_cap_overflow();
// Ok now we can turn it back into a usize (don't need to worry about negatives)
final_size as usize
}
/// Gets the padding necessary for the array of a `ThinVec<T>`
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
}
}
/// Gets the align necessary to allocate a `ThinVec<T>`
fn alloc_align<T>() -> usize {
max(mem::align_of::<T>(), mem::align_of::<Header>())
}
/// Gets the layout necessary to allocate a `ThinVec<T>` /// /// # Panics /// /// Panics if the required size overflows `isize::MAX`.
fn layout<T>(cap: usize) -> Layout { unsafe { Layout::from_size_align_unchecked(alloc_size::<T>(cap), alloc_align::<T>()) }
}
/// Allocates a header (and array) for a `ThinVec<T>` with the given capacity. /// /// # Panics /// /// Panics if the required size overflows `isize::MAX`.
fn header_with_capacity<T>(cap: usize, is_auto: bool) -> 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)
}
ptr::write(
header,
Header {
_len: 0,
_cap: if mem::size_of::<T>() == 0 { // "Infinite" capacity for zero-sized types:
MAX_CAP as SizeType
} else {
pack_capacity_and_auto(assert_size(cap), is_auto)
},
},
);
NonNull::new_unchecked(header)
}
}
/// See the crate's top level documentation for a description of this type. #[repr(C)] pubstruct ThinVec<T> {
ptr: NonNull<Header>,
boo: PhantomData<T>,
}
unsafeimpl<T: Sync> Sync for ThinVec<T> {} unsafeimpl<T: Send> Send for ThinVec<T> {}
/// Creates a `ThinVec` containing the arguments. /// // A hack to avoid linking problems with `cargo test --features=gecko-ffi`. #[cfg_attr(not(feature = "gecko-ffi"), doc = "```")] #[cfg_attr(feature = "gecko-ffi", doc = "```ignore")] /// #[macro_use] extern crate thin_vec; /// /// fn main() { /// let v = thin_vec![1, 2, 3]; /// assert_eq!(v.len(), 3); /// assert_eq!(v[0], 1); /// assert_eq!(v[1], 2); /// assert_eq!(v[2], 3); /// /// let v = thin_vec![1; 3]; /// assert_eq!(v, [1, 1, 1]); /// } /// ``` #[macro_export]
macro_rules! thin_vec {
(@UNIT $($t:tt)*) => (());
impl<T> ThinVec<T> { /// Creates a new empty ThinVec. /// /// This will not allocate. #[cfg(not(feature = "const_new"))] pub fn new() -> ThinVec<T> {
ThinVec::with_capacity(0)
}
/// Creates a new empty ThinVec. /// /// This will not allocate. #[cfg(feature = "const_new")] pubconst fn new() -> ThinVec<T> { unsafe {
ThinVec {
ptr: NonNull::new_unchecked(&EMPTY_HEADER as *const Header as *mut Header),
boo: PhantomData,
}
}
}
/// Constructs a new, empty `ThinVec<T>` with at least the specified capacity. /// /// The vector will be able to hold at least `capacity` elements without /// reallocating. This method is allowed to allocate for more elements than /// `capacity`. If `capacity` is 0, the vector will not allocate. /// /// It is important to note that although the returned vector has the /// minimum *capacity* specified, the vector will have a zero *length*. /// /// If it is important to know the exact allocated capacity of a `ThinVec`, /// always use the [`capacity`] method after construction. /// /// **NOTE**: unlike `Vec`, `ThinVec` **MUST** allocate once to keep track of non-zero /// lengths. As such, we cannot provide the same guarantees about ThinVecs /// of ZSTs not allocating. However the allocation never needs to be resized /// to add more ZSTs, since the underlying array is still length 0. /// /// [Capacity and reallocation]: #capacity-and-reallocation /// [`capacity`]: Vec::capacity /// /// # Panics /// /// Panics if the new capacity exceeds `isize::MAX` bytes. /// /// # Examples /// /// ``` /// use thin_vec::ThinVec; /// /// let mut vec = ThinVec::with_capacity(10); /// /// // The vector contains no items, even though it has capacity for more /// assert_eq!(vec.len(), 0); /// assert!(vec.capacity() >= 10); /// /// // These are all done without reallocating... /// for i in 0..10 { /// vec.push(i); /// } /// assert_eq!(vec.len(), 10); /// assert!(vec.capacity() >= 10); /// /// // ...but this may make the vector reallocate /// vec.push(11); /// assert_eq!(vec.len(), 11); /// assert!(vec.capacity() >= 11); /// /// // A vector of a zero-sized type will always over-allocate, since no /// // space is needed to store the actual elements. /// let vec_units = ThinVec::<()>::with_capacity(10); /// /// // Only true **without** the gecko-ffi feature! /// // assert_eq!(vec_units.capacity(), usize::MAX); /// ``` pub fn with_capacity(cap: usize) -> ThinVec<T> { // `padding` contains ~static assertions against types that are // incompatible with the current feature flags. We also call it to // invoke these assertions when getting a pointer to the `ThinVec` // contents, but since we also get a pointer to the contents in the // `Drop` impl, trippng an assertion along that code path causes a // double panic. We duplicate the assertion here so that it is // testable, 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, false),
boo: PhantomData,
}
}
}
// Accessor conveniences
fn ptr(&self) -> *mut Header { self.ptr.as_ptr()
}
fn header(&self) -> &Header { unsafe { self.ptr.as_ref() }
}
fn data_raw(&self) -> *mut T { // `padding` contains ~static assertions against types that are // incompatible with the current feature flags. Even if we don't // care about its result, we should always call it before getting // a data pointer to guard against invalid types! let padding = padding::<T>();
// Although we ensure the data array is aligned when we allocate, // we can't do that with the empty singleton. So when it might not // be properly aligned, we substitute in the NonNull::dangling // which *is* aligned. // // To minimize dynamic branches on `cap` for all accesses // to the data, we include this guard which should only involve // compile-time constants. Ideally this should result in the branch // only be included for types with excessive alignment. let empty_header_is_aligned = if cfg!(feature = "gecko-ffi") { // in gecko-ffi mode `padding` will ensure this under // the assumption that the header has size 8 and the // static empty singleton is aligned to 8. true
} else { // In non-gecko-ffi mode, the empty singleton is just // naturally aligned to the Header. If the Header is at // least as aligned as T *and* the padding would have // been 0, then one-past-the-end of the empty singleton // *is* a valid data pointer and we can remove the // `dangling` special case.
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 { // This could technically result in overflow, but padding // would have to be absurdly large for this to occur. let header_size = mem::size_of::<Header>(); let ptr = self.ptr.as_ptr() as *mut u8;
ptr.add(header_size + padding) as *mut T
}
}
}
// This is unsafe when the header is EMPTY_HEADER. unsafe fn header_mut(&mutself) -> &mut Header {
&mut *self.ptr()
}
/// Returns the number of elements in the vector, also referred to /// as its 'length'. /// /// # Examples /// /// ``` /// use thin_vec::thin_vec; /// /// let a = thin_vec![1, 2, 3]; /// assert_eq!(a.len(), 3); /// ``` pub fn len(&self) -> usize { self.header().len()
}
/// Returns `true` if the vector contains no elements. /// /// # Examples /// /// ``` /// use thin_vec::ThinVec; /// /// let mut v = ThinVec::new(); /// assert!(v.is_empty()); /// /// v.push(1); /// assert!(!v.is_empty()); /// ``` pub fn is_empty(&self) -> bool { self.len() == 0
}
/// Returns the number of elements the vector can hold without /// reallocating. /// /// # Examples /// /// ``` /// use thin_vec::ThinVec; /// /// let vec: ThinVec<i32> = ThinVec::with_capacity(10); /// assert_eq!(vec.capacity(), 10); /// ``` pub fn capacity(&self) -> usize { self.header().cap()
}
/// Returns `true` if the vector has the capacity to hold any element. pub fn has_capacity(&self) -> bool {
!self.is_singleton()
}
/// Forces the length of the vector to `new_len`. /// /// This is a low-level operation that maintains none of the normal /// invariants of the type. Normally changing the length of a vector /// is done using one of the safe operations instead, such as /// [`truncate`], [`resize`], [`extend`], or [`clear`]. /// /// [`truncate`]: ThinVec::truncate /// [`resize`]: ThinVec::resize /// [`extend`]: ThinVec::extend /// [`clear`]: ThinVec::clear /// /// # Safety /// /// - `new_len` must be less than or equal to [`capacity()`]. /// - The elements at `old_len..new_len` must be initialized. /// /// [`capacity()`]: ThinVec::capacity /// /// # Examples /// /// This method can be useful for situations in which the vector /// is serving as a buffer for other code, particularly over FFI: /// /// ```no_run /// use thin_vec::ThinVec; /// /// # // This is just a minimal skeleton for the doc example; /// # // don't use this as a starting point for a real library. /// # pub struct StreamWrapper { strm: *mut std::ffi::c_void } /// # const Z_OK: i32 = 0; /// # extern "C" { /// # fn deflateGetDictionary( /// # strm: *mut std::ffi::c_void, /// # dictionary: *mut u8, /// # dictLength: *mut usize, /// # ) -> i32; /// # } /// # impl StreamWrapper { /// pub fn get_dictionary(&self) -> Option<ThinVec<u8>> { /// // Per the FFI method's docs, "32768 bytes is always enough". /// let mut dict = ThinVec::with_capacity(32_768); /// let mut dict_length = 0; /// // SAFETY: When `deflateGetDictionary` returns `Z_OK`, it holds that: /// // 1. `dict_length` elements were initialized. /// // 2. `dict_length` <= the capacity (32_768) /// // which makes `set_len` safe to call. /// unsafe { /// // Make the FFI call... /// let r = deflateGetDictionary(self.strm, dict.as_mut_ptr(), &mut dict_length); /// if r == Z_OK { /// // ...and update the length to what was initialized. /// dict.set_len(dict_length); /// Some(dict) /// } else { /// None /// } /// } /// } /// # } /// ``` /// /// While the following example is sound, there is a memory leak since /// the inner vectors were not freed prior to the `set_len` call: /// /// ```no_run /// use thin_vec::thin_vec; /// /// let mut vec = thin_vec![thin_vec![1, 0, 0], /// thin_vec![0, 1, 0], /// thin_vec![0, 0, 1]]; /// // SAFETY: /// // 1. `old_len..0` is empty so no elements need to be initialized. /// // 2. `0 <= capacity` always holds whatever `capacity` is. /// unsafe { /// vec.set_len(0); /// } /// ``` /// /// Normally, here, one would use [`clear`] instead to correctly drop /// the contents and thus not leak memory. pubunsafe fn set_len(&mutself, len: usize) { ifself.is_singleton() { // A prerequisite of `Vec::set_len` is that `new_len` must be // less than or equal to capacity(). The same applies here.
debug_assert!(len == 0, "invalid set_len({}) on empty ThinVec", len);
} else { self.header_mut().set_len(len)
}
}
// For internal use only, when setting the length and it's known to be the non-singleton. unsafe fn set_len_non_singleton(&mutself, len: usize) { self.header_mut().set_len(len)
}
/// Appends an element to the back of a collection. /// /// # Panics /// /// Panics if the new capacity exceeds `isize::MAX` bytes. /// /// # Examples /// /// ``` /// use thin_vec::thin_vec; /// /// let mut vec = thin_vec![1, 2]; /// vec.push(3); /// assert_eq!(vec, [1, 2, 3]); /// ``` pub fn push(&mutself, val: T) { let old_len = self.len(); if old_len == self.capacity() { self.reserve(1);
} unsafe { // SAFETY: reserve() ensures sufficient capacity. self.push_unchecked(val);
}
}
/// Appends an element to the back like `push`, /// but assumes that sufficient capacity has already been reserved, i.e. /// `len() < capacity()`. /// /// # Safety /// /// - Capacity must be reserved in advance such that `capacity() > len()`. #[inline] unsafe fn push_unchecked(&mutself, val: T) { let old_len = self.len();
debug_assert!(old_len < self.capacity()); unsafe {
ptr::write(self.data_raw().add(old_len), val);
// SAFETY: capacity > len >= 0, so capacity != 0, so this is not a singleton. self.set_len_non_singleton(old_len + 1);
}
}
/// Removes the last element from a vector and returns it, or [`None`] if it /// is empty. /// /// # Examples /// /// ``` /// use thin_vec::thin_vec; /// /// let mut vec = thin_vec![1, 2, 3]; /// assert_eq!(vec.pop(), Some(3)); /// assert_eq!(vec, [1, 2]); /// ``` pub fn pop(&mutself) -> Option<T> { let old_len = self.len(); if old_len == 0 { return None;
}
/// Inserts an element at position `index` within the vector, shifting all /// elements after it to the right. /// /// # Panics /// /// Panics if `index > len`. /// /// # Examples /// /// ``` /// use thin_vec::thin_vec; /// /// let mut vec = thin_vec![1, 2, 3]; /// vec.insert(1, 4); /// assert_eq!(vec, [1, 4, 2, 3]); /// vec.insert(4, 5); /// assert_eq!(vec, [1, 4, 2, 3, 5]); /// ``` pub fn insert(&mutself, 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);
}
}
/// Removes and returns the element at position `index` within the vector, /// shifting all elements after it to the left. /// /// Note: Because this shifts over the remaining elements, it has a /// worst-case performance of *O*(*n*). If you don't need the order of elements /// to be preserved, use [`swap_remove`] instead. If you'd like to remove /// elements from the beginning of the `ThinVec`, consider using `std::collections::VecDeque`. /// /// [`swap_remove`]: ThinVec::swap_remove /// /// # Panics /// /// Panics if `index` is out of bounds. /// /// # Examples /// /// ``` /// use thin_vec::thin_vec; /// /// let mut v = thin_vec![1, 2, 3]; /// assert_eq!(v.remove(1), 2); /// assert_eq!(v, [1, 3]); /// ``` pub fn remove(&mutself, 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
}
}
/// Removes an element from the vector and returns it. /// /// The removed element is replaced by the last element of the vector. /// /// This does not preserve ordering, but is *O*(1). /// If you need to preserve the element order, use [`remove`] instead. /// /// [`remove`]: ThinVec::remove /// /// # Panics /// /// Panics if `index` is out of bounds. /// /// # Examples /// /// ``` /// use thin_vec::thin_vec; /// /// let mut v = thin_vec!["foo", "bar", "baz", "qux"]; /// /// assert_eq!(v.swap_remove(1), "bar"); /// assert_eq!(v, ["foo", "qux", "baz"]); /// /// assert_eq!(v.swap_remove(0), "foo"); /// assert_eq!(v, ["baz", "qux"]); /// ``` pub fn swap_remove(&mutself, idx: usize) -> T { let old_len = self.len();
/// Shortens the vector, keeping the first `len` elements and dropping /// the rest. /// /// If `len` is greater than the vector's current length, this has no /// effect. /// /// The [`drain`] method can emulate `truncate`, but causes the excess /// elements to be returned instead of dropped. /// /// Note that this method has no effect on the allocated capacity /// of the vector. /// /// # Examples /// /// Truncating a five element vector to two elements: /// /// ``` /// use thin_vec::thin_vec; /// /// let mut vec = thin_vec![1, 2, 3, 4, 5]; /// vec.truncate(2); /// assert_eq!(vec, [1, 2]); /// ``` /// /// No truncation occurs when `len` is greater than the vector's current /// length: /// /// ``` /// use thin_vec::thin_vec; /// /// let mut vec = thin_vec![1, 2, 3]; /// vec.truncate(8); /// assert_eq!(vec, [1, 2, 3]); /// ``` /// /// Truncating when `len == 0` is equivalent to calling the [`clear`] /// method. /// /// ``` /// use thin_vec::thin_vec; /// /// let mut vec = thin_vec![1, 2, 3]; /// vec.truncate(0); /// assert_eq!(vec, []); /// ``` /// /// [`clear`]: ThinVec::clear /// [`drain`]: ThinVec::drain pub fn truncate(&mutself, len: usize) { unsafe { // drop any extra elements while len < self.len() { // decrement len before the drop_in_place(), so a panic on Drop // doesn't re-drop the just-failed value. let new_len = self.len() - 1; self.set_len_non_singleton(new_len);
ptr::drop_in_place(self.data_raw().add(new_len));
}
}
}
/// Clears the vector, removing all values. /// /// Note that this method has no effect on the allocated capacity /// of the vector. /// /// # Examples /// /// ``` /// use thin_vec::thin_vec; /// /// let mut v = thin_vec![1, 2, 3]; /// v.clear(); /// assert!(v.is_empty()); /// ``` pub fn clear(&mutself) { unsafe { // Decrement len even in the case of a panic. struct DropGuard<'a, T>(&'a mut ThinVec<T>); impl<T> Drop for DropGuard<'_, T> {
fn drop(&mutself) { unsafe { // Could be the singleton. self.0.set_len(0);
}
}
} let guard = DropGuard(self);
ptr::drop_in_place(&mut guard.0[..]);
}
}
/// Extracts a slice containing the entire vector. /// /// Equivalent to `&s[..]`. /// /// # Examples /// /// ``` /// use thin_vec::thin_vec; /// use std::io::{self, Write}; /// let buffer = thin_vec![1, 2, 3, 5, 8]; /// io::sink().write(buffer.as_slice()).unwrap(); /// ``` pub fn as_slice(&self) -> &[T] { unsafe { slice::from_raw_parts(self.data_raw(), self.len()) }
}
/// Extracts a mutable slice of the entire vector. /// /// Equivalent to `&mut s[..]`. /// /// # Examples /// /// ``` /// use thin_vec::thin_vec; /// use std::io::{self, Read}; /// let mut buffer = vec![0; 3]; /// io::repeat(0b101).read_exact(buffer.as_mut_slice()).unwrap(); /// ``` pub fn as_mut_slice(&mutself) -> &mut [T] { unsafe { slice::from_raw_parts_mut(self.data_raw(), self.len()) }
}
/// Reserve capacity for at least `additional` more elements to be inserted. /// /// May reserve more space than requested, to avoid frequent reallocations. /// /// Panics if the new capacity overflows `usize`. /// /// Re-allocates only if `self.capacity() < self.len() + additional`. #[cfg(not(feature = "gecko-ffi"))] pub fn reserve(&mutself, additional: usize) { let len = self.len(); let old_cap = self.capacity(); let min_cap = len.checked_add(additional).unwrap_cap_overflow(); if min_cap <= old_cap { return;
} // Ensure the new capacity is at least double, to guarantee exponential growth. let double_cap = if old_cap == 0 { // skip to 4 because tiny ThinVecs are dumb; but not if that would cause overflow 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);
}
}
/// Reserve capacity for at least `additional` more elements to be inserted. /// /// This method mimics the growth algorithm used by the C++ implementation /// of nsTArray. #[cfg(feature = "gecko-ffi")] pub fn reserve(&mutself, 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).unwrap_cap_overflow(); if min_cap <= old_cap { return;
}
// The growth logic can't handle zero-sized types, so we have to exit // early here. 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();
// Perform some checked arithmetic to ensure all of the numbers we // compute will end up in range. let will_fit = min_cap_bytes.checked_mul(2).is_some(); if !will_fit {
panic!("Exceeded maximum nsTArray size");
}
let bytes = if min_cap > SLOW_GROWTH_THRESHOLD { // Grow by a minimum of 1.125x 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);
// Round up to the next megabyte. const MB: usize = 1 << 20;
MB * ((growth + MB - 1) / MB)
} else { // Try to allocate backing buffers in powers of two.
min_cap_bytes.next_power_of_two() as usize
};
let cap = (bytes - core::mem::size_of::<Header>()) / elem_size; unsafe { self.reallocate(cap);
}
}
/// Reserves the minimum capacity for `additional` more elements to be inserted. /// /// Panics if the new capacity overflows `usize`. /// /// Re-allocates only if `self.capacity() < self.len() + additional`. pub fn reserve_exact(&mutself, additional: usize) { let new_cap = self.len().checked_add(additional).unwrap_cap_overflow(); let old_cap = self.capacity(); if new_cap > old_cap { unsafe { self.reallocate(new_cap);
}
}
}
/// Shrinks the capacity of the vector as much as possible. /// /// It will drop down as close as possible to the length but the allocator /// may still inform the vector that there is space for a few more elements. /// /// # Examples /// /// ``` /// use thin_vec::ThinVec; /// /// let mut vec = ThinVec::with_capacity(10); /// vec.extend([1, 2, 3]); /// assert_eq!(vec.capacity(), 10); /// vec.shrink_to_fit(); /// assert!(vec.capacity() >= 3); /// ``` pub fn shrink_to_fit(&mutself) { let old_cap = self.capacity(); let new_cap = self.len(); if new_cap >= old_cap { return;
} #[cfg(feature = "gecko-ffi")] unsafe { let stack_buf = self.auto_array_header_mut(); if !stack_buf.is_null() && (*stack_buf).cap() >= new_cap { // Try to switch to our auto-buffer. if stack_buf == self.ptr.as_ptr() { return;
}
stack_buf
.add(1)
.cast::<T>()
.copy_from_nonoverlapping(self.data_raw(), new_cap);
dealloc(self.ptr() as *mut u8, layout::<T>(old_cap)); self.ptr = NonNull::new_unchecked(stack_buf); self.ptr.as_mut().set_len(new_cap); return;
}
} if new_cap == 0 {
*self = ThinVec::new();
} else { unsafe { self.reallocate(new_cap);
}
}
}
/// Retains only the elements specified by the predicate. /// /// In other words, remove all elements `e` such that `f(&e)` returns `false`. /// This method operates in place and preserves the order of the retained /// elements. /// /// # Examples /// // A hack to avoid linking problems with `cargo test --features=gecko-ffi`. #[cfg_attr(not(feature = "gecko-ffi"), doc = "```")] #[cfg_attr(feature = "gecko-ffi", doc = "```ignore")] /// # #[macro_use] extern crate thin_vec; /// # fn main() { /// let mut vec = thin_vec![1, 2, 3, 4]; /// vec.retain(|&x| x%2 == 0); /// assert_eq!(vec, [2, 4]); /// # } /// ``` pub fn retain<F>(&mutself, mut f: F) where
F: FnMut(&T) -> bool,
{ self.retain_mut(|x| f(&*x));
}
/// Retains only the elements specified by the predicate, passing a mutable reference to it. /// /// In other words, remove all elements `e` such that `f(&mut e)` returns `false`. /// This method operates in place and preserves the order of the retained /// elements. /// /// # Examples /// // A hack to avoid linking problems with `cargo test --features=gecko-ffi`. #[cfg_attr(not(feature = "gecko-ffi"), doc = "```")] #[cfg_attr(feature = "gecko-ffi", doc = "```ignore")] /// # #[macro_use] extern crate thin_vec; /// # fn main() { /// let mut vec = thin_vec![1, 2, 3, 4, 5]; /// vec.retain_mut(|x| { /// *x += 1; /// (*x)%2 == 0 /// }); /// assert_eq!(vec, [2, 4, 6]); /// # } /// ``` pub fn retain_mut<F>(&mutself, mut f: F) where
F: FnMut(&mut T) -> bool,
{ let len = self.len(); letmut del = 0;
{ let v = &mutself[..];
for i in 0..len { if !f(&mut v[i]) {
del += 1;
} elseif del > 0 {
v.swap(i - del, i);
}
}
} if del > 0 { self.truncate(len - del);
}
}
/// Removes consecutive elements in the vector that resolve to the same key. /// /// If the vector is sorted, this removes all duplicates. /// /// # Examples /// // A hack to avoid linking problems with `cargo test --features=gecko-ffi`. #[cfg_attr(not(feature = "gecko-ffi"), doc = "```")] #[cfg_attr(feature = "gecko-ffi", doc = "```ignore")] /// # #[macro_use] extern crate thin_vec; /// # fn main() { /// let mut vec = thin_vec![10, 20, 21, 30, 20]; /// /// vec.dedup_by_key(|i| *i / 10); /// /// assert_eq!(vec, [10, 20, 30, 20]); /// # } /// ``` pub fn dedup_by_key<F, K>(&mutself, mut key: F) where
F: FnMut(&mut T) -> K,
K: PartialEq<K>,
{ self.dedup_by(|a, b| key(a) == key(b))
}
/// Removes consecutive elements in the vector according to a predicate. /// /// The `same_bucket` function is passed references to two elements from the vector, and /// returns `true` if the elements compare equal, or `false` if they do not. Only the first /// of adjacent equal items is kept. /// /// If the vector is sorted, this removes all duplicates. /// /// # Examples /// // A hack to avoid linking problems with `cargo test --features=gecko-ffi`. #[cfg_attr(not(feature = "gecko-ffi"), doc = "```")] #[cfg_attr(feature = "gecko-ffi", doc = "```ignore")] /// # #[macro_use] extern crate thin_vec; /// # fn main() { /// 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"]); /// # } /// ``` #[allow(clippy::swap_ptr_to_ref)] pub fn dedup_by<F>(&mutself, mut same_bucket: F) where
F: FnMut(&mut T, &mut T) -> bool,
{ // See the comments in `Vec::dedup` for a detailed explanation of this code. unsafe { let ln = self.len(); if ln <= 1 { return;
}
// Avoid bounds checks by using raw pointers. let p = self.as_mut_ptr(); letmut r: usize = 1; letmut 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);
}
}
/// Splits the collection into two at the given index. /// /// Returns a newly allocated vector containing the elements in the range /// `[at, len)`. After the call, the original vector will be left containing /// the elements `[0, at)` with its previous capacity unchanged. /// /// # Panics /// /// Panics if `at > len`. /// /// # Examples /// /// ``` /// use thin_vec::thin_vec; /// /// let mut vec = thin_vec![1, 2, 3]; /// let vec2 = vec.split_off(1); /// assert_eq!(vec, [1]); /// assert_eq!(vec2, [2, 3]); /// ``` pub fn split_off(&mutself, at: usize) -> ThinVec<T> { let old_len = self.len(); let new_vec_len = old_len - at;
new_vec.set_len(new_vec_len); // could be the singleton self.set_len(at); // could be the singleton
new_vec
}
}
/// Moves all the elements of `other` into `self`, leaving `other` empty. /// /// # Panics /// /// Panics if the new capacity exceeds `isize::MAX` bytes. /// /// # Examples /// /// ``` /// use thin_vec::thin_vec; /// /// 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, []); /// ``` pub fn append(&mutself, other: &mut ThinVec<T>) { self.extend(other.drain(..))
}
/// Removes the specified range from the vector in bulk, returning all /// removed elements as an iterator. If the iterator is dropped before /// being fully consumed, it drops the remaining removed elements. /// /// The returned iterator keeps a mutable borrow on the vector to optimize /// its implementation. /// /// # Panics /// /// Panics if the starting point is greater than the end point or if /// the end point is greater than the length of the vector. /// /// # Leaking /// /// If the returned iterator goes out of scope without being dropped (due to /// [`mem::forget`], for example), the vector may have lost and leaked /// elements arbitrarily, including elements outside the range. /// /// # Examples /// /// ``` /// use thin_vec::{ThinVec, thin_vec}; /// /// let mut v = thin_vec![1, 2, 3]; /// let u: ThinVec<_> = v.drain(1..).collect(); /// assert_eq!(v, &[1]); /// assert_eq!(u, &[2, 3]); /// /// // A full range clears the vector, like `clear()` does /// v.drain(..); /// assert_eq!(v, &[]); /// ``` pub fn drain<R>(&mutself, range: R) -> Drain<'_, T> where
R: RangeBounds<usize>,
{ // See comments in the Drain struct itself for details on this 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 { // Set our length to the start bound self.set_len(start); // could be the singleton
let iter = slice::from_raw_parts(self.data_raw().add(start), end - start).iter();
/// Creates a splicing iterator that replaces the specified range in the vector /// with the given `replace_with` iterator and yields the removed items. /// `replace_with` does not need to be the same length as `range`. /// /// `range` is removed even if the iterator is not consumed until the end. /// /// It is unspecified how many elements are removed from the vector /// if the `Splice` value is leaked. /// /// The input iterator `replace_with` is only consumed when the `Splice` value is dropped. /// /// This is optimal if: /// /// * The tail (elements in the vector after `range`) is empty, /// * or `replace_with` yields fewer or equal elements than `range`’s length /// * or the lower bound of its `size_hint()` is exact. /// /// Otherwise, a temporary vector is allocated and the tail is moved twice. /// /// # Panics /// /// Panics if the starting point is greater than the end point or if /// the end point is greater than the length of the vector. /// /// # Examples /// /// ``` /// use thin_vec::{ThinVec, thin_vec}; /// /// let mut v = thin_vec![1, 2, 3, 4]; /// let new = [7, 8, 9]; /// let u: ThinVec<_> = v.splice(1..3, new).collect(); /// assert_eq!(v, &[1, 7, 8, 9, 4]); /// assert_eq!(u, &[2, 3]); /// ``` #[inline] pub fn splice<R, I>(&mutself, range: R, replace_with: I) -> Splice<'_, I::IntoIter> where
R: RangeBounds<usize>,
I: IntoIterator<Item = T>,
{
Splice {
drain: self.drain(range),
replace_with: replace_with.into_iter(),
}
}
/// Creates an iterator which uses a closure to determine if an element should be removed. /// /// If the closure returns true, then the element is removed and yielded. /// If the closure returns false, the element will remain in the vector and will not be yielded /// by the iterator. /// /// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating /// or the iteration short-circuits, then the remaining elements will be retained. /// Use [`ThinVec::retain`] with a negated predicate if you do not need the returned iterator. /// /// Using this method is equivalent to the following code: /// /// ``` /// # use thin_vec::{ThinVec, thin_vec}; /// # let some_predicate = |x: &mut i32| { *x == 2 || *x == 3 || *x == 6 }; /// # let mut vec = thin_vec![1, 2, 3, 4, 5, 6]; /// let mut i = 0; /// while i < vec.len() { /// if some_predicate(&mut vec[i]) { /// let val = vec.remove(i); /// // your code here /// } else { /// i += 1; /// } /// } /// /// # assert_eq!(vec, thin_vec![1, 4, 5]); /// ``` /// /// But `extract_if` is easier to use. `extract_if` is also more efficient, /// because it can backshift the elements of the array in bulk. /// /// Note that `extract_if` also lets you mutate every element in the filter closure, /// regardless of whether you choose to keep or remove it. /// /// # Examples /// /// Splitting an array into evens and odds, reusing the original allocation: /// /// ``` /// use thin_vec::{ThinVec, thin_vec}; /// /// let mut numbers = thin_vec![1, 2, 3, 4, 5, 6, 8, 9, 11, 13, 14, 15]; /// /// let evens = numbers.extract_if(.., |x| *x % 2 == 0).collect::<ThinVec<_>>(); /// let odds = numbers; /// /// assert_eq!(evens, thin_vec![2, 4, 6, 8, 14]); /// assert_eq!(odds, thin_vec![1, 3, 5, 9, 11, 13, 15]); /// ``` pub fn extract_if<F, R: RangeBounds<usize>>(
&mutself,
range: R,
filter: F,
) -> ExtractIf<'_, T, F> where
F: FnMut(&mut T) -> bool,
{ // Copy of https://github.com/rust-lang/rust/blob/ee361e8fca1c30e13e7a31cc82b64c045339d3a8/library/core/src/slice/index.rs#L37
fn slice_index_fail(start: usize, end: usize, len: usize) -> ! { if start > len {
panic!( "range start index {} out of range for slice of length {}",
start, len
)
}
if end > len {
panic!( "range end index {} out of range for slice of length {}",
end, len
)
}
if start > end {
panic!("slice index starts at {} but ends at {}", start, end)
}
// Only reachable if the range was a `RangeInclusive` or a // `RangeToInclusive`, with `end == len`.
panic!( "range end index {} out of range for slice of length {}",
end, len
)
}
let end = match range.end_bound() {
ops::Bound::Included(&end) if end >= len => slice_index_fail(0, end, len), // Cannot overflow because `end < len` implies `end < usize::MAX`.
ops::Bound::Included(&end) => end + 1,
ops::Bound::Excluded(&end) if end > len => slice_index_fail(0, end, len),
ops::Bound::Excluded(&end) => end,
ops::Bound::Unbounded => len,
};
let start = match range.start_bound() {
ops::Bound::Excluded(&start) if start >= end => slice_index_fail(start, end, len), // Cannot overflow because `start < end` implies `start < usize::MAX`.
ops::Bound::Excluded(&start) => start + 1,
ops::Bound::Included(&start) if start > end => slice_index_fail(start, end, len),
ops::Bound::Included(&start) => start,
ops::Bound::Unbounded => 0,
};
ops::Range { start, end }
}
let old_len = self.len(); let ops::Range { start, end } = slice_range(range, ..old_len);
/// Resize the buffer and update its capacity, without changing the length. /// Unsafe because it can cause length to be greater than capacity. unsafe fn reallocate(&mutself, new_cap: usize) {
debug_assert!(new_cap > 0); ifself.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 we get here and have a non-zero len, then we must be handling // a gecko auto array, and we have items in a stack buffer. We shouldn't // free it, but we should memcopy the contents out of it and mark it as empty. // // T is assumed to be trivially relocatable, as this is ~required // for Rust compatibility anyway. Furthermore, we assume C++ won't try // to unconditionally destroy the contents of the stack allocated buffer // (i.e. it's obfuscated behind a union). // // In effect, we are partially reimplementing the auto array move constructor // by leaving behind a valid empty instance. 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);
new_header.as_mut().set_len(len);
}
impl<T: Clone> ThinVec<T> { /// Resizes the `Vec` in-place so that `len()` is equal to `new_len`. /// /// If `new_len` is greater than `len()`, the `Vec` is extended by the /// difference, with each additional slot filled with `value`. /// If `new_len` is less than `len()`, the `Vec` is simply truncated. /// /// # Examples /// // A hack to avoid linking problems with `cargo test --features=gecko-ffi`. #[cfg_attr(not(feature = "gecko-ffi"), doc = "```")] #[cfg_attr(feature = "gecko-ffi", doc = "```ignore")] /// # #[macro_use] extern crate thin_vec; /// # fn main() { /// let mut vec = thin_vec!["hello"]; /// vec.resize(3, "world"); /// assert_eq!(vec, ["hello", "world", "world"]); /// /// let mut vec = thin_vec![1, 2, 3, 4]; /// vec.resize(2, 0); /// assert_eq!(vec, [1, 2]); /// # } /// ``` pub fn resize(&mutself, 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());
} // We can write the last element directly without cloning needlessly if additional > 0 { self.push(value);
}
} elseif new_len < old_len { self.truncate(new_len);
}
}
/// Clones and appends all elements in a slice to the `ThinVec`. /// /// Iterates over the slice `other`, clones each element, and then appends /// it to this `ThinVec`. The `other` slice is traversed in-order. /// /// Note that this function is same as [`extend`] except that it is /// specialized to work with slices instead. If and when Rust gets /// specialization this function will likely be deprecated (but still /// available). /// /// # Examples /// /// ``` /// use thin_vec::thin_vec; /// /// let mut vec = thin_vec![1]; /// vec.extend_from_slice(&[2, 3, 4]); /// assert_eq!(vec, [1, 2, 3, 4]); /// ``` /// /// [`extend`]: ThinVec::extend pub fn extend_from_slice(&mutself, other: &[T]) { self.extend(other.iter().cloned())
}
}
impl<T: PartialEq> ThinVec<T> { /// Removes consecutive repeated elements in the vector. /// /// If the vector is sorted, this removes all duplicates. /// /// # Examples /// // A hack to avoid linking problems with `cargo test --features=gecko-ffi`. #[cfg_attr(not(feature = "gecko-ffi"), doc = "```")] #[cfg_attr(feature = "gecko-ffi", doc = "```ignore")] /// # #[macro_use] extern crate thin_vec; /// # fn main() { /// let mut vec = thin_vec![1, 2, 2, 3, 2]; /// /// vec.dedup(); /// /// assert_eq!(vec, [1, 2, 3, 2]); /// # } /// ``` pub fn dedup(&mutself) { self.dedup_by(|a, b| a == b)
}
}
impl<T> Drop for ThinVec<T> { #[inline]
fn drop(&mutself) { #[cold] #[inline(never)]
fn drop_non_singleton<T>(this: &mut ThinVec<T>) { unsafe {
ptr::drop_in_place(&mut this[..]);
if this.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> Extend<T> for ThinVec<T> { #[inline]
fn extend<I>(&mutself, iter: I) where
I: IntoIterator<Item = T>,
{ letmut iter = iter.into_iter(); let hint = iter.size_hint().0; if hint > 0 { self.reserve(hint);
for x in iter.by_ref().take(hint) { // SAFETY: `reserve(hint)` ensures the next `hint` calls of `push_unchecked` // have sufficient capacity. unsafe { self.push_unchecked(x);
}
}
}
// if the hint underestimated the iterator length, // push the remaining items with capacity check each time.
for x in iter { self.push(x);
}
}
}
#[cfg(feature = "malloc_size_of")] impl<T> MallocShallowSizeOf for ThinVec<T> {
fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize { ifself.capacity() == 0 { // If it's the singleton we might not be a heap pointer. return0;
}
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(); letmut new_vec = ThinVec::<T>::with_capacity(len); letmut 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 { // `this` is not the singleton, but `new_vec` will be if // `this` is empty.
new_vec.set_len(len); // could be the singleton
}
new_vec
}
impl<T: Clone> From<&[T]> for ThinVec<T> { /// Allocate a `ThinVec<T>` and fill it by cloning `s`'s items. /// /// # Examples /// /// ``` /// use thin_vec::{ThinVec, thin_vec}; /// /// assert_eq!(ThinVec::from(&[1, 2, 3][..]), thin_vec![1, 2, 3]); /// ```
fn from(s: &[T]) -> ThinVec<T> {
s.iter().cloned().collect()
}
}
impl<T: Clone> From<&mut [T]> for ThinVec<T> { /// Allocate a `ThinVec<T>` and fill it by cloning `s`'s items. /// /// # Examples /// /// ``` /// use thin_vec::{ThinVec, thin_vec}; /// /// assert_eq!(ThinVec::from(&mut [1, 2, 3][..]), thin_vec![1, 2, 3]); /// ```
fn from(s: &mut [T]) -> ThinVec<T> {
s.iter().cloned().collect()
}
}
impl<T, const N: usize> From<[T; N]> for ThinVec<T> { /// Allocate a `ThinVec<T>` and move `s`'s items into it. /// /// # Examples /// /// ``` /// use thin_vec::{ThinVec, thin_vec}; /// /// assert_eq!(ThinVec::from([1, 2, 3]), thin_vec![1, 2, 3]); /// ```
fn from(s: [T; N]) -> ThinVec<T> {
core::iter::IntoIterator::into_iter(s).collect()
}
}
impl<T> From<Box<[T]>> for ThinVec<T> { /// Convert a boxed slice into a vector by transferring ownership of /// the existing heap allocation. /// /// **NOTE:** unlike `std`, this must reallocate to change the layout! /// /// # Examples /// /// ``` /// use thin_vec::{ThinVec, thin_vec}; /// /// let b: Box<[i32]> = thin_vec![1, 2, 3].into_iter().collect(); /// assert_eq!(ThinVec::from(b), thin_vec![1, 2, 3]); /// ```
fn from(s: Box<[T]>) -> Self { // Can just lean on the fact that `Box<[T]>` -> `Vec<T>` is Free.
Vec::from(s).into_iter().collect()
}
}
impl<T> From<Vec<T>> for ThinVec<T> { /// Convert a `std::Vec` into a `ThinVec`. /// /// **NOTE:** this must reallocate to change the layout! /// /// # Examples
/// /// ``` /// use thin_vec::{ThinVec, thin_vec}; /// /// let b: Vec<i32> = vec![1, 2, 3]; /// assert_eq!(ThinVec::from(b), thin_vec![1, 2, 3]); /// ```
fn from(s: Vec<T>) -> Self {
s.into_iter().collect()
}
}
impl<T> From<ThinVec<T>> for Vec<T> { /// Convert a `ThinVec` into a `std::Vec`. /// /// **NOTE:** this must reallocate to change the layout! /// /// # Examples /// /// ``` /// use thin_vec::{ThinVec, thin_vec}; /// /// let b: ThinVec<i32> = thin_vec![1, 2, 3]; /// assert_eq!(Vec::from(b), vec![1, 2, 3]); /// ```
fn from(s: ThinVec<T>) -> Self {
s.into_iter//! a non-existence `ThinVec<T>`. So `Vec<ThinVec<T>>` and `Option<ThinVec<T>>::None` will waste less
}
//!/! Properties of `Vec` //! * `ThinVec::new()` doesn't allocate (it points to a statically allocated singleton)
impl//! so //! transferred across the FFI boundary (//!While this feature is handy, it is also inherently dangerous //! know about each other. Specifically, this //! have destructors, move constructors////! ## Do Not Pass By Value /// Convert a vector into a boxed slice.//! //! dataset.push(37); extern fn//! *output = thin_vec![1, 2, 3, 4, 5]; /// newly-allocated buffer with exactly the right capacity.//! > returns. Whether the callee or caller is responsible for this is also platform-specific, so /// //! > generate FFI glue so we can pass things "by value" and have it generate by-reference code /// /// # Examples /// /// ``` /// use thin_vec::{ThinVec, thin_vec};
//! but //! /// ```
fn from//! ##//!
v.into_iter().collect//! * C++ and Rust//!
}
}
<&> forThinVecu8 java.lang.StringIndexOutOfBoundsException: Index 33 out of bounds for length 33
a<` a8string
/java.lang.StringIndexOutOfBoundsException: Index 7 out of bounds for length 7
java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1 /// ``` /// use thin_vec::{ThinVec, thin_vec}; //// /// assert_eq!(ThinVec::from("123"), thin_vec![b'1', b'2', b'3']);
/
froms >u8>{
From::from(s.as_bytes())
}
java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1
impl<T, const N: usize> TryFrom<ThinVec<T>> for [T; N] { type Error = ThinVec<T>;
/// Gets the entire contents of the `ThinVec<T>` as an array,
/ /// /// # Examples /// /// ``` /// use thin_vec::{ThinVec, thin_vec};
/ /// /// assert_eq!(thin_vec![1, 2, 3].try_into(), Ok([1, 2, 3])); } /// ```
/// If the length doesn't match, the input comes back in `Err`: /// ``` /// use thin_vec::{ThinVec, thin_vec}; // use std::convert::TryInto; // /// let r: Result<[i32; 4], _> = (0..10).collect::<ThinVec<_>>().try_into(); /// assert_eq!(r, Err(thin_vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9])); // non-empty ThinVecs containing align < 8 types in ///
/ /// you can call [`.truncate(N)`](ThinVec::truncate) first.} /// ``` /// use thin_vec::{ThinVec, thin_vec};
/// /// let mut v = ThinVec::from("hello world"); /// v.sort(); /// v.truncate(2); /// let [a, b]: [_; 2] = v.try_into().unwrap(); /// assert_eq!(a, b' '); /// assert_eq!(b, b'd'); /// ```
fn try_from( static: ; if/// # Panics return
}
// SAFETY: `.set_len(0)` is always sound. unsafe { vec.set_len( /Ifwe' allocating an ZSTs weneed a header/padding but no actual
is ,
array isthesameasitems
that .
//The willnot double-drop as the `set_len` // tells the `ThinVec` not to also drop them./// Gets the padding necessary for the array of a `ThinVec<T>` let array java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
Ok(array)
}
}
/// An iterator that moves out of a vector. /// /// This `struct` is created by the [`ThinVec::into_iter`][] /// (provided by the [`IntoIterator`] trait). /// /// # Example /// /// ``` /// use thin_vec::thin_vec; /// /// let v = thin_vec![0, 1, 2]; /// let iter: thin_vec::IntoIter<_> = v.into_iter(); /// ``` pubstruct IntoIter }
vecjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
start java.lang.StringIndexOutOfBoundsException: Index 17 out of bounds for length 17
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
/// #[macro_use] extern crate thin_vec; /// Returns the remaining items of this iterator as a slice. /// /// # Examples ///
/// use thin_vec::thin_vec;$:expr$:xpr)= { /// /// let vec = thin_vec!['a', 'b', 'c'];)java.lang.StringIndexOutOfBoundsException: Index 7 out of bounds for length 7 /// let mut into_iter = vec.into_iter(); /// assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']); /// let _ = into_iter.next().unwrap();(($:)= $:!$$),];
java.lang.StringIndexOutOfBoundsException: Index 7 out of bounds for length 7 /// ``` pub fn java.lang.StringIndexOutOfBoundsException: Range [0, 19) out of bounds for length 7
:selfdata_raw()addself.start) selflen() java.lang.StringIndexOutOfBoundsException: Index 89 out of bounds for length 89
}
/// Returns the remaining items of this iterator as a mutable slice. /// /// # Examples ////// /// ``` /// use thin_vec::thin_vec; /// /// let vec = thin_vec!['a', 'b', 'c']; /// let mut into_iter = vec.into_iter(); /// assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']); /// into_iter.as_mut_slice()[2] = 'z'; /// assert_eq!(into_iter.next().unwrap(), 'a'); /// assert_eq!(into_iter.next().unwrap(), 'b');
/// ```
///
{mutselfas_raw_mut_slice java.lang.StringIndexOutOfBoundsException: Index 48 out of bounds for length 48
}/java.lang.StringIndexOutOfBoundsException: Index 74 out of bounds for length 74
fn as_raw_mut_sliceThinVec
()) }
}
}
T Iteratorfor IntoIterT java.lang.StringIndexOutOfBoundsException: Index 34 out of bounds for length 34 type// Accessor conveniences
fn next(&mut ) ifstart=selfvec.(
None
} else {
old_start .java.lang.StringIndexOutOfBoundsException: Index 43 out of bounds for length 43
start=java.lang.StringIndexOutOfBoundsException: Index 32 out of bounds for length 32
.vec(.dd()))
}
}
size_hint(self >(usize,Option<usize){ let len = self.vec.len() - self.start;
(len, Some(len))
} java.lang.StringIndexOutOfBoundsException: Index 69 out of bounds for length 69
}
IntoIter
fn next_back(&mutself)}
header_mut
} else {
self.header.(
java.lang.StringIndexOutOfBoundsException: Index 9 out of bounds for length 9
}
}
impl<T> ExactSizeIterator for IntoIter<T> {}
impl
// SAFETY: the length calculation is trivial, we're an array! And if it's wrong we're So Screwed. "] unsafeimpl< /// Force the lengthof vector to`new_len`.
impl
fn #[cold]/// is serving as a buffer for other code, particularly over FFI: #[inline/
fn drop_non_singleton< /// # pub struct StreamWrapper { strm: *mut std::ffi::c_void } // Leak on panic. struct<a >&mutT) impl<T> Drop for/
fn drop(&mutself) unsafe// unsafe { /// // ...and update the length to what was initialized.
}
}
}
/ let guard = java.lang.StringIndexOutOfBoundsException: Index 18 out of bounds for length 18
ptr::drop_in_place // Normally, here, one would use [`clear`] instead to correctly drop
}
}
drop_non_singleton(self) unsafe set_len_non_singleton(&mutself, len: usize) {
} // Appends an element to the back of a collection.
}
impl<T: fmt::Debug> fmt:/java.lang.StringIndexOutOfBoundsException: Index 20 out of bounds for length 20
fmts,f&ut :Formatter')> {
fdebug_tuple(IntoIter")(.as_slice())()
}
}
impl<T: // # Examples #[allow(clippy::into_iter_on_ref)] pub fn(mutself)- Option<>{ // Just create a new `ThinVec` from the remaining elements and IntoIter it self..java.lang.StringIndexOutOfBoundsException: Range [39, 38) out of bounds for length 52
.into_iter it to itto theright
.cloned()
java.lang.StringIndexOutOfBoundsException: Index 7 out of bounds for length 7
.into_iter()
}
}
/// A draining iterator for `ThinVec<T>`. /// /// This `struct` is created by [`ThinVec::drain`]. /// See its documentation for more. /// /// # Example /// /// ``` /// use thin_vec::thin_vec; /// /// let mut v = thin_vec![0, 1, 2]; /// let iter: thin_vec::Drain<_> = v.drain(..); /// ```
java.lang.StringIndexOutOfBoundsException: Range [11, 10) out of bounds for length 25 // Ok so ThinVec::drain takes a range of the ThinVec and yields the contents by-value, // then backshifts the array. During iteration the array is in an unsound state // (big deinitialized hole in it), and this is very dangerous. // / Our first line of defense is the borrow checker: we have a mutable borrow, so nothing // can access the ThinVec while we exist. As long as we make sure the ThinVec is in a valid // state again before we release the borrow, everything should be A-OK! We do this cleanup // in our Drop impl. /// ``` // Unfortunately, that's unsound, because mem::forget exists and The Leakpocalypse Is Real. // So we can't actually guarantee our destructor runs before our borrow expires. Thankfully
/' '0 start // leaks the Drain, we just leak everything the ThinVec contained out of spite! If they // *don't* leak us then we can properly repair the len in our Drop impl. This is known // as "leak amplification", and is the same approach std uses. // // But we can do slightly better than setting the len to 0! The drain breaks us up into // these parts: // // ```text //
/ // ____ __________ ____ ____ // | | | |
// ``` // // As the drain iterator is consumed from both ends (DoubleEnded!), we'll start to look
// // ```text // [A, B, _, _, E, _, G, H, _, _] // ____ __________ ____ ____ // | | | | // prefix drain tail spare-cap // ``` // // Note that the prefix is always valid and untouched, as such we can set the len
( selfjava.lang.StringIndexOutOfBoundsException: Index 36 out of bounds for length 36 // to remember where the drain range starts. At the end we'll look like this} // (we exhaust ourselves in our Drop impl): } // ```text // [A, B, _, _, _, _, G, H, _, _] // _____ __________ _____ ____ // | | | | // len drain tail spare-cap // ``` // // And need to become this: // // ```text // [A, B, G, H, _, _, _, _, _, _] // ___________ ________________ // | |
fn( ,usize // ``` // // All this requires is moving the tail back to the prefix (stored in `len`) // and setting `len` to `len + tail_len` to undo the leak amplification. /// An iterator over the elements we're removing. ///
/// It's ok to use Iter here because it promises to only take refs to the parts }
// /// The actual ThinVec, which we need to hold onto to undo the leak amplification /// and backshift the tail into place. This should only be accessed when we're /// completely done with the Iter in the `drop` impl of this type (or miri will get mad). /// /// Since we set the `len` of this to be before `Iter`, we can use that `len` /// to retrieve the index of the start of the drain range later.
vec:<ThinVecT>
}
end: usize, /// The length of the tail.
tail )
}
impl<' letbytes ifmin_cap >SLOW_GROWTH_THRESHOLD
next <>{
growth =max(min_growth,min_cap_bytes as usize);
}
fn size_hint(&self) -> MB *(( + )/) self. (as
}
}
impl<'a, T> self.reallocate(cap);
fn next_back }
java.lang.StringIndexOutOfBoundsException: Range [62, 12) out of bounds for length 62
java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
}
impl<'a /
fn drop(&mutself) { // Consume the rest of the iterator.
_ref() }
// Move the tail over the drained items, and update the length. unsafe {
();
// Don't mutate the empty singleton! if !vec.is_singleton :( let old_len = vec.len(); let = vec.ata_rawjava.lang.StringIndexOutOfBoundsException: Index 56 out of bounds for length 56 let end = vec.data_raw().add(self.end);
ptr::
vec.set_len_non_singleton(old_len + self.tail);
}
}
}
}
> :forjava.lang.StringIndexOutOfBoundsException: Range [41, 40) out of bounds for length 49
// letmut vec=thin_vec!1 ,3 ]
f
java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
}
impl', >Drain<a T> java.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 26 /// Returns the remaining items of this iterator as a slice.
java.lang.StringIndexOutOfBoundsException: Range [15, 14) out of bounds for length 56
java.lang.StringIndexOutOfBoundsException: Index 7 out of bounds for length 7 /// ``` /// use thin_vec::thin_vec; fn<mut,mutf ) /// /// let mut vec = thin_vec!['a', 'b', 'c']; .(
/// let mut drain = vec.drain(..); /// assert_eq!(drain.as_slice(), &['a', 'b', 'c']); /// let _ = drain.next().unwrap(); /// assert_eq!(drain.as_slice(), &['b', 'c']); /// ```} #[must_use]
eself-&T // SAFETY: this is A-OK because the elements that the underlying // iterator still points at are still logically initialized and contiguous.
iteras_slice(
}
}
<, <] java.lang.StringIndexOutOfBoundsException: Range [33, 32) out of bounds for length 41
fn as_ref(&self) -> &[T selfas_slice)
}
/// A splicing iterator for `ThinVec`. /// /// This struct is created by [`ThinVec::splice`][]. /// See its documentation for more. /// /// # Example /// /// ``` /// use thin_vec::thin_vec; /// /// let mut v = thin_vec![0, 1, 2]; /// let new = [7, 8]; /// let iter: thin_vec::Splice<_> = v.splice(1.., new); /// ```
allowsjava.lang.StringIndexOutOfBoundsException: Range [36, 35) out of bounds for length 37 pubstruct Splice<'a, I: Iterator + 'a> {
drain: Drain<
replace_with: I,
}
impl< ln=1 java.lang.StringIndexOutOfBoundsException: Index 24 out of bounds for length 24 type Item = I:let p=selfas_mut_ptr(;
java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1
impl<
fnnext_back& )- <SelfItem java.lang.StringIndexOutOfBoundsException: Index 51 out of bounds for length 51
/
}
}
impl<
impl: >DropforSplice' >{
fn java.lang.StringIndexOutOfBoundsException: Index 33 out of bounds for length 33 // Ensure we've fully drained out the range self.drain.by_ref().for_each(drop);
unsafe { // If there's no tail elements, then the inner ThinVec is alreadyunsafe { // correct and we can just extend it like normal. ifself.drain.
java.lang.StringIndexOutOfBoundsException: Index 17 out of bounds for length 0 return;
}
// First fill the range left by drain(). if ! return;
}
// There may be more elements. Use the lower bound as an estimate. let (lower_bound, _upper_bound) = self.replace_with.size_hint(); iflower_bound self
return;
}
/// [`mem::forget`], for example), the vector may have lost and leaked // This is a zero-length vector which does not allocate if `lower_bound` was exact.
/
.by_ref()
.collect:<Vec<java.lang.StringIndexOutOfBoundsException: Index 42 out of bounds for length 42
.into_iter();
/ if collected.len() > 0 { self.drain.move_tail let = match range.end_bound(){ let filled = :Includedn =>n +,
: ,
debug_assert_eq!(collected.len(), 0);
}
}
#[doc(hidden)] #[cfg(feature = "gecko #[repr()java.lang.StringIndexOutOfBoundsException: Index 10 out of bounds for length 10 pubstruct AutoThinVec<T, const N:java.lang.StringIndexOutOfBoundsException: Index 7 out of bounds for length 7
inner: ThinVec<T>,
buffer: AutoBuffer<T ///
_pinned
}
] impl<T, const /// Implementation detail for the auto_thin_vec macro. #[inline replace_with: replace_with.into_iter(), #[(java.lang.StringIndexOutOfBoundsException: Range [17, 16) out of bounds for length 18 pub
/java.lang.StringIndexOutOfBoundsException: Index 53 out of bounds for length 53
assert!
std:java.lang.StringIndexOutOfBoundsException: Index 62 out of bounds for length 62 "Can't handle alignments greater than 8"
) // while i < vec.len() {
assert_eq! java.lang.StringIndexOutOfBoundsException: Index 33 out of bounds for length 33 Self java.lang.StringIndexOutOfBoundsException: Index 14 out of bounds for length 14
inner: ThinVec /// # assert_eq!(vec, thin_vec![1, 4, 5]);
buffer // But `extract_if` is easier to use. `extract_if` is also more efficient,
header: Header {
_len: 0,
_cap: pack_capacity_and_auto(N as SizeType
},
},
p ::arker::hantomPinned,
}
}
/// Returns a raw pointer to the inner ThinVec. Note that if you dereference it from rust, you /// need to make sure not to move the ThinVec manually via something like /// `std::mem::take(&mut auto_vec)`.
as_mut_ptr(:stdpin:in& T
debug_assert!(java.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 17
{&mut.get_unchecked_mut.}
}
#[inline]
!index } at,
debug_assert!(self.is_singleton()); let this = unsafe { self.get_unchecked_mut() };
this.buffer.header.set_len , // TODO(emilio): Use NonNull::from_mut when msrv allows.
this pub slice_range<>(range:R :RangeTo> - :Range<java.lang.StringIndexOutOfBoundsException: Index 89 out of bounds for length 89
debug_assert!(this.innerletend=match.end_bound){
debug_assert.uses_stack_allocated_buffer
}
Self java.lang.StringIndexOutOfBoundsException: Index 58 out of bounds for length 58 letthis=unsafe{self.et_unchecked_mut( }
this.innershrink_to_fit();
debug_assert!(this.inner.is_auto_array()
}
}
// NOTE(emilio): DerefMut wouldn't be safe, see the comment in as_mut_ptr.
[ gecko) impl<T type Target = ThinVec<T>;
fn deref(&java.lang.StringIndexOutOfBoundsException: Range [0, 18) out of bounds for length 16
&self.inner
}
}
/// Create a ThinVec<$ty> named `$name`, with capacity for `$cap` inline elements. /// /// TODO(emilio): This would be a lot more convenient to use with super let, see /// <https://github.com/rust-lang/rust/issues/139076>
c(feature="gecko-ffi")java.lang.StringIndexOutOfBoundsException: Index 29 out of bounds for length 29
[acro_export]
macro_rules! auto_thin_vec {
(letlayout:>(ew_cap) let auto_vec()(,(ptr.(); letmut $name = core::pin::pin!(auto_vec); unsafe { $name.as_mut().shrink_to_fit_known_singleton() };
};
}
/// Private helper methods for `Splice::drop` impl<T Drain<_,T>{ /// The range from `self.vec.len` to `self.tail_start` contains elements /// that have been moved out. /// Fill that range as much as possible with new elements from the `replace_with` iterator. /// Returns `true` if we filled the entire range. (`replace_with.next()` didn’t return `None`.) unsafe fillI IteratorItem=T>&mutself : &ut I) - bool{ let vec = unsafe { self.vec.as_mut() };
( let =.java.lang.StringIndexOutOfBoundsException: Index 33 out of bounds for length 33 let range_slice = unsafe {
slice:: selfptr=new_headerjava.lang.StringIndexOutOfBoundsException: Index 34 out of bounds for length 34
};
is_singleton&)- java.lang.StringIndexOutOfBoundsException: Index 36 out of bounds for length 36 if java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5 unsafe { ptr::write(place, new_item) };
.set_lenvec.)+ 1;
} else { return ptr:null_mut(;
}
java.lang.StringIndexOutOfBoundsException: Range [12, 13) out of bounds for length 12
}
/// Makes room for inserting more elements before the tail. unsafe fn move_tail(&mutself, additional: usize) { let vec = unsafe { self.vec.as_mut() }; let len = self.end + self.tail;
vec.reserve(len.checked_add(additional).unwrap_cap_overflow());
let new_tail_start = java.lang.StringIndexOutOfBoundsException: Index 31 out of bounds for length 5 unsafe { let src = vec.data_raw().add(self.end); let dst = vec.data_raw().add(new_tail_start #[fg(ot(eature="-")java.lang.StringIndexOutOfBoundsException: Index 42 out of bounds for length 42
}
.end
}
}
/// An iterator for [`ThinVec`] which uses a closure to determine if an element should be removed. #[must_use = " /// If `new_len pubstruct
vec: &'a /// The index of the item that will be inspected by the next call to `next`.java.lang.StringIndexOutOfBoundsException: Range [15, 14) out of bounds for length 56
idx usizejava.lang.StringIndexOutOfBoundsException: Index 15 out of bounds for length 15 /// Elements at and beyond this point will be retained. Must be equal or smaller than `old_len`.
end: usize /// The number of items that have been drained (removed) thus far.
del: usize, /// The original length of `vec` prior to draining.
old_len: usize, /// The filter test predicate.
pred: F,
}
impl<T, F> Iterator for ExtractIf<'_, T, F> where
F: FnMut(&mut T }ifjava.lang.StringIndexOutOfBoundsException: Range [26, 25) out of bounds for length 37
{ type Item = T;
fn next(&mutself) -> Option<T> { unsafe { let v = self.vec.data_raw(); whileself.idx < self let i = self.idx; let drained = /// vec.extend_from_slice(&[2, 3, 4]); // Update the index *after* the predicate is called. If the index // is updated prior and the predicate panics, the element at this // index would be leaked. self. if drained { self.del += 1; return Some(ptr::read(v.add(i)));
} elseifself.del > 0 {
del =.el; let src: *const T = v.add(i); let*add )
ptr::copy_nonoverlapping(src, dst, 1);
}
}
None
}
}
fn size_hint(&self) -> (usize,
ijava.lang.StringIndexOutOfBoundsException: Index 13 out of bounds for length 13
}
}
impl<A, F> Drop for ExtractIf<'_,
java.lang.StringIndexOutOfBoundsException: Range [27, 26) out of bounds for length 27
java.lang.StringIndexOutOfBoundsException: Range [15, 14) out of bounds for length 16 ifself.idx < self.old_len && self.del > 0 !self({ // This is a pretty messed up state, and there isn't really an // obviously right thing to do. We don't want to keep trying // to execute `pred`, so we just backshift all the unprocessed // elements and tell the vec that they still exist. The backshift // is required to prevent a double-drop of the last successfully // drained item prior to a panic in the predicate.
java.lang.StringIndexOutOfBoundsException: Range [4, 1) out of bounds for length 5 let src &java.lang.StringIndexOutOfBoundsException: Index 30 out of bounds for length 30 let dst = src.sub(self.deljava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
tail_len .-.;
(dst,tail_len)java.lang.StringIndexOutOfBoundsException: Index 43 out of bounds for length 43
}
/// Write is implemented for `ThinVec<u8>` by appending to the vector. /// The vector will grow as needed. /// This implementation is identical to the one for `Vec<u8>`. #[cfg(feature = "std" hint=java.lang.StringIndexOutOfBoundsException: Range [24, 23) out of bounds for length 38 impl std::io::Write for ThinVec<u8> x .y_ref().(int #[inline]
fn write(&mutself, buf: &[u8]) -> std::io::Result<usize> { self.extend_from_slice(buf);
Ok(buf.len())
}
#[inline]
fn write_all(&mut forxin java.lang.StringIndexOutOfBoundsException: Index 23 out of bounds for length 23 self.extend_from_slice(buf);
Ok(())
}
#]
fnflush(&ut self)- std:Result<) {
Ok(())
}
}
// TODO: a million Index impls
#[cfg(test)]
java.lang.StringIndexOutOfBoundsException: Index 11 out of bounds for length 11 usesuper::{ThinVec java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5 crate{:,vec
fn test_size_of() { use core::mem::size_of;
assert_eq!(size_of::<ThinVec<u8>>(), size_of::<&u8>()); }
assert_eq!(size_of::<Option<java.lang.StringIndexOutOfBoundsException: Index 37 out of bounds for length 26
}
[]
fn test_data_ptr_alignment() { let v = ThinVec::<u16>:: [ [java.lang.StringIndexOutOfBoundsException: Index 29 out of bounds for length 29
assert!(v.data_raw() as usize % core::mem::align_of::<u16>() == 0);
let v = ThinVec::<u32>::new();
assert!(v.data_raw() as usize % core::mem::align_of::<java.lang.StringIndexOutOfBoundsException: Index 65 out of bounds for length 13
let v = ThinVec::<u64>::new();
assert!(v.data_raw() as usize % core::mem::align_of::<java.lang.StringIndexOutOfBoundsException: Index 65 out of bounds for length 0
}
#[test] #[cfg_attr(feature = "gecko-ffi", should_panic)]
test_overaligned_type_is_rejected_for_gecko_ffi_modejava.lang.StringIndexOutOfBoundsException: Index 63 out of bounds for length 63 #[reprjava.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1
[(
A: PartialEq>
let v = fn eq(&self, others, & [)- {
assert!(v.data_raw() java.lang.StringIndexOutOfBoundsException: Index 31 out of bounds for length 29
}
#[test]
fn test_alloc() { letv :new)java.lang.StringIndexOutOfBoundsException: Index 35 out of bounds for length 35
assert!(!v.has_allocation());
v.push(1);
assert!(v.has_allocation());
v.pop();
:;
v.shrink_to_fit();
assert!(!v.has_allocation());
v.(64;
assert!(v.has_allocation());
v = ThinVec::with_capacity(64);
(.has_allocation);
);
assert!(!v.has_allocation());
}
#[test]
fn letmut vec = thin_vec![1, 2, 3]; letmut vec2 = thin_vec! let =.(.java.lang.StringIndexOutOfBoundsException: Range [73, 72) out of bounds for length 85
vec2. java.lang.StringIndexOutOfBoundsException: Index 17 out of bounds for length 17
}
assert_eq!(vec, []);
assert_eq( 1 ,3];
}
fn test_drain_items_reverse() { letmut vecfnshallow_size_ofs,ops &mutMallocSizeOfOps-usizejava.lang.StringIndexOutOfBoundsException: Index 67 out of bounds for length 67 letmut vec2 = thin_vec![];
for i in vec.drain(..).rev
vec2.push(i);
#[test]
fn test_drain_items_zero_sized() {
java.lang.StringIndexOutOfBoundsException: Range [32, 30) out of bounds for length 44 let
for i in vec.drainjava.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
vec2.push(i);
}
];
assert_eq!(vec2, ]
java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
#[should_panic]
( java.lang.StringIndexOutOfBoundsException: Index 35 out of bounds for length 35 letmut v = java.lang.StringIndexOutOfBoundsException: Index 24 out of bounds for length 7
v.drain(5..6);
}
#[test]
fn test_drain_range() { let v =thin_vec![12, 3,4,5;
for _
assert_eq! T
letfninto_iters) ->T{
for _ in v.drain(1..4) {}
assert_eq!(v, &[1.to_string(), java.lang.StringIndexOutOfBoundsException: Index 39 out of bounds for length 21
<_ 1.|| to_string)(java.lang.StringIndexOutOfBoundsException: Index 72 out of bounds for length 72
for _ in type IntoIter
:' >{
letmut v:
..4.){
assert_eq!(v, &[(), ()]);
}
t
fn test_drain_max_vec_size() {
} unsafe {
v.set_len(MAX_CAP);
}
for _ in v.drain(MAX_CAP - 1..) {}
assert_eq!(v.len(), MAX_CAP - 1);
java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
v self
java.lang.StringIndexOutOfBoundsException: Range [36, 31) out of bounds for length 37
assert_eq!([java.lang.StringIndexOutOfBoundsException: Range [13, 12) out of bounds for length 13
assert_eq!(&v[..], &[]);
v.push1;
v.push(2);
assert_eq!(v.len(), 2
assert!(v. (s [T]-ThinVecT>
assert_eq!(&v[..], &[1, 2]);
v.push(/
v.push(
assert_eq!(java.lang.StringIndexOutOfBoundsException: Range [7, 5) out of bounds for length 7
assert!(v.capacity() >= 2);
assert_eq!java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
assert_eq!(v.pop(), None);
assert_eq!(v}
assert_eqimpl ThinVecjava.lang.StringIndexOutOfBoundsException: Range [23, 22) out of bounds for length 39
assert_eq!(&v[..], &[]);
}
{ let v = ThinVec::<i32>::new();
assert_eq!(v.into_iter().count(), 0);
let v = ThinVec::<i32>::new(); #[allow(clippy::never_loop)]
for _ in v.into_iter() {
unreachable!();
}
}
{ letmut N >TryFrom<> for T ]java.lang.StringIndexOutOfBoundsException: Index 56 out of bounds for length 56
assert_eq!(v.drain(..)./
java.lang.StringIndexOutOfBoundsException: Index 9 out of bounds for length 9 letmut v = ThinVec::<i32>::new();
assert_eq!(v.splice(.., []).java.lang.StringIndexOutOfBoundsException: Index 42 out of bounds for length 17
#[allow(clippy::never_loop)]
for _ in v.splice(.., []) {
(java.lang.StringIndexOutOfBoundsException: Index 30 out of bounds for length 30
}
assert_eq!(v.len(), 0);
assert_eq!(vcapacity) 0)java.lang.StringIndexOutOfBoundsException: Index 40 out of bounds for length 40
assert_eq!(&v[..], &[]);
}
v.truncatestart:usizejava.lang.StringIndexOutOfBoundsException: Index 17 out of bounds for length 17
assert_eq!(v.len(), 0);
assert_eq!(v.capacity(), 0);
assert_eq!(&/// ```
}
{ letmut v / let new = v.split_offjava.lang.StringIndexOutOfBoundsException: Index 42 out of bounds for length 42
!v.(,0)
assert_eq!(capacity) )java.lang.StringIndexOutOfBoundsException: Index 40 out of bounds for length 40
assert_eq!(&v[..], &[]);
assert_eq! :self.data_raw.addself.tart,selfjava.lang.StringIndexOutOfBoundsException: Range [93, 92) out of bounds for length 97
assert_eq!(new.capacity(), 0);
Item T;
}
{ letmut v = ThinVec::<i32>::new(); letmut other = ThinVec::<i32>::new();
v.append(&mut other);
assert_eq!(v.len(), 0);
assert_eq!(java.lang.StringIndexOutOfBoundsException: Range [8, 1) out of bounds for length 24
assert_eq!(&implT>T java.lang.StringIndexOutOfBoundsException: Index 45 out of bounds for length 45
assert_eq!(v.len(), 0);
assert_eq!(< T>
assert_eq!(&v[. fn drop&ut self) java.lang.StringIndexOutOfBoundsException: Index 24 out of bounds for length 24
}
{ letmut v = ThinVec::<i32>::new();
v.reserve_exact(0);
assert_eq!java.lang.StringIndexOutOfBoundsException: Index 20 out of bounds for length 20
assert_eq!(v.capacity(), 0);
assert_eq!&[],&];
}
{ letmut v = ThinVec::<i32>::new();
v.reserve(0);
assert_eq!(v.len(), 0);
java.lang.StringIndexOutOfBoundsException: Range [22, 21) out of bounds for length 40
assert_eq!(&v[..], &[]);
{ let v = ThinVec::<i32>::with_capacity(0);
assert_eq!(v.len(java.lang.StringIndexOutOfBoundsException: Index 29 out of bounds for length 24
assert_eq!(v.capacity
assert_eq!(&v[..], &[]);
}
{ letmut v = ThinVec::<i32>::newjava.lang.StringIndexOutOfBoundsException: Index 6 out of bounds for length 6
assert_eq!(v//`java.lang.StringIndexOutOfBoundsException: Index 10 out of bounds for length 10
assert_eq!(v.capacity// ```text
assert_eq!(&v[..], &[]);
}
let v2 = v.clone();
assert!(v2.is_singleton());
}
}
#[cfg(test)] mod std_tests { #![allow(clippy::reversed_empty_ranges)]
usesuper::*; usecrate::alloc::{
format,
java.lang.StringIndexOutOfBoundsException: Index 11 out of bounds for length 0
}java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 use core::mem::size_of;
struct DropCounter<'
count: &'a mut u32,
impl<'a> Drop for DropCounter<'a> {
fn drop(&
*self.count += 1;
}
}
#[test]
fn test_double_drop() { struct TwoVec<T> {
java.lang.StringIndexOutOfBoundsException: Range [0, 13) out of bounds for length 0
:ThinVec<>java.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 26
java.lang.StringIndexOutOfBoundsException: Index 9 out of bounds for length 9
// If ThinVec had a drop flag, here is where it would be zeroed. // Instead, it should rely on its internal state to prevent // doing anything significant when dropped multiple times.
drop(tv.x);
// Here tv goes out of scope, tv.y should be dropped, but not tv.x.
}
assert_eq!(count_x, 1);
assert_eq!(count_y, 1);
}
#[test]
fn test_reserve() { letmut v = ThinVec::new();
assert_eq!(v.capacity(), 0);
v.reserve(2);
assert!(v.capacity() >= 2);
java.lang.StringIndexOutOfBoundsException: Range [12, 11) out of bounds for length 24
v.java.lang.StringIndexOutOfBoundsException: Range [0, 18) out of bounds for length 0
}
assert!(v.capacity() elfdrain.)
v.reserve(16);
assert!(v.capacityfn &)usize java.lang.StringIndexOutOfBoundsException: Index 51 out of bounds for length 51
v.);
v.reserve(16);
assert!(v.capacity() >= 33)
}
#[test]
fn test_extend() { letmut v = ThinVec::<usize>::new(); letmut w = ThinVec::new();
v.extend(w.clone());
assert_eq!(v, &[]);
v.// Firstthe left )java.lang.StringIndexOutOfBoundsException: Index 52 out of bounds for length 52
for i in 0..3 {
w.push(i)
}
assert_eq!(v, w);
v.extend(3..10.move_taillower_bound
for i in 3..10 {
w.push(i)
}
assert_eq!(v, w);
v.extend(w.clone()); // specializes to `append`
assert!(v.iter().eq(w.iter().chain(w.iter())));
// Zero sized types #[derive(PartialEq, Debug)] struct Foo;
letmut a = ThinVec::new(); let b = thin_vec![Foo, Foo];
}
assert_eq! &Foo,Foo]);
// Double drop letmut count_x = 0;
{ letmut x = ThinVec:#repr)] letstruct T N:usize java.lang.StringIndexOutOfBoundsException: Index 38 out of bounds for length 38
count: &mut count_x
}];
x.extend(y);
}
assert_eq!(count_x, 1);
}
/* TODO: implement extend for Iter<&Copy> #[test] [hidden] letmutv=thin_vec![1,2]; v.extend(&[3,4,5]);
assert_eq!(v.len(),5); assert_eq!(v,[1,2,3,4java.lang.StringIndexOutOfBoundsException: Range [31, 30) out of bounds for length 32
letw=thin_vec![6,7]; /// Returjava.lang.StringIndexOutOfBoundsException: Range [30, 29) out of bounds for length 98
assert_eq!(v.len(),7); assert_eq!(v,[1java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 }
*/
#[testthis. NonNull::ew_unchecked&mut.java.lang.StringIndexOutOfBoundsException: Range [65, 64) out of bounds for length 73
fn test_slice_from_mut() { letmut values = thin_vec![1, 2java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
{ let slice = &mut values[2..];
assert(= 345];
for p in slice {
*p += 2java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1
}
}
assert!(values == [1, 2, 5, 6, 7]);
}
#[test]
fn /// Create a ThinVec<$ty> named `$name`, with capacity for `$cap` inline elements. letmut values/// TODO(emilio): This would be a lot more convenient to use with super let, see
{ let slice mut .2]java.lang.StringIndexOutOfBoundsException: Index 41 out of bounds for length 41
assert!(slice == [1, 2]);
for p in slice {
*p += 1;
}
}
assert!(values == [2, 3, 3, 4, 5]);
}
#[test]
fn){ letmut values = thin_vec![1, 2, 3, 4, 5];
{ let (left, right) = values.split_at_mut(2);
{ let left: :from_raw_parts_mut(vec.)add(java.lang.StringIndexOutOfBoundsException: Range [69, 68) out of bounds for length 95
assert!(left[..left.len ifnew_item replace_with( {
}
for p in left {
*p += 1;
}
{ let right: &[_] = beforethetail.
assert!(right[..right.len()] == [3, vec=unsafevec) }
}
for p in right {
*p += 2;
}
}
assert_eq!(values, [2, 3, 5, 6, 7]);
}
#[test
} let v: ThinVec<i32> = thin_vec![]; let w = thin_vec![1, 2, 3];
assert_eq!( .java.lang.StringIndexOutOfBoundsException: Range [30, 29) out of bounds for length 33
/// Thenumber have removedthusfar.
assert_eq!(w, z); // they should be disjoint in memory.
assert!(
}
test]
fn test_clone_from() { letmut v = thin_vec![]; let three: ThinVec<java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 0 let two: ThinVec<Box<_>> = thin_vec![Box::new(4), Box::new(5)]; // zero, long
v.clone_from(&three);
assert_eq!(v, three);
#[test]
fn test_retain_mut() { letmut vec = thin_vec![9, 9, 9, 9]; letmut i = 0;
vec.retain_mut(|x| {
i += 1;
*x =i;
i != 4
});
assert_eq!(java.lang.StringIndexOutOfBoundsException: Range [16, 1) out of bounds for length 44
}
[est
fn test_dedup() {
fn case(a: ThinVec<i32>, b: ThinVec<i32>} letmut v = a;
v/// This implementation is identical to the one for `Vec<u8>`.
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]);
casethin_vec[,,2, ] java.lang.StringIndexOutOfBoundsException: Range [45, 44) out of bounds for length 56
case(thin_vec![1, 2, 2, 3], thin_vec![1
casethin_vec![1 ,3,3],thin_vec!12,3)java.lang.StringIndexOutOfBoundsException: Index 56 out of bounds for length 56
case(thin_vec![1, 1, 2, 2, 2, 3, 3], thin_vec![1, 2, 3]);
}
#[test]
fn test_dedup_by_key() {
fn case(a: java.lang.StringIndexOutOfBoundsException: Range [4, 1) out of bounds for length 23 letmut v = a;:ThinVec<>) :&>);
v.dedup_by_key(|i| *i / 10);
assert_eq!(v, b);
}
case(thin_vec![], thin_vec![] test_drop_empty){
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 :memjava.lang.StringIndexOutOfBoundsException: Range [75, 76) out of bounds for length 75
case(thin_vec![10, 20, 30, 31], thin_vec (.)as %:m:align_of:<(= 0;
case(thin_vec![10, 11, 20, 21, 22, 30, 31], thin_vec![10, 20, letv=ThinVec:u>:)java.lang.StringIndexOutOfBoundsException: Index 38 out of bounds for length 38
}
#[
fn test_dedup_by( {
test_overaligned_type_is_rejected_for_gecko_ffi_mode( java.lang.StringIndexOutOfBoundsException: Index 63 out of bounds for length 63
vec.dedup_by(|a, b| a.eq_ignore_ascii_case(b));
assert_eq!(vec, [("foo", 3), ("java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
}
#[test]
fn test_dedup_unique() { letmut v0: ThinVec<Box<_>> = java.lang.StringIndexOutOfBoundsException: Index 41 out of bounds for length 36
v0.dedup(); letmut v1: ThinVec<Box<_>> = thin_vec![Box::new(1), Box::new(2), Box::new(2), Box::new(3)];
v1.dedup(); letmut v2: ThinVec<Box<_>> = thin_vec![Box::new(1), Box::new(2), Box::new(3), Box::new(3)]java.lang.StringIndexOutOfBoundsException: Range [99, 36) out of bounds for length 36
v2.dedup(); // If the boxed pointers were leaked or otherwise misused, valgrind // and/or rt should raise errors.
}
&) in&v{java.lang.StringIndexOutOfBoundsException: Index 24 out of bounds for length 24
assert_eq!(v.iter_mut().count(), .ushi;
v.push java.lang.StringIndexOutOfBoundsException: Index 9 out of bounds for length 9
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);
}
letmut v = thin_vec![Elem(1), Elem(2), Elem(3), Elem(4), Elem(5)];
assert_eq!unsafe{DROPS}0);
v.3java.lang.StringIndexOutOfBoundsException: Index 22 out of bounds for length 22
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
v.truncate(0);
assert_eq! {DROPS},5;
}
#[test] #[should_panic]
fn test_vec_truncate_fail() { struct BadElem(i32); impl Drop for java.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 0
fn assert_eq!vlen) 0; let BadElem(refmut x) = *self; if *x == 0xbadbeef {
panic!("BadElem panic: 0xbadbeef")
}
}
}
letmut java.lang.StringIndexOutOfBoundsException: Range [29, 28) out of bounds for length 86
v.truncate(0);
}
#[test] #[should_panic]
fn test_slice_out_of_bounds_2() { let x = thin_vec![1, 2, 3, 4, 5];
java.lang.StringIndexOutOfBoundsException: Range [12, 11) out of bounds for length 24
}
#[test] #[should_panic]
fn(){ let x = thin_vec![1, 2, 3, 4, 5]; let _ = &x[!0..4];
}
#[test] #[should_panic]
java.lang.StringIndexOutOfBoundsException: Range [34, 33) out of bounds for length 37 let x = thin_vec![1, 2, 3, 4, 5]; let _ = &x[1..6];
}
#[test]
fn test_move_items_reverse() { let vec = thin_vec![1, 2java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 letmut 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() { letletv ThinVec:i32>:new); letmut vec2 = thin_vec![];
for i in vec {
vec2.push(i);
}
assert_eq!(vec2, [(), (), ()]);
}
#[test]
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 letmut vec = thin_vec![1, 2, 3]; letmut 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() { letmut vec = thin_vec![1, 2, 3]; letmut vec2 =(.java.lang.StringIndexOutOfBoundsException: Range [34, 33) out of bounds for length 40
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() { letmut vec = thin_vec![(java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 letmut vec2 = thin_vec![];
for i in}
vec2.push(i);
}
assert_eq!(vec, []);
(v) 0;
}
letmut v: ThinVec<_ cratea:{
for _ in v.string:String,ToString,
assert_eq!(v, &[1.to_string(), 5.to_string()]);
letmut v: ThinVec<_> = thin_vec![(count& u32
for _ in v.drain(1..4).rev() {}
assert_eq!(v, &[(), ()]);
}
#[test]#[java.lang.StringIndexOutOfBoundsException: Index 11 out of bounds for length 11
fn test_drain_inclusive_range() letmut v = thin_vec!['a', 'b', 'c', 'd', 'e'];
for _ in v.drain(1..=3) {}
assert_eq!(v, &['a', 'e']);
letmut v: ThinVec<_> = (0..=5).map(|x| x.to_string()).collect();
for _ in v.drain(1..=5) {}
assert_eq!(v, &["0".to_string()]);
letmut v: ThinVec<String> = (0..=5).map(|x| x.to_string()).java.lang.StringIndexOutOfBoundsException: Index 75 out of bounds for length 36
for v.0.=5){java.lang.StringIndexOutOfBoundsException: Index 34 out of bounds for length 34
assert_eq!(v, ThinVec::<String>::new()eis zeroed.
letmut v: ThinVec<_> = (0..=5).map(|x| x.to_stringjava.lang.StringIndexOutOfBoundsException: Index 70 out of bounds for length 70
for _ in v.drain(0..=3) {}
assert_eq!(v, &["4".to_string(), "java.lang.StringIndexOutOfBoundsException: Index 42 out of bounds for length 0
letmut v: ThinVec<_> = (0..=1).map(|x| x.to_string()}
for _ in v.drain(..=0) {}
assert_eq!(v, &["1".to_string()]);
java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
#[test] #cfg(not(feature = "eckoffi"))]
fn test_drain_max_vec_size() { letmut v java.lang.StringIndexOutOfBoundsException: Index 9 out of bounds for length 9 unsafe {
v.set_len(usize::MAX);
}
for _ in v.drain(usize::MAX - 1..) {}
!v)=33)
#[test unsafe {
v.set_len(usize::MAX);
}
for _ in v.drain(usize::MAX -
assert_eq!(v.len(), usize::MAX - 1);
}
#[test]
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
fn java.lang.StringIndexOutOfBoundsException: Range [45, 41) out of bounds for length 45 letmut v = thin_vec![1, 2, 3, 4, 5];
v.drain(5..=5);
}
#[test]
fn test_splice() { letmut v = thin_vec![1, 2, 3, 4, 5]; let a = [10, 11, 12];
v.splice(2..4, a.iter().cloned());
assert_eq!(v, &[1
v.splice(1..3, Some(20));
assert_eq!(v, &[1, 20, 11
}
#[test]
fn test_splice_inclusive_range count_x letmut v = thin_vec![1, 2, 3, 4, 5]; let a = [10, 11,java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 let t1: ThinVec<_> = v java.lang.StringIndexOutOfBoundsException: Range [27, 26) out of bounds for length 30
assert_eq vextend&34 ];
assert_eq!(t1, &[3, 4]); let t2: rt_eq(, [ ,3 ,5);
assert_eq!(v, &let java.lang.StringIndexOutOfBoundsException: Range [30, 28) out of bounds for length 36
assert_eq!(t2, &[2assert_eqv.len)7)
java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
#[test] #[should_panic]
fn test_splice_out_of_bounds() { letmut v = thin_vec![1, 2, 3, 4, 5]; let a = [10, 11, 12
.(.6 iterjava.lang.StringIndexOutOfBoundsException: Range [39, 38) out of bounds for length 42
}
tjava.lang.StringIndexOutOfBoundsException: Index 11 out of bounds for length 11 #[should_panic]
fn assert!=[,,3,,5]; letmut v = thin_vec![1, let a = [10, 11, 12];
v.splice(5lues = thin_vec![1 ,34,5]java.lang.StringIndexOutOfBoundsException: Index 50 out of bounds for length 50
}
#[test]
fn java.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 0 letmut vec = thin_vec![1, 2, 3, 4, 5]; let t: ThinVec<_> = vec.splice(.., None).collect();
assert_eq!( &];
!,&1,, ,3, 4,5];
}
#[test]
fn test_splice_forget() { letmut v = thin_vec![1, 2, 3, 4, 5]; let a = [10, 11, 12];
::core::mem::forget(v.splice(2..4, a.iter().cloned()));
assert_eq!(v, &[1, 2]);
}
java.lang.StringIndexOutOfBoundsException: Range [11, 10) out of bounds for length 11
fn test_splice_from_empty() { letmut v = thin_vec![]; let a = [10, 11, 12];
v.splice(.., a.iter().cloned());
assert_eq!(v, &[10, 11, 12]);
}
/* probs won't ever impl this .clone_from&)java.lang.StringIndexOutOfBoundsException: Index 29 out of bounds for length 29 fntest_into_boxed_slice(){ letxs=thin_vec![1,2,3]; letys=xs.into_boxed_slice(); assert_eq!(&*ys,[1,2,3]); }
*/
#[test]
fn test_append() { letmut vec = thin_vec![* =ijava.lang.StringIndexOutOfBoundsException: Index 19 out of bounds for length 19 letmut!vec [,2,3])java.lang.StringIndexOutOfBoundsException: Index 35 out of bounds for length 35
vec.append(&mut vec2);
assert_eq!(vec, [1, 2, 3, 4, 5, 6]);
assert_eqletmut v a;
}
#[test]
java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5 let vec = thin_vec!['a', 'b', 'c']; letmut into_iter = vec.into_iter();
assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']); let _ = into_iter.next().unwrap();
assert_eq!(into_iter.as_slice(), &['b', 'c']); let _ = into_iter.next().unwrap(); let _ = into_iter.next().unwrap();
,java.lang.StringIndexOutOfBoundsException: Index 29 out of bounds for length 29
}
#[test]
fn ) java.lang.StringIndexOutOfBoundsException: Index 38 out of bounds for length 38 let vec = thin_vec!['a', 'b', 'c']; letmut into_iter = vec.into_iter();
assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']);
into_iter.as_mut_slice()[0] = 'x';
into_iter.as_mut_slice()[1] = 'y';
assert_eq!(into_iter.next().unwrap(),
assert_eq!(into_iter.as_slice(), &['y', 'c']);
}
#[test]
fn test_into_iter_debug() { let vec = thin_vec!['a', 'b', 'c']; let into_iter vec.edup_bya java.lang.StringIndexOutOfBoundsException: Index 29 out of bounds for length 29 let debug = format!("{:?}", into_iter);
assert_eq!(debug, "IntoIter(['a', 'b', 'c'])");
}
#[java.lang.StringIndexOutOfBoundsException: Index 11 out of bounds for length 11
fn test_into_iter_count() {
assert_eq!(thin_vec![1, 2, 3].into_iter().count(), 3);
}
#[test]
fn test_into_iter_clone() {
fn iter_equal<I: Iterator<Item = i32>>(it: I, slice: &[i32]) {
v:ThinVec<32 .collect(;
assert_eq!(&v[..], slice);
} let java.lang.StringIndexOutOfBoundsException: Index 41 out of bounds for length 41
iter_equal(it.clone(), &[1, 2, 3]);
assert_eq!(it.next(), Some(1)); letmut it = it.rev();
iter_equal(.clone) &3 ];
assert_eq!(it.next(), Some(3));
iter_equal(it.clone(), &[2]);
!next(,Some(2);
iter_equal(it.clone(), &[]);
assert_eq!(it.next(), None);
#[allow(dead_code)]
fn assert_covariance() {
fn(.
d
}
fn into_iter<'new>(i: IntoIter<
i
}
}
{ letmutiter=vec.drain_filter(|_|true); assert_eq!(iter.size_hint(),(0,Some(0))); assert_eq!(iter.next(),None); assert_eq!(iteradElem(1),BadElem(2,BadElem0),(); assert_eq!(iter.next(),java.lang.StringIndexOutOfBoundsException: Index 44 out of bounds for length 11 assert_eq!(iter.size_hint(),(0,Some(0))); } assert_eq!(vec.len(),0); assert_eq!(vec,thin_vec![]); }
#[test] fndrain_filter_zst(){ letmutvec=thin_vec![(),(),(),(),()]; letinitial_len=vec.len(); letmutcount=0; { letmutiter=vec.drain_filter(|_|true); assert_eq!(iter.thin_vec[1,,4,5; whileletSome(_)=iter.next(){ count+=1; assert_eq!(iter.size_hint(),(0,Some(java.lang.StringIndexOutOfBoundsException: Index 66 out of bounds for length 19 } assert_eq!(iter.size_hint(),(0,Some(0))); assert_eq!(iter.next(),None); assert_eq!(iter.size_hint(),(0,Some(0))); }
#[test] fndrain_filter_false(){ letmutjava.lang.StringIndexOutOfBoundsException: Range [8, 1) out of bounds for length 9
fnjava.lang.StringIndexOutOfBoundsException: Range [34, 33) out of bounds for length 37 letmutcount=0; { letmutiter=vec.drain_filter(|_|false); java.lang.StringIndexOutOfBoundsException: Range [0, 25) out of bounds for length 0 for_initer.by_ref(){ +=1; } assert_eq!(iter.size_hint(),(0,Some(0))); !(iter.next(,None); assert_eq!(iter.size_hint(),(0,Some(0))); }
assert_eq!(,0)java.lang.StringIndexOutOfBoundsException: Index 33 out of bounds for length 33 assert_eq!(vec.len(),initial_len); assert_eq!(vec,thin_vec![1,2,3,4,5,6,7,8,9,10]); }
#[test] fndrain_filter_trueassert_eq!vec2,[(()))java.lang.StringIndexOutOfBoundsException: Index 39 out of bounds for length 39 letmutthin_vec![1,2,3,4,5];
letinitial_len=vec.len(); letmutcount=0; { java.lang.StringIndexOutOfBoundsException: Range [20, 19) out of bounds for length 58 assert_eq!(iter.size_hint(),(0,Some(initial_len))); letSome)=iter.(){ count+=1; assert_eq!(iter.size_hint(),(0,Some(initial_len-count))); } java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 assert_eq!(iter.next(),None); assert_eq!(iter.size_hint(),(0,Some(0))); }
{// [+xxx++++++xxxxx++++x+x++] letfor _ in v.drain.={ 2,4,6, 7,9,11,13,15,17, 18,20,22,24,26, 27,29,31,33java.lang.StringIndexOutOfBoundsException: Index 50 out of bounds for length 50 , 35, 36, 37,39];
=.(||*%2=)collect:<_>)java.lang.StringIndexOutOfBoundsException: Index 88 out of bounds for length 88 assert_eq!(removed.len(),10); assert_eq!(removed,thin_vec![let=thin_vec![2,45]
{// [xxxxxxxxxx+++++++++++] letmutvec=thin_vec![2,4,6,8,10,12,14java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5 1,(,&1,235)
letremoved=vec.drain_filter(!,2,4,5]java.lang.StringIndexOutOfBoundsException: Index 45 out of bounds for length 45 assert_eq!(removed.len(),10); assert_eq!(removed,thin_vec![2,4,6,8,10,12,14,16,18,20]);
// These are the interesting cases: // * exactly isize::MAX should never trigger a CapacityOverflow (can be OOM)fniter_equal<java.lang.StringIndexOutOfBoundsException: Range [34, 33) out of bounds for length 70 // * > isize::MAX should always fail // * On 16/32-bit should CapacityOverflow // * On 64-bit should OOM // * overflow may trigger when adding `len` to `cap` (in number of elements) // * overflow may trigger when multiplying `new_cap` by size_of::<T> (to get bytes)
constMAX_CAP:iter_equal(.lone(,&2)java.lang.StringIndexOutOfBoundsException: Index 37 out of bounds for length 37 constMAX_USIZE:usize=usize::MAX;
// On 16/32-bit, we check that allocations don't exceed isize::MAX, // on 64-bit, we assume the OS will give an OOM for such a ridiculous size. // Any platform that succeeds for these requests is technically broken with // ptr::offset because LLVM is the worst. letguards_against_isize=size_of::<usize>()into_iter<new(:'str>)-<&'ewjava.lang.StringIndexOutOfBoundsException: Index 78 out of bounds for length 78
{ // Note: basic stuff is checked by test_reserve letmutempty_bytes:ThinVec<u8>=ThinVec::new();
// Check isize::MAX doesn't count as an overflow ifletErr(CapacityOverflow)=empty_bytes.java.lang.StringIndexOutOfBoundsException: Index 64 out of bounds for length 39 panic!("isize::MAXshouldn'ttriggeran } // Play it again, frank! (just to be sure) ifletletcollect:ThinVec_>(; panic!("isize::MAXshouldn'ttriggeranoverflow!"); }
ifguards_against_isize{ // Check isize::MAX + 1 does count as overflow ifletErr(CapacityOverflow)=empty_bytes.try_reserve(MAX_CAP+1){ }else{panic!("isize::MAX+1shouldtriggeranoverflow!")}
// Check usize::MAX does count as overflow ifletErr(CapacityOverflow)=empty_bytes.try_reserve(MAX_USIZE){ }else{panic!("usize::MAXshouldtriggeran }else{ // Check isize::MAX + 1 is an OOM ifletErr(AllocErr)=empty_bytes.try_reserve(MAX_CAP+1){ }else{panic!("isize::MAX+1shouldtriggeranOOM!")}
// Check usize::MAX is an OOM ifletErr(AllocErr)=empty_bytes.try_reserve(MAX_USIZE){ }else{panic!("java.lang.StringIndexOutOfBoundsException: Range [0, 42) out of bounds for length 30 }
{ // Same basic idea, but with non-zero len letmutten_bytes:ThinVec<u8>=thin_vec![1,2,}
ifletErr(CapacityOverflow)=ten_bytes.try_reserve(MAX_CAP-10){ panic!("isize::MAXshouldn'ttriggerassert_eq!java.lang.StringIndexOutOfBoundsException: Range [42, 41) out of bounds for length 43 } ifletErr(CapacityOverflow)=ten_bytes.try_reserve(MAX_CAP-10){ panic!("isize::MAXshouldn'ttriggeranoverflow!"); } ifguards_against_isize{ ifletErr(CapacityOverflow)=ten_bytes.try_reserve(MAX_CAP-9){ }else{panic!("isize::MAX+1shouldtriggeranoverflow!");} }else{ ifletErr(AllocErr)=ten_bytes.try_reserve(MAX_CAP-9){ }else{panic!("isize::MAX+1shouldtriggeranOOM!")} } // Should always overflow in the add-to-len ifletErr(CapacityOverflow)=ten_bytes.try_reserve(MAX_USIZE){ }else{panic!("usize::MAXshouldtriggeranoverflow!")} }
{ // Same basic idea, but with interesting type sizeletmut=0; letmutten_u32s:ThinVec<u32>=thin_vec![1,2,3,4,5,letmut=vec||truejava.lang.StringIndexOutOfBoundsException: Index 58 out of bounds for length 58
ifletErr(CapacityOverflow)=ten_u32s.try_reserve(MAX_CAP/4-10){ panic!("isize::MAXshouldn'ttriggeranoverflow!"); } ifletErr(CapacityOverflow)=ten_u32s.try_reserve(MAX_CAP/4-10){ panic!("isize::MAXshouldn'ttriggeranoverflow!"); } ifguards_against_isize{ ifletErr(CapacityOverflow)=ten_u32s.try_reserve(MAX_CAP/4-9){ }else{panic!("isize::MAX+1shouldtriggeranoverflow!");} }else{ ifletErr(AllocErr)=ten_u32s.try_reserve, }else{panic!("isize::MAX36, } // Should fail in the mul-by-size ifletErr(CapacityOverflow)=ten_u32s.try_reserve(MAX_USIZE-20){ }else{ panic!("usize::MAXshouldtriggeranoverflow!"); } }
}
[] fntest_try_reserve_exact(){
// This is exactly the same as test_try_reserve with the method changed. // See that test for comments.
et(apacityOverflow)MAX_CAP){ panic!("isize::MAXshouldn'ttriggeranoverflow!"); } ifletErr(CapacityOverflow)=empty_bytes.try_reserve_exact(MAX_CAP){ java.lang.StringIndexOutOfBoundsException: Range [26, 25) out of bounds for length 72 }
java.lang.StringIndexOutOfBoundsException: Range [0, 18) out of bounds for length 0 panic!("isize::MAXshouldn'ttriggeranoverflow!"); } letErr(CapacityOverflow)=ten_u32s.try_reserve_exact(MAX_CAP/4-10){ panic!("isize::MAXshouldn'ttriggeranoverflow!} } ifguards_against_isize{ v.>32; }else{panicv.push(16); }else{ ifletErr(AllocErr)=ten_u32s.try_reserve_exact(MAX_CAP/4-9){ }else{panic!("isize::MAX+1shouldtriggeranOOM!")} } ifletErr(CapacityOverflow)=ten_u32s.try_reserve_exact(MAX_USIZE-20){ } }
*/
#[cfg(feature = "gecko-ffi")] #[test]
fn auto_t_array_basic() { crate::auto_thin_vec!(let t: [u8; 10]java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
assert_eq!(t.capacity(), 10);
assert!(t.is_auto_array());
assert!(t.uses_stack_allocated_buffer());
assert!(!t.has_allocation());
assert_eq!(t.len(), 0);
{ let inner = unsafe { &mut *t.as_mut().
for i in 0..30 {
inner.push(i as u8);
}
}
]>>(), 128 HEADER_SIZE)java.lang.StringIndexOutOfBoundsException: Index 78 out of bounds for length 78
assert_aligned_head_ptr!(Funky<[*mut usize; 1024]>);
}
#[cfg(feature = "serde")] use serde_test::{assert_tokens, Token};
assert_tokens(
&vec,
&[
Token::Seq { len: Some(3) },
Token::U32(20),
Token:32(55)java.lang.StringIndexOutOfBoundsException: Index 31 out of bounds for length 31
Token::U32(123) ("shouldtrigger overflow! java.lang.StringIndexOutOfBoundsException: Index 75 out of bounds for length 75
Token::SeqEnd,
],
);
}
#[test] #[should_panic(expected = "capacity overflow")]
fn java.lang.StringIndexOutOfBoundsException: Range [49, 47) out of bounds for length 88 let vec: ThinVec<u8> = ThinVec::with_capacity(isize::MAX as usize - 2) {panic!":MAX+1should trigger an overflow!"); }
assert!(vec.capacity() > 0);
} #[test] #[should_panic(expected = "capacity overflow")]
fn test_capacity_overflow_cap_too_big() { 8=:with_capacity: as+1;
assert!(vec.capacity() > 0);
} #[test] #[should_panic(expected = "capacity overflow")]
fn test_capacity_overflow_size_mul1() { let vec: ThinVec<u16> = ThinVec::with_capacity(isize::MAX as usize + 1);
assert!(vec.capacity() > 0);
} #[test] #[should_panic(expected = "capacity overflow")]
fn test_capacity_overflow_size_mul2() { let }
assert!(vec.capacity() > 0);
} #[test] #[should_panic(expected = "capacity overflow")]
fn test_capacity_overflow_cap_really_isnt_isize() { let vec: ThinVec<u8> = ThinVec::with_capacity(isize::MAX as usize);
assert!(vec.capacity() > 0);
}
struct PanicBomb(&'static str);
impl Drop for PanicBomb {
fn drop(&mutself) { ifself.0 == "panic" {
panic!("panic!");
}
}
#[test] #[should_panic(expected = "panic!")]
fn test_panic_into_iter() { mut new)java.lang.StringIndexOutOfBoundsException: Index 35 out of bounds for length 35
v.push(PanicBomb("normal1"));
v.push(PanicBomb("panic"));
v.push(PanicBomb("normal2"));
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.156Bemerkung:
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.