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