abi_stable/
inline_storage.rs

1//! Contains the `InlineStorage` trait,and related items.
2
3use std::{marker::PhantomData, mem::ManuallyDrop};
4
5/// Type used as the inline storage of a RSmallBox<>/NonExhaustive<>.
6///
7/// # Safety
8///
9/// Implementors must:
10///
11/// - Be types for which all bitpatterns are valid.
12///
13/// - Not implement Drop,and have no drop glue.
14///
15pub unsafe trait InlineStorage {}
16
17macro_rules! impl_for_arrays {
18    ( ty=$ty:ty , len[ $($len:expr),* $(,)* ] ) => (
19        $(
20            unsafe impl InlineStorage for [$ty;$len] {}
21        )*
22    )
23}
24
25impl_for_arrays! {
26    ty=u8,
27    len[
28        0,1,2,3,4,5,6,7,8,9,
29        10,11,12,13,14,15,16,17,18,19,
30        20,21,22,23,24,25,26,27,28,29,
31        30,31,32,33,34,35,36,37,38,39,
32        40,41,42,43,44,45,46,47,48,49,
33        50,51,52,53,54,55,56,57,58,59,
34        60,61,62,63,64,
35    ]
36}
37
38impl_for_arrays! {
39    ty=u32,
40    len[
41        0,1,2,3,4,5,6,7,8,9,
42        10,11,12,13,14,15,16,17,18,19,
43        20,21,22,23,24,25,26,27,28,29,
44        30,31,32,33,34,35,36,37,38,39,
45        40,41,42,43,44,45,46,47,48,
46    ]
47}
48
49impl_for_arrays! {
50    ty=u64,
51    len[
52        0,1,2,3,4,5,6,7,8,9,
53        10,11,12,13,14,15,16,17,18,19,
54        20,21,22,23,24,
55    ]
56}
57
58impl_for_arrays! {
59    ty=usize,
60    len[
61        0,1,2,3,4,5,6,7,8,9,
62        10,11,12,13,14,15,16,17,18,19,
63        20,21,22,23,24,25,26,27,28,29,
64        30,31,32,33,34,35,36,37,38,39,
65        40,41,42,43,44,45,46,47,48,
66    ]
67}
68
69mod private {
70    use super::*;
71    pub struct Private<T, const ALIGNMENT: usize>(pub(super) PhantomData<T>);
72}
73use private::Private;
74
75/// For getting the `AlignTo*` type which aligns `Self` to `ALIGNMENT`.
76pub trait AlignerFor<const ALIGNMENT: usize>: Sized {
77    // prevents implementations outside this crate.
78    #[doc(hidden)]
79    const __PRIVATE_12350662443733019984: Private<Self, ALIGNMENT>;
80
81    /// The `AlignTo*` type which aligns `Self` to `ALIGNMENT`.
82    type Aligner;
83}
84
85/// For getting the `AlignTo*` type which aligns `T` to `ALIGNMENT`.
86pub type GetAlignerFor<T, const ALIGNMENT: usize> = <T as AlignerFor<ALIGNMENT>>::Aligner;
87
88macro_rules! declare_alignments {
89    (
90        $(( $aligner:ident, $alignment:expr),)*
91    ) => (
92        $(
93            #[doc = concat!(
94                "Aligns its contents to an address at a multiple of ",
95                $alignment,
96                " bytes."
97            )]
98            #[derive(StableAbi, Debug, PartialEq, Eq, Copy, Clone)]
99            #[repr(C)]
100            #[repr(align($alignment))]
101            pub struct $aligner<Inline>(pub Inline);
102
103            unsafe impl<Inline> InlineStorage for $aligner<Inline>
104            where
105                Inline: InlineStorage,
106            {}
107
108            impl<T> AlignerFor<$alignment> for T {
109                #[doc(hidden)]
110                const __PRIVATE_12350662443733019984: Private<T, $alignment> = Private(PhantomData);
111
112                type Aligner = $aligner<T>;
113            }
114        )*
115    )
116}
117
118/// Helper types related to the alignemnt of inline storage.
119pub mod alignment {
120    use super::*;
121
122    /*
123        fn main(){
124            for pow in 0..=16 {
125                let val = 1u32 << pow;
126                println!("        (AlignTo{val}, {val}),")
127            }
128        }
129    */
130    declare_alignments! {
131        (AlignTo1, 1),
132        (AlignTo2, 2),
133        (AlignTo4, 4),
134        (AlignTo8, 8),
135        (AlignTo16, 16),
136        (AlignTo32, 32),
137        (AlignTo64, 64),
138        (AlignTo128, 128),
139        (AlignTo256, 256),
140        (AlignTo512, 512),
141        (AlignTo1024, 1024),
142        (AlignTo2048, 2048),
143        (AlignTo4096, 4096),
144        (AlignTo8192, 8192),
145        (AlignTo16384, 16384),
146        (AlignTo32768, 32768),
147    }
148
149    /// Aligns its contents to an address to an address at
150    /// a multiple of the size of a pointer.
151    #[repr(C)]
152    #[derive(Debug, PartialEq, Eq, Copy, Clone)]
153    #[cfg_attr(target_pointer_width = "128", repr(C, align(16)))]
154    #[cfg_attr(target_pointer_width = "64", repr(C, align(8)))]
155    #[cfg_attr(target_pointer_width = "32", repr(C, align(4)))]
156    #[cfg_attr(target_pointer_width = "16", repr(C, align(2)))]
157    pub struct AlignToUsize<Inline>(pub Inline);
158
159    unsafe impl<Inline> InlineStorage for AlignToUsize<Inline> where Inline: InlineStorage {}
160}
161
162///////////////////////////////////////////////////////////////////////////////
163
164#[repr(transparent)]
165pub(crate) struct ScratchSpace<T, Inline> {
166    #[allow(dead_code)]
167    inner: ScratchSpaceInner<T, Inline>,
168}
169
170#[repr(C)]
171union ScratchSpaceInner<T, Inline> {
172    value: ManuallyDrop<T>,
173    storage: ManuallyDrop<Inline>,
174    uninit: (),
175}
176
177// These constructors don't require `Inline: InlineStorage` because
178// the `storage` field is only used for its side/alignment,
179// it is never actually constructed.
180impl<T, Inline> ScratchSpace<T, Inline> {
181    #[inline]
182    #[allow(dead_code)]
183    #[track_caller]
184    pub(crate) const fn uninit() -> Self {
185        Self::assert_fits_within_storage();
186        Self {
187            inner: ScratchSpaceInner { uninit: () },
188        }
189    }
190
191    #[inline]
192    #[allow(dead_code)]
193    #[track_caller]
194    pub(crate) const fn new(value: T) -> Self {
195        Self::assert_fits_within_storage();
196        Self {
197            inner: ScratchSpaceInner {
198                value: ManuallyDrop::new(value),
199            },
200        }
201    }
202
203    /// Asserts that `T` fits within `Inline`,with the correct alignment and size.
204    #[track_caller]
205    const fn assert_fits_within_storage() {
206        use crate::nonexhaustive_enum::AssertCsArgs;
207
208        crate::nonexhaustive_enum::assert_correct_storage::<T, Inline>(AssertCsArgs::UNKNOWN)
209    }
210}