pub use crate::cast::*;
pub use crate::marker;
pub trait Transmute<T: Sized>: Sized {
fn transmute(self) -> T;
}
pub trait TryTransmute<T: Sized>: Sized {
fn try_transmute(self) -> Result<T, Self>;
}
pub trait TransmuteRef<T>: marker::Transmute<T> {
fn transmute_ref(&self) -> &T;
}
pub trait TryTransmuteRef<T>: marker::TryTransmute<T> {
fn try_transmute_ref(&self) -> Option<&T>;
}
pub trait TransmuteMut<T>: marker::Transmute<T>
where
T: Transmute<Self>,
{
fn transmute_mut(&mut self) -> &mut T;
}
pub trait TryTransmuteMut<T>: marker::TryTransmute<T>
where
T: Transmute<Self>,
{
fn try_transmute_mut(&mut self) -> Option<&mut T>;
}
pub trait Container {
type Item;
}
pub trait TransmuteEach<T>: Container + Sized
where
T: Container,
Self::Item: marker::Transmute<T::Item>,
{
fn transmute_each(self) -> T;
}
pub trait TryTransmuteEach<T>: Container + Sized
where
T: Container,
Self::Item: marker::TryTransmute<T::Item>,
{
fn try_transmute_each(self) -> Result<T, Self>;
}
pub trait TransmuteEachRef<T>: Container
where
T: Container + ?Sized,
Self::Item: marker::Transmute<T::Item>,
{
fn transmute_each_ref(&self) -> &T;
}
pub trait TryTransmuteEachRef<T>: Container
where
T: Container + ?Sized,
Self::Item: marker::TryTransmute<T::Item>,
{
fn try_transmute_each_ref(&self) -> Option<&T>;
}
pub trait TransmuteEachMut<T>: Container
where
T: Container + ?Sized,
Self::Item: marker::Transmute<T::Item>,
{
fn transmute_each_mut(&mut self) -> &mut T;
}
pub trait TryTransmuteEachMut<T>: Container
where
T: Container + ?Sized,
Self::Item: marker::TryTransmute<T::Item>,
{
fn try_transmute_each_mut(&mut self) -> Option<&mut T>;
}
impl<A, B> Transmute<B> for A
where
A: marker::Transmute<B>,
{
#[inline]
fn transmute(self) -> B {
unsafe { cast_val(self) }
}
}
impl<A, B> TryTransmute<B> for A
where
A: marker::TryTransmute<B>,
{
#[inline]
fn try_transmute(self) -> Result<B, Self> {
unsafe {
if self.can_transmute() {
Ok(cast_val(self))
} else {
Err(self)
}
}
}
}
impl<A, B> TransmuteRef<B> for A
where
A: marker::Transmute<B>,
{
#[inline]
fn transmute_ref(&self) -> &B {
unsafe { cast_ref(self) }
}
}
impl<A, B> TryTransmuteRef<B> for A
where
A: marker::TryTransmute<B>,
{
#[inline]
fn try_transmute_ref(&self) -> Option<&B> {
unsafe {
if self.can_transmute() {
Some(cast_ref(self))
} else {
None
}
}
}
}
impl<A, B> TransmuteMut<B> for A
where
A: marker::Transmute<B>,
B: marker::Transmute<A>,
{
#[inline]
fn transmute_mut(&mut self) -> &mut B {
unsafe { cast_mut(self) }
}
}
impl<A, B> TryTransmuteMut<B> for A
where
A: marker::TryTransmute<B>,
B: marker::Transmute<A>,
{
#[inline]
fn try_transmute_mut(&mut self) -> Option<&mut B> {
unsafe {
if self.can_transmute() {
Some(cast_mut(self))
} else {
None
}
}
}
}
impl<T> Container for Vec<T> {
type Item = T;
}
impl<A, B> TransmuteEach<Vec<B>> for Vec<A>
where
A: marker::Transmute<B>,
{
#[inline]
fn transmute_each(self) -> Vec<B> {
unsafe { cast_vec(self) }
}
}
impl<A, B> TryTransmuteEach<Vec<B>> for Vec<A>
where
A: marker::TryTransmute<B>,
{
#[inline]
fn try_transmute_each(self) -> Result<Vec<B>, Self> {
unsafe {
if self.iter().all(A::can_transmute) {
Ok(cast_vec(self))
} else {
Err(self)
}
}
}
}
impl<T> Container for [T] {
type Item = T;
}
impl<A, B> TransmuteEachRef<[B]> for [A]
where
A: marker::Transmute<B>,
{
#[inline]
fn transmute_each_ref(&self) -> &[B] {
unsafe { cast_slice(self) }
}
}
impl<A, B> TransmuteEachMut<[B]> for [A]
where
A: marker::Transmute<B>,
B: marker::Transmute<A>,
{
#[inline]
fn transmute_each_mut(&mut self) -> &mut [B] {
unsafe { cast_slice_mut(self) }
}
}
impl<A, B> TryTransmuteEachRef<[B]> for [A]
where
A: marker::TryTransmute<B>,
{
#[inline]
fn try_transmute_each_ref(&self) -> Option<&[B]> {
unsafe {
if self.iter().all(A::can_transmute) {
Some(cast_slice(self))
} else {
None
}
}
}
}
impl<A, B> TryTransmuteEachMut<[B]> for [A]
where
A: marker::TryTransmute<B>,
B: marker::Transmute<A>,
{
#[inline]
fn try_transmute_each_mut(&mut self) -> Option<&mut [B]> {
unsafe {
if self.iter().all(A::can_transmute) {
Some(cast_slice_mut(self))
} else {
None
}
}
}
}
macro_rules! array_impls {
($($N: expr,)*) => {
$(
impl<T> Container for [T; $N] {
type Item = T;
}
impl<A, B> TransmuteEach<[B; $N]> for [A; $N]
where
A: marker::Transmute<B>,
{
#[inline]
fn transmute_each(self) -> [B; $N] {
unsafe {
cast_val(self)
}
}
}
impl<A, B> TryTransmuteEach<[B; $N]> for [A; $N]
where
A: marker::TryTransmute<B>,
{
#[inline]
fn try_transmute_each(self) -> Result<[B; $N], Self> {
unsafe {
if self.iter().all(A::can_transmute) {
Ok(cast_val(self))
} else {
Err(self)
}
}
}
}
)*
};
}
array_impls!(
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
27, 28, 29, 30, 31, 32,
);
#[cfg(test)]
mod tests {
use super::*;
use std::num::NonZeroU32;
macro_rules! unsafe_impl_transmute {
($A:ty => $B:ty) => {
unsafe impl marker::Transmute<$B> for $A {}
};
($A:ty => $B:ty where $can_transmute: expr) => {
unsafe impl marker::TryTransmute<$B> for $A {
#[inline]
fn can_transmute(&self) -> bool {
$can_transmute(self)
}
}
};
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
struct Name(NonZeroU32);
unsafe_impl_transmute!(Name => Option<Name>);
unsafe_impl_transmute!(Option<Name> => Name where Option::is_some);
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
struct U8(u8);
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
struct I8(i8);
unsafe_impl_transmute!(U8 => I8);
unsafe_impl_transmute!(I8 => U8);
fn on(val: u32) -> Option<Name> {
NonZeroU32::new(val).map(Name)
}
fn n(val: u32) -> Name {
on(val).unwrap()
}
#[test]
fn transmute() {
assert_eq!(on(1), n(1).transmute());
}
#[test]
fn try_transmute() {
assert_eq!(Ok(n(1)), on(1).try_transmute());
assert_eq!(
Result::<Name, Option<Name>>::Err(None),
on(0).try_transmute()
);
}
#[test]
fn transmute_ref() {
assert_eq!(&on(1), n(1).transmute_ref());
}
#[test]
fn try_transmute_ref_success() {
assert_eq!(Some(&n(1)), on(1).try_transmute_ref());
}
#[test]
fn try_transmute_ref_fail() {
assert_eq!(Option::<&Name>::None, on(0).try_transmute_ref());
}
#[test]
fn transmute_mut() {
let mut val = U8(200);
let ref_: &mut I8 = val.transmute_mut();
assert_eq!(*ref_, I8(-56));
*ref_ = I8(-55);
assert_eq!(val, U8(201));
}
#[test]
fn try_transmute_mut_success() {
let mut v = on(1);
let r: &mut Name = v.try_transmute_mut().unwrap();
assert_eq!(r, &mut n(1));
*r = n(2);
assert_eq!(v, on(2));
}
#[test]
fn try_transmute_mut_fail() {
assert_eq!(Option::<&mut Name>::None, on(0).try_transmute_mut());
}
#[test]
fn transmute_each() {
assert_eq!([on(1), on(2)], [n(1), n(2)].transmute_each(),);
assert_eq!(vec![on(1), on(2)], vec![n(1), n(2)].transmute_each(),);
}
#[test]
fn try_transmute_each() {
assert_eq!(Ok([n(1), n(2)]), [on(1), on(2)].try_transmute_each(),);
assert_eq!(
Result::<[Name; 2], _>::Err([on(1), on(0)]),
[on(1), on(0)].try_transmute_each(),
);
assert_eq!(
Ok(vec![n(1), n(2)]),
vec![on(1), on(2)].try_transmute_each(),
);
assert_eq!(
Result::<Vec<Name>, _>::Err(vec![on(0), on(2)]),
vec![on(0), on(2)].try_transmute_each(),
);
}
#[test]
fn transmute_each_ref() {
assert_eq!(
&[on(1), on(2)][..],
[n(1), n(2)][..].transmute_each_ref(),
);
}
#[test]
fn try_transmute_each_ref() {
assert_eq!(
Some(&[n(1), n(2)][..]),
[on(1), on(2)].try_transmute_each_ref(),
);
assert_eq!(
Option::<&[Name]>::None,
[on(0), on(2)].try_transmute_each_ref(),
);
assert_eq!(
Option::<&[Name]>::None,
[on(1), on(0)].try_transmute_each_ref(),
);
}
#[test]
fn transmute_each_mut() {
assert_eq!(
&mut [I8(1), I8(2)][..],
[U8(1), U8(2)][..].transmute_each_mut(),
);
}
#[test]
fn try_transmute_each_mut() {
assert_eq!(
Some(&mut [n(1), n(2)][..]),
[on(1), on(2)].try_transmute_each_mut(),
);
assert_eq!(
Option::<&mut [Name]>::None,
[on(0), on(2)].try_transmute_each_mut(),
);
assert_eq!(
Option::<&mut [Name]>::None,
[on(1), on(0)].try_transmute_each_mut(),
);
}
}