#![no_std]
#![allow(unused)]
extern crate alloc;
use core::{
any::{TypeId, type_name},
char,
mem::ManuallyDrop,
num::*,
ptr::NonNull,
str,
mem::size_of,
slice
};
use alloc::{
alloc::Layout,
boxed::Box,
};
#[inline]
unsafe fn transmute<T, U>(x: T) -> U {
#[repr(C, packed)]
union Transmutter<T, U> {
a: ManuallyDrop<T>,
b: ManuallyDrop<U>,
}
ManuallyDrop::into_inner(
Transmutter {
a: ManuallyDrop::new(x),
}
.b,
)
}
pub unsafe trait Transmutable: 'static {
type Dummy: Transmutable + ?Sized;
type ElementType;
fn is_valid(x: &Self::Dummy) -> bool;
#[inline]
fn transmute<T: Transmutable + 'static>(self) -> Result<T, Self> where Self: Sized + 'static {
T::transmute_i(self)
}
#[doc(hidden)]
fn transmute_i<T: Transmutable + 'static>(x: T) -> Result<Self, T>
where
Self: Sized + 'static,
{
if Layout::new::<T>() == Layout::new::<Self>() {
unsafe {
if TypeId::of::<Self>() == TypeId::of::<Self::Dummy>()
|| TypeId::of::<Self>() == TypeId::of::<T>()
{
Ok(transmute(x))
} else {
let dummy = match TransmutableRef::transmute(&x) {
Ok(x) => x,
Err(_) => return Err(x)
};
if Self::is_valid(dummy) {
Ok(transmute(x))
} else {
Err(transmute(x))
}
}
}
} else {
Err(x)
}
}
fn transmute_ref<T: TransmutableRef>(&self) -> Result<T, &Self> {
TransmutableRef::transmute(self)
}
fn transmute_mut<T: TransmutableMut>(&mut self) -> Result<T, &mut Self> {
TransmutableMut::transmute(self)
}
fn transmute_box<T: TransmutableBox>(self: Box<Self>) -> Result<T, Box<Self>> where Self: Sized {
TransmutableBox::transmute(self)
}
}
#[doc(hidden)]
pub trait TransmutableRef: Sized {
fn transmute<T: TransmutableRef>(self) -> Result<T, Self>;
unsafe fn transmute_i<T: ?Sized + Transmutable + 'static>(x: &T) -> Result<Self, &T>;
}
impl<'a, U: Transmutable + ?Sized + 'static> TransmutableRef for &'a U {
fn transmute<T: TransmutableRef>(self) -> Result<T, Self> {
unsafe { T::transmute_i(self) }
}
#[doc(hidden)]
unsafe fn transmute_i<T: ?Sized + Transmutable + 'static>(x: &T) -> Result<Self, &T> {
let input_is_sized = size_of::<*const T>() == size_of::<usize>();
let output_is_sized = size_of::<*const Self>() == size_of::<usize>();
if !(input_is_sized || type_name::<U>().starts_with("[")) || !(output_is_sized || type_name::<U>().starts_with("[")) {
panic!("Custom DST's are not supported ;).")
}
if input_is_sized {
if output_is_sized {
let output = Layout::new::<U::ElementType>();
let input = Layout::new::<T::ElementType>();
if output.align() == input.align() && input.size() >= output.size() {
if TypeId::of::<U>() == TypeId::of::<U::Dummy>() || TypeId::of::<U>() == TypeId::of::<T>() {
Ok(transmute(x))
} else {
let dummy = TransmutableRef::transmute(x)?;
if U::is_valid(dummy) {
Ok(transmute(dummy))
} else {
Err(transmute(dummy))
}
}
} else {
Err(x)
}
} else {
let a = size_of::<T::ElementType>();
let b = size_of::<U::ElementType>();
let mut len = 0;
while let Some(e) = a.checked_sub(b) {
len += 1;
}
if len > 0 {
let x = slice::from_raw_parts(x as *const T as *const T::ElementType, len);
if TypeId::of::<[T::ElementType]>() == TypeId::of::<T::Dummy>() || TypeId::of::<U>() == TypeId::of::<T>() {
Ok(transmute(x))
} else {
let dummy = TransmutableRef::transmute(transmute::<_, &T>(x))?;
if T::is_valid(dummy) {
Ok(transmute(dummy))
} else {
Err(transmute(dummy))
}
}
} else {
Err(x)
}
}
} else {
if output_is_sized {
let z = Layout::for_value(x);
let len = z.size() / size_of::<T::ElementType>();
let y = Layout::new::<U::ElementType>();
if Layout::new::<T::ElementType>() == y {
return if TypeId::of::<U>() == TypeId::of::<U::Dummy>() || TypeId::of::<U>() == TypeId::of::<T>() {
Ok(transmute(x))
} else {
let dummy = TransmutableRef::transmute(x)?;
if U::is_valid(dummy) {
Ok(transmute(dummy))
} else {
Err(transmute(dummy))
}
};
}
if z.align() != y.align() {
return Err(x);
}
let a = y.size();
let b = size_of::<T::ElementType>();
let mut len = 0;
while let Some(e) = a.checked_sub(b) {
len += 1;
}
if len > 0 {
let x = slice::from_raw_parts(x as *const T as *const T::ElementType, len);
if TypeId::of::<U>() == TypeId::of::<U::Dummy>() || TypeId::of::<U>() == TypeId::of::<T>() {
Ok(transmute(x))
} else {
let dummy = TransmutableRef::transmute(transmute::<_, &T>(x))?;
if U::is_valid(dummy) {
Ok(transmute(dummy))
} else {
Err(transmute(dummy))
}
}
} else {
Err(x)
}
} else {
let a = Layout::new::<T::ElementType>();
let b = Layout::new::<U::ElementType>();
let z = Layout::for_value(x);
let len = z.size() / size_of::<T::ElementType>();
if a == b {
return if TypeId::of::<U>() == TypeId::of::<U::Dummy>() || TypeId::of::<U>() == TypeId::of::<T>() {
Ok(transmute(x))
} else {
let dummy = TransmutableRef::transmute(x)?;
if U::is_valid(dummy) {
Ok(transmute(dummy))
} else {
Err(transmute(dummy))
}
};
}
if a.align() == b.align() {
let d = if a.size() <= b.size() {
b.size() / a.size()
} else {
a.size() / b.size()
};
let y = x;
let x = slice::from_raw_parts(y as *const T as *const U::ElementType, len / d);
if TypeId::of::<U>() == TypeId::of::<U::Dummy>() || TypeId::of::<U>() == TypeId::of::<T>() {
Ok(transmute(x))
} else {
let dummy = match TransmutableRef::transmute(transmute::<_, &<U::Dummy as Transmutable>::Dummy>(x)) {
Ok(x) => x,
Err(_) => return Err(transmute(y))
};
if U::is_valid(dummy) {
Ok(transmute(x))
} else {
Err(y)
}
}
} else {
Err(x)
}
}
}
}
}
#[doc(hidden)]
pub unsafe trait TransmutableMut: Sized {
fn transmute<T: TransmutableMut>(self) -> Result<T, Self>;
#[doc(hidden)]
unsafe fn transmute_i<T: ?Sized + Transmutable + 'static>(x: &mut T) -> Result<Self, &mut T>;
}
unsafe impl<'a, U: Transmutable + ?Sized + 'static> TransmutableMut for &'a mut U {
fn transmute<T: TransmutableMut>(self) -> Result<T, Self> {
unsafe { T::transmute_i(self) }
}
#[doc(hidden)]
unsafe fn transmute_i<T: ?Sized + Transmutable + 'static>(x: &mut T) -> Result<Self, &mut T> {
let input_is_sized = size_of::<*const T>() == size_of::<usize>();
let output_is_sized = size_of::<*const Self>() == size_of::<usize>();
if !(input_is_sized || type_name::<U>().starts_with("[")) || !(output_is_sized || type_name::<U>().starts_with("[")) {
panic!("Custom DST's are not supported ;).")
}
if input_is_sized {
if output_is_sized {
let output = Layout::new::<U::ElementType>();
let input = Layout::new::<T::ElementType>();
if output.align() == input.align() && input.size() >= output.size() {
if TypeId::of::<U>() == TypeId::of::<U::Dummy>() || TypeId::of::<U>() == TypeId::of::<T>() {
Ok(transmute(x))
} else {
let dummy = match TransmutableRef::transmute(&*x) {
Ok(x) => x,
Err(_) => return Err(x)
};
if U::is_valid(dummy) {
Ok(transmute(dummy))
} else {
Err(transmute(dummy))
}
}
} else {
Err(x)
}
} else {
let a = size_of::<T::ElementType>();
let b = size_of::<U::ElementType>();
let mut len = 0;
while let Some(e) = a.checked_sub(b) {
len += 1;
}
if len > 0 {
let x = slice::from_raw_parts_mut(x as *mut T as *mut T::ElementType, len);
if TypeId::of::<[T::ElementType]>() == TypeId::of::<T::Dummy>() || TypeId::of::<U>() == TypeId::of::<T>() {
Ok(transmute(x))
} else {
let dummy = match TransmutableRef::transmute(transmute::<_, &T>(&*x)) {
Ok(x) => x,
Err(_) => return Err(transmute(x))
};
if T::is_valid(dummy) {
Ok(transmute(dummy))
} else {
Err(transmute(dummy))
}
}
} else {
Err(x)
}
}
} else {
if output_is_sized {
let z = Layout::for_value(x);
let len = z.size() / size_of::<T::ElementType>();
let y = Layout::new::<U::ElementType>();
if Layout::new::<T::ElementType>() == y {
return if TypeId::of::<U>() == TypeId::of::<U::Dummy>() || TypeId::of::<U>() == TypeId::of::<T>() {
Ok(transmute(x))
} else {
let dummy = match TransmutableRef::transmute(&*x) {
Ok(x) => x,
Err(_) => return Err(x)
};
if U::is_valid(dummy) {
Ok(transmute(dummy))
} else {
Err(transmute(dummy))
}
};
}
if z.align() != y.align() {
return Err(x);
}
let a = y.size();
let b = size_of::<T::ElementType>();
let mut len = 0;
while let Some(e) = a.checked_sub(b) {
len += 1;
}
if len > 0 {
let x = slice::from_raw_parts_mut(x as *mut T as *mut T::ElementType, len);
if TypeId::of::<U>() == TypeId::of::<U::Dummy>() || TypeId::of::<U>() == TypeId::of::<T>() {
Ok(transmute(x))
} else {
let dummy = match TransmutableRef::transmute(transmute::<_, &T>(&*x)) {
Ok(x) => x,
Err(_) => return Err(transmute(x))
};
if U::is_valid(dummy) {
Ok(transmute(dummy))
} else {
Err(transmute(dummy))
}
}
} else {
Err(x)
}
} else {
let a = Layout::new::<T::ElementType>();
let b = Layout::new::<U::ElementType>();
let z = Layout::for_value(x);
let len = z.size() / size_of::<T::ElementType>();
if a == b {
return if TypeId::of::<U>() == TypeId::of::<U::Dummy>() || TypeId::of::<U>() == TypeId::of::<T>() {
Ok(transmute(x))
} else {
let dummy = match TransmutableRef::transmute(&*x) {
Ok(x) => x,
Err(_) => return Err(x)
};
if U::is_valid(dummy) {
Ok(transmute(dummy))
} else {
Err(transmute(dummy))
}
};
}
if a.align() == b.align() {
let d = if a.size() <= b.size() {
b.size() / a.size()
} else {
a.size() / b.size()
};
let y = x;
let x = slice::from_raw_parts_mut(y as *mut T as *mut U::ElementType, len / d);
if TypeId::of::<U>() == TypeId::of::<U::Dummy>() || TypeId::of::<U>() == TypeId::of::<T>() {
Ok(transmute(x))
} else {
let dummy = match TransmutableRef::transmute(transmute::<_, &<U::Dummy as Transmutable>::Dummy>(&*x)) {
Ok(x) => x,
Err(_) => return Err(transmute(y))
};
if U::is_valid(dummy) {
Ok(transmute(x))
} else {
Err(y)
}
}
} else {
Err(x)
}
}
}
}
}
#[doc(hidden)]
pub unsafe trait TransmutableBox: Sized {
fn transmute<T: TransmutableBox>(self) -> Result<T, Self>;
#[doc(hidden)]
unsafe fn transmute_i<T: ?Sized + Transmutable + 'static>(x: Box<T>) -> Result<Self, Box<T>>;
}
unsafe impl<U: Transmutable + 'static> TransmutableBox for Box<U> {
fn transmute<T: TransmutableBox>(self) -> Result<T, Self> {
unsafe { T::transmute_i(self) }
}
#[doc(hidden)]
unsafe fn transmute_i<T: ?Sized + Transmutable + 'static>(x: Box<T>) -> Result<Self, Box<T>> {
if Layout::for_value(&*x) == Layout::new::<Self>() {
unsafe {
if TypeId::of::<U>() == TypeId::of::<U::Dummy>()
|| TypeId::of::<U>() == TypeId::of::<T>()
{
Ok(Box::from_raw(Box::into_raw(x) as *mut U))
} else {
let dummy = match TransmutableRef::transmute(&*x) {
Ok(x) => x,
Err(_) => return Err(x)
};
if U::is_valid(dummy) {
Ok(Box::from_raw(Box::into_raw(x) as *mut U))
} else {
Err(x)
}
}
}
} else {
Err(x)
}
}
}
unsafe impl Transmutable for str {
type Dummy = [u8];
type ElementType = u8;
fn is_valid(x: &Self::Dummy) -> bool {
str::from_utf8(x).is_ok()
}
}
unsafe impl<'a> Transmutable for bool {
type Dummy = u8;
type ElementType = Self;
fn is_valid(x: &Self::Dummy) -> bool {
*x < 2
}
}
macro_rules! impl_transmutable {
($($p:ty),*) => {
$(
unsafe impl Transmutable for $p {
type Dummy = Self;
type ElementType = Self;
fn is_valid(_: &Self::Dummy) -> bool {
true
}
}
)*
}
}
impl_transmutable! { u8, i8, u16, i16, u32, i32, u64, i64, usize, isize, u128, i128, () }
macro_rules! impl_transmutable_nonzero {
($($p:ty; $a:ty),*) => {
$(
unsafe impl Transmutable for $a {
type Dummy = $p;
type ElementType = Self;
fn is_valid(x: &Self::Dummy) -> bool {
*x > 0
}
}
)*
}
}
impl_transmutable_nonzero! {
u8; NonZeroU8,
i8; NonZeroI8,
u16; NonZeroU16,
i16; NonZeroI16,
u32; NonZeroU32,
i32; NonZeroI32,
u64; NonZeroU64,
i64; NonZeroI64,
usize; NonZeroUsize,
isize; NonZeroIsize,
u128; NonZeroU128,
i128; NonZeroI128
}
unsafe impl<T: ?Sized + 'static> Transmutable for *const T {
type Dummy = Self;
type ElementType = Self;
fn is_valid(_: &Self::Dummy) -> bool {
true
}
}
unsafe impl<T: ?Sized + 'static> Transmutable for *mut T {
type Dummy = Self;
type ElementType = Self;
fn is_valid(_: &Self::Dummy) -> bool {
true
}
}
unsafe impl<T: ?Sized + 'static> Transmutable for NonNull<T> {
type Dummy = *mut T;
type ElementType = Self;
fn is_valid(x: &Self::Dummy) -> bool {
NonNull::new(*x).is_some()
}
}
unsafe impl Transmutable for char {
type Dummy = u32;
type ElementType = Self;
fn is_valid(x: &Self::Dummy) -> bool {
char::from_u32(*x).is_some()
}
}
unsafe impl<A: Transmutable<Dummy = B>,
B: Transmutable<Dummy = C>,
C: Transmutable<Dummy = D>,
D: Transmutable<Dummy = E>,
E: Transmutable<Dummy = F>,
F: Transmutable<Dummy = G>,
G: Transmutable<Dummy = H>,
H: Transmutable<Dummy = I>,
I: Transmutable<Dummy = J>,
J: Transmutable<Dummy = K>,
K: Transmutable<Dummy = L>,
L: Transmutable<Dummy = M>,
M: Transmutable<Dummy = N>,
N: Transmutable<Dummy = O>,
O: Transmutable<Dummy = P>,
P: Transmutable<Dummy = Q>,
Q: Transmutable<Dummy = R>,
R: Transmutable<Dummy = S>,
S: Transmutable<Dummy = T>,
T: Transmutable<Dummy = U>,
U: Transmutable<Dummy = V>,
V: Transmutable<Dummy = W>,
W: Transmutable<Dummy = X>,
X: Transmutable<Dummy = Y>,
Y: Transmutable<Dummy = Z>,
Z: Transmutable<Dummy = ZA>,
ZA: Transmutable<Dummy = ZB>,
ZB: Transmutable<Dummy = ZC>,
ZC: Transmutable<Dummy = ZD>,
ZD: Transmutable<Dummy = ZE>,
ZE: Transmutable<Dummy = ZF>,
ZF: Transmutable<Dummy = ZG>,
ZG: Transmutable<Dummy = ZH>,
ZH: Transmutable<Dummy = ZI>,
ZI: Transmutable<Dummy = ZJ>,
ZJ: Transmutable<Dummy = ZK>,
ZK: Transmutable<Dummy = ZL>,
ZL: Transmutable<Dummy = ZM>,
ZM: Transmutable<Dummy = ZN>,
ZN: Transmutable<Dummy = ZO>,
ZO: Transmutable<Dummy = ZP>,
ZP: Transmutable<Dummy = ZQ>,
ZQ: Transmutable<Dummy = ZR>,
ZR: Transmutable<Dummy = ZS>,
ZS: Transmutable<Dummy = ZT>,
ZT: Transmutable<Dummy = ZU>,
ZU: Transmutable<Dummy = ZV>,
ZV: Transmutable<Dummy = ZW>,
ZW: Transmutable<Dummy = ZX>,
ZX: Transmutable<Dummy = ZY>,
ZY: Transmutable<Dummy = ZZ>,
ZZ: Transmutable<Dummy = ZZA>,
ZZA: Transmutable<Dummy = ZZB>,
ZZB: Transmutable<Dummy = ZZC>,
ZZC: Transmutable<Dummy = ZZD>,
ZZD: Transmutable<Dummy = ZZE>,
ZZE: Transmutable<Dummy = ZZF>,
ZZF: Transmutable<Dummy = ZZG>,
ZZG: Transmutable<Dummy = ZZH>,
ZZH: Transmutable<Dummy = ZZI>,
ZZI: Transmutable<Dummy = ZZJ>,
ZZJ: Transmutable<Dummy = ZZK>,
ZZK: Transmutable<Dummy = ZZL>,
ZZL: Transmutable<Dummy = ZZM>,
ZZM: Transmutable<Dummy = ZZN>,
ZZN: Transmutable<Dummy = ZZO>,
ZZO: Transmutable<Dummy = ZZP>,
ZZP: Transmutable<Dummy = ZZQ>,
ZZQ: Transmutable<Dummy = ZZR>,
ZZR: Transmutable<Dummy = ZZS>,
ZZS: Transmutable<Dummy = ZZT>,
ZZT: Transmutable<Dummy = ZZU>,
ZZU: Transmutable<Dummy = ZZV>,
ZZV: Transmutable<Dummy = ZZW>,
ZZW: Transmutable<Dummy = ZZX>,
ZZX: Transmutable<Dummy = ZZY>,
ZZY: Transmutable<Dummy = ZZZ>,
ZZZ: Transmutable<Dummy = ZZZA>,
ZZZA: Transmutable<Dummy = ZZZB>,
ZZZB: Transmutable<Dummy = ZZZC>,
ZZZC: Transmutable<Dummy = ZZZD>,
ZZZD: Transmutable<Dummy = ZZZE>,
ZZZE: Transmutable<Dummy = ZZZF>,
ZZZF: Transmutable<Dummy = ZZZG>,
ZZZG: Transmutable<Dummy = ZZZH>,
ZZZH: Transmutable<Dummy = ZZZI>,
ZZZI: Transmutable<Dummy = ZZZJ>,
ZZZJ: Transmutable<Dummy = ZZZK>,
ZZZK: Transmutable<Dummy = ZZZL>,
ZZZL: Transmutable<Dummy = ZZZM>,
ZZZM: Transmutable<Dummy = ZZZN>,
ZZZN: Transmutable<Dummy = ZZZO>,
ZZZO: Transmutable<Dummy = ZZZP>,
ZZZP: Transmutable<Dummy = ZZZQ>,
ZZZQ: Transmutable<Dummy = ZZZR>,
ZZZR: Transmutable<Dummy = ZZZS>,
ZZZS: Transmutable<Dummy = ZZZT>,
ZZZT: Transmutable<Dummy = ZZZU>,
ZZZU: Transmutable<Dummy = ZZZV>,
ZZZV: Transmutable<Dummy = ZZZW>,
ZZZW: Transmutable<Dummy = ZZZX>,
ZZZX: Transmutable<Dummy = ZZZX>>
Transmutable for [A] {
type Dummy = [A::Dummy];
type ElementType = A;
fn is_valid(x: &Self::Dummy) -> bool {
x.iter().all(A::is_valid)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn a() {
assert!(1u8.transmute::<bool>().unwrap());
assert!(!0u8.transmute::<bool>().unwrap());
assert!(2u8.transmute::<bool>().is_err());
let a = [1, 2];
let r: Result<&[bool], &[u32]> = a[..].transmute_ref();
assert_eq!(r, Err(&[1, 2][..]))
}
}