1 use core::alloc::Layout as StdLayout;
2 use core::mem;
3 
4 /// Aborts the process.
5 ///
6 /// To abort, this function simply panics while panicking.
abort() -> !7 pub(crate) fn abort() -> ! {
8     struct Panic;
9 
10     impl Drop for Panic {
11         fn drop(&mut self) {
12             panic!("aborting the process");
13         }
14     }
15 
16     let _panic = Panic;
17     panic!("aborting the process");
18 }
19 
20 /// Calls a function and aborts if it panics.
21 ///
22 /// This is useful in unsafe code where we can't recover from panics.
23 #[inline]
abort_on_panic<T>(f: impl FnOnce() -> T) -> T24 pub(crate) fn abort_on_panic<T>(f: impl FnOnce() -> T) -> T {
25     struct Bomb;
26 
27     impl Drop for Bomb {
28         fn drop(&mut self) {
29             abort();
30         }
31     }
32 
33     let bomb = Bomb;
34     let t = f();
35     mem::forget(bomb);
36     t
37 }
38 
39 /// A version of `alloc::alloc::Layout` that can be used in the const
40 /// position.
41 #[derive(Clone, Copy, Debug)]
42 pub(crate) struct Layout {
43     size: usize,
44     align: usize,
45 }
46 
47 impl Layout {
48     /// Creates a new `Layout` with the given size and alignment.
49     #[inline]
from_size_align(size: usize, align: usize) -> Self50     pub(crate) const fn from_size_align(size: usize, align: usize) -> Self {
51         Self { size, align }
52     }
53 
54     /// Creates a new `Layout` for the given sized type.
55     #[inline]
new<T>() -> Self56     pub(crate) const fn new<T>() -> Self {
57         Self::from_size_align(mem::size_of::<T>(), mem::align_of::<T>())
58     }
59 
60     /// Convert this into the standard library's layout type.
61     ///
62     /// # Safety
63     ///
64     /// - `align` must be non-zero and a power of two.
65     /// - When rounded up to the nearest multiple of `align`, the size
66     ///   must not overflow.
67     #[inline]
into_std(self) -> StdLayout68     pub(crate) const unsafe fn into_std(self) -> StdLayout {
69         StdLayout::from_size_align_unchecked(self.size, self.align)
70     }
71 
72     /// Get the alignment of this layout.
73     #[inline]
align(&self) -> usize74     pub(crate) const fn align(&self) -> usize {
75         self.align
76     }
77 
78     /// Get the size of this layout.
79     #[inline]
size(&self) -> usize80     pub(crate) const fn size(&self) -> usize {
81         self.size
82     }
83 
84     /// Returns the layout for `a` followed by `b` and the offset of `b`.
85     ///
86     /// This function was adapted from the `Layout::extend()`:
87     /// https://doc.rust-lang.org/nightly/std/alloc/struct.Layout.html#method.extend
88     #[inline]
extend(self, other: Layout) -> Option<(Layout, usize)>89     pub(crate) const fn extend(self, other: Layout) -> Option<(Layout, usize)> {
90         let new_align = max(self.align(), other.align());
91         let pad = self.padding_needed_for(other.align());
92 
93         let offset = leap!(self.size().checked_add(pad));
94         let new_size = leap!(offset.checked_add(other.size()));
95 
96         // return None if any of the following are true:
97         // - align is 0 (implied false by is_power_of_two())
98         // - align is not a power of 2
99         // - size rounded up to align overflows
100         if !new_align.is_power_of_two() || new_size > isize::MAX as usize - (new_align - 1) {
101             return None;
102         }
103 
104         let layout = Layout::from_size_align(new_size, new_align);
105         Some((layout, offset))
106     }
107 
108     /// Returns the padding after `layout` that aligns the following address to `align`.
109     ///
110     /// This function was adapted from the `Layout::padding_needed_for()`:
111     /// https://doc.rust-lang.org/nightly/std/alloc/struct.Layout.html#method.padding_needed_for
112     #[inline]
padding_needed_for(self, align: usize) -> usize113     pub(crate) const fn padding_needed_for(self, align: usize) -> usize {
114         let len = self.size();
115         let len_rounded_up = len.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1);
116         len_rounded_up.wrapping_sub(len)
117     }
118 }
119 
120 #[inline]
max(left: usize, right: usize) -> usize121 pub(crate) const fn max(left: usize, right: usize) -> usize {
122     if left > right {
123         left
124     } else {
125         right
126     }
127 }
128