1 // This file is part of ICU4X. For terms of use, please see the file 2 // called LICENSE at the top level of the ICU4X source tree 3 // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). 4 5 // The mutation operations in this file should panic to prevent undefined behavior 6 #![allow(clippy::unwrap_used)] 7 #![allow(clippy::expect_used)] 8 #![allow(clippy::indexing_slicing)] 9 #![allow(clippy::panic)] 10 11 use super::*; 12 use crate::ule::*; 13 use alloc::vec::Vec; 14 use core::any; 15 use core::convert::TryInto; 16 use core::marker::PhantomData; 17 use core::ops::Deref; 18 use core::ops::Range; 19 use core::{fmt, ptr, slice}; 20 21 use super::components::IntegerULE; 22 23 /// A fully-owned [`VarZeroVec`]. This type has no lifetime but has the same 24 /// internal buffer representation of [`VarZeroVec`], making it cheaply convertible to 25 /// [`VarZeroVec`] and [`VarZeroSlice`]. 26 /// 27 /// The `F` type parameter is a [`VarZeroVecFormat`] (see its docs for more details), which can be used to select the 28 /// precise format of the backing buffer with various size and performance tradeoffs. It defaults to [`Index16`]. 29 pub struct VarZeroVecOwned<T: ?Sized, F = Index16> { 30 marker1: PhantomData<T>, 31 marker2: PhantomData<F>, 32 // safety invariant: must parse into a valid VarZeroVecComponents 33 entire_slice: Vec<u8>, 34 } 35 36 impl<T: ?Sized, F> Clone for VarZeroVecOwned<T, F> { clone(&self) -> Self37 fn clone(&self) -> Self { 38 VarZeroVecOwned { 39 marker1: PhantomData, 40 marker2: PhantomData, 41 entire_slice: self.entire_slice.clone(), 42 } 43 } 44 } 45 46 // The effect of a shift on the indices in the varzerovec. 47 #[derive(PartialEq)] 48 enum ShiftType { 49 Insert, 50 Replace, 51 Remove, 52 } 53 54 impl<T: VarULE + ?Sized, F: VarZeroVecFormat> Deref for VarZeroVecOwned<T, F> { 55 type Target = VarZeroSlice<T, F>; deref(&self) -> &VarZeroSlice<T, F>56 fn deref(&self) -> &VarZeroSlice<T, F> { 57 self.as_slice() 58 } 59 } 60 61 impl<T: VarULE + ?Sized, F> VarZeroVecOwned<T, F> { 62 /// Construct an empty VarZeroVecOwned new() -> Self63 pub fn new() -> Self { 64 Self { 65 marker1: PhantomData, 66 marker2: PhantomData, 67 entire_slice: Vec::new(), 68 } 69 } 70 } 71 72 impl<T: VarULE + ?Sized, F: VarZeroVecFormat> VarZeroVecOwned<T, F> { 73 /// Construct a VarZeroVecOwned from a [`VarZeroSlice`] by cloning the internal data from_slice(slice: &VarZeroSlice<T, F>) -> Self74 pub fn from_slice(slice: &VarZeroSlice<T, F>) -> Self { 75 Self { 76 marker1: PhantomData, 77 marker2: PhantomData, 78 entire_slice: slice.as_bytes().into(), 79 } 80 } 81 82 /// Construct a VarZeroVecOwned from a list of elements try_from_elements<A>(elements: &[A]) -> Result<Self, &'static str> where A: EncodeAsVarULE<T>,83 pub fn try_from_elements<A>(elements: &[A]) -> Result<Self, &'static str> 84 where 85 A: EncodeAsVarULE<T>, 86 { 87 Ok(if elements.is_empty() { 88 Self::from_slice(VarZeroSlice::new_empty()) 89 } else { 90 Self { 91 marker1: PhantomData, 92 marker2: PhantomData, 93 // TODO(#1410): Rethink length errors in VZV. 94 entire_slice: components::get_serializable_bytes_non_empty::<T, A, F>(elements) 95 .ok_or(F::Index::TOO_LARGE_ERROR)?, 96 } 97 }) 98 } 99 100 /// Obtain this `VarZeroVec` as a [`VarZeroSlice`] as_slice(&self) -> &VarZeroSlice<T, F>101 pub fn as_slice(&self) -> &VarZeroSlice<T, F> { 102 let slice: &[u8] = &self.entire_slice; 103 unsafe { 104 // safety: the slice is known to come from a valid parsed VZV 105 VarZeroSlice::from_bytes_unchecked(slice) 106 } 107 } 108 109 /// Try to allocate a buffer with enough capacity for `capacity` 110 /// elements. Since `T` can take up an arbitrary size this will 111 /// just allocate enough space for 4-byte Ts with_capacity(capacity: usize) -> Self112 pub(crate) fn with_capacity(capacity: usize) -> Self { 113 Self { 114 marker1: PhantomData, 115 marker2: PhantomData, 116 entire_slice: Vec::with_capacity(capacity * (F::Index::SIZE + 4)), 117 } 118 } 119 120 /// Try to reserve space for `capacity` 121 /// elements. Since `T` can take up an arbitrary size this will 122 /// just allocate enough space for 4-byte Ts reserve(&mut self, capacity: usize)123 pub(crate) fn reserve(&mut self, capacity: usize) { 124 self.entire_slice.reserve(capacity * (F::Index::SIZE + 4)) 125 } 126 127 /// Get the position of a specific element in the data segment. 128 /// 129 /// If `idx == self.len()`, it will return the size of the data segment (where a new element would go). 130 /// 131 /// ## Safety 132 /// `idx <= self.len()` and `self.as_encoded_bytes()` is well-formed. element_position_unchecked(&self, idx: usize) -> usize133 unsafe fn element_position_unchecked(&self, idx: usize) -> usize { 134 let len = self.len(); 135 let out = if idx == len { 136 self.entire_slice.len() - F::Len::SIZE - (F::Index::SIZE * (len - 1)) 137 } else if let Some(idx) = self.index_data(idx) { 138 idx.iule_to_usize() 139 } else { 140 0 141 }; 142 debug_assert!(out + F::Len::SIZE + (len - 1) * F::Index::SIZE <= self.entire_slice.len()); 143 out 144 } 145 146 /// Get the range of a specific element in the data segment. 147 /// 148 /// ## Safety 149 /// `idx < self.len()` and `self.as_encoded_bytes()` is well-formed. element_range_unchecked(&self, idx: usize) -> core::ops::Range<usize>150 unsafe fn element_range_unchecked(&self, idx: usize) -> core::ops::Range<usize> { 151 let start = self.element_position_unchecked(idx); 152 let end = self.element_position_unchecked(idx + 1); 153 debug_assert!(start <= end, "{start} > {end}"); 154 start..end 155 } 156 157 /// Set the number of elements in the list without any checks. 158 /// 159 /// ## Safety 160 /// No safe functions may be called until `self.as_encoded_bytes()` is well-formed. set_len(&mut self, len: usize)161 unsafe fn set_len(&mut self, len: usize) { 162 assert!(len <= F::Len::MAX_VALUE as usize); 163 let len_bytes = len.to_le_bytes(); 164 let len_ule = F::Len::iule_from_usize(len).expect(F::Len::TOO_LARGE_ERROR); 165 self.entire_slice[0..F::Len::SIZE].copy_from_slice(ULE::slice_as_bytes(&[len_ule])); 166 // Double-check that the length fits in the length field 167 assert_eq!(len_bytes[F::Len::SIZE..].iter().sum::<u8>(), 0); 168 } 169 170 /// Get the range in the full data for a given index. Returns None for index 0 171 /// since there is no stored index for it. index_range(index: usize) -> Option<Range<usize>>172 fn index_range(index: usize) -> Option<Range<usize>> { 173 let index_minus_one = index.checked_sub(1)?; 174 let pos = F::Len::SIZE + F::Index::SIZE * index_minus_one; 175 Some(pos..pos + F::Index::SIZE) 176 } 177 178 /// Return the raw bytes representing the given `index`. Returns None when given index 0 179 /// 180 /// ## Safety 181 /// The index must be valid, and self.as_encoded_bytes() must be well-formed index_data(&self, index: usize) -> Option<&F::Index>182 unsafe fn index_data(&self, index: usize) -> Option<&F::Index> { 183 let index_range = Self::index_range(index)?; 184 Some(&F::Index::slice_from_bytes_unchecked(&self.entire_slice[index_range])[0]) 185 } 186 187 /// Return the mutable slice representing the given `index`. Returns None when given index 0 188 /// 189 /// ## Safety 190 /// The index must be valid. self.as_encoded_bytes() must have allocated space 191 /// for this index, but need not have its length appropriately set. index_data_mut(&mut self, index: usize) -> Option<&mut F::Index>192 unsafe fn index_data_mut(&mut self, index: usize) -> Option<&mut F::Index> { 193 let ptr = self.entire_slice.as_mut_ptr(); 194 let range = Self::index_range(index)?; 195 196 // Doing this instead of just `get_unchecked_mut()` because it's unclear 197 // if `get_unchecked_mut()` can be called out of bounds on a slice even 198 // if we know the buffer is larger. 199 let data = slice::from_raw_parts_mut(ptr.add(range.start), F::Index::SIZE); 200 Some(&mut F::Index::iule_from_bytes_unchecked_mut(data)[0]) 201 } 202 203 /// Shift the indices starting with and after `starting_index` by the provided `amount`. 204 /// 205 /// ## Panics 206 /// Should never be called with a starting index of 0, since that index cannot be shifted. 207 /// 208 /// ## Safety 209 /// Adding `amount` to each index after `starting_index` must not result in the slice from becoming malformed. 210 /// The length of the slice must be correctly set. shift_indices(&mut self, starting_index: usize, amount: i32)211 unsafe fn shift_indices(&mut self, starting_index: usize, amount: i32) { 212 let normalized_idx = starting_index 213 .checked_sub(1) 214 .expect("shift_indices called with a 0 starting index"); 215 let len = self.len(); 216 let indices = F::Index::iule_from_bytes_unchecked_mut( 217 &mut self.entire_slice[F::Len::SIZE..F::Len::SIZE + F::Index::SIZE * (len - 1)], 218 ); 219 for idx in &mut indices[normalized_idx..] { 220 let mut new_idx = idx.iule_to_usize(); 221 if amount > 0 { 222 new_idx = new_idx.checked_add(amount.try_into().unwrap()).unwrap(); 223 } else { 224 new_idx = new_idx.checked_sub((-amount).try_into().unwrap()).unwrap(); 225 } 226 *idx = F::Index::iule_from_usize(new_idx).expect(F::Index::TOO_LARGE_ERROR); 227 } 228 } 229 230 /// Get this [`VarZeroVecOwned`] as a borrowed [`VarZeroVec`] 231 /// 232 /// If you wish to repeatedly call methods on this [`VarZeroVecOwned`], 233 /// it is more efficient to perform this conversion first as_varzerovec<'a>(&'a self) -> VarZeroVec<'a, T, F>234 pub fn as_varzerovec<'a>(&'a self) -> VarZeroVec<'a, T, F> { 235 self.as_slice().into() 236 } 237 238 /// Empty the vector clear(&mut self)239 pub fn clear(&mut self) { 240 self.entire_slice.clear() 241 } 242 243 /// Consume this vector and return the backing buffer 244 #[inline] into_bytes(self) -> Vec<u8>245 pub fn into_bytes(self) -> Vec<u8> { 246 self.entire_slice 247 } 248 249 /// Invalidate and resize the data at an index, optionally inserting or removing the index. 250 /// Also updates affected indices and the length. 251 /// 252 /// `new_size` is the encoded byte size of the element that is going to be inserted 253 /// 254 /// Returns a slice to the new element data - it doesn't contain uninitialized data but its value is indeterminate. 255 /// 256 /// ## Safety 257 /// - `index` must be a valid index, or, if `shift_type == ShiftType::Insert`, `index == self.len()` is allowed. 258 /// - `new_size` musn't result in the data segment growing larger than `F::Index::MAX_VALUE`. shift(&mut self, index: usize, new_size: usize, shift_type: ShiftType) -> &mut [u8]259 unsafe fn shift(&mut self, index: usize, new_size: usize, shift_type: ShiftType) -> &mut [u8] { 260 // The format of the encoded data is: 261 // - four bytes of "len" 262 // - len*4 bytes for an array of indices 263 // - the actual data to which the indices point 264 // 265 // When inserting or removing an element, the size of the indices segment must be changed, 266 // so the data before the target element must be shifted by 4 bytes in addition to the 267 // shifting needed for the new element size. 268 let len = self.len(); 269 let slice_len = self.entire_slice.len(); 270 271 let prev_element = match shift_type { 272 ShiftType::Insert => { 273 let pos = self.element_position_unchecked(index); 274 // In the case of an insert, there's no previous element, 275 // so it's an empty range at the new position. 276 pos..pos 277 } 278 _ => self.element_range_unchecked(index), 279 }; 280 281 // How much shifting must be done in bytes due to removal/insertion of an index. 282 let index_shift: i64 = match shift_type { 283 ShiftType::Insert => F::Index::SIZE as i64, 284 ShiftType::Replace => 0, 285 ShiftType::Remove => -(F::Index::SIZE as i64), 286 }; 287 // The total shift in byte size of the owned slice. 288 let shift: i64 = 289 new_size as i64 - (prev_element.end - prev_element.start) as i64 + index_shift; 290 let new_slice_len = slice_len.wrapping_add(shift as usize); 291 if shift > 0 { 292 if new_slice_len > F::Index::MAX_VALUE as usize { 293 panic!( 294 "Attempted to grow VarZeroVec to an encoded size that does not fit within the length size used by {}", 295 any::type_name::<F>() 296 ); 297 } 298 self.entire_slice.resize(new_slice_len, 0); 299 } 300 301 // Now that we've ensured there's enough space, we can shift the data around. 302 { 303 // Note: There are no references introduced between pointer creation and pointer use, and all 304 // raw pointers are derived from a single &mut. This preserves pointer provenance. 305 let slice_range = self.entire_slice.as_mut_ptr_range(); 306 // The start of the indices buffer 307 let indices_start = slice_range.start.add(F::Len::SIZE); 308 let old_slice_end = slice_range.start.add(slice_len); 309 let data_start = indices_start.add((len - 1) * F::Index::SIZE); 310 let prev_element_p = 311 data_start.add(prev_element.start)..data_start.add(prev_element.end); 312 313 // The memory range of the affected index. 314 // When inserting: where the new index goes. 315 // When removing: where the index being removed is. 316 // When replacing: unused. 317 // Will be None when the affected index is index 0, which is special 318 let index_range = if let Some(index_minus_one) = index.checked_sub(1) { 319 let index_start = indices_start.add(F::Index::SIZE * index_minus_one); 320 Some(index_start..index_start.add(F::Index::SIZE)) 321 } else { 322 None 323 }; 324 325 unsafe fn shift_bytes(block: Range<*const u8>, to: *mut u8) { 326 debug_assert!(block.end >= block.start); 327 ptr::copy(block.start, to, block.end.offset_from(block.start) as usize); 328 } 329 330 if shift_type == ShiftType::Remove { 331 if let Some(ref index_range) = index_range { 332 shift_bytes(index_range.end..prev_element_p.start, index_range.start); 333 } else { 334 // We are removing the first index, so we skip the second index and copy it over. The second index 335 // is now zero and unnecessary. 336 shift_bytes( 337 indices_start.add(F::Index::SIZE)..prev_element_p.start, 338 indices_start, 339 ) 340 } 341 } 342 343 // Shift data after the element to its new position. 344 shift_bytes( 345 prev_element_p.end..old_slice_end, 346 prev_element_p 347 .start 348 .offset((new_size as i64 + index_shift) as isize), 349 ); 350 351 let first_affected_index = match shift_type { 352 ShiftType::Insert => { 353 if let Some(index_range) = index_range { 354 // Move data before the element forward by 4 to make space for a new index. 355 shift_bytes(index_range.start..prev_element_p.start, index_range.end); 356 let index_data = self 357 .index_data_mut(index) 358 .expect("If index_range is some, index is > 0 and should not panic in index_data_mut"); 359 *index_data = F::Index::iule_from_usize(prev_element.start) 360 .expect(F::Index::TOO_LARGE_ERROR); 361 } else { 362 // We are adding a new index 0. There's nothing in the indices array for index 0, but the element 363 // that is currently at index 0 will become index 1 and need a value 364 // We first shift bytes to make space 365 shift_bytes( 366 indices_start..prev_element_p.start, 367 indices_start.add(F::Index::SIZE), 368 ); 369 // And then we write a temporary zero to the zeroeth index, which will get shifted later 370 let index_data = self 371 .index_data_mut(1) 372 .expect("Should be able to write to index 1"); 373 *index_data = F::Index::iule_from_usize(0).expect("0 is always valid!"); 374 } 375 376 self.set_len(len + 1); 377 index + 1 378 } 379 ShiftType::Remove => { 380 self.set_len(len - 1); 381 if index == 0 { 382 // We don't need to shift index 0 since index 0 is not stored in the indices buffer 383 index + 1 384 } else { 385 index 386 } 387 } 388 ShiftType::Replace => index + 1, 389 }; 390 // No raw pointer use should occur after this point (because of self.index_data and self.set_len). 391 392 // Set the new slice length. This must be done after shifting data around to avoid uninitialized data. 393 self.entire_slice.set_len(new_slice_len); 394 // Shift the affected indices. 395 self.shift_indices(first_affected_index, (shift - index_shift) as i32); 396 }; 397 398 debug_assert!(self.verify_integrity()); 399 400 // Return a mut slice to the new element data. 401 let element_pos = F::Len::SIZE 402 + (self.len() - 1) * F::Index::SIZE 403 + self.element_position_unchecked(index); 404 &mut self.entire_slice[element_pos..element_pos + new_size] 405 } 406 407 /// Checks the internal invariants of the vec to ensure safe code will not cause UB. 408 /// Returns whether integrity was verified. 409 /// 410 /// Note: an index is valid if it doesn't point to data past the end of the slice and is 411 /// less than or equal to all future indices. The length of the index segment is not part of each index. verify_integrity(&self) -> bool412 fn verify_integrity(&self) -> bool { 413 if self.is_empty() { 414 if self.entire_slice.is_empty() { 415 return true; 416 } else { 417 panic!( 418 "VarZeroVecOwned integrity: Found empty VarZeroVecOwned with a nonempty slice" 419 ); 420 } 421 } 422 let len = unsafe { 423 <F::Len as ULE>::slice_from_bytes_unchecked(&self.entire_slice[..F::Len::SIZE])[0] 424 .iule_to_usize() 425 }; 426 if len == 0 { 427 // An empty vec must have an empty slice: there is only a single valid byte representation. 428 panic!("VarZeroVecOwned integrity: Found empty VarZeroVecOwned with a nonempty slice"); 429 } 430 if self.entire_slice.len() < F::Len::SIZE + (len - 1) * F::Index::SIZE { 431 panic!("VarZeroVecOwned integrity: Not enough room for the indices"); 432 } 433 let data_len = self.entire_slice.len() - F::Len::SIZE - (len - 1) * F::Index::SIZE; 434 if data_len > F::Index::MAX_VALUE as usize { 435 panic!("VarZeroVecOwned integrity: Data segment is too long"); 436 } 437 438 // Test index validity. 439 let indices = unsafe { 440 F::Index::slice_from_bytes_unchecked( 441 &self.entire_slice[F::Len::SIZE..F::Len::SIZE + (len - 1) * F::Index::SIZE], 442 ) 443 }; 444 for idx in indices { 445 if idx.iule_to_usize() > data_len { 446 panic!("VarZeroVecOwned integrity: Indices must not point past the data segment"); 447 } 448 } 449 for window in indices.windows(2) { 450 if window[0].iule_to_usize() > window[1].iule_to_usize() { 451 panic!("VarZeroVecOwned integrity: Indices must be in non-decreasing order"); 452 } 453 } 454 true 455 } 456 457 /// Insert an element at the end of this vector push<A: EncodeAsVarULE<T> + ?Sized>(&mut self, element: &A)458 pub fn push<A: EncodeAsVarULE<T> + ?Sized>(&mut self, element: &A) { 459 self.insert(self.len(), element) 460 } 461 462 /// Insert an element at index `idx` insert<A: EncodeAsVarULE<T> + ?Sized>(&mut self, index: usize, element: &A)463 pub fn insert<A: EncodeAsVarULE<T> + ?Sized>(&mut self, index: usize, element: &A) { 464 let len = self.len(); 465 if index > len { 466 panic!("Called out-of-bounds insert() on VarZeroVec, index {index} len {len}"); 467 } 468 469 let value_len = element.encode_var_ule_len(); 470 471 if len == 0 { 472 let header_len = F::Len::SIZE; // Index array is size 0 for len = 1 473 let cap = header_len + value_len; 474 self.entire_slice.resize(cap, 0); 475 self.entire_slice[0] = 1; // set length 476 element.encode_var_ule_write(&mut self.entire_slice[header_len..]); 477 return; 478 } 479 480 assert!(value_len < F::Index::MAX_VALUE as usize); 481 unsafe { 482 let place = self.shift(index, value_len, ShiftType::Insert); 483 element.encode_var_ule_write(place); 484 } 485 } 486 487 /// Remove the element at index `idx` remove(&mut self, index: usize)488 pub fn remove(&mut self, index: usize) { 489 let len = self.len(); 490 if index >= len { 491 panic!("Called out-of-bounds remove() on VarZeroVec, index {index} len {len}"); 492 } 493 if len == 1 { 494 // This is removing the last element. Set the slice to empty to ensure all empty vecs have empty data slices. 495 self.entire_slice.clear(); 496 return; 497 } 498 unsafe { 499 self.shift(index, 0, ShiftType::Remove); 500 } 501 } 502 503 /// Replace the element at index `idx` with another replace<A: EncodeAsVarULE<T> + ?Sized>(&mut self, index: usize, element: &A)504 pub fn replace<A: EncodeAsVarULE<T> + ?Sized>(&mut self, index: usize, element: &A) { 505 let len = self.len(); 506 if index >= len { 507 panic!("Called out-of-bounds replace() on VarZeroVec, index {index} len {len}"); 508 } 509 510 let value_len = element.encode_var_ule_len(); 511 512 assert!(value_len < F::Index::MAX_VALUE as usize); 513 unsafe { 514 let place = self.shift(index, value_len, ShiftType::Replace); 515 element.encode_var_ule_write(place); 516 } 517 } 518 } 519 520 impl<T: VarULE + ?Sized, F: VarZeroVecFormat> fmt::Debug for VarZeroVecOwned<T, F> 521 where 522 T: fmt::Debug, 523 { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result524 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 525 VarZeroSlice::fmt(self, f) 526 } 527 } 528 529 impl<T: VarULE + ?Sized, F> Default for VarZeroVecOwned<T, F> { default() -> Self530 fn default() -> Self { 531 Self::new() 532 } 533 } 534 535 impl<T, A, F> PartialEq<&'_ [A]> for VarZeroVecOwned<T, F> 536 where 537 T: VarULE + ?Sized, 538 T: PartialEq, 539 A: AsRef<T>, 540 F: VarZeroVecFormat, 541 { 542 #[inline] eq(&self, other: &&[A]) -> bool543 fn eq(&self, other: &&[A]) -> bool { 544 self.iter().eq(other.iter().map(|t| t.as_ref())) 545 } 546 } 547 548 impl<'a, T: ?Sized + VarULE, F: VarZeroVecFormat> From<&'a VarZeroSlice<T, F>> 549 for VarZeroVecOwned<T, F> 550 { from(other: &'a VarZeroSlice<T, F>) -> Self551 fn from(other: &'a VarZeroSlice<T, F>) -> Self { 552 Self::from_slice(other) 553 } 554 } 555 556 #[cfg(test)] 557 mod test { 558 use super::VarZeroVecOwned; 559 #[test] test_insert_integrity()560 fn test_insert_integrity() { 561 let mut items: Vec<String> = Vec::new(); 562 let mut zerovec = VarZeroVecOwned::<str>::new(); 563 564 // Insert into an empty vec. 565 items.insert(0, "1234567890".into()); 566 zerovec.insert(0, "1234567890"); 567 assert_eq!(zerovec, &*items); 568 569 zerovec.insert(1, "foo3"); 570 items.insert(1, "foo3".into()); 571 assert_eq!(zerovec, &*items); 572 573 // Insert at the end. 574 items.insert(items.len(), "qwertyuiop".into()); 575 zerovec.insert(zerovec.len(), "qwertyuiop"); 576 assert_eq!(zerovec, &*items); 577 578 items.insert(0, "asdfghjkl;".into()); 579 zerovec.insert(0, "asdfghjkl;"); 580 assert_eq!(zerovec, &*items); 581 582 items.insert(2, "".into()); 583 zerovec.insert(2, ""); 584 assert_eq!(zerovec, &*items); 585 } 586 587 #[test] 588 // ensure that inserting empty items works test_empty_inserts()589 fn test_empty_inserts() { 590 let mut items: Vec<String> = Vec::new(); 591 let mut zerovec = VarZeroVecOwned::<str>::new(); 592 593 // Insert into an empty vec. 594 items.insert(0, "".into()); 595 zerovec.insert(0, ""); 596 assert_eq!(zerovec, &*items); 597 598 items.insert(0, "".into()); 599 zerovec.insert(0, ""); 600 assert_eq!(zerovec, &*items); 601 602 items.insert(0, "1234567890".into()); 603 zerovec.insert(0, "1234567890"); 604 assert_eq!(zerovec, &*items); 605 606 items.insert(0, "".into()); 607 zerovec.insert(0, ""); 608 assert_eq!(zerovec, &*items); 609 } 610 611 #[test] test_small_insert_integrity()612 fn test_small_insert_integrity() { 613 // Tests that insert() works even when there 614 // is not enough space for the new index in entire_slice.len() 615 let mut items: Vec<String> = Vec::new(); 616 let mut zerovec = VarZeroVecOwned::<str>::new(); 617 618 // Insert into an empty vec. 619 items.insert(0, "abc".into()); 620 zerovec.insert(0, "abc"); 621 assert_eq!(zerovec, &*items); 622 623 zerovec.insert(1, "def"); 624 items.insert(1, "def".into()); 625 assert_eq!(zerovec, &*items); 626 } 627 628 #[test] 629 #[should_panic] test_insert_past_end()630 fn test_insert_past_end() { 631 VarZeroVecOwned::<str>::new().insert(1, ""); 632 } 633 634 #[test] test_remove_integrity()635 fn test_remove_integrity() { 636 let mut items: Vec<&str> = vec!["apples", "bananas", "eeples", "", "baneenees", "five", ""]; 637 let mut zerovec = VarZeroVecOwned::<str>::try_from_elements(&items).unwrap(); 638 639 for index in [0, 2, 4, 0, 1, 1, 0] { 640 items.remove(index); 641 zerovec.remove(index); 642 assert_eq!(zerovec, &*items, "index {}, len {}", index, items.len()); 643 } 644 } 645 646 #[test] test_removing_last_element_clears()647 fn test_removing_last_element_clears() { 648 let mut zerovec = VarZeroVecOwned::<str>::try_from_elements(&["buy some apples"]).unwrap(); 649 assert!(!zerovec.as_bytes().is_empty()); 650 zerovec.remove(0); 651 assert!(zerovec.as_bytes().is_empty()); 652 } 653 654 #[test] 655 #[should_panic] test_remove_past_end()656 fn test_remove_past_end() { 657 VarZeroVecOwned::<str>::new().remove(0); 658 } 659 660 #[test] test_replace_integrity()661 fn test_replace_integrity() { 662 let mut items: Vec<&str> = vec!["apples", "bananas", "eeples", "", "baneenees", "five", ""]; 663 let mut zerovec = VarZeroVecOwned::<str>::try_from_elements(&items).unwrap(); 664 665 // Replace with an element of the same size (and the first element) 666 items[0] = "blablah"; 667 zerovec.replace(0, "blablah"); 668 assert_eq!(zerovec, &*items); 669 670 // Replace with a smaller element 671 items[1] = "twily"; 672 zerovec.replace(1, "twily"); 673 assert_eq!(zerovec, &*items); 674 675 // Replace an empty element 676 items[3] = "aoeuidhtns"; 677 zerovec.replace(3, "aoeuidhtns"); 678 assert_eq!(zerovec, &*items); 679 680 // Replace the last element 681 items[6] = "0123456789"; 682 zerovec.replace(6, "0123456789"); 683 assert_eq!(zerovec, &*items); 684 685 // Replace with an empty element 686 items[2] = ""; 687 zerovec.replace(2, ""); 688 assert_eq!(zerovec, &*items); 689 } 690 691 #[test] 692 #[should_panic] test_replace_past_end()693 fn test_replace_past_end() { 694 VarZeroVecOwned::<str>::new().replace(0, ""); 695 } 696 } 697