Next Generation WASM Microkernel Operating System

refactor: replace external `arrayvec` dependency

This change replaces the external `arrayvec` dependency with an API-equivalent internal one. We do this for two reasons:
1. the external dependency does not mark enough functions as `const` which we would like to have
2. general code quality and maintainance questions with the external dependency

+932 -10
+1 -3
Cargo.lock
··· 110 110 111 111 [[package]] 112 112 name = "arrayvec" 113 - version = "0.7.6" 114 - source = "registry+https://github.com/rust-lang/crates.io-index" 115 - checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" 113 + version = "0.1.0" 116 114 117 115 [[package]] 118 116 name = "autocfg"
+2 -2
Cargo.toml
··· 95 95 kfastrand = { path = "libs/kfastrand" } 96 96 abort = { path = "libs/abort" } 97 97 panic-unwind2 = { path = "libs/panic-unwind2" } 98 - util = { path = "libs/util"} 98 + util = { path = "libs/util" } 99 99 kasync = { path = "libs/kasync" } 100 100 kmem = { path = "libs/kmem" } 101 + arrayvec = { path = "libs/arrayvec" } 101 102 102 103 # 3rd-party dependencies 103 104 cfg-if = "1.0.0" ··· 108 109 static_assertions = "1.1.0" 109 110 rand = { version = "0.9.2", default-features = false } 110 111 rand_chacha = { version = "0.9.0", default-features = false } 111 - arrayvec = { version = "0.7.6", default-features = false } 112 112 gimli = { version = "0.31.1", default-features = false, features = ["read"] } 113 113 talc = { version = "4.4.2", default-features = false, features = ["lock_api", "counters"] } 114 114 smallvec = { version = "1", default-features = false }
+1 -1
kernel/src/backtrace/mod.rs
··· 135 135 let mut iter = iter.take(MAX_FRAMES); 136 136 137 137 while let Some(frame) = iter.next()? { 138 - frames.try_push(frame.ip()).unwrap(); 138 + frames.push(frame.ip()); 139 139 } 140 140 let frames_omitted = iter.next()?.is_some(); 141 141
+11
libs/arrayvec/Cargo.toml
··· 1 + [package] 2 + name = "arrayvec" 3 + version.workspace = true 4 + edition.workspace = true 5 + authors.workspace = true 6 + license.workspace = true 7 + 8 + [dependencies] 9 + 10 + [lints] 11 + workspace = true
+912
libs/arrayvec/src/lib.rs
··· 1 + #![cfg_attr(not(test), no_std)] 2 + // #![no_std] 3 + 4 + use core::error::Error; 5 + use core::mem::MaybeUninit; 6 + use core::ops::{Bound, Deref, DerefMut, RangeBounds}; 7 + use core::ptr::NonNull; 8 + use core::{cmp, fmt, mem, ptr, slice}; 9 + 10 + pub struct CapacityError<T>(pub T); 11 + 12 + impl<T> Error for CapacityError<T> {} 13 + 14 + impl<T> fmt::Display for CapacityError<T> { 15 + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 16 + f.write_str("insufficient capacity") 17 + } 18 + } 19 + 20 + impl<T> fmt::Debug for CapacityError<T> { 21 + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 22 + write!(f, "CapacityError: insufficient capacity") 23 + } 24 + } 25 + 26 + /// A vector with a fixed capacity. 27 + /// 28 + /// The `ArrayVec` is a vector backed by a fixed size array. Elements are stored inline in the vector 29 + /// itself (rather than on the heap) making `ArrayVec` suitable to be allocated on the stack or 30 + /// used in `const` contexts. 31 + /// 32 + /// The maximum capacity of the vector is determined by the `CAP` generic parameter, attempting to 33 + /// insert more elements than `CAP` will always fail. 34 + #[derive(Debug)] 35 + pub struct ArrayVec<T, const CAP: usize> { 36 + len: usize, 37 + data: [MaybeUninit<T>; CAP], 38 + } 39 + 40 + impl<T, const CAP: usize> Default for ArrayVec<T, CAP> { 41 + fn default() -> Self { 42 + Self::new() 43 + } 44 + } 45 + 46 + impl<T, const CAP: usize> Drop for ArrayVec<T, CAP> { 47 + fn drop(&mut self) { 48 + self.clear(); 49 + } 50 + } 51 + 52 + impl<T, const CAP: usize> ArrayVec<T, CAP> { 53 + /// Create a new empty `ArrayVec`. 54 + /// 55 + /// The maximum capacity is given by the generic parameter `CAP`. 56 + #[inline] 57 + pub const fn new() -> Self { 58 + Self { 59 + data: [const { MaybeUninit::uninit() }; CAP], 60 + len: 0, 61 + } 62 + } 63 + 64 + /// Returns the number of elements in the `ArrayVec`. 65 + #[inline(always)] 66 + pub const fn len(&self) -> usize { 67 + self.len 68 + } 69 + 70 + /// Returns `true` if the `ArrayVec` is empty, `false` otherwise. 71 + #[inline] 72 + pub const fn is_empty(&self) -> bool { 73 + self.len() == 0 74 + } 75 + 76 + /// Returns the capacity of the `ArrayVec`. 77 + #[inline(always)] 78 + pub const fn capacity(&self) -> usize { 79 + CAP 80 + } 81 + 82 + /// Returns `true` if the `ArrayVec` is completely filled to its capacity, `false` otherwise. 83 + pub const fn is_full(&self) -> bool { 84 + self.len() == self.capacity() 85 + } 86 + 87 + /// Returns the capacity left in the `ArrayVec`. 88 + pub const fn remaining_capacity(&self) -> usize { 89 + self.capacity() - self.len() 90 + } 91 + 92 + /// Returns a raw pointer to the vector’s buffer. 93 + pub const fn as_ptr(&self) -> *const T { 94 + self.data.as_ptr().cast() 95 + } 96 + 97 + /// Returns a raw mutable pointer to the vector’s buffer. 98 + pub const fn as_mut_ptr(&mut self) -> *mut T { 99 + self.data.as_mut_ptr().cast() 100 + } 101 + 102 + /// Extracts a slice containing the entire vector. 103 + pub const fn as_slice(&self) -> &[T] { 104 + // SAFETY: `slice::from_raw_parts` requires 105 + // 1. pointee is a contiguous, aligned buffer of size `len` containing properly-initialized `T`s. 106 + // 2. Data must not be mutated for the returned lifetime. 107 + // 3. Further, `len * size_of::<T>` <= `isize::MAX`, and allocation does not "wrap" through overflowing memory addresses. 108 + // 109 + // The ArrayVec API guarantees properly-initialized items within 0..len 110 + // and the backing store being a Rust array guarantees correct alignment and contiguity. 111 + // 3. Is also guaranteed by construction (can't express a type that's too large) and we 112 + // since we borrow self here 2. is upheld as well. 113 + unsafe { slice::from_raw_parts(self.as_ptr(), self.len) } 114 + } 115 + 116 + /// Extracts a mutable slice of the entire vector. 117 + pub const fn as_mut_slice(&mut self) -> &mut [T] { 118 + // SAFETY: `slice::from_raw_parts` requires 119 + // 1. pointee is a contiguous, aligned buffer of size `len` containing properly-initialized `T`s. 120 + // 2. Data must not be mutated for the returned lifetime. 121 + // 3. Further, `len * size_of::<T>` <= `isize::MAX`, and allocation does not "wrap" through overflowing memory addresses. 122 + // 123 + // The ArrayVec API guarantees properly-initialized items within 0..len 124 + // and the backing store being a Rust array guarantees correct alignment and contiguity. 125 + // 3. Is also guaranteed by construction (can't express a type that's too large) and we 126 + // since we borrow self here 2. is upheld as well. 127 + unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) } 128 + } 129 + 130 + /// Push `element` to the end of the vector. 131 + /// 132 + /// # Panics 133 + /// 134 + /// Panics if the `ArrayVec` is full. 135 + pub fn push(&mut self, element: T) { 136 + self.try_push(element).unwrap(); 137 + } 138 + 139 + /// Push `element` to the end of the vector. 140 + /// 141 + /// # Errors 142 + /// 143 + /// Returns `Err(CapacityError)` with the element if the `ArrayVec` is full. 144 + pub const fn try_push(&mut self, element: T) -> Result<(), CapacityError<T>> { 145 + if self.len() < CAP { 146 + // Safety: we have checked the capacity above 147 + unsafe { 148 + self.push_unchecked(element); 149 + } 150 + Ok(()) 151 + } else { 152 + Err(CapacityError(element)) 153 + } 154 + } 155 + 156 + /// Push `element` to the end of the vector, without doing bounds checking. 157 + /// 158 + /// # Safety 159 + /// 160 + /// Calling this method with on an already full vector is *[undefined behavior]*. 161 + /// The caller has to ensure that `self.len() < self.capacity()`. 162 + #[track_caller] 163 + pub const unsafe fn push_unchecked(&mut self, element: T) { 164 + let len = self.len(); 165 + debug_assert!(len < CAP); 166 + self.data[len].write(element); 167 + self.len += 1; 168 + } 169 + 170 + /// Remove all elements in the vector. 171 + pub fn clear(&mut self) { 172 + let len = self.len; 173 + self.len = 0; 174 + for elt in self.data.iter_mut().take(len) { 175 + // Safety: ArrayVec API guarantees properly-initialized items within 0..len 176 + unsafe { MaybeUninit::assume_init_drop(elt) }; 177 + } 178 + } 179 + 180 + /// Retains only the elements specified by the predicate. 181 + pub fn retain<F>(&mut self, mut f: F) 182 + where 183 + F: FnMut(&mut T) -> bool, 184 + { 185 + // The implementation below is taken from std::vec::Vec 186 + 187 + let original_len = self.len(); 188 + self.len = 0; 189 + 190 + struct BackshiftOnDrop<'a, T, const CAP: usize> { 191 + v: &'a mut ArrayVec<T, CAP>, 192 + processed_len: usize, 193 + deleted_cnt: usize, 194 + original_len: usize, 195 + } 196 + 197 + impl<T, const CAP: usize> Drop for BackshiftOnDrop<'_, T, CAP> { 198 + fn drop(&mut self) { 199 + if self.deleted_cnt > 0 { 200 + // Safety: Trailing unchecked items must be valid since we never touch them. 201 + unsafe { 202 + ptr::copy( 203 + self.v.as_ptr().add(self.processed_len), 204 + self.v 205 + .as_mut_ptr() 206 + .add(self.processed_len - self.deleted_cnt), 207 + self.original_len - self.processed_len, 208 + ); 209 + } 210 + } 211 + self.v.len = self.original_len - self.deleted_cnt; 212 + } 213 + } 214 + 215 + let mut g = BackshiftOnDrop { 216 + v: self, 217 + processed_len: 0, 218 + deleted_cnt: 0, 219 + original_len, 220 + }; 221 + 222 + #[inline(always)] 223 + fn process_one<F: FnMut(&mut T) -> bool, T, const CAP: usize, const DELETED: bool>( 224 + f: &mut F, 225 + g: &mut BackshiftOnDrop<'_, T, CAP>, 226 + ) -> bool { 227 + // Safety: Unchecked element must be valid. 228 + let cur = unsafe { g.v.as_mut_ptr().add(g.processed_len) }; 229 + // Safety: Unchecked element must be valid. 230 + if !f(unsafe { cur.as_mut().unwrap() }) { 231 + g.processed_len += 1; 232 + g.deleted_cnt += 1; 233 + // Safety: We never touch this element again after dropped. 234 + unsafe { ptr::drop_in_place(cur) }; 235 + return false; 236 + } 237 + if DELETED { 238 + // Safety: `deleted_cnt` > 0, so the hole slot must not overlap with current element. 239 + // We use copy for move, and never touch this element again. 240 + unsafe { 241 + let hole_slot = cur.sub(g.deleted_cnt); 242 + ptr::copy_nonoverlapping(cur, hole_slot, 1); 243 + } 244 + } 245 + g.processed_len += 1; 246 + true 247 + } 248 + 249 + // Stage 1: Nothing was deleted. 250 + while g.processed_len != original_len { 251 + if !process_one::<F, T, CAP, false>(&mut f, &mut g) { 252 + break; 253 + } 254 + } 255 + 256 + // Stage 2: Some elements were deleted. 257 + while g.processed_len != original_len { 258 + process_one::<F, T, CAP, true>(&mut f, &mut g); 259 + } 260 + 261 + drop(g); 262 + } 263 + 264 + /// Removes the subslice indicated by the given range from the vector, 265 + /// returning a double-ended iterator over the removed subslice. 266 + /// 267 + /// If the iterator is dropped before being fully consumed, 268 + /// it drops the remaining removed elements. 269 + /// 270 + /// The returned iterator keeps a mutable borrow on the vector to optimize 271 + /// its implementation. 272 + /// 273 + /// # Panics 274 + /// 275 + /// Panics if the starting point is greater than the end point or if 276 + /// the end point is greater than the length of the vector. 277 + /// 278 + /// # Leaking 279 + /// 280 + /// If the returned iterator goes out of scope without being dropped (due to 281 + /// [`mem::forget`], for example), the vector may have lost and leaked 282 + /// elements arbitrarily, including elements outside the range. 283 + pub fn drain<R>(&mut self, range: R) -> Drain<'_, T, CAP> 284 + where 285 + R: RangeBounds<usize>, 286 + { 287 + // Memory safety 288 + // 289 + // When the Drain is first created, it shortens the length of 290 + // the source vector to make sure no uninitialized or moved-from elements 291 + // are accessible at all if the Drain's destructor never gets to run. 292 + // 293 + // Drain will ptr::read out the values to remove. 294 + // When finished, remaining tail of the vec is copied back to cover 295 + // the hole, and the vector length is restored to the new length. 296 + 297 + let len = self.len(); 298 + let start = match range.start_bound() { 299 + Bound::Unbounded => 0, 300 + Bound::Included(&i) => i, 301 + Bound::Excluded(&i) => i.saturating_add(1), 302 + }; 303 + let end = match range.end_bound() { 304 + Bound::Excluded(&j) => j, 305 + Bound::Included(&j) => j.saturating_add(1), 306 + Bound::Unbounded => len, 307 + }; 308 + 309 + // set our length to start, to be safe in case Drain is leaked 310 + self.len = start; 311 + // Safety: ArrayVec API guarantees properly-initialized items within 0..len 312 + // Note: we do this unsafe slicing here because we also need to mutably borrow self (for backshifting the tail) 313 + let range_slice = unsafe { slice::from_raw_parts(self.as_ptr().add(start), end - start) }; 314 + 315 + Drain { 316 + tail_start: end, 317 + tail_len: len - end, 318 + iter: range_slice.iter(), 319 + #[expect(clippy::ref_as_ptr, reason = "passing &mut self to a function would invalidate the slice iterator")] 320 + // Safety: We have a &mut to self, so creating a pointer from it is always safe. 321 + vec: unsafe { NonNull::new_unchecked(self as *mut _) }, 322 + } 323 + } 324 + 325 + /// Shortens the vector, keeping the first `len` elements and dropping 326 + /// the rest 327 + pub fn truncate(&mut self, new_len: usize) { 328 + let len = self.len(); 329 + if new_len < len { 330 + // Safety: ArrayVec API guarantees properly-initialized items within 0..len 331 + // we have checked that new_len is less than len so all elements within 0..new_len must be 332 + // initialized 333 + unsafe { 334 + self.len = new_len; 335 + let tail = slice::from_raw_parts_mut(self.as_mut_ptr().add(new_len), len - new_len); 336 + ptr::drop_in_place(tail); 337 + } 338 + } 339 + } 340 + 341 + /// Returns the remaining spare capacity of the vector as a slice of 342 + /// `MaybeUninit<T>`. 343 + pub fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit<T>] { 344 + let len = self.len(); 345 + &mut self.data[len..] 346 + } 347 + 348 + /// Extend the `ArrayVec` with elements from the provided slice 349 + /// 350 + /// # Panics 351 + /// 352 + /// Panics if the `ArrayVec` does not have enough capacity to accommodate 353 + /// the elements. 354 + pub fn extend_from_slice(&mut self, slice: &[T]) 355 + where 356 + T: Clone, 357 + { 358 + self.try_extend_from_slice(slice).unwrap(); 359 + } 360 + 361 + /// Extend the `ArrayVec` with elements from the provided slice 362 + /// 363 + /// # Errors 364 + /// 365 + /// Returns a `CapacityError` if the `ArrayVec` does not have enough capacity to accommodate 366 + /// the elements. 367 + pub fn try_extend_from_slice(&mut self, other: &[T]) -> Result<(), CapacityError<()>> 368 + where 369 + T: Clone, 370 + { 371 + if self.remaining_capacity() < other.len() { 372 + return Err(CapacityError(())); 373 + } 374 + 375 + for (element, slot) in other.iter().cloned().zip(self.spare_capacity_mut()) { 376 + slot.write(element); 377 + } 378 + self.len += other.len(); 379 + 380 + Ok(()) 381 + } 382 + } 383 + 384 + impl<T, const CAP: usize> Clone for ArrayVec<T, CAP> 385 + where 386 + T: Clone, 387 + { 388 + fn clone(&self) -> Self { 389 + self.iter().cloned().collect() 390 + } 391 + 392 + fn clone_from(&mut self, rhs: &Self) { 393 + // recursive case for the common prefix 394 + let prefix = cmp::min(self.len(), rhs.len()); 395 + self[..prefix].clone_from_slice(&rhs[..prefix]); 396 + 397 + if prefix < self.len() { 398 + // rhs was shorter 399 + self.truncate(prefix); 400 + } else { 401 + let rhs_elems = &rhs[self.len()..]; 402 + self.extend_from_slice(rhs_elems); 403 + } 404 + } 405 + } 406 + 407 + /// Create an `ArrayVec` from an iterator. 408 + /// 409 + /// ***Panics*** if the number of elements in the iterator exceeds the arrayvec's capacity. 410 + impl<T, const CAP: usize> FromIterator<T> for ArrayVec<T, CAP> { 411 + /// Create an `ArrayVec` from an iterator. 412 + /// 413 + /// ***Panics*** if the number of elements in the iterator exceeds the arrayvec's capacity. 414 + fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self { 415 + let mut array = ArrayVec::new(); 416 + for element in iter { 417 + array.push(element); 418 + } 419 + array 420 + } 421 + } 422 + 423 + impl<T, const CAP: usize> Deref for ArrayVec<T, CAP> { 424 + type Target = [T]; 425 + #[inline] 426 + fn deref(&self) -> &Self::Target { 427 + self.as_slice() 428 + } 429 + } 430 + 431 + impl<T, const CAP: usize> DerefMut for ArrayVec<T, CAP> { 432 + #[inline] 433 + fn deref_mut(&mut self) -> &mut Self::Target { 434 + self.as_mut_slice() 435 + } 436 + } 437 + 438 + impl<'a, T: 'a, const CAP: usize> IntoIterator for &'a ArrayVec<T, CAP> { 439 + type Item = &'a T; 440 + type IntoIter = slice::Iter<'a, T>; 441 + fn into_iter(self) -> Self::IntoIter { 442 + self.iter() 443 + } 444 + } 445 + 446 + impl<'a, T: 'a, const CAP: usize> IntoIterator for &'a mut ArrayVec<T, CAP> { 447 + type Item = &'a mut T; 448 + type IntoIter = slice::IterMut<'a, T>; 449 + fn into_iter(self) -> Self::IntoIter { 450 + self.iter_mut() 451 + } 452 + } 453 + 454 + impl<T, const CAP: usize> IntoIterator for ArrayVec<T, CAP> { 455 + type Item = T; 456 + type IntoIter = IntoIter<T, CAP>; 457 + fn into_iter(self) -> IntoIter<T, CAP> { 458 + IntoIter { 459 + index: 0, 460 + vec: self, 461 + } 462 + } 463 + } 464 + 465 + pub struct IntoIter<T, const CAP: usize> { 466 + index: usize, 467 + vec: ArrayVec<T, CAP>, 468 + } 469 + 470 + impl<T, const CAP: usize> Drop for IntoIter<T, CAP> { 471 + fn drop(&mut self) { 472 + let len = self.vec.len(); 473 + self.vec.len = 0; 474 + for elt in &mut self.vec.data[self.index..len] { 475 + // Safety: ArrayVec API guarantees properly-initialized items within 0..len 476 + unsafe { MaybeUninit::assume_init_drop(elt) }; 477 + } 478 + } 479 + } 480 + 481 + impl<T, const CAP: usize> Iterator for IntoIter<T, CAP> { 482 + type Item = T; 483 + 484 + fn next(&mut self) -> Option<Self::Item> { 485 + if self.vec.is_empty() { 486 + None 487 + } else { 488 + let elt = mem::replace(&mut self.vec.data[self.index], MaybeUninit::uninit()); 489 + self.index += 1; 490 + // Safety: ArrayVec API guarantees properly-initialized items within 0..len 491 + Some(unsafe { MaybeUninit::assume_init(elt) }) 492 + } 493 + } 494 + 495 + fn size_hint(&self) -> (usize, Option<usize>) { 496 + (self.vec.len(), Some(self.vec.len())) 497 + } 498 + } 499 + 500 + impl<T, const CAP: usize> DoubleEndedIterator for IntoIter<T, CAP> { 501 + fn next_back(&mut self) -> Option<Self::Item> { 502 + if self.vec.is_empty() { 503 + None 504 + } else { 505 + let elt = mem::replace(&mut self.vec.data[self.vec.len - 1], MaybeUninit::uninit()); 506 + self.index -= 1; 507 + // Safety: ArrayVec API guarantees properly-initialized items within 0..len 508 + Some(unsafe { MaybeUninit::assume_init(elt) }) 509 + } 510 + } 511 + } 512 + 513 + impl<T, const CAP: usize> ExactSizeIterator for IntoIter<T, CAP> {} 514 + 515 + /// A draining iterator for `ArrayVec`. 516 + pub struct Drain<'a, T, const CAP: usize> { 517 + /// Index of tail to preserve 518 + tail_start: usize, 519 + /// Length of tail 520 + tail_len: usize, 521 + /// Current remaining range to remove 522 + iter: slice::Iter<'a, T>, 523 + vec: NonNull<ArrayVec<T, CAP>>, 524 + } 525 + 526 + impl<T, const CAP: usize> Iterator for Drain<'_, T, CAP> { 527 + type Item = T; 528 + 529 + fn next(&mut self) -> Option<Self::Item> { 530 + self.iter.next().map(|elt| { 531 + // Safety: ArrayVec API guarantees properly-initialized items within 0..len 532 + unsafe { ptr::read(ptr::from_ref(elt)) } 533 + }) 534 + } 535 + 536 + fn size_hint(&self) -> (usize, Option<usize>) { 537 + self.iter.size_hint() 538 + } 539 + } 540 + 541 + impl<T, const CAP: usize> DoubleEndedIterator for Drain<'_, T, CAP> { 542 + fn next_back(&mut self) -> Option<Self::Item> { 543 + self.iter.next_back().map(|elt| { 544 + // Safety: ArrayVec API guarantees properly-initialized items within 0..len 545 + unsafe { ptr::read(ptr::from_ref(elt)) } 546 + }) 547 + } 548 + } 549 + 550 + impl<T, const CAP: usize> ExactSizeIterator for Drain<'_, T, CAP> {} 551 + 552 + impl<T, const CAP: usize> Drop for Drain<'_, T, CAP> { 553 + fn drop(&mut self) { 554 + /// Fill the drained range by backshifting the "tail" (elements after the drained range). 555 + /// 556 + /// We do this in a drop guard so that no matter what happens, even if T's drop panics 557 + /// we leave an ArrayVec without uninitialized holes behind. 558 + struct DropGuard<'r, 'a, T, const CAP: usize>(&'r mut Drain<'a, T, CAP>); 559 + 560 + impl<'r, 'a, T, const CAP: usize> Drop for DropGuard<'r, 'a, T, CAP> { 561 + fn drop(&mut self) { 562 + if self.0.tail_len > 0 { 563 + // Safety: See ArrayVec::drain comment 564 + unsafe { 565 + let source_vec = self.0.vec.as_mut(); 566 + 567 + // memmove back untouched tail, update to new length 568 + let start = source_vec.len(); 569 + let tail = self.0.tail_start; 570 + if tail != start { 571 + // as_mut_ptr creates a &mut, invalidating other pointers. 572 + // This pattern avoids calling it with a pointer already present. 573 + let ptr = source_vec.as_mut_ptr(); 574 + let src = ptr.add(tail); 575 + let dst = ptr.add(start); 576 + ptr::copy(src, dst, self.0.tail_len); 577 + } 578 + source_vec.len = start + self.0.tail_len; 579 + } 580 + } 581 + } 582 + } 583 + 584 + let guard = DropGuard(self); 585 + 586 + // drain the iterator and drop its elements 587 + for _ in guard.0.by_ref() {} 588 + // while let Some(_) = guard.0.next() {} 589 + } 590 + } 591 + 592 + #[cfg(test)] 593 + mod tests { 594 + use super::*; 595 + 596 + #[test] 597 + fn new_creates_empty_vec() { 598 + let vec: ArrayVec<i32, 10> = ArrayVec::new(); 599 + assert_eq!(vec.len(), 0); 600 + assert!(vec.is_empty()); 601 + assert_eq!(vec.capacity(), 10); 602 + } 603 + 604 + #[test] 605 + fn default_creates_empty_vec() { 606 + let vec: ArrayVec<i32, 10> = ArrayVec::default(); 607 + assert_eq!(vec.len(), 0); 608 + assert!(vec.is_empty()); 609 + } 610 + 611 + #[test] 612 + fn push_increases_length() { 613 + let mut vec: ArrayVec<i32, 10> = ArrayVec::new(); 614 + vec.push(1); 615 + assert_eq!(vec.len(), 1); 616 + vec.push(2); 617 + assert_eq!(vec.len(), 2); 618 + } 619 + 620 + #[test] 621 + #[should_panic] 622 + fn push_panics_when_full() { 623 + let mut vec: ArrayVec<i32, 2> = ArrayVec::new(); 624 + vec.push(1); 625 + vec.push(2); 626 + vec.push(3); 627 + } 628 + 629 + #[test] 630 + fn try_push_succeeds_when_not_full() { 631 + let mut vec: ArrayVec<i32, 2> = ArrayVec::new(); 632 + assert!(vec.try_push(1).is_ok()); 633 + assert!(vec.try_push(2).is_ok()); 634 + } 635 + 636 + #[test] 637 + fn try_push_fails_when_full() { 638 + let mut vec: ArrayVec<i32, 2> = ArrayVec::new(); 639 + vec.push(1); 640 + vec.push(2); 641 + let result = vec.try_push(3); 642 + assert!(result.is_err()); 643 + assert_eq!(result.unwrap_err().0, 3); 644 + } 645 + 646 + #[test] 647 + fn is_full_returns_true_when_at_capacity() { 648 + let mut vec: ArrayVec<i32, 2> = ArrayVec::new(); 649 + assert!(!vec.is_full()); 650 + vec.push(1); 651 + assert!(!vec.is_full()); 652 + vec.push(2); 653 + assert!(vec.is_full()); 654 + } 655 + 656 + #[test] 657 + fn as_slice_returns_valid_slice() { 658 + let mut vec: ArrayVec<i32, 10> = ArrayVec::new(); 659 + vec.push(1); 660 + vec.push(2); 661 + vec.push(3); 662 + let slice = vec.as_slice(); 663 + assert_eq!(slice, &[1, 2, 3]); 664 + } 665 + 666 + #[test] 667 + fn as_mut_slice_allows_modification() { 668 + let mut vec: ArrayVec<i32, 10> = ArrayVec::new(); 669 + vec.push(1); 670 + vec.push(2); 671 + let slice = vec.as_mut_slice(); 672 + slice[0] = 10; 673 + assert_eq!(vec.as_slice(), &[10, 2]); 674 + } 675 + #[test] 676 + fn clear_removes_all_elements() { 677 + let mut vec: ArrayVec<i32, 10> = ArrayVec::new(); 678 + vec.push(1); 679 + vec.push(2); 680 + vec.push(3); 681 + vec.clear(); 682 + assert_eq!(vec.len(), 0); 683 + assert!(vec.is_empty()); 684 + } 685 + 686 + #[test] 687 + fn retain_keeps_matching_elements() { 688 + let mut vec: ArrayVec<i32, 10> = ArrayVec::new(); 689 + vec.push(1); 690 + vec.push(2); 691 + vec.push(3); 692 + vec.push(4); 693 + vec.retain(|x| *x % 2 == 0); 694 + assert_eq!(vec.as_slice(), &[2, 4]); 695 + } 696 + 697 + #[test] 698 + fn clone_from_updates_to_match_source() { 699 + let mut vec1: ArrayVec<i32, 10> = ArrayVec::new(); 700 + vec1.push(1); 701 + vec1.push(2); 702 + let mut vec2: ArrayVec<i32, 10> = ArrayVec::new(); 703 + vec2.push(3); 704 + vec2.push(4); 705 + vec2.push(5); 706 + vec2.clone_from(&vec1); 707 + assert_eq!(vec2.as_slice(), &[1, 2]); 708 + } 709 + 710 + #[test] 711 + fn try_extend_from_slice_succeeds_with_capacity() { 712 + let mut vec: ArrayVec<i32, 10> = ArrayVec::new(); 713 + vec.push(1); 714 + assert!(vec.try_extend_from_slice(&[2, 3]).is_ok()); 715 + assert_eq!(vec.as_slice(), &[1, 2, 3]); 716 + } 717 + 718 + #[test] 719 + fn try_extend_from_slice_fails_without_capacity() { 720 + let mut vec: ArrayVec<i32, 3> = ArrayVec::new(); 721 + vec.push(1); 722 + let result = vec.try_extend_from_slice(&[2, 3, 4]); 723 + assert!(result.is_err()); 724 + } 725 + 726 + #[test] 727 + fn extend_from_slice_adds_elements() { 728 + let mut vec: ArrayVec<i32, 10> = ArrayVec::new(); 729 + vec.push(1); 730 + vec.extend_from_slice(&[2, 3, 4]); 731 + assert_eq!(vec.as_slice(), &[1, 2, 3, 4]); 732 + } 733 + 734 + #[test] 735 + #[should_panic] 736 + fn extend_from_slice_panics_when_insufficient_capacity() { 737 + let mut vec: ArrayVec<i32, 3> = ArrayVec::new(); 738 + vec.push(1); 739 + vec.extend_from_slice(&[2, 3, 4]); 740 + } 741 + 742 + #[test] 743 + fn truncate_removes_trailing_elements() { 744 + let mut vec: ArrayVec<i32, 10> = ArrayVec::new(); 745 + vec.push(1); 746 + vec.push(2); 747 + vec.push(3); 748 + vec.push(4); 749 + vec.truncate(2); 750 + assert_eq!(vec.len(), 2); 751 + assert_eq!(vec.as_slice(), &[1, 2]); 752 + } 753 + 754 + #[test] 755 + fn drain_removes_elements_in_range() { 756 + let mut vec: ArrayVec<i32, 10> = ArrayVec::new(); 757 + vec.extend_from_slice(&[1, 2, 3, 4, 5]); 758 + let drained: Vec<_> = vec.drain(1..3).collect(); 759 + assert_eq!(drained, &[2, 3]); 760 + assert_eq!(vec.as_slice(), &[1, 4, 5]); 761 + } 762 + 763 + #[test] 764 + fn drain_calls_drop_on_remaining_elements() { 765 + use core::sync::atomic::{AtomicUsize, Ordering}; 766 + static DROP_COUNT: AtomicUsize = AtomicUsize::new(0); 767 + 768 + struct DropCounter; 769 + impl Drop for DropCounter { 770 + fn drop(&mut self) { 771 + DROP_COUNT.fetch_add(1, Ordering::SeqCst); 772 + } 773 + } 774 + 775 + { 776 + let mut vec: ArrayVec<DropCounter, 5> = ArrayVec::new(); 777 + vec.push(DropCounter); 778 + vec.push(DropCounter); 779 + vec.push(DropCounter); 780 + let mut drain = vec.drain(0..2); 781 + drain.next(); // consume one element 782 + // Drop drain without consuming all elements 783 + drop(drain); 784 + 785 + assert_eq!(DROP_COUNT.load(Ordering::SeqCst), 2); 786 + } 787 + // All 3 elements should be dropped: 1 consumed, 1 remaining in drain, 1 in vec 788 + assert_eq!(DROP_COUNT.load(Ordering::SeqCst), 3); 789 + } 790 + 791 + #[test] 792 + fn drain_restores_tail_on_early_drop() { 793 + let mut vec: ArrayVec<i32, 10> = ArrayVec::new(); 794 + vec.extend_from_slice(&[1, 2, 3, 4, 5]); 795 + assert_eq!(vec.len(), 5); 796 + { 797 + let mut drain = vec.drain(1..3); 798 + drain.next(); // consume one element (2) 799 + // drain is dropped here without consuming all elements 800 + } 801 + // Tail should be restored: [1, 4, 5] 802 + assert_eq!(vec.as_slice(), &[1, 4, 5]); 803 + } 804 + 805 + #[test] 806 + fn drain_empty_range() { 807 + let mut vec: ArrayVec<i32, 10> = ArrayVec::new(); 808 + vec.extend_from_slice(&[1, 2, 3]); 809 + assert_eq!(vec.len(), 3); 810 + let drained: Vec<_> = vec.drain(1..1).collect(); 811 + assert_eq!(drained.len(), 0); 812 + assert_eq!(vec.as_slice(), &[1, 2, 3]); 813 + } 814 + 815 + #[test] 816 + fn drain_full_range() { 817 + let mut vec: ArrayVec<i32, 10> = ArrayVec::new(); 818 + vec.extend_from_slice(&[1, 2, 3, 4]); 819 + assert_eq!(vec.len(), 4); 820 + let drained: Vec<_> = vec.drain(..).collect(); 821 + assert_eq!(drained, &[1, 2, 3, 4]); 822 + assert_eq!(vec.len(), 0); 823 + assert!(vec.is_empty()); 824 + } 825 + 826 + #[test] 827 + fn drain_double_ended() { 828 + let mut vec: ArrayVec<i32, 10> = ArrayVec::new(); 829 + vec.extend_from_slice(&[1, 2, 3, 4, 5]); 830 + assert_eq!(vec.len(), 5); 831 + let mut drain = vec.drain(1..4); 832 + assert_eq!(drain.next(), Some(2)); 833 + assert_eq!(drain.next_back(), Some(4)); 834 + assert_eq!(drain.next(), Some(3)); 835 + assert_eq!(drain.next(), None); 836 + drop(drain); 837 + assert_eq!(vec.as_slice(), &[1, 5]); 838 + } 839 + 840 + #[test] 841 + fn into_iter_panic_in_drop() { 842 + use core::sync::atomic::{AtomicUsize, Ordering}; 843 + static DROP_COUNT: AtomicUsize = AtomicUsize::new(0); 844 + 845 + enum DropEl { 846 + Count, 847 + Panic, 848 + } 849 + 850 + impl Drop for DropEl { 851 + fn drop(&mut self) { 852 + match *self { 853 + DropEl::Count => { 854 + DROP_COUNT.fetch_add(1, Ordering::SeqCst); 855 + } 856 + DropEl::Panic => { 857 + panic!("Oh no"); 858 + } 859 + } 860 + } 861 + } 862 + 863 + let mut vec: ArrayVec<DropEl, 5> = ArrayVec::new(); 864 + vec.push(DropEl::Count); 865 + vec.push(DropEl::Panic); 866 + vec.push(DropEl::Count); 867 + 868 + let mut iter = vec.into_iter(); 869 + iter.next(); 870 + let _ = std::panic::catch_unwind(|| drop(iter)); 871 + 872 + // Note we don't see enough drop counts, essentially every element after the panic is leaked 873 + // but at least we don't access uninitialized elements and trigger UB 874 + assert_eq!(DROP_COUNT.load(Ordering::SeqCst), 1); 875 + } 876 + 877 + #[test] 878 + fn drain_panic_in_drop() { 879 + use core::sync::atomic::{AtomicUsize, Ordering}; 880 + static DROP_COUNT: AtomicUsize = AtomicUsize::new(0); 881 + 882 + enum DropEl { 883 + Count, 884 + Panic, 885 + } 886 + 887 + impl Drop for DropEl { 888 + fn drop(&mut self) { 889 + match *self { 890 + DropEl::Count => { 891 + DROP_COUNT.fetch_add(1, Ordering::SeqCst); 892 + } 893 + DropEl::Panic => { 894 + panic!("Oh no"); 895 + } 896 + } 897 + } 898 + } 899 + 900 + let mut vec: ArrayVec<DropEl, 5> = ArrayVec::new(); 901 + vec.push(DropEl::Count); 902 + vec.push(DropEl::Panic); 903 + vec.push(DropEl::Count); 904 + 905 + let drain = vec.drain(1..2); 906 + assert_eq!(drain.len(), 1); 907 + let _ = std::panic::catch_unwind(|| drop(drain)); 908 + assert_eq!(vec.len(), 2); 909 + drop(vec); 910 + assert_eq!(DROP_COUNT.load(Ordering::SeqCst), 2); 911 + } 912 + }
+1 -1
libs/kasync/src/sync/wake_batch.rs
··· 24 24 impl WakeBatch { 25 25 pub const fn new() -> Self { 26 26 Self { 27 - inner: ArrayVec::new_const(), 27 + inner: ArrayVec::new(), 28 28 } 29 29 } 30 30
+2 -2
loader/src/machine_info.rs
··· 7 7 8 8 use core::cmp::Ordering; 9 9 use core::ffi::{CStr, c_void}; 10 - use core::fmt; 11 10 use core::fmt::Formatter; 12 11 use core::ops::Range; 13 12 use core::str::FromStr; 13 + use core::{fmt, mem}; 14 14 15 15 use arrayvec::ArrayVec; 16 16 use fallible_iterator::FallibleIterator; ··· 115 115 } 116 116 117 117 let mut exclude_region = |entry: Range<PhysicalAddress>| { 118 - let _memories = memories.take(); 118 + let _memories = mem::take(&mut memories); 119 119 120 120 for mut region in _memories { 121 121 if entry.contains(&region.start) && entry.contains(&region.end) {
+2 -1
loader/src/main.rs
··· 11 11 #![feature(alloc_layout_extra)] 12 12 13 13 use core::ffi::c_void; 14 + use core::mem; 14 15 use core::ops::Range; 15 16 16 17 use arrayvec::ArrayVec; ··· 249 250 let mut temp: ArrayVec<Range<PhysicalAddress>, 16> = minfo.memories.clone(); 250 251 251 252 let mut exclude = |to_exclude: Range<PhysicalAddress>| { 252 - for mut region in temp.take() { 253 + for mut region in mem::take(&mut temp) { 253 254 if to_exclude.contains(&region.start) && to_exclude.contains(&region.end) { 254 255 // remove region 255 256 continue;