abi_stable/
utils.rs

1//! Utility functions.
2
3use std::{
4    cmp::Ord,
5    fmt::{self, Debug, Display},
6    mem::{self, ManuallyDrop},
7    ptr::NonNull,
8};
9
10use core_extensions::{strings::LeftPadder, StringExt, TypeIdentity};
11
12use crate::{
13    sabi_types::RMut,
14    std_types::{RStr, RString},
15};
16
17//////////////////////////////////////
18
19/// Information about a panic, used in `ffi_panic_message`.
20#[derive(Debug, Copy, Clone)]
21pub struct PanicInfo {
22    ///
23    pub file: &'static str,
24    ///
25    pub line: u32,
26}
27
28/// Prints an error message for attempting to panic across the
29/// ffi boundary and aborts the process.
30#[inline(never)]
31#[cold]
32pub fn ffi_panic_message(info: &'static PanicInfo) -> ! {
33    eprintln!("\nfile:{}\nline:{}", info.file, info.line);
34    eprintln!("Attempted to panic across the ffi boundary.");
35    eprintln!("Aborting to handle the panic...\n");
36    std::process::exit(1);
37}
38
39//////////////////////////////////
40
41/// Only used inside `PhantomData`,
42/// workaround for `PhantomData<&mut T>` not being constructible in const fns.
43#[repr(transparent)]
44pub(crate) struct MutRef<'a, T>(&'a mut T);
45
46unsafe impl<'a, T> crate::abi_stability::GetStaticEquivalent_ for MutRef<'a, T>
47where
48    T: crate::abi_stability::GetStaticEquivalent_,
49{
50    type StaticEquivalent = crate::abi_stability::GetStaticEquivalent<&'a mut T>;
51}
52unsafe impl<'a, T> crate::StableAbi for MutRef<'a, T>
53where
54    T: crate::StableAbi + 'a,
55{
56    type IsNonZeroType = crate::type_level::bools::True;
57
58    const LAYOUT: &'static crate::type_layout::TypeLayout = <&'a mut T as crate::StableAbi>::LAYOUT;
59}
60
61//////////////////////////////////
62
63/// Converts a `&T` to a `NonNull<T>`.
64///
65/// # Example
66///
67/// ```rust
68/// use abi_stable::utils::ref_as_nonnull;
69///
70/// use std::ptr::NonNull;
71///
72/// const NUMBER: NonNull<u64> = ref_as_nonnull(&100);
73///
74/// ```
75pub const fn ref_as_nonnull<T: ?Sized>(reference: &T) -> NonNull<T> {
76    unsafe { NonNull::new_unchecked(reference as *const T as *mut T) }
77}
78
79/// Casts a `&'a mut ManuallyDrop<T>` to `RMut<'a, T>`
80pub fn manuallydrop_as_rmut<T>(this: &mut ManuallyDrop<T>) -> RMut<'_, T> {
81    unsafe { RMut::new(this).transmute() }
82}
83
84/// Casts a `&'a mut ManuallyDrop<T>` to `*mut T`
85pub fn manuallydrop_as_raw_mut<T>(this: &mut ManuallyDrop<T>) -> *mut T {
86    this as *mut ManuallyDrop<T> as *mut T
87}
88
89//////////////////////////////////
90
91#[doc(hidden)]
92pub struct AbortBomb {
93    pub fuse: &'static PanicInfo,
94}
95
96impl Drop for AbortBomb {
97    fn drop(&mut self) {
98        ffi_panic_message(self.fuse);
99    }
100}
101
102//////////////////////////////////
103
104/// Helper type for transmuting between `Copy` types
105/// without adding any overhead in debug builds.
106///
107/// # Safety
108///
109/// Be aware that using this type is equivalent to using [`std::mem::transmute_copy`],
110/// which doesn't check that `T` and `U` have the same size.
111///
112/// [`std::mem::transmute_copy`]: https://doc.rust-lang.org/std/mem/fn.transmute_copy.html
113#[repr(C)]
114pub union Transmuter<T: Copy, U: Copy> {
115    ///
116    pub from: T,
117    ///
118    pub to: U,
119}
120
121//////////////////////////////////
122
123#[repr(C)]
124pub(crate) union Dereference<'a, T> {
125    pub ptr: *const T,
126    pub reff: &'a T,
127}
128
129macro_rules! deref {
130    ($ptr:expr) => {
131        crate::utils::Dereference { ptr: $ptr }.reff
132    };
133}
134pub(crate) use deref;
135
136//////////////////////////////////
137
138/// Helper type for transmuting non-Copy types without adding any overhead in debug builds.
139///
140#[doc(hidden)]
141#[repr(C)]
142pub union TransmuterMD<T, U> {
143    pub from: ManuallyDrop<T>,
144    pub to: ManuallyDrop<U>,
145}
146
147macro_rules! const_transmute {
148    ($from:ty, $to:ty, $val:expr) => {
149        $crate::pmr::ManuallyDrop::into_inner(
150            $crate::utils::TransmuterMD::<$from, $to> {
151                from: $crate::pmr::ManuallyDrop::new($val),
152            }
153            .to,
154        )
155    };
156}
157
158pub(crate) use const_transmute;
159
160//////////////////////////////////
161
162/// Leaks `value` into the heap, and returns a reference to it.
163///
164/// # Warning
165///
166/// You must be careful when calling this function,
167/// since this leak is ignored by [miri](https://github.com/rust-lang/miri).
168///
169#[inline]
170pub fn leak_value<'a, T>(value: T) -> &'a T
171where
172    T: 'a, // T: 'a is for the docs
173{
174    let x = Box::new(value);
175    let leaked: &'a T = Box::leak(x);
176    #[cfg(miri)]
177    unsafe {
178        crate::miri_static_root(leaked as *const T as *const u8);
179    }
180    leaked
181}
182
183/// Transmute a reference to another reference,
184/// changing the referent's type.
185///
186/// # Safety
187///
188/// This has the same safety concerns that `std::mem::transmute` has, including that
189/// `T` has to have an alignment and be compatible with `U`.
190#[inline]
191#[allow(clippy::needless_lifetimes)]
192pub const unsafe fn transmute_reference<T, U>(ref_: &T) -> &U {
193    unsafe { &*(ref_ as *const _ as *const U) }
194}
195
196/// Transmute a mutable reference to another mutable reference,
197/// changing the referent's type.
198///
199/// # Safety
200///
201/// This has the same safety concerns that `std::mem::transmute` has, including that
202/// `T` has to have an alignment and be compatible with `U`.
203#[inline]
204#[allow(clippy::needless_lifetimes)]
205pub unsafe fn transmute_mut_reference<'a, T, U>(ref_: &'a mut T) -> &'a mut U {
206    unsafe { &mut *(ref_ as *mut _ as *mut U) }
207}
208
209//////////////////////////////////////
210
211#[allow(dead_code)]
212pub(crate) fn min_by<T, F, K>(l: T, r: T, mut f: F) -> T
213where
214    F: FnMut(&T) -> K,
215    K: Ord,
216{
217    if f(&l) < f(&r) {
218        l
219    } else {
220        r
221    }
222}
223
224#[allow(dead_code)]
225pub(crate) fn max_by<T, F, K>(l: T, r: T, mut f: F) -> T
226where
227    F: FnMut(&T) -> K,
228    K: Ord,
229{
230    if f(&l) > f(&r) {
231        l
232    } else {
233        r
234    }
235}
236
237#[doc(hidden)]
238pub fn min_max_by<T, F, K>(l: T, r: T, mut f: F) -> (T, T)
239where
240    F: FnMut(&T) -> K,
241    K: Ord,
242{
243    if f(&l) < f(&r) {
244        (l, r)
245    } else {
246        (r, l)
247    }
248}
249
250//////////////////////////////////////
251
252pub(crate) trait FmtPadding {
253    fn display_pad<'a, T>(
254        &'a mut self,
255        padding: usize,
256        v: &T,
257    ) -> Result<LeftPadder<'a>, fmt::Error>
258    where
259        T: Display;
260
261    fn debug_pad<'a, T>(&'a mut self, padding: usize, v: &T) -> Result<LeftPadder<'a>, fmt::Error>
262    where
263        T: Debug;
264}
265
266macro_rules! impl_fmt_padding {
267    ($ty: ty) => {
268        impl FmtPadding for $ty {
269            fn display_pad<'a, T>(
270                &'a mut self,
271                padding: usize,
272                v: &T,
273            ) -> Result<LeftPadder<'a>, fmt::Error>
274            where
275                T: Display,
276            {
277                use std::fmt::Write;
278                let this = self.as_type_mut();
279
280                this.clear();
281
282                writeln!(this, "{}", v)?;
283
284                Ok(this.left_padder(padding))
285            }
286
287            fn debug_pad<'a, T>(
288                &'a mut self,
289                padding: usize,
290                v: &T,
291            ) -> Result<LeftPadder<'a>, fmt::Error>
292            where
293                T: Debug,
294            {
295                use std::fmt::Write;
296                let this = self.as_type_mut();
297
298                this.clear();
299
300                writeln!(this, "{:#?}", v)?;
301
302                Ok(this.left_padder(padding))
303            }
304        }
305    };
306}
307
308impl_fmt_padding! { String }
309impl_fmt_padding! { RString }
310
311//////////////////////////////////////////////////////////////////////
312
313/// Takes the contents out of a `ManuallyDrop<T>`.
314///
315/// # Safety
316///
317/// After this function is called `slot` will become uninitialized and
318/// must not be read again.
319pub unsafe fn take_manuallydrop<T>(slot: &mut ManuallyDrop<T>) -> T {
320    unsafe { ManuallyDrop::take(slot) }
321}
322
323#[doc(hidden)]
324#[inline(always)]
325pub const fn assert_fnonce<F, R>(_: &F)
326where
327    F: FnOnce() -> R,
328{
329}
330
331/// This function allows calculating the distance (in `T`s) from `from` to `to`.
332///
333/// This returns `None` if `from` has a higher address than `to`,
334/// or if `T` is a zero sized type.
335///
336/// # Example
337///
338/// ```
339/// use abi_stable::utils;
340///
341/// let arr = ["hello", "world", "foo", "bar", "baz"];
342///
343/// assert_eq!(utils::distance_from(&arr[0], &arr[0]), Some(0));
344/// assert_eq!(utils::distance_from(&arr[0], &arr[4]), Some(4));
345///
346/// assert_eq!(utils::distance_from(&arr[4], &arr[0]), None);
347///
348/// ```
349pub fn distance_from<T>(from: *const T, to: *const T) -> Option<usize> {
350    (to as usize)
351        .checked_sub(from as usize)?
352        .checked_div(mem::size_of::<T>())
353}
354
355//////////////////////////////////////////////////////////////////////
356
357#[doc(hidden)]
358pub extern "C" fn get_type_name<T>() -> RStr<'static> {
359    RStr::from(std::any::type_name::<T>())
360}
361
362#[cfg(test)]
363mod tests {
364    use super::*;
365
366    #[test]
367    fn distance_from_() {
368        let int_array = [0, 1, 2, 3, 4];
369        let unit_array = [(), (), (), (), ()];
370
371        for (ix, x) in int_array.iter().enumerate() {
372            for (iy, y) in int_array.iter().enumerate() {
373                if ix <= iy {
374                    assert_eq!(distance_from(x, y), Some(iy - ix));
375                } else {
376                    assert_eq!(distance_from(x, y), None);
377                }
378            }
379        }
380
381        for x in &unit_array {
382            for y in &unit_array {
383                assert_eq!(distance_from(x, y), None);
384            }
385        }
386    }
387}