use std::{
cmp::Ord,
fmt::{self,Debug,Display},
mem::{self,ManuallyDrop},
ptr::NonNull,
};
use core_extensions::{
strings::LeftPadder,
prelude::*,
};
use crate::std_types::{RString,RStr};
#[derive(Debug,Copy,Clone)]
pub struct PanicInfo{
pub file:&'static str,
pub line:u32,
}
#[inline(never)]
#[cold]
pub fn ffi_panic_message(info:&'static PanicInfo) -> ! {
eprintln!("\nfile:{}\nline:{}", info.file, info.line);
eprintln!("Attempted to panic across the ffi boundary.");
eprintln!("Aborting to handle the panic...\n");
std::process::exit(1);
}
pub const fn ref_as_nonnull<T>(reference: &T) -> NonNull<T> {
unsafe{
NonNull::new_unchecked(reference as *const T as *mut T)
}
}
#[doc(hidden)]
pub struct AbortBomb{
pub fuse:&'static PanicInfo,
}
impl Drop for AbortBomb{
fn drop(&mut self){
ffi_panic_message(self.fuse);
}
}
#[repr(C)]
pub union Transmuter<T: Copy, U: Copy> {
pub from: T,
pub to: U,
}
#[inline]
pub fn leak_value<'a,T>(value:T)->&'a T
where T:'a {
let x = Box::new(value);
let leaked: &'a T = Box::leak(x);
#[cfg(miri)]
unsafe{
crate::miri_static_root(leaked as *const T as *const u8);
}
leaked
}
#[inline]
#[allow(clippy::needless_lifetimes)]
pub unsafe fn transmute_reference<T,U>(ref_:&T)->&U{
&*(ref_ as *const _ as *const U)
}
#[inline]
#[allow(clippy::needless_lifetimes)]
pub unsafe fn transmute_mut_reference<'a,T,U>(ref_:&'a mut T)->&'a mut U{
&mut *(ref_ as *mut _ as *mut U)
}
#[allow(dead_code)]
pub(crate) fn min_by<T,F,K>(l:T,r:T,mut f:F)->T
where
F:FnMut(&T)->K,
K:Ord,
{
if f(&l) < f(&r) {
l
}else{
r
}
}
#[allow(dead_code)]
pub(crate) fn max_by<T,F,K>(l:T,r:T,mut f:F)->T
where
F:FnMut(&T)->K,
K:Ord,
{
if f(&l) > f(&r) {
l
}else{
r
}
}
#[doc(hidden)]
pub fn min_max_by<T,F,K>(l:T,r:T,mut f:F)->(T,T)
where
F:FnMut(&T)->K,
K:Ord,
{
if f(&l) < f(&r) {
(l,r)
}else{
(r,l)
}
}
pub(crate) trait FmtPadding{
fn display_pad<'a,T>(&'a mut self,padding:usize,v:&T)->Result<LeftPadder<'a> ,fmt::Error>
where T:Display;
fn debug_pad<'a,T>(&'a mut self,padding:usize,v:&T)->Result<LeftPadder<'a> ,fmt::Error>
where T:Debug;
}
macro_rules! impl_fmt_padding {
($ty:ty) => (
impl FmtPadding for $ty{
fn display_pad<'a,T>(
&'a mut self,
padding:usize,
v:&T
)->Result<LeftPadder<'a> ,fmt::Error>
where T:Display
{
use std::fmt::Write;
let this=self.into_type_mut();
this.clear();
writeln!(this,"{}",v)?;
Ok(this.left_padder(padding))
}
fn debug_pad<'a,T>(
&'a mut self,
padding:usize,
v:&T
)->Result<LeftPadder<'a> ,fmt::Error>
where T:Debug
{
use std::fmt::Write;
let this=self.into_type_mut();
this.clear();
writeln!(this,"{:#?}",v)?;
Ok(this.left_padder(padding))
}
}
)
}
impl_fmt_padding!{ String }
impl_fmt_padding!{ RString }
pub unsafe fn take_manuallydrop<T>(slot: &mut ManuallyDrop<T>) -> T {
#[cfg(feature = "rust_1_42")]
{
ManuallyDrop::take(slot)
}
#[cfg(not(feature = "rust_1_42"))]
{
ManuallyDrop::into_inner(std::ptr::read(slot))
}
}
#[doc(hidden)]
#[inline(always)]
pub fn assert_fnonce<F,R>(_:&F)
where
F:FnOnce()->R
{}
pub fn distance_from<T>(from:*const T,to:*const T)->Option<usize>{
(to as usize)
.checked_sub(from as usize)?
.checked_div(mem::size_of::<T>())
}
#[doc(hidden)]
pub extern "C" fn get_type_name<T>()->RStr<'static>{
RStr::from(std::any::type_name::<T>())
}
#[cfg(test)]
mod tests{
use super::*;
#[test]
fn distance_from_(){
let int_array=[0,1,2,3,4];
let unit_array=[(),(),(),(),()];
for (ix,x) in int_array.iter().enumerate() {
for (iy,y) in int_array.iter().enumerate() {
if ix <= iy {
assert_eq!(distance_from(x,y), Some(iy-ix));
}else{
assert_eq!(distance_from(x,y), None);
}
}
}
for x in &unit_array {
for y in &unit_array {
assert_eq!(distance_from(x,y), None);
}
}
}
}