use core::fmt::{Debug, Write};
use faer_traits::ComplexConj;
use num_complex::Complex;
#[inline(always)]
pub fn nonstatic_typeid<T: ?Sized>() -> core::any::TypeId {
trait NonStaticAny {
fn type_id(&self) -> core::any::TypeId
where
Self: 'static;
}
impl<T: ?Sized> NonStaticAny for core::marker::PhantomData<T> {
#[inline(always)]
fn type_id(&self) -> core::any::TypeId
where
Self: 'static,
{
core::any::TypeId::of::<T>()
}
}
let it = core::marker::PhantomData::<T>;
unsafe {
core::mem::transmute::<&dyn NonStaticAny, &'static dyn NonStaticAny>(
&it,
)
.type_id()
}
}
#[inline(always)]
pub unsafe fn coerce<Src, Dst>(src: Src) -> Dst {
crate::assert!(nonstatic_typeid::<Src>() == nonstatic_typeid::<Dst>());
transmute(src)
}
#[inline(always)]
pub unsafe fn transmute<Src, Dst>(src: Src) -> Dst {
if const {
core::mem::size_of::<Src>() != core::mem::size_of::<Dst>()
|| core::mem::align_of::<Src>() != core::mem::align_of::<Dst>()
} {
panic!();
} else {
unsafe { core::mem::transmute_copy(&core::mem::ManuallyDrop::new(src)) }
}
}
#[repr(C)]
pub struct ComplexDebug<T> {
re: T,
im: T,
}
#[repr(C)]
pub struct ComplexConjDebug<T> {
re: T,
neg_im: T,
}
#[repr(C)]
pub struct C32 {
re: f32,
im: f32,
}
#[repr(C)]
pub struct C64 {
re: f64,
im: f64,
}
#[repr(C)]
pub struct C32Conj {
re: f32,
neg_im: f32,
}
#[repr(C)]
pub struct C64Conj {
re: f64,
neg_im: f64,
}
impl<T: Debug> Debug for ComplexDebug<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
if f.alternate() {
(unsafe { &*(self as *const _ as *const Complex<T>) }).fmt(f)
} else {
let re = &self.re;
let im = &self.im;
f.write_str("(")?;
re.fmt(f)?;
write!(f, " + ")?;
im.fmt(f)?;
f.write_char('i')?;
f.write_str(")")
}
}
}
impl<T: Debug> Debug for ComplexConjDebug<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
if f.alternate() {
(unsafe { &*(self as *const _ as *const Complex<T>) }).fmt(f)
} else {
let re = &self.re;
let im = &self.neg_im;
f.write_str("(")?;
re.fmt(f)?;
write!(f, " - ")?;
im.fmt(f)?;
f.write_char('i')?;
f.write_str(")")
}
}
}
impl Debug for C32 {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let im_sign = if self.im.is_sign_negative() { '-' } else { '+' };
let re = self.re;
let im = self.im.abs();
re.fmt(f)?;
write!(f, " {im_sign} ")?;
im.fmt(f)?;
f.write_char('i')
}
}
impl Debug for C64 {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let im_sign = if self.im.is_sign_negative() { '-' } else { '+' };
let re = self.re;
let im = self.im.abs();
re.fmt(f)?;
write!(f, " {im_sign} ")?;
im.fmt(f)?;
f.write_char('i')
}
}
impl Debug for C32Conj {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let re_sign = if self.re.is_sign_negative() { '-' } else { '+' };
let im_sign = if self.neg_im.is_sign_negative() {
'+'
} else {
'-'
};
let re = self.re.abs();
let im = self.neg_im.abs();
write!(f, "{re_sign}")?;
re.fmt(f)?;
write!(f, " {im_sign} ")?;
im.fmt(f)?;
f.write_char('i')
}
}
impl Debug for C64Conj {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let re_sign = if self.re.is_sign_negative() { '-' } else { '+' };
let im_sign = if self.neg_im.is_sign_negative() {
'+'
} else {
'-'
};
let re = self.re.abs();
let im = self.neg_im.abs();
write!(f, "{re_sign}")?;
re.fmt(f)?;
write!(f, " {im_sign} ")?;
im.fmt(f)?;
f.write_char('i')
}
}
pub fn hijack_debug<T: Debug>(x: &T) -> &dyn Debug {
if nonstatic_typeid::<T>() == nonstatic_typeid::<Complex<f32>>() {
unsafe { &*(x as *const T as *const C32) }
} else if nonstatic_typeid::<T>() == nonstatic_typeid::<Complex<f64>>() {
unsafe { &*(x as *const T as *const C64) }
} else if nonstatic_typeid::<T>() == nonstatic_typeid::<ComplexConj<f32>>()
{
unsafe { &*(x as *const T as *const C32Conj) }
} else if nonstatic_typeid::<T>() == nonstatic_typeid::<ComplexConj<f64>>()
{
unsafe { &*(x as *const T as *const C64Conj) }
} else {
x
}
}