Skip to main content

thin_dst/
polyfill.rs

1//! Polyfills for unstable features `slice_from_raw_parts` and `alloc_layout_extra`,
2//! along with a theoretical `fn repr_c` to compute `#[repr(C)]` layouts.
3
4pub(crate) use self::slice_from_raw_parts::{make_slice, make_slice_mut};
5
6#[cfg(not(slice_from_raw_parts))] // https://github.com/rust-lang/rust/issues/36925
7mod slice_from_raw_parts {
8    use core::slice;
9    pub(crate) unsafe fn make_slice<T>(data: *const T, len: usize) -> *const [T] {
10        slice::from_raw_parts(data, len) as *const [T]
11    }
12    pub(crate) unsafe fn make_slice_mut<T>(data: *mut T, len: usize) -> *mut [T] {
13        slice::from_raw_parts_mut(data, len) as *mut [T]
14    }
15}
16
17#[cfg(slice_from_raw_parts)] // https://github.com/rust-lang/rust/issues/36925
18mod slice_from_raw_parts {
19    use core::ptr;
20    pub(crate) use ptr::slice_from_raw_parts as make_slice;
21    pub(crate) use ptr::slice_from_raw_parts_mut as make_slice_mut;
22}
23
24pub(crate) use alloc_layout_extra::{extend_layout, layout_array, pad_layout_to_align};
25
26#[cfg(not(alloc_layout_extra))] // https://github.com/rust-lang/rust/issues/55724
27mod alloc_layout_extra {
28    use core::{
29        alloc::{Layout, LayoutErr},
30        cmp,
31    };
32
33    fn layout_err() -> LayoutErr {
34        Layout::from_size_align(0, 0).unwrap_err()
35    }
36
37    pub(crate) fn extend_layout(this: &Layout, next: Layout) -> Result<(Layout, usize), LayoutErr> {
38        let new_align = cmp::max(this.align(), next.align());
39        let pad = layout_padding_needed_for(&this, next.align());
40        let offset = this.size().checked_add(pad).ok_or_else(layout_err)?;
41        let new_size = offset.checked_add(next.size()).ok_or_else(layout_err)?;
42        let layout = Layout::from_size_align(new_size, new_align)?;
43        Ok((layout, offset))
44    }
45
46    pub(crate) fn layout_array<T>(n: usize) -> Result<Layout, LayoutErr> {
47        repeat_layout(&Layout::new::<T>(), n).map(|(k, _)| k)
48    }
49
50    pub(crate) fn pad_layout_to_align(this: &Layout) -> Layout {
51        let pad = layout_padding_needed_for(this, this.align());
52        let new_size = this.size() + pad;
53        unsafe { Layout::from_size_align_unchecked(new_size, this.align()) }
54    }
55
56    fn layout_padding_needed_for(this: &Layout, align: usize) -> usize {
57        let len = this.size();
58        let len_rounded_up = len.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1);
59        len_rounded_up.wrapping_sub(len)
60    }
61
62    fn repeat_layout(this: &Layout, n: usize) -> Result<(Layout, usize), LayoutErr> {
63        let padded_size = pad_layout_to_align(this).size();
64        let alloc_size = padded_size.checked_mul(n).ok_or_else(layout_err)?;
65        unsafe {
66            Ok((
67                Layout::from_size_align_unchecked(alloc_size, this.align()),
68                padded_size,
69            ))
70        }
71    }
72}
73
74#[cfg(alloc_layout_extra)] // https://github.com/rust-lang/rust/issues/55724
75mod alloc_layout_extra {
76    use core::alloc::{Layout, LayoutErr};
77    pub(crate) fn extend_layout(this: &Layout, next: Layout) -> Result<(Layout, usize), LayoutErr> {
78        this.extend(next)
79    }
80    pub(crate) fn layout_array<T>(n: usize) -> Result<Layout, LayoutErr> {
81        Layout::array::<T>(n)
82    }
83    pub(crate) fn pad_layout_to_align(this: &Layout) -> Layout {
84        this.pad_to_align().unwrap()
85    }
86}
87
88use core::alloc::{Layout, LayoutErr};
89pub fn repr_c_3(fields: [Layout; 3]) -> Result<(Layout, [usize; 3]), LayoutErr> {
90    let mut offsets = [0; 3];
91    let mut layout = fields[0];
92    for i in 1..3 {
93        let (new_layout, this_offset) = extend_layout(&layout, fields[i])?;
94        layout = new_layout;
95        offsets[i] = this_offset;
96    }
97    Ok((pad_layout_to_align(&layout), offsets))
98}