1 use super::{TryClone, TryNew, Vec, try_alloc}; 2 use crate::error::OutOfMemory; 3 use core::{ 4 alloc::Layout, 5 mem::{self, MaybeUninit}, 6 }; 7 use std_alloc::boxed::Box; 8 9 /// Allocate an `Box<MaybeUninit<T>>` with uninitialized contents, returning 10 /// `Err(OutOfMemory)` on allocation failure. 11 /// 12 /// You can initialize the resulting box's value via [`Box::write`]. 13 #[inline] 14 fn new_uninit_box<T>() -> Result<Box<MaybeUninit<T>>, OutOfMemory> { 15 let layout = Layout::new::<MaybeUninit<T>>(); 16 17 if layout.size() == 0 { 18 // NB: no actual allocation takes place when boxing zero-sized 19 // types. 20 return Ok(Box::new(MaybeUninit::uninit())); 21 } 22 23 // Safety: layout size is non-zero. 24 let ptr = unsafe { try_alloc(layout)? }; 25 26 let ptr = ptr.cast::<MaybeUninit<T>>(); 27 28 // Safety: The pointer's memory block was allocated by the global allocator. 29 Ok(unsafe { Box::from_raw(ptr.as_ptr()) }) 30 } 31 32 impl<T> TryNew for Box<T> { 33 type Value = T; 34 35 #[inline] 36 fn try_new(value: T) -> Result<Self, OutOfMemory> 37 where 38 Self: Sized, 39 { 40 let boxed = new_uninit_box::<T>()?; 41 Ok(Box::write(boxed, value)) 42 } 43 } 44 45 impl<T> TryClone for Box<T> 46 where 47 T: TryClone, 48 { 49 fn try_clone(&self) -> Result<Self, OutOfMemory> { 50 let b = new_uninit_box::<T>()?; 51 let v = (**self).try_clone()?; 52 Ok(Box::write(b, v)) 53 } 54 } 55 56 impl<T> TryClone for Box<[T]> 57 where 58 T: TryClone, 59 { 60 fn try_clone(&self) -> Result<Self, OutOfMemory> { 61 let mut builder = BoxedSliceBuilder::new(self.len())?; 62 for v in &*self { 63 builder.push(v.try_clone()?).expect("reserved capacity"); 64 } 65 debug_assert_eq!(builder.init_len(), builder.capacity()); 66 Ok(builder.finish()) 67 } 68 } 69 70 /// Allocate a new `Box<[MaybeUninit<T>]>` of the given length with 71 /// uninitialized contents, returning `Err(OutOfMemory)` on allocation failure. 72 /// 73 /// You can initialize the resulting boxed slice with 74 /// [`boxed_slice_write_iter`]. 75 pub fn new_uninit_boxed_slice<T>(len: usize) -> Result<Box<[MaybeUninit<T>]>, OutOfMemory> { 76 let layout = Layout::array::<MaybeUninit<T>>(len) 77 .map_err(|_| OutOfMemory::new(mem::size_of::<T>().saturating_mul(len)))?; 78 79 if layout.size() == 0 { 80 // NB: no actual allocation takes place when boxing zero-sized 81 // types. 82 return Ok(Box::new_uninit_slice(len)); 83 } 84 85 // Safety: layout size is non-zero. 86 let ptr = unsafe { try_alloc(layout)? }; 87 88 let ptr = ptr.cast::<MaybeUninit<T>>().as_ptr(); 89 let ptr = core::ptr::slice_from_raw_parts_mut(ptr, len); 90 91 // Safety: The pointer's memory block was allocated by the global allocator 92 // and holds room for `[T; len]`. 93 Ok(unsafe { Box::from_raw(ptr) }) 94 } 95 96 use boxed_slice_builder::BoxedSliceBuilder; 97 mod boxed_slice_builder { 98 use super::*; 99 100 /// Builder for constructing and initalizing a boxed slice. 101 /// 102 /// Also acts as an RAII guard to handle dropping the already-initialized 103 /// elements when we get too few items or an iterator panics during 104 /// construction. 105 pub struct BoxedSliceBuilder<T> { 106 vec: Vec<T>, 107 } 108 109 impl<T> BoxedSliceBuilder<T> { 110 pub fn new(len: usize) -> Result<Self, OutOfMemory> { 111 let mut vec = Vec::new(); 112 vec.reserve_exact(len)?; 113 Ok(Self { vec }) 114 } 115 116 pub fn from_boxed_slice(boxed: Box<[MaybeUninit<T>]>) -> Self { 117 let len = boxed.len(); 118 let ptr = Box::into_raw(boxed); 119 let ptr = ptr.cast::<T>(); 120 // Safety: the pointer was allocated by the global allocator and is 121 // valid for `[T; len]` since it was a boxed slice. 122 let vec = unsafe { Vec::from_raw_parts(ptr, 0, len) }; 123 Self { vec } 124 } 125 126 pub fn init_len(&self) -> usize { 127 self.vec.len() 128 } 129 130 pub fn capacity(&self) -> usize { 131 self.vec.capacity() 132 } 133 134 pub fn push(&mut self, value: T) -> Result<(), OutOfMemory> { 135 self.vec.push(value) 136 } 137 138 /// Finish this builder and take its boxed slice out. 139 /// 140 /// Panics if `self.init_len() != self.capacity()`. Call 141 /// `self.shrink_to_fit()` if necessary. 142 pub fn finish(mut self) -> Box<[T]> { 143 assert_eq!(self.init_len(), self.capacity()); 144 let vec = mem::take(&mut self.vec); 145 mem::forget(self); 146 let (ptr, len, cap) = vec.into_raw_parts(); 147 debug_assert_eq!(len, cap); 148 let ptr = core::ptr::slice_from_raw_parts_mut(ptr, len); 149 unsafe { Box::from_raw(ptr) } 150 } 151 152 /// Shrink this builder's allocation such that `self.init_len() == 153 /// self.capacity()`. 154 pub fn shrink_to_fit(&mut self) -> Result<(), OutOfMemory> { 155 if self.init_len() == self.capacity() { 156 return Ok(()); 157 } 158 159 let len = self.init_len(); 160 let cap = self.capacity(); 161 let vec = mem::take(&mut self.vec); 162 163 let old_layout = Layout::array::<T>(cap).expect( 164 "already have an allocation with this layout so should be able to recreate it", 165 ); 166 let new_layout = Layout::array::<T>(len) 167 .expect("if `cap` is fine for an array layout, then `len` must be as well"); 168 debug_assert_eq!(old_layout.align(), new_layout.align()); 169 170 // Handle zero-sized reallocations, since the global `realloc` function 171 // does not. 172 if new_layout.size() == 0 { 173 debug_assert!(mem::size_of::<T>() == 0 || len == 0); 174 if len == 0 { 175 debug_assert_eq!(self.capacity(), 0); 176 debug_assert_eq!(self.init_len(), 0); 177 } else { 178 debug_assert_eq!(mem::size_of::<T>(), 0); 179 let ptr = core::ptr::dangling_mut::<T>(); 180 debug_assert!(!ptr.is_null()); 181 debug_assert!(ptr.is_aligned()); 182 // Safety: T's dangling pointer is always non-null and aligned. 183 self.vec = unsafe { Vec::from_raw_parts(ptr, len, len) }; 184 } 185 debug_assert_eq!(self.capacity(), self.init_len()); 186 return Ok(()); 187 } 188 189 let (ptr, _len, _cap) = vec.into_raw_parts(); 190 debug_assert_eq!(len, _len); 191 debug_assert_eq!(cap, _cap); 192 193 // Safety: `ptr` was allocated by the global allocator, its memory block 194 // is described by `old_layout`, the new size is non-zero, and the new 195 // size will not overflow `isize::MAX` when rounded up to the layout's 196 // alignment (this is checked in the construction of `new_layout`). 197 let new_ptr = unsafe { 198 std_alloc::alloc::realloc(ptr.cast::<u8>(), old_layout, new_layout.size()) 199 }; 200 201 // Update `self` based on whether the reallocation succeeded or not, 202 // either inserting the new vec or reconstructing and replacing the 203 // old one. 204 if new_ptr.is_null() { 205 // Safety: The allocation failed so we retain ownership of `ptr`, 206 // which was a valid vec and we can safely make it a vec again. 207 self.vec = unsafe { Vec::from_raw_parts(ptr, len, cap) }; 208 Err(OutOfMemory::new(new_layout.size())) 209 } else { 210 let new_ptr = new_ptr.cast::<T>(); 211 // Safety: The allocation succeeded, `new_ptr` was reallocated by 212 // the global allocator and points to a valid boxed slice of length 213 // `len`. 214 self.vec = unsafe { Vec::from_raw_parts(new_ptr, len, len) }; 215 debug_assert_eq!(self.capacity(), self.init_len()); 216 Ok(()) 217 } 218 } 219 } 220 } 221 222 /// An error returned when an iterator yields too few items to fully initialize 223 /// a `Box<[MaybeUninit<T>]>`. 224 #[non_exhaustive] 225 #[derive(Debug, Clone, Copy)] 226 pub struct TooFewItems; 227 228 impl core::fmt::Display for TooFewItems { 229 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 230 f.write_str("iterator yielded too few items to fully initialize boxed slice") 231 } 232 } 233 234 impl core::error::Error for TooFewItems {} 235 236 /// An error returned by [`new_boxed_slice_from_iter`]. 237 #[derive(Debug)] 238 pub enum TooFewItemsOrOom { 239 /// The iterator did not yield enough items to fill the boxed slice. 240 TooFewItems(TooFewItems), 241 /// Failed to allocate space for the boxed slice. 242 Oom(OutOfMemory), 243 } 244 245 impl TooFewItemsOrOom { 246 /// Unwrap the inner `OutOfMemory` error, or panic if this is a different 247 /// error variant. 248 pub fn unwrap_oom(&self) -> OutOfMemory { 249 match self { 250 TooFewItemsOrOom::TooFewItems(_) => panic!("`unwrap_oom` on non-OOM error"), 251 TooFewItemsOrOom::Oom(oom) => *oom, 252 } 253 } 254 } 255 256 impl From<TooFewItems> for TooFewItemsOrOom { 257 fn from(e: TooFewItems) -> Self { 258 Self::TooFewItems(e) 259 } 260 } 261 262 impl From<OutOfMemory> for TooFewItemsOrOom { 263 fn from(oom: OutOfMemory) -> Self { 264 Self::Oom(oom) 265 } 266 } 267 268 impl core::fmt::Display for TooFewItemsOrOom { 269 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 270 match self { 271 Self::TooFewItems(_) => { 272 f.write_str("The iterator did not yield enough items to fill the boxed slice") 273 } 274 Self::Oom(_) => f.write_str("Failed to allocate space for the boxed slice"), 275 } 276 } 277 } 278 279 impl core::error::Error for TooFewItemsOrOom { 280 fn cause(&self) -> Option<&dyn core::error::Error> { 281 match self { 282 Self::TooFewItems(e) => Some(e), 283 Self::Oom(oom) => Some(oom), 284 } 285 } 286 } 287 288 /// Initialize a `Box<[MaybeUninit<T>]>` slice by writing the elements of the 289 /// given iterator into it. 290 pub fn boxed_slice_write_iter<T>( 291 boxed: Box<[MaybeUninit<T>]>, 292 iter: impl IntoIterator<Item = T>, 293 ) -> Result<Box<[T]>, TooFewItems> { 294 let len = boxed.len(); 295 let builder = BoxedSliceBuilder::from_boxed_slice(boxed); 296 assert_eq!(len, builder.capacity()); 297 write_iter_into_builder(builder, iter) 298 } 299 300 /// Create a `Box<[T]>` of length `len` from the given iterator's elements. 301 /// 302 /// Returns an error on allocation failure, or if `iter` yields fewer than `len` 303 /// elements. 304 /// 305 /// The iterator is dropped after `len` elements have been yielded, this 306 /// function does not check that the iterator yields exactly `len` elements. 307 pub fn new_boxed_slice_from_iter_with_len<T>( 308 len: usize, 309 iter: impl IntoIterator<Item = T>, 310 ) -> Result<Box<[T]>, TooFewItemsOrOom> { 311 let builder = BoxedSliceBuilder::new(len)?; 312 assert_eq!(len, builder.capacity()); 313 let boxed = write_iter_into_builder(builder, iter)?; 314 Ok(boxed) 315 } 316 317 fn write_iter_into_builder<T>( 318 mut builder: BoxedSliceBuilder<T>, 319 iter: impl IntoIterator<Item = T>, 320 ) -> Result<Box<[T]>, TooFewItems> { 321 let len = builder.capacity(); 322 323 for elem in iter.into_iter().take(len) { 324 builder.push(elem).expect("reserved capacity"); 325 } 326 327 if builder.init_len() < builder.capacity() { 328 return Err(TooFewItems); 329 } 330 331 debug_assert_eq!(builder.init_len(), builder.capacity()); 332 Ok(builder.finish()) 333 } 334 335 /// An error returned by [`new_boxed_slice_from_fallible_iter`]. 336 #[derive(Debug)] 337 pub enum BoxedSliceFromFallibleIterError<E> { 338 /// The fallible iterator produced an error. 339 IterError(E), 340 /// Failed to allocate space for the boxed slice. 341 Oom(OutOfMemory), 342 } 343 344 impl<E> From<OutOfMemory> for BoxedSliceFromFallibleIterError<E> { 345 fn from(oom: OutOfMemory) -> Self { 346 Self::Oom(oom) 347 } 348 } 349 350 impl<E> core::fmt::Display for BoxedSliceFromFallibleIterError<E> { 351 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 352 match self { 353 Self::IterError(_) => f.write_str("The fallible iterator produced an error"), 354 Self::Oom(_) => f.write_str("Failed to allocate space for the boxed slice"), 355 } 356 } 357 } 358 359 impl<E> core::error::Error for BoxedSliceFromFallibleIterError<E> 360 where 361 E: core::error::Error, 362 { 363 fn cause(&self) -> Option<&dyn core::error::Error> { 364 match self { 365 Self::IterError(e) => Some(e), 366 Self::Oom(oom) => Some(oom), 367 } 368 } 369 } 370 371 impl BoxedSliceFromFallibleIterError<OutOfMemory> { 372 /// Flatten this error into its inner OOM. 373 pub fn flatten(self) -> OutOfMemory { 374 match self { 375 Self::IterError(oom) | Self::Oom(oom) => oom, 376 } 377 } 378 } 379 380 /// Create a `Box<[T]>` from the given iterator's `Result<T, E>` items. 381 /// 382 /// Returns an error on allocation failure or if an iterator item is an `Err`. 383 pub fn new_boxed_slice_from_fallible_iter<T, E>( 384 iter: impl IntoIterator<Item = Result<T, E>>, 385 ) -> Result<Box<[T]>, BoxedSliceFromFallibleIterError<E>> { 386 let iter = iter.into_iter(); 387 388 let (min, max) = iter.size_hint(); 389 let len = max.unwrap_or_else(|| min); 390 391 let mut builder = BoxedSliceBuilder::new(len)?; 392 assert_eq!(len, builder.capacity()); 393 394 for result in iter { 395 let elem = result.map_err(BoxedSliceFromFallibleIterError::IterError)?; 396 builder.push(elem)?; 397 } 398 399 debug_assert!(builder.init_len() <= builder.capacity()); 400 builder.shrink_to_fit()?; 401 debug_assert_eq!(builder.init_len(), builder.capacity()); 402 403 Ok(builder.finish()) 404 } 405 406 /// Create a `Box<[T]>` from the given iterator's elements. 407 /// 408 /// Returns an error on allocation failure. 409 pub fn new_boxed_slice_from_iter<T>( 410 iter: impl IntoIterator<Item = T>, 411 ) -> Result<Box<[T]>, OutOfMemory> { 412 let iter = iter 413 .into_iter() 414 .map(Result::<T, core::convert::Infallible>::Ok); 415 new_boxed_slice_from_fallible_iter(iter).map_err(|e| match e { 416 BoxedSliceFromFallibleIterError::Oom(oom) => oom, 417 BoxedSliceFromFallibleIterError::IterError(_) => unreachable!(), 418 }) 419 } 420 421 #[cfg(test)] 422 mod tests { 423 use super::*; 424 use core::cell::Cell; 425 use std_alloc::rc::Rc; 426 427 struct SetFlagOnDrop(Rc<Cell<bool>>); 428 429 impl Drop for SetFlagOnDrop { 430 fn drop(&mut self) { 431 let old_value = self.0.replace(true); 432 assert_eq!(old_value, false); 433 } 434 } 435 436 impl SetFlagOnDrop { 437 fn new() -> (Rc<Cell<bool>>, Self) { 438 let flag = Rc::new(Cell::new(false)); 439 (flag.clone(), SetFlagOnDrop(flag)) 440 } 441 } 442 443 #[test] 444 fn try_new() { 445 <Box<_> as TryNew>::try_new(4).unwrap(); 446 } 447 448 #[test] 449 fn new_boxed_slice_from_iter_with_len_smoke_test() { 450 let slice = new_boxed_slice_from_iter_with_len(3, [42, 36, 1337]).unwrap(); 451 assert_eq!(&*slice, &[42, 36, 1337]); 452 } 453 454 #[test] 455 fn new_boxed_slice_from_iter_with_len_with_too_few_elems() { 456 let (a_dropped, a) = SetFlagOnDrop::new(); 457 let (b_dropped, b) = SetFlagOnDrop::new(); 458 let (c_dropped, c) = SetFlagOnDrop::new(); 459 460 match new_boxed_slice_from_iter_with_len(4, [a, b, c]) { 461 Err(TooFewItemsOrOom::TooFewItems(_)) => {} 462 Ok(_) | Err(TooFewItemsOrOom::Oom(_)) => unreachable!(), 463 } 464 465 assert!(a_dropped.get()); 466 assert!(b_dropped.get()); 467 assert!(c_dropped.get()); 468 } 469 470 #[test] 471 fn new_boxed_slice_from_iter_with_len_with_too_many_elems() { 472 let (a_dropped, a) = SetFlagOnDrop::new(); 473 let (b_dropped, b) = SetFlagOnDrop::new(); 474 let (c_dropped, c) = SetFlagOnDrop::new(); 475 476 let slice = new_boxed_slice_from_iter_with_len(2, [a, b, c]).unwrap(); 477 478 assert!(!a_dropped.get()); 479 assert!(!b_dropped.get()); 480 assert!(c_dropped.get()); 481 482 drop(slice); 483 484 assert!(a_dropped.get()); 485 assert!(b_dropped.get()); 486 assert!(c_dropped.get()); 487 } 488 489 #[test] 490 fn new_boxed_slice_from_iter_smoke_test() { 491 let slice = new_boxed_slice_from_iter([10, 20, 30]).unwrap(); 492 assert_eq!(&*slice, &[10, 20, 30]); 493 } 494 495 #[test] 496 fn new_boxed_slice_from_fallible_iter_smoke_test() { 497 let slice = 498 new_boxed_slice_from_fallible_iter::<_, &str>([Ok(10), Ok(20), Ok(30)]).unwrap(); 499 assert_eq!(&*slice, &[10, 20, 30]); 500 } 501 502 #[test] 503 fn new_boxed_slice_from_fallible_iter_error() { 504 let result = new_boxed_slice_from_fallible_iter::<_, u32>([Ok(10), Ok(20), Err(30)]); 505 let Err(BoxedSliceFromFallibleIterError::IterError(err)) = result else { 506 panic!("unexpected result: {result:?}"); 507 }; 508 assert_eq!(err, 30); 509 } 510 511 #[test] 512 fn new_uninit_boxed_slice_smoke_test() { 513 let slice = new_uninit_boxed_slice::<u32>(5).unwrap(); 514 assert_eq!(slice.len(), 5); 515 } 516 517 #[test] 518 fn boxed_slice_write_iter_smoke_test() { 519 let uninit = new_uninit_boxed_slice(3).unwrap(); 520 let init = boxed_slice_write_iter(uninit, [10, 20, 30]).unwrap(); 521 assert_eq!(&*init, &[10, 20, 30]); 522 } 523 524 #[test] 525 fn boxed_slice_write_iter_with_too_few_elems() { 526 let (a_dropped, a) = SetFlagOnDrop::new(); 527 let (b_dropped, b) = SetFlagOnDrop::new(); 528 let (c_dropped, c) = SetFlagOnDrop::new(); 529 530 let uninit = new_uninit_boxed_slice(4).unwrap(); 531 match boxed_slice_write_iter(uninit, [a, b, c]) { 532 Err(_) => {} 533 Ok(_) => unreachable!(), 534 } 535 536 assert!(a_dropped.get()); 537 assert!(b_dropped.get()); 538 assert!(c_dropped.get()); 539 } 540 541 #[test] 542 fn boxed_slice_write_iter_with_too_many_elems() { 543 let (a_dropped, a) = SetFlagOnDrop::new(); 544 let (b_dropped, b) = SetFlagOnDrop::new(); 545 let (c_dropped, c) = SetFlagOnDrop::new(); 546 547 let uninit = new_uninit_boxed_slice(2).unwrap(); 548 let slice = boxed_slice_write_iter(uninit, [a, b, c]).unwrap(); 549 550 assert!(!a_dropped.get()); 551 assert!(!b_dropped.get()); 552 assert!(c_dropped.get()); 553 554 drop(slice); 555 556 assert!(a_dropped.get()); 557 assert!(b_dropped.get()); 558 assert!(c_dropped.get()); 559 } 560 } 561