1use 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#[derive(Debug, Copy, Clone)]
21pub struct PanicInfo {
22 pub file: &'static str,
24 pub line: u32,
26}
27
28#[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#[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
61pub 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
79pub fn manuallydrop_as_rmut<T>(this: &mut ManuallyDrop<T>) -> RMut<'_, T> {
81 unsafe { RMut::new(this).transmute() }
82}
83
84pub fn manuallydrop_as_raw_mut<T>(this: &mut ManuallyDrop<T>) -> *mut T {
86 this as *mut ManuallyDrop<T> as *mut T
87}
88
89#[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#[repr(C)]
114pub union Transmuter<T: Copy, U: Copy> {
115 pub from: T,
117 pub to: U,
119}
120
121#[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#[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#[inline]
170pub fn leak_value<'a, T>(value: T) -> &'a T
171where
172 T: 'a, {
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#[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#[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#[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
250pub(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
311pub 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
331pub 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#[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}