commonlibsse_ng\re\t/TESBox.rs
1// Unstable Rust code
2//
3// SPDX-FileCopyrightText: (c) The Rust Project Contributors
4// SPDX-License-Identifier: Apache-2.0 OR MIT
5// - https://github.com/rust-lang/rust/blob/master/LICENSE-MIT
6//! The `TESBox<T>` type for heap allocation.
7//!
8//! [`TESBox<T>`], casually referred to as a 'box', provides the simplest form of
9//! heap allocation in Rust. Boxes provide ownership for this allocation, and
10//! drop their contents when they go out of scope. Boxes also ensure that they
11//! never allocate more than `isize::MAX` bytes.
12//!
13//! # Examples
14//!
15//! Move a value from the stack to the heap by creating a [`Box`]:
16//!
17//! ```
18//! # use commonlibsse_ng::re::TESBox::TESBox;
19//! let val: u8 = 5;
20//! let boxed: TESBox<u8> = TESBox::new(val);
21//! ```
22//!
23//! Move a value from a [`Box`] back to the stack by [dereferencing]:
24//!
25//! ```
26//! # use commonlibsse_ng::re::TESBox::TESBox;
27//! let boxed: TESBox<u8> = TESBox::new(5);
28//! let val: u8 = *boxed;
29//! ```
30//!
31//! Creating a recursive data structure:
32//!
33//! ```
34//! # use commonlibsse_ng::re::TESBox::TESBox;
35//! # #[allow(dead_code)]
36//! #[derive(Debug)]
37//! enum List<T> {
38//! Cons(T, TESBox<List<T>>),
39//! Nil,
40//! }
41//!
42//! let list: List<i32> = List::Cons(1, TESBox::new(List::Cons(2, TESBox::new(List::Nil))));
43//! println!("{list:?}");
44//! ```
45//!
46//! This will print `Cons(1, Cons(2, Nil))`.
47//!
48//! Recursive structures must be boxed, because if the definition of `Cons`
49//! looked like this:
50//!
51//! ```compile_fail,E0072
52//! # enum List<T> {
53//! Cons(T, List<T>),
54//! # }
55//! ```
56//!
57//! It wouldn't work. This is because the size of a `List` depends on how many
58//! elements are in the list, and so we don't know how much memory to allocate
59//! for a `Cons`. By introducing a [`TESBox<T>`], which has a defined size, we know how
60//! big `Cons` needs to be.
61//!
62//! # Memory layout
63//!
64//! For non-zero-sized values, a [`Box`] will use the [`Global`] allocator for its allocation. It is
65//! valid to convert both ways between a [`Box`] and a raw pointer allocated with the [`Global`]
66//! allocator, given that the [`Layout`] used with the allocator is correct for the type and the raw
67//! pointer points to a valid value of the right type. More precisely, a `value: *mut T` that has
68//! been allocated with the [`Global`] allocator with `Layout::for_value(&*value)` may be converted
69//! into a box using [`Box::<T>::from_raw(value)`]. Conversely, the memory backing a `value: *mut T`
70//! obtained from [`Box::<T>::into_raw`] may be deallocated using the [`Global`] allocator with
71//! [`Layout::for_value(&*value)`].
72//!
73//! For zero-sized values, the `Box` pointer has to be non-null and sufficiently aligned. The
74//! recommended way to build a Box to a ZST if `Box::new` cannot be used is to use
75//! [`ptr::NonNull::dangling`].
76//!
77//! On top of these basic layout requirements, a `TESBox<T>` must point to a valid value of `T`.
78//!
79//! So long as `T: Sized`, a `TESBox<T>` is guaranteed to be represented
80//! as a single pointer and is also ABI-compatible with C pointers
81//! (i.e. the C type `T*`). This means that if you have extern "C"
82//! Rust functions that will be called from C, you can define those
83//! Rust functions using `TESBox<T>` types, and use `T*` as corresponding
84//! type on the C side. As an example, consider this C header which
85//! declares functions that create and destroy some kind of `Foo`
86//! value:
87//!
88//! ```c
89//! /* C header */
90//!
91//! /* Returns ownership to the caller */
92//! struct Foo* foo_new(void);
93//!
94//! /* Takes ownership from the caller; no-op when invoked with null */
95//! void foo_delete(struct Foo*);
96//! ```
97//!
98//! These two functions might be implemented in Rust as follows. Here, the
99//! `struct Foo*` type from C is translated to `TESBox<Foo>`, which captures
100//! the ownership constraints. Note also that the nullable argument to
101//! `foo_delete` is represented in Rust as `Option<TESBox<Foo>>`, since `TESBox<Foo>`
102//! cannot be null.
103//!
104//! ```
105//! # use commonlibsse_ng::re::TESBox::TESBox;
106//! #[repr(C)]
107//! pub struct Foo;
108//!
109//! #[unsafe(no_mangle)]
110//! pub extern "C" fn foo_new() -> TESBox<Foo> {
111//! TESBox::new(Foo)
112//! }
113//!
114//! #[unsafe(no_mangle)]
115//! pub extern "C" fn foo_delete(_: Option<TESBox<Foo>>) {}
116//! ```
117//!
118//! Even though `TESBox<T>` has the same representation and C ABI as a C pointer,
119//! this does not mean that you can convert an arbitrary `T*` into a `TESBox<T>`
120//! and expect things to work. `TESBox<T>` values will always be fully aligned,
121//! non-null pointers. Moreover, the destructor for `TESBox<T>` will attempt to
122//! free the value with the global allocator. In general, the best practice
123//! is to only use `TESBox<T>` for pointers that originated from the global
124//! allocator.
125//!
126//! **Important.** At least at present, you should avoid using
127//! `TESBox<T>` types for functions that are defined in C but invoked
128//! from Rust. In those cases, you should directly mirror the C types
129//! as closely as possible. Using types like `TESBox<T>` where the C
130//! definition is just using `T*` can lead to undefined behavior, as
131//! described in [rust-lang/unsafe-code-guidelines#198][ucg#198].
132//!
133//! # Considerations for unsafe code
134//!
135//! **Warning: This section is not normative and is subject to change, possibly
136//! being relaxed in the future! It is a simplified summary of the rules
137//! currently implemented in the compiler.**
138//!
139//! The aliasing rules for `TESBox<T>` are the same as for `&mut T`. `TESBox<T>`
140//! asserts uniqueness over its content. Using raw pointers derived from a box
141//! after that box has been mutated through, moved or borrowed as `&mut T`
142//! is not allowed. For more guidance on working with box from unsafe code, see
143//! [rust-lang/unsafe-code-guidelines#326][ucg#326].
144//!
145//! # Editions
146//!
147//! A special case exists for the implementation of `IntoIterator` for arrays on the Rust 2021
148//! edition, as documented [here][array]. Unfortunately, it was later found that a similar
149//! workaround should be added for boxed slices, and this was applied in the 2024 edition.
150//!
151//! Specifically, `IntoIterator` is implemented for `TESBox<[T]>` on all editions, but specific calls
152//! to `into_iter()` for boxed slices will defer to the slice implementation on editions before
153//! 2024:
154//!
155//! ```rust,edition2021
156//! # use commonlibsse_ng::re::TESBox::TESBox;
157//! // Rust 2015, 2018, and 2021:
158//!
159//! // # #![allow(boxed_slice_into_iter)] // override our `deny(warnings)`
160//! let boxed_slice: Box<[i32]> = vec![0; 3].into_boxed_slice();
161//!
162//! // This creates a slice iterator, producing references to each value.
163//! for item in boxed_slice.into_iter().enumerate() {
164//! let (i, x): (usize, &i32) = item;
165//! println!("boxed_slice[{i}] = {x}");
166//! }
167//!
168//! // The `boxed_slice_into_iter` lint suggests this change for future compatibility:
169//! for item in boxed_slice.iter().enumerate() {
170//! let (i, x): (usize, &i32) = item;
171//! println!("boxed_slice[{i}] = {x}");
172//! }
173//!
174//! // You can explicitly iterate a boxed slice by value using `IntoIterator::into_iter`
175//! for item in IntoIterator::into_iter(boxed_slice).enumerate() {
176//! let (i, x): (usize, i32) = item;
177//! println!("boxed_slice[{i}] = {x}");
178//! }
179//! ```
180//!
181//! Similar to the array implementation, this may be modified in the future to remove this override,
182//! and it's best to avoid relying on this edition-dependent behavior if you wish to preserve
183//! compatibility with future versions of the compiler.
184//!
185//! [ucg#198]: https://github.com/rust-lang/unsafe-code-guidelines/issues/198
186//! [ucg#326]: https://github.com/rust-lang/unsafe-code-guidelines/issues/326
187//! [dereferencing]: core::ops::Deref
188//! [`Box::<T>::from_raw(value)`]: TESBox::from_raw
189//! [`Global`]: crate::alloc::Global
190//! [`Layout`]: crate::alloc::Layout
191//! [`Layout::for_value(&*value)`]: crate::alloc::Layout::for_value
192//! [valid]: ptr#safety
193#![allow(clippy::explicit_auto_deref)]
194#![allow(clippy::missing_const_for_fn)]
195#![allow(clippy::missing_errors_doc)]
196#![allow(clippy::option_if_let_else)]
197#![allow(clippy::ptr_as_ptr)]
198#![allow(clippy::use_self)]
199
200use core::borrow::{Borrow, BorrowMut};
201use core::cmp::Ordering;
202use core::error::Error;
203use core::hash::{Hash, Hasher};
204use core::mem::{self};
205use core::ops::{Deref, DerefMut};
206use core::pin::Pin;
207use core::ptr::NonNull;
208use core::{fmt, ptr};
209use std::alloc::handle_alloc_error;
210
211use crate::re::MemoryManager::TESGlobalAlloc as Global;
212use core::alloc::Layout;
213use stdx::{
214 alloc::{AllocError, Allocator},
215 ptr::Unique,
216};
217
218// The declaration of the `Box` struct must be kept in sync with the
219// compiler or ICEs will happen.
220
221/// Heap memory allocation smart pointer that `MemoryManager` `malloc` and `free` trigger by default.
222///
223/// The allocator side is always of type zero size and represents `owned *mut ptr`. (i.e. size is type ptr)
224// #[repr(transparent)] // FIXME: maybe need this.
225///
226/// # Examples
227///
228/// ```
229/// # use commonlibsse_ng::re::TESBox::TESBox;
230/// let five = TESBox::new(5);
231/// ```
232pub struct TESBox<T: ?Sized, A: Allocator = Global>(Unique<T>, A);
233const _: () = assert!(core::mem::size_of::<TESBox<()>>() == core::mem::size_of::<usize>());
234
235// #[repr(transparent)]
236// pub struct TESBox<T: ?Sized, A: Allocator = Global>(Unique<T>, core::marker::PhantomData<A>);
237// const _: () = assert!(core::mem::size_of::<TESBox<()>>() == core::mem::size_of::<usize>());
238
239impl<T> TESBox<T> {
240 /// Allocates memory on the heap and then places `x` into it.
241 ///
242 /// This doesn't actually allocate if `T` is zero-sized.
243 ///
244 /// # Examples
245 ///
246 /// ```
247 /// # use commonlibsse_ng::re::TESBox::TESBox;
248 /// let five = TESBox::new(5);
249 /// ```
250 #[inline(always)]
251 #[must_use]
252 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
253 pub fn new(x: T) -> Self {
254 Self::new_in(x, Global)
255 }
256
257 /// Constructs a new box with uninitialized contents.
258 ///
259 /// # Examples
260 ///
261 /// ```
262 /// # use commonlibsse_ng::re::TESBox::TESBox;
263 /// let mut five = TESBox::<u32>::new_uninit();
264 /// // Deferred initialization:
265 /// five.write(5);
266 /// let five = unsafe { five.assume_init() };
267 ///
268 /// assert_eq!(*five, 5)
269 /// ```
270 #[must_use]
271 #[inline]
272 pub fn new_uninit() -> TESBox<mem::MaybeUninit<T>> {
273 Self::new_uninit_in(Global)
274 }
275
276 /// Allocates memory on the heap then places `x` into it,
277 /// returning an error if the allocation fails
278 ///
279 /// This doesn't actually allocate if `T` is zero-sized.
280 ///
281 /// # Examples
282 ///
283 /// ```
284 /// # use commonlibsse_ng::re::TESBox::TESBox;
285 ///
286 /// let five = TESBox::try_new(5)?;
287 /// # Ok::<(), stdx::alloc::AllocError>(())
288 /// ```
289 #[inline]
290 pub fn try_new(x: T) -> Result<Self, AllocError> {
291 Self::try_new_in(x, Global)
292 }
293}
294
295impl<T, A: Allocator> TESBox<T, A> {
296 /// Allocates memory in the given allocator then places `x` into it.
297 ///
298 /// This doesn't actually allocate if `T` is zero-sized.
299 ///
300 /// # Examples
301 ///
302 /// ```
303 /// # use commonlibsse_ng::re::TESBox::TESBox;
304 ///
305 /// use stdx::alloc::Global;
306 ///
307 /// let five = TESBox::new_in(5, Global);
308 /// ```
309 #[must_use]
310 #[inline]
311 pub fn new_in(x: T, alloc: A) -> Self
312 where
313 A: Allocator,
314 {
315 let mut boxed = Self::new_uninit_in(alloc);
316 boxed.write(x);
317 unsafe { boxed.assume_init() }
318 }
319
320 /// Allocates memory in the given allocator then places `x` into it,
321 /// returning an error if the allocation fails
322 ///
323 /// This doesn't actually allocate if `T` is zero-sized.
324 ///
325 /// # Examples
326 ///
327 /// ```
328 /// # use commonlibsse_ng::re::TESBox::TESBox;
329 ///
330 /// use stdx::alloc::Global;
331 ///
332 /// let five = TESBox::try_new_in(5, Global)?;
333 /// # Ok::<(), stdx::alloc::AllocError>(())
334 /// ```
335 #[inline]
336 pub fn try_new_in(x: T, alloc: A) -> Result<Self, AllocError>
337 where
338 A: Allocator,
339 {
340 let mut boxed = Self::try_new_uninit_in(alloc)?;
341 boxed.write(x);
342 unsafe { Ok(boxed.assume_init()) }
343 }
344
345 /// Constructs a new box with uninitialized contents in the provided allocator.
346 ///
347 /// # Examples
348 ///
349 /// ```
350 /// # use commonlibsse_ng::re::TESBox::TESBox;
351 ///
352 /// use stdx::alloc::Global;
353 ///
354 /// let mut five = TESBox::<u32, _>::new_uninit_in(Global);
355 /// // Deferred initialization:
356 /// five.write(5);
357 /// let five = unsafe { five.assume_init() };
358 ///
359 /// assert_eq!(*five, 5)
360 /// ```
361 #[must_use]
362 pub fn new_uninit_in(alloc: A) -> TESBox<mem::MaybeUninit<T>, A>
363 where
364 A: Allocator,
365 {
366 let layout = Layout::new::<mem::MaybeUninit<T>>();
367 // NOTE: Prefer match over unwrap_or_else since closure sometimes not inline-able.
368 // That would make code size bigger.
369 match Self::try_new_uninit_in(alloc) {
370 Ok(m) => m,
371 Err(_) => handle_alloc_error(layout),
372 }
373 }
374
375 /// Constructs a new box with uninitialized contents in the provided allocator,
376 /// returning an error if the allocation fails
377 ///
378 /// # Examples
379 ///
380 /// ```
381 /// # use commonlibsse_ng::re::TESBox::TESBox;
382 ///
383 /// use stdx::alloc::Global;
384 ///
385 /// let mut five = TESBox::<u32, _>::try_new_uninit_in(Global)?;
386 /// // Deferred initialization:
387 /// five.write(5);
388 /// let five = unsafe { five.assume_init() };
389 ///
390 /// assert_eq!(*five, 5);
391 /// # Ok::<(), stdx::alloc::AllocError>(())
392 /// ```
393 pub fn try_new_uninit_in(alloc: A) -> Result<TESBox<mem::MaybeUninit<T>, A>, AllocError>
394 where
395 A: Allocator,
396 {
397 let ptr = if core::mem::size_of::<T>() == 0 {
398 NonNull::dangling()
399 } else {
400 let layout = Layout::new::<mem::MaybeUninit<T>>();
401 alloc.allocate(layout)?.cast()
402 };
403 unsafe { Ok(TESBox::from_raw_in(ptr.as_ptr(), alloc)) }
404 }
405}
406
407impl<T> TESBox<[T]> {
408 /// Converts the boxed slice into a boxed array.
409 ///
410 /// This operation does not reallocate; the underlying array of the slice is simply reinterpreted as an array type.
411 ///
412 /// If `N` is not exactly equal to the length of `self`, then this method returns `None`.
413 #[inline]
414 #[must_use]
415 pub fn into_array<const N: usize>(self) -> Option<TESBox<[T; N]>> {
416 if self.len() == N {
417 let ptr = Self::into_raw(self).cast::<[T; N]>();
418
419 // SAFETY: The underlying array of a slice has the exact same layout as an actual array `[T; N]` if `N` is equal to the slice's length.
420 let me = unsafe { TESBox::from_raw(ptr) };
421 Some(me)
422 } else {
423 None
424 }
425 }
426}
427
428impl<T, A: Allocator> TESBox<mem::MaybeUninit<T>, A> {
429 /// Converts to `Box<T, A>`.
430 ///
431 /// # Safety
432 ///
433 /// As with [`MaybeUninit::assume_init`],
434 /// it is up to the caller to guarantee that the value
435 /// really is in an initialized state.
436 /// Calling this when the content is not yet fully initialized
437 /// causes immediate undefined behavior.
438 ///
439 /// [`MaybeUninit::assume_init`]: mem::MaybeUninit::assume_init
440 ///
441 /// # Examples
442 ///
443 /// ```
444 /// # use commonlibsse_ng::re::TESBox::TESBox;
445 /// let mut five = TESBox::<u32>::new_uninit();
446 /// // Deferred initialization:
447 /// five.write(5);
448 /// let five: TESBox<u32> = unsafe { five.assume_init() };
449 ///
450 /// assert_eq!(*five, 5)
451 /// ```
452 #[inline]
453 pub unsafe fn assume_init(self) -> TESBox<T, A> {
454 let (raw, alloc) = TESBox::into_raw_with_allocator(self);
455 unsafe { TESBox::from_raw_in(raw as *mut T, alloc) }
456 }
457
458 /// Writes the value and converts to `Box<T, A>`.
459 ///
460 /// This method converts the box similarly to [`Box::assume_init`] but
461 /// writes `value` into it before conversion thus guaranteeing safety.
462 /// In some scenarios use of this method may improve performance because
463 /// the compiler may be able to optimize copying from stack.
464 ///
465 /// # Examples
466 ///
467 /// ```
468 /// # use commonlibsse_ng::re::TESBox::TESBox;
469 ///
470 /// let big_box = TESBox::<[usize; 1024]>::new_uninit();
471 ///
472 /// let mut array = [0; 1024];
473 /// for (i, place) in array.iter_mut().enumerate() {
474 /// *place = i;
475 /// }
476 ///
477 /// // The optimizer may be able to elide this copy, so previous code writes
478 /// // to heap directly.
479 /// let big_box = TESBox::write(big_box, array);
480 ///
481 /// for (i, x) in big_box.iter().enumerate() {
482 /// assert_eq!(*x, i);
483 /// }
484 /// ```
485 #[inline]
486 pub fn write(mut boxed: Self, value: T) -> TESBox<T, A> {
487 unsafe {
488 (*boxed).write(value);
489 boxed.assume_init()
490 }
491 }
492}
493
494impl<T: ?Sized> TESBox<T> {
495 /// Constructs a box from a raw pointer.
496 ///
497 /// After calling this function, the raw pointer is owned by the
498 /// resulting `Box`. Specifically, the `Box` destructor will call
499 /// the destructor of `T` and free the allocated memory. For this
500 /// to be safe, the memory must have been allocated in accordance
501 /// with the [memory layout] used by `Box` .
502 ///
503 /// # Safety
504 ///
505 /// This function is unsafe because improper use may lead to
506 /// memory problems. For example, a double-free may occur if the
507 /// function is called twice on the same raw pointer.
508 ///
509 /// The raw pointer must point to a block of memory allocated by the global allocator.
510 ///
511 /// The safety conditions are described in the [memory layout] section.
512 ///
513 /// # Examples
514 ///
515 /// Recreate a `Box` which was previously converted to a raw pointer
516 /// using [`Box::into_raw`]:
517 /// ```
518 /// # use commonlibsse_ng::re::TESBox::TESBox;
519 /// let x = TESBox::new(5);
520 /// let ptr = TESBox::into_raw(x);
521 /// let x = unsafe { TESBox::from_raw(ptr) };
522 /// ```
523 /// Manually create a `Box` from scratch by using the global allocator:
524 /// ```
525 /// use std::alloc::{alloc, Layout};
526 /// use stdx::alloc::{Allocator, Global};
527 /// use commonlibsse_ng::re::TESBox::TESBox;
528 ///
529 /// unsafe {
530 /// let ptr = alloc(Layout::new::<i32>()) as *mut i32;
531 /// // In general .write is required to avoid attempting to destruct
532 /// // the (uninitialized) previous contents of `ptr`, though for this
533 /// // simple example `*ptr = 5` would have worked as well.
534 /// ptr.write(5);
535 /// let x = TESBox::from_raw(ptr);
536 /// }
537 /// ```
538 ///
539 /// [memory layout]: self#memory-layout
540 /// [`Layout`]: crate::Layout
541 #[inline]
542 #[must_use = "call `drop(Box::from_raw(ptr))` if you intend to drop the `Box`"]
543 pub const unsafe fn from_raw(raw: *mut T) -> Self {
544 unsafe { Self::from_raw_in(raw, Global) }
545 }
546
547 /// Constructs a box from a `NonNull` pointer.
548 ///
549 /// After calling this function, the `NonNull` pointer is owned by
550 /// the resulting `Box`. Specifically, the `Box` destructor will call
551 /// the destructor of `T` and free the allocated memory. For this
552 /// to be safe, the memory must have been allocated in accordance
553 /// with the [memory layout] used by `Box` .
554 ///
555 /// # Safety
556 ///
557 /// This function is unsafe because improper use may lead to
558 /// memory problems. For example, a double-free may occur if the
559 /// function is called twice on the same `NonNull` pointer.
560 ///
561 /// The non-null pointer must point to a block of memory allocated by the global allocator.
562 ///
563 /// The safety conditions are described in the [memory layout] section.
564 ///
565 /// # Examples
566 ///
567 /// Recreate a `Box` which was previously converted to a `NonNull`
568 /// pointer using [`Box::into_non_null`]:
569 /// ```
570 /// # use stdx::alloc::{Allocator, Global};
571 /// # use std::alloc::Layout;
572 /// # use commonlibsse_ng::re::TESBox::TESBox;
573 ///
574 /// let x = TESBox::new(5);
575 /// let non_null = TESBox::into_non_null(x);
576 /// let x = unsafe { TESBox::from_non_null(non_null) };
577 /// ```
578 /// Manually create a `Box` from scratch by using the global allocator:
579 /// ```
580 /// use stdx::alloc::{Allocator, Global};
581 /// use std::alloc::{alloc, Layout};
582 /// use std::ptr::NonNull;
583 /// use commonlibsse_ng::re::TESBox::TESBox;
584 ///
585 /// unsafe {
586 /// let non_null = NonNull::new(alloc(Layout::new::<i32>()).cast::<i32>())
587 /// .expect("allocation failed");
588 /// // In general .write is required to avoid attempting to destruct
589 /// // the (uninitialized) previous contents of `non_null`.
590 /// non_null.write(5);
591 /// let x = TESBox::from_non_null(non_null);
592 /// }
593 /// ```
594 ///
595 /// [memory layout]: self#memory-layout
596 /// [`Layout`]: crate::Layout
597 #[inline]
598 #[must_use = "call `drop(Box::from_non_null(ptr))` if you intend to drop the `Box`"]
599 pub unsafe fn from_non_null(ptr: NonNull<T>) -> Self {
600 unsafe { Self::from_raw(ptr.as_ptr()) }
601 }
602}
603
604impl<T: ?Sized, A: Allocator> TESBox<T, A> {
605 /// Constructs a box from a raw pointer in the given allocator.
606 ///
607 /// After calling this function, the raw pointer is owned by the
608 /// resulting `Box`. Specifically, the `Box` destructor will call
609 /// the destructor of `T` and free the allocated memory. For this
610 /// to be safe, the memory must have been allocated in accordance
611 /// with the [memory layout] used by `Box` .
612 ///
613 /// # Safety
614 ///
615 /// This function is unsafe because improper use may lead to
616 /// memory problems. For example, a double-free may occur if the
617 /// function is called twice on the same raw pointer.
618 ///
619 /// The raw pointer must point to a block of memory allocated by `alloc`.
620 ///
621 /// # Examples
622 ///
623 /// Recreate a `Box` which was previously converted to a raw pointer
624 /// using [`Box::into_raw_with_allocator`]:
625 /// ```
626 ///
627 /// # use commonlibsse_ng::re::TESBox::TESBox;
628 /// use stdx::alloc::Global;
629 ///
630 /// let x = TESBox::new_in(5, Global);
631 /// let (ptr, alloc) = TESBox::into_raw_with_allocator(x);
632 /// let x = unsafe { TESBox::from_raw_in(ptr, alloc) };
633 /// ```
634 /// Manually create a `Box` from scratch by using the system allocator:
635 /// ```
636 ///
637 /// // use std::alloc::Layout;
638 /// // use stdx::alloc::{Allocator, Global};
639 /// // use commonlibsse_ng::re::TESBox::TESBox;
640 ///
641 /// // unsafe {
642 /// // let ptr = Global.allocate(Layout::new::<i32>())?.as_mut_ptr() as *mut i32;
643 /// // // In general .write is required to avoid attempting to destruct
644 /// // // the (uninitialized) previous contents of `ptr`, though for this
645 /// // // simple example `*ptr = 5` would have worked as well.
646 /// // ptr.write(5);
647 /// // let x = TESBox::from_raw_in(ptr, Global);
648 /// // }
649 /// // # Ok::<(), stdx::alloc::AllocError>(())
650 /// ```
651 ///
652 /// [memory layout]: self#memory-layout
653 /// [`Layout`]: crate::Layout
654 #[inline]
655 pub const unsafe fn from_raw_in(raw: *mut T, alloc: A) -> Self {
656 TESBox(unsafe { Unique::new_unchecked(raw) }, alloc)
657 }
658
659 /// Constructs a box from a `NonNull` pointer in the given allocator.
660 ///
661 /// After calling this function, the `NonNull` pointer is owned by
662 /// the resulting `Box`. Specifically, the `Box` destructor will call
663 /// the destructor of `T` and free the allocated memory. For this
664 /// to be safe, the memory must have been allocated in accordance
665 /// with the [memory layout] used by `Box` .
666 ///
667 /// # Safety
668 ///
669 /// This function is unsafe because improper use may lead to
670 /// memory problems. For example, a double-free may occur if the
671 /// function is called twice on the same raw pointer.
672 ///
673 /// The non-null pointer must point to a block of memory allocated by `alloc`.
674 ///
675 /// # Examples
676 ///
677 /// Recreate a `Box` which was previously converted to a `NonNull` pointer
678 /// using [`Box::into_non_null_with_allocator`]:
679 /// ```
680 ///
681 /// use stdx::alloc::Global;
682 /// use commonlibsse_ng::re::TESBox::TESBox;
683 ///
684 /// let x = TESBox::new_in(5, Global);
685 /// let (non_null, alloc) = TESBox::into_non_null_with_allocator(x);
686 /// let x = unsafe { TESBox::from_non_null_in(non_null, alloc) };
687 /// ```
688 /// Manually create a `Box` from scratch by using the system allocator:
689 /// ```
690 /// use std::alloc::Layout;
691 /// use stdx::alloc::{Allocator, Global};
692 /// use commonlibsse_ng::re::TESBox::TESBox;
693 ///
694 /// unsafe {
695 /// let non_null = Global.allocate(Layout::new::<i32>())?.cast::<i32>();
696 /// // In general .write is required to avoid attempting to destruct
697 /// // the (uninitialized) previous contents of `non_null`.
698 /// non_null.write(5);
699 /// let x = TESBox::from_non_null_in(non_null, Global);
700 /// }
701 /// # Ok::<(), stdx::alloc::AllocError>(())
702 /// ```
703 ///
704 /// [memory layout]: self#memory-layout
705 /// [`Layout`]: crate::Layout
706 #[inline]
707 pub const unsafe fn from_non_null_in(raw: NonNull<T>, alloc: A) -> Self {
708 // SAFETY: guaranteed by the caller.
709 unsafe { TESBox::from_raw_in(raw.as_ptr(), alloc) }
710 }
711
712 /// Consumes the `Box`, returning a wrapped raw pointer.
713 ///
714 /// The pointer will be properly aligned and non-null.
715 ///
716 /// After calling this function, the caller is responsible for the
717 /// memory previously managed by the `Box`. In particular, the
718 /// caller should properly destroy `T` and release the memory, taking
719 /// into account the [memory layout] used by `Box`. The easiest way to
720 /// do this is to convert the raw pointer back into a `Box` with the
721 /// [`Box::from_raw`] function, allowing the `Box` destructor to perform
722 /// the cleanup.
723 ///
724 /// Note: this is an associated function, which means that you have
725 /// to call it as `Box::into_raw(b)` instead of `b.into_raw()`. This
726 /// is so that there is no conflict with a method on the inner type.
727 ///
728 /// # Examples
729 /// Converting the raw pointer back into a `Box` with [`Box::from_raw`]
730 /// for automatic cleanup:
731 /// ```
732 /// # use commonlibsse_ng::re::TESBox::TESBox;
733 /// let x = TESBox::new(String::from("Hello"));
734 /// let ptr = TESBox::into_raw(x);
735 /// let x = unsafe { TESBox::from_raw(ptr) };
736 /// ```
737 /// Manual cleanup by explicitly running the destructor and deallocating
738 /// the memory:
739 /// ```
740 /// use std::alloc::{dealloc, Layout};
741 /// use std::ptr;
742 /// # use commonlibsse_ng::re::TESBox::TESBox;
743 ///
744 /// let x = TESBox::new(String::from("Hello"));
745 /// let ptr = TESBox::into_raw(x);
746 /// unsafe {
747 /// ptr::drop_in_place(ptr);
748 /// dealloc(ptr as *mut u8, Layout::new::<String>());
749 /// }
750 /// ```
751 /// Note: This is equivalent to the following:
752 /// ```
753 /// # use commonlibsse_ng::re::TESBox::TESBox;
754 /// let x = TESBox::new(String::from("Hello"));
755 /// let ptr = TESBox::into_raw(x);
756 /// unsafe {
757 /// drop(TESBox::from_raw(ptr));
758 /// }
759 /// ```
760 ///
761 /// [memory layout]: self#memory-layout
762 #[must_use = "losing the pointer will leak memory"]
763 #[inline]
764 pub fn into_raw(b: Self) -> *mut T {
765 // Make sure Miri realizes that we transition from a noalias pointer to a raw pointer here.
766 &raw mut *Self::into_raw_with_allocator(b).0
767 }
768
769 /// Consumes the `Box`, returning a wrapped `NonNull` pointer.
770 ///
771 /// The pointer will be properly aligned.
772 ///
773 /// After calling this function, the caller is responsible for the
774 /// memory previously managed by the `Box`. In particular, the
775 /// caller should properly destroy `T` and release the memory, taking
776 /// into account the [memory layout] used by `Box`. The easiest way to
777 /// do this is to convert the `NonNull` pointer back into a `Box` with the
778 /// [`Box::from_non_null`] function, allowing the `Box` destructor to
779 /// perform the cleanup.
780 ///
781 /// Note: this is an associated function, which means that you have
782 /// to call it as `Box::into_non_null(b)` instead of `b.into_non_null()`.
783 /// This is so that there is no conflict with a method on the inner type.
784 ///
785 /// # Examples
786 /// Converting the `NonNull` pointer back into a `Box` with [`Box::from_non_null`]
787 /// for automatic cleanup:
788 /// ```
789 /// use commonlibsse_ng::re::TESBox::TESBox;
790 ///
791 /// let x = TESBox::new(String::from("Hello"));
792 /// let non_null = TESBox::into_non_null(x);
793 /// let x = unsafe { TESBox::from_non_null(non_null) };
794 /// ```
795 /// Manual cleanup by explicitly running the destructor and deallocating
796 /// the memory:
797 /// ```
798 ///
799 /// use std::alloc::{dealloc, Layout};
800 /// use commonlibsse_ng::re::TESBox::TESBox;
801 ///
802 /// let x = TESBox::new(String::from("Hello"));
803 /// let non_null = TESBox::into_non_null(x);
804 /// unsafe {
805 /// non_null.drop_in_place();
806 /// dealloc(non_null.as_ptr().cast::<u8>(), Layout::new::<String>());
807 /// }
808 /// ```
809 /// Note: This is equivalent to the following:
810 /// ```
811 /// use commonlibsse_ng::re::TESBox::TESBox;
812 ///
813 /// let x = TESBox::new(String::from("Hello"));
814 /// let non_null = TESBox::into_non_null(x);
815 /// unsafe {
816 /// drop(TESBox::from_non_null(non_null));
817 /// }
818 /// ```
819 ///
820 /// [memory layout]: self#memory-layout
821 #[must_use = "losing the pointer will leak memory"]
822 #[inline]
823 pub fn into_non_null(b: Self) -> NonNull<T> {
824 // SAFETY: `Box` is guaranteed to be non-null.
825 unsafe { NonNull::new_unchecked(Self::into_raw(b)) }
826 }
827
828 /// Consumes the `Box`, returning a wrapped raw pointer and the allocator.
829 ///
830 /// The pointer will be properly aligned and non-null.
831 ///
832 /// After calling this function, the caller is responsible for the
833 /// memory previously managed by the `Box`. In particular, the
834 /// caller should properly destroy `T` and release the memory, taking
835 /// into account the [memory layout] used by `Box`. The easiest way to
836 /// do this is to convert the raw pointer back into a `Box` with the
837 /// [`Box::from_raw_in`] function, allowing the `Box` destructor to perform
838 /// the cleanup.
839 ///
840 /// Note: this is an associated function, which means that you have
841 /// to call it as `Box::into_raw_with_allocator(b)` instead of `b.into_raw_with_allocator()`. This
842 /// is so that there is no conflict with a method on the inner type.
843 ///
844 /// # Examples
845 /// Converting the raw pointer back into a `Box` with [`Box::from_raw_in`]
846 /// for automatic cleanup:
847 /// ```
848 ///
849 /// use stdx::alloc::Global;
850 /// use commonlibsse_ng::re::TESBox::TESBox;
851 ///
852 /// let x = TESBox::new_in(String::from("Hello"), Global);
853 /// let (ptr, alloc) = TESBox::into_raw_with_allocator(x);
854 /// let x = unsafe { TESBox::from_raw_in(ptr, alloc) };
855 /// ```
856 /// Manual cleanup by explicitly running the destructor and deallocating
857 /// the memory:
858 /// ```
859 ///
860 /// use std::alloc::Layout;
861 /// use std::ptr::{self, NonNull};
862 /// use stdx::alloc::{Allocator, Global};
863 /// use commonlibsse_ng::re::TESBox::TESBox;
864 ///
865 /// let x = TESBox::new_in(String::from("Hello"), Global);
866 /// let (ptr, alloc) = TESBox::into_raw_with_allocator(x);
867 /// unsafe {
868 /// ptr::drop_in_place(ptr);
869 /// let non_null = NonNull::new_unchecked(ptr);
870 /// alloc.deallocate(non_null.cast(), Layout::new::<String>());
871 /// }
872 /// ```
873 ///
874 /// [memory layout]: self#memory-layout
875 #[must_use = "losing the pointer will leak memory"]
876 #[inline]
877 pub fn into_raw_with_allocator(b: Self) -> (*mut T, A) {
878 let mut b = mem::ManuallyDrop::new(b);
879 // We carefully get the raw pointer out in a way that Miri's aliasing model understands what
880 // is happening: using the primitive "deref" of `Box`. In case `A` is *not* `Global`, we
881 // want *no* aliasing requirements here!
882 // In case `A` *is* `Global`, this does not quite have the right behavior; `into_raw`
883 // works around that.
884 let ptr = &raw mut **b;
885 let alloc = unsafe { ptr::read(&b.1) };
886 (ptr, alloc)
887 }
888
889 /// Consumes the `TESBox`, returning a wrapped `NonNull` pointer and the allocator.
890 ///
891 /// The pointer will be properly aligned.
892 ///
893 /// After calling this function, the caller is responsible for the
894 /// memory previously managed by the `Box`. In particular, the
895 /// caller should properly destroy `T` and release the memory, taking
896 /// into account the [memory layout] used by `TESBox`. The easiest way to
897 /// do this is to convert the `NonNull` pointer back into a `Box` with the
898 /// [`TESBox::from_non_null_in`] function, allowing the `Box` destructor to
899 /// perform the cleanup.
900 ///
901 /// Note: this is an associated function, which means that you have
902 /// to call it as `Box::into_non_null_with_allocator(b)` instead of
903 /// `b.into_non_null_with_allocator()`. This is so that there is no
904 /// conflict with a method on the inner type.
905 ///
906 /// # Examples
907 /// Converting the `NonNull` pointer back into a `Box` with
908 /// [`Box::from_non_null_in`] for automatic cleanup:
909 /// ```
910 ///
911 /// # use commonlibsse_ng::re::TESBox::TESBox;
912 /// use stdx::alloc::Global;
913 ///
914 /// let x = TESBox::new_in(String::from("Hello"), Global);
915 /// let (non_null, alloc) = TESBox::into_non_null_with_allocator(x);
916 /// let x = unsafe { TESBox::from_non_null_in(non_null, alloc) };
917 /// ```
918 /// Manual cleanup by explicitly running the destructor and deallocating
919 /// the memory:
920 /// ```
921 ///
922 /// use stdx::alloc::{Allocator, Global};
923 /// use std::alloc::Layout;
924 /// use commonlibsse_ng::re::TESBox::TESBox;
925 ///
926 /// let x = TESBox::new_in(String::from("Hello"), Global);
927 /// let (non_null, alloc) = TESBox::into_non_null_with_allocator(x);
928 /// unsafe {
929 /// non_null.drop_in_place();
930 /// alloc.deallocate(non_null.cast::<u8>(), Layout::new::<String>());
931 /// }
932 /// ```
933 ///
934 /// [memory layout]: self#memory-layout
935 #[must_use = "losing the pointer will leak memory"]
936 #[inline]
937 pub fn into_non_null_with_allocator(b: Self) -> (NonNull<T>, A) {
938 let (ptr, alloc) = TESBox::into_raw_with_allocator(b);
939 // SAFETY: `Box` is guaranteed to be non-null.
940 unsafe { (NonNull::new_unchecked(ptr), alloc) }
941 }
942
943 /// Returns a raw mutable pointer to the `Box`'s contents.
944 ///
945 /// The caller must ensure that the `Box` outlives the pointer this
946 /// function returns, or else it will end up dangling.
947 ///
948 /// This method guarantees that for the purpose of the aliasing model, this method
949 /// does not materialize a reference to the underlying memory, and thus the returned pointer
950 /// will remain valid when mixed with other calls to [`as_ptr`] and [`as_mut_ptr`].
951 /// Note that calling other methods that materialize references to the memory
952 /// may still invalidate this pointer.
953 /// See the example below for how this guarantee can be used.
954 ///
955 /// # Examples
956 ///
957 /// Due to the aliasing guarantee, the following code is legal:
958 ///
959 /// ```rust
960 /// use commonlibsse_ng::re::TESBox::TESBox;
961 ///
962 /// unsafe {
963 /// let mut b = TESBox::new(0);
964 /// let ptr1 = TESBox::as_mut_ptr(&mut b);
965 /// ptr1.write(1);
966 /// let ptr2 = TESBox::as_mut_ptr(&mut b);
967 /// ptr2.write(2);
968 /// // Notably, the write to `ptr2` did *not* invalidate `ptr1`:
969 /// ptr1.write(3);
970 /// }
971 /// ```
972 ///
973 /// [`as_mut_ptr`]: Self::as_mut_ptr
974 /// [`as_ptr`]: Self::as_ptr
975 #[inline]
976 pub fn as_mut_ptr(b: &mut Self) -> *mut T {
977 // This is a primitive deref, not going through `DerefMut`, and therefore not materializing
978 // any references.
979 &raw mut **b
980 }
981
982 /// Returns a raw pointer to the `Box`'s contents.
983 ///
984 /// The caller must ensure that the `Box` outlives the pointer this
985 /// function returns, or else it will end up dangling.
986 ///
987 /// The caller must also ensure that the memory the pointer (non-transitively) points to
988 /// is never written to (except inside an `UnsafeCell`) using this pointer or any pointer
989 /// derived from it. If you need to mutate the contents of the `Box`, use [`as_mut_ptr`].
990 ///
991 /// This method guarantees that for the purpose of the aliasing model, this method
992 /// does not materialize a reference to the underlying memory, and thus the returned pointer
993 /// will remain valid when mixed with other calls to [`as_ptr`] and [`as_mut_ptr`].
994 /// Note that calling other methods that materialize mutable references to the memory,
995 /// as well as writing to this memory, may still invalidate this pointer.
996 /// See the example below for how this guarantee can be used.
997 ///
998 /// # Examples
999 ///
1000 /// Due to the aliasing guarantee, the following code is legal:
1001 ///
1002 /// ```rust
1003 /// # use commonlibsse_ng::re::TESBox::TESBox;
1004 ///
1005 /// unsafe {
1006 /// let mut v = TESBox::new(0);
1007 /// let ptr1 = TESBox::as_ptr(&v);
1008 /// let ptr2 = TESBox::as_mut_ptr(&mut v);
1009 /// let _val = ptr2.read();
1010 /// // No write to this memory has happened yet, so `ptr1` is still valid.
1011 /// let _val = ptr1.read();
1012 /// // However, once we do a write...
1013 /// ptr2.write(1);
1014 /// // ... `ptr1` is no longer valid.
1015 /// // This would be UB: let _val = ptr1.read();
1016 /// }
1017 /// ```
1018 ///
1019 /// [`as_mut_ptr`]: Self::as_mut_ptr
1020 /// [`as_ptr`]: Self::as_ptr
1021 #[inline]
1022 pub fn as_ptr(b: &Self) -> *const T {
1023 // This is a primitive deref, not going through `DerefMut`, and therefore not materializing
1024 // any references.
1025 &raw const **b
1026 }
1027
1028 /// Returns a reference to the underlying allocator.
1029 ///
1030 /// Note: this is an associated function, which means that you have
1031 /// to call it as `Box::allocator(&b)` instead of `b.allocator()`. This
1032 /// is so that there is no conflict with a method on the inner type.
1033 #[inline]
1034 pub const fn allocator(b: &Self) -> &A {
1035 &b.1
1036 }
1037
1038 /// Consumes and leaks the `Box`, returning a mutable reference,
1039 /// `&'a mut T`.
1040 ///
1041 /// Note that the type `T` must outlive the chosen lifetime `'a`. If the type
1042 /// has only static references, or none at all, then this may be chosen to be
1043 /// `'static`.
1044 ///
1045 /// This function is mainly useful for data that lives for the remainder of
1046 /// the program's life. Dropping the returned reference will cause a memory
1047 /// leak. If this is not acceptable, the reference should first be wrapped
1048 /// with the [`Box::from_raw`] function producing a `Box`. This `Box` can
1049 /// then be dropped which will properly destroy `T` and release the
1050 /// allocated memory.
1051 ///
1052 /// Note: this is an associated function, which means that you have
1053 /// to call it as `Box::leak(b)` instead of `b.leak()`. This
1054 /// is so that there is no conflict with a method on the inner type.
1055 ///
1056 /// # Examples
1057 ///
1058 /// Simple usage:
1059 ///
1060 /// ```
1061 /// # use commonlibsse_ng::re::TESBox::TESBox;
1062 /// let x = TESBox::new(41);
1063 /// let static_ref: &'static mut usize = TESBox::leak(x);
1064 /// *static_ref += 1;
1065 /// assert_eq!(*static_ref, 42);
1066 /// # // FIXME(https://github.com/rust-lang/miri/issues/3670):
1067 /// # // use -Zmiri-disable-leak-check instead of unleaking in tests meant to leak.
1068 /// # drop(unsafe { TESBox::from_raw(static_ref) });
1069 /// ```
1070 ///
1071 /// Unsized data:
1072 ///
1073 /// ```
1074 /// # use commonlibsse_ng::re::TESBox::TESBox;
1075 /// // let x = vec![1, 2, 3].into_boxed_slice();
1076 /// // let static_ref = TESBox::leak(x);
1077 /// // static_ref[0] = 4;
1078 /// // assert_eq!(*static_ref, [4, 2, 3]);
1079 /// # // FIXME(https://github.com/rust-lang/miri/issues/3670):
1080 /// # // use -Zmiri-disable-leak-check instead of unleaking in tests meant to leak.
1081 /// // # drop(unsafe { TESBox::from_raw(static_ref) });
1082 /// ```
1083 #[inline]
1084 pub fn leak<'a>(b: Self) -> &'a mut T
1085 where
1086 A: 'a,
1087 {
1088 unsafe { &mut *TESBox::into_raw(b) }
1089 }
1090
1091 /// Converts a `TESBox<T>` into a `Pin<TESBox<T>>`. If `T` does not implement [`Unpin`], then
1092 /// `*boxed` will be pinned in memory and unable to be moved.
1093 ///
1094 /// This conversion does not allocate on the heap and happens in place.
1095 ///
1096 /// This is also available via [`From`].
1097 ///
1098 /// Constructing and pinning a `TESBox` with <code>TESBox::into_pin([TESBox::new]\(x))</code>
1099 /// can also be written more concisely using <code>[TESBox::pin]\(x)</code>.
1100 /// This `into_pin` method is useful if you already have a `TESBox<T>`, or you are
1101 /// constructing a (pinned) `TESBox` in a different way than with [`TESBox::new`].
1102 ///
1103 /// # Notes
1104 ///
1105 /// It's not recommended that crates add an impl like `From<TESBox<T>> for Pin<T>`,
1106 /// as it'll introduce an ambiguity when calling `Pin::from`.
1107 /// A demonstration of such a poor impl is shown below.
1108 ///
1109 /// ```compile_fail
1110 /// # use std::pin::Pin;
1111 /// # use commonlibsse_ng::re::TESBox::TESBox;
1112 /// struct Foo; // A type defined in this crate.
1113 /// impl From<TESBox<()>> for Pin<Foo> {
1114 /// fn from(_: TESBox<()>) -> Pin<Foo> {
1115 /// Pin::new(Foo)
1116 /// }
1117 /// }
1118 ///
1119 /// let foo = TESBox::new(());
1120 /// let bar = Pin::from(foo);
1121 /// ```
1122 pub const fn into_pin(boxed: Self) -> Pin<Self>
1123 where
1124 A: 'static,
1125 {
1126 // It's not possible to move or replace the insides of a `Pin<TESBox<T>>`
1127 // when `T: !Unpin`, so it's safe to pin it directly without any
1128 // additional requirements.
1129 unsafe { Pin::new_unchecked(boxed) }
1130 }
1131}
1132
1133impl<T: ?Sized, A: Allocator> Drop for TESBox<T, A> {
1134 #[inline]
1135 fn drop(&mut self) {
1136 // the T in the Box is dropped by the compiler before the destructor is run
1137
1138 let ptr = self.0;
1139
1140 unsafe {
1141 let layout = Layout::for_value::<T>(&**self);
1142 if layout.size() != 0 {
1143 self.1.deallocate(ptr.as_non_null_ptr().cast(), layout);
1144 }
1145 }
1146 }
1147}
1148
1149impl<T: Default> Default for TESBox<T> {
1150 /// Creates a `TESBox<T>`, with the `Default` value for T.
1151 #[inline]
1152 fn default() -> Self {
1153 TESBox::write(TESBox::new_uninit(), T::default())
1154 }
1155}
1156
1157impl<T> Default for TESBox<[T]> {
1158 #[inline]
1159 fn default() -> Self {
1160 // SAFETY: [T; 0] is a valid allocation
1161 let layout = Layout::array::<T>(0).unwrap();
1162 let Ok(ptr) = Global::allocate(&Global, layout) else {
1163 panic!("TESBox: allocation failed for empty slice");
1164 };
1165
1166 let slice = unsafe { core::slice::from_raw_parts_mut(ptr.cast().as_ptr(), 0) };
1167 let slice = unsafe { NonNull::new_unchecked(slice as *mut [T]) };
1168 unsafe { Self::from_raw_in(slice.as_ptr(), Global) }
1169 }
1170}
1171
1172impl<T: Clone, A: Allocator + Clone> Clone for TESBox<T, A> {
1173 /// Returns a new box with a `clone()` of this box's contents.
1174 ///
1175 /// # Examples
1176 ///
1177 /// ```
1178 /// # use commonlibsse_ng::re::TESBox::TESBox;
1179 /// let x = TESBox::new(5);
1180 /// let y = x.clone();
1181 ///
1182 /// // The value is the same
1183 /// assert_eq!(x, y);
1184 ///
1185 /// // But they are unique objects
1186 /// assert_ne!(&*x as *const i32, &*y as *const i32);
1187 /// ```
1188 #[inline]
1189 fn clone(&self) -> Self {
1190 let cloned = (**self).clone();
1191 TESBox::new_in(cloned, self.1.clone())
1192 }
1193
1194 /// Copies `source`'s contents into `self` without creating a new allocation.
1195 ///
1196 /// # Examples
1197 ///
1198 /// ```
1199 /// # use commonlibsse_ng::re::TESBox::TESBox;
1200 /// let x = TESBox::new(5);
1201 /// let mut y = TESBox::new(10);
1202 /// let yp: *const i32 = &*y;
1203 ///
1204 /// y.clone_from(&x);
1205 ///
1206 /// // The value is the same
1207 /// assert_eq!(x, y);
1208 ///
1209 /// // And no allocation occurred
1210 /// assert_eq!(yp, &*y);
1211 /// ```
1212 #[inline]
1213 fn clone_from(&mut self, source: &Self) {
1214 (**self).clone_from(&(**source));
1215 }
1216}
1217
1218impl<T: Clone, A: Allocator + Clone> Clone for TESBox<[T], A> {
1219 fn clone(&self) -> Self {
1220 let mut vec: Vec<T> = self.iter().cloned().collect();
1221
1222 // -- from_vec_in --
1223 let len = vec.len();
1224 let ptr = vec.as_mut_ptr();
1225 // SAFETY: This was created from a Vec<T, A>
1226 let slice = unsafe { core::slice::from_raw_parts_mut(ptr, len) };
1227 let slice = unsafe { NonNull::new_unchecked(slice as *mut [T]) };
1228
1229 // Prevent Vec from dropping
1230 let _ = mem::ManuallyDrop::new(vec);
1231
1232 Self(unsafe { Unique::new_unchecked(slice.as_ptr()) }, self.1.clone())
1233 }
1234
1235 /// Copies `source`'s contents into `self` without creating a new allocation,
1236 /// so long as the two are of the same length.
1237 ///
1238 /// # Examples
1239 ///
1240 /// ```
1241 /// # use commonlibsse_ng::re::TESBox::TESBox;
1242 /// let x = TESBox::new([5, 6, 7]);
1243 /// let mut y = TESBox::new([8, 9, 10]);
1244 /// let yp: *const [i32] = &*y;
1245 ///
1246 /// y.clone_from(&x);
1247 ///
1248 /// // The value is the same
1249 /// assert_eq!(x, y);
1250 ///
1251 /// // And no allocation occurred
1252 /// assert_eq!(yp, &*y);
1253 /// ```
1254 fn clone_from(&mut self, source: &Self) {
1255 if self.len() == source.len() {
1256 self.clone_from_slice(source);
1257 } else {
1258 *self = source.clone();
1259 }
1260 }
1261}
1262
1263impl<T: ?Sized + PartialEq, A: Allocator> PartialEq for TESBox<T, A> {
1264 #[inline]
1265 fn eq(&self, other: &Self) -> bool {
1266 PartialEq::eq(&**self, &**other)
1267 }
1268 #[inline]
1269 #[allow(clippy::partialeq_ne_impl)]
1270 fn ne(&self, other: &Self) -> bool {
1271 PartialEq::ne(&**self, &**other)
1272 }
1273}
1274
1275impl<T: ?Sized + PartialOrd, A: Allocator> PartialOrd for TESBox<T, A> {
1276 #[inline]
1277 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1278 PartialOrd::partial_cmp(&**self, &**other)
1279 }
1280 #[inline]
1281 fn lt(&self, other: &Self) -> bool {
1282 PartialOrd::lt(&**self, &**other)
1283 }
1284 #[inline]
1285 fn le(&self, other: &Self) -> bool {
1286 PartialOrd::le(&**self, &**other)
1287 }
1288 #[inline]
1289 fn ge(&self, other: &Self) -> bool {
1290 PartialOrd::ge(&**self, &**other)
1291 }
1292 #[inline]
1293 fn gt(&self, other: &Self) -> bool {
1294 PartialOrd::gt(&**self, &**other)
1295 }
1296}
1297
1298impl<T: ?Sized + Ord, A: Allocator> Ord for TESBox<T, A> {
1299 #[inline]
1300 fn cmp(&self, other: &Self) -> Ordering {
1301 Ord::cmp(&**self, &**other)
1302 }
1303}
1304
1305impl<T: ?Sized + Eq, A: Allocator> Eq for TESBox<T, A> {}
1306
1307impl<T: ?Sized + Hash, A: Allocator> Hash for TESBox<T, A> {
1308 fn hash<H: Hasher>(&self, state: &mut H) {
1309 (**self).hash(state);
1310 }
1311}
1312
1313impl<T: ?Sized + Hasher, A: Allocator> Hasher for TESBox<T, A> {
1314 fn finish(&self) -> u64 {
1315 (**self).finish()
1316 }
1317 fn write(&mut self, bytes: &[u8]) {
1318 (**self).write(bytes);
1319 }
1320 fn write_u8(&mut self, i: u8) {
1321 (**self).write_u8(i);
1322 }
1323 fn write_u16(&mut self, i: u16) {
1324 (**self).write_u16(i);
1325 }
1326 fn write_u32(&mut self, i: u32) {
1327 (**self).write_u32(i);
1328 }
1329 fn write_u64(&mut self, i: u64) {
1330 (**self).write_u64(i);
1331 }
1332 fn write_u128(&mut self, i: u128) {
1333 (**self).write_u128(i);
1334 }
1335 fn write_usize(&mut self, i: usize) {
1336 (**self).write_usize(i);
1337 }
1338 fn write_i8(&mut self, i: i8) {
1339 (**self).write_i8(i);
1340 }
1341 fn write_i16(&mut self, i: i16) {
1342 (**self).write_i16(i);
1343 }
1344 fn write_i32(&mut self, i: i32) {
1345 (**self).write_i32(i);
1346 }
1347 fn write_i64(&mut self, i: i64) {
1348 (**self).write_i64(i);
1349 }
1350 fn write_i128(&mut self, i: i128) {
1351 (**self).write_i128(i);
1352 }
1353 fn write_isize(&mut self, i: isize) {
1354 (**self).write_isize(i);
1355 }
1356}
1357
1358impl<T: fmt::Display + ?Sized, A: Allocator> fmt::Display for TESBox<T, A> {
1359 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1360 fmt::Display::fmt(&**self, f)
1361 }
1362}
1363
1364impl<T: fmt::Debug + ?Sized, A: Allocator> fmt::Debug for TESBox<T, A> {
1365 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1366 fmt::Debug::fmt(&**self, f)
1367 }
1368}
1369
1370impl<T: ?Sized, A: Allocator> fmt::Pointer for TESBox<T, A> {
1371 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1372 // It's not possible to extract the inner Uniq directly from the Box,
1373 // instead we cast it to a *const which aliases the Unique
1374 let ptr: *const T = &**self;
1375 fmt::Pointer::fmt(&ptr, f)
1376 }
1377}
1378
1379impl<T: ?Sized, A: Allocator> Deref for TESBox<T, A> {
1380 type Target = T;
1381
1382 fn deref(&self) -> &T {
1383 unsafe { self.0.as_ref() }
1384 }
1385}
1386
1387impl<T: ?Sized, A: Allocator> DerefMut for TESBox<T, A> {
1388 fn deref_mut(&mut self) -> &mut T {
1389 unsafe { self.0.as_mut() }
1390 }
1391}
1392
1393impl<T: ?Sized, A: Allocator> Borrow<T> for TESBox<T, A> {
1394 fn borrow(&self) -> &T {
1395 &**self
1396 }
1397}
1398
1399impl<T: ?Sized, A: Allocator> BorrowMut<T> for TESBox<T, A> {
1400 fn borrow_mut(&mut self) -> &mut T {
1401 &mut **self
1402 }
1403}
1404
1405impl<T: ?Sized, A: Allocator> AsRef<T> for TESBox<T, A> {
1406 fn as_ref(&self) -> &T {
1407 &**self
1408 }
1409}
1410
1411impl<T: ?Sized, A: Allocator> AsMut<T> for TESBox<T, A> {
1412 fn as_mut(&mut self) -> &mut T {
1413 &mut **self
1414 }
1415}
1416
1417impl<E: Error> Error for TESBox<E> {
1418 #[allow(deprecated, deprecated_in_future)]
1419 fn description(&self) -> &str {
1420 Error::description(&**self)
1421 }
1422
1423 #[allow(deprecated)]
1424 fn cause(&self) -> Option<&dyn Error> {
1425 Error::cause(&**self)
1426 }
1427
1428 fn source(&self) -> Option<&(dyn Error + 'static)> {
1429 Error::source(&**self)
1430 }
1431}