use self::private::CompatibleCastPriv;
use crate::data::layout::valid_layout::ValidLayout;
pub unsafe trait Compatible<U>: ValidLayout {}
unsafe impl<T: ValidLayout> Compatible<T> for T {}
pub trait CompatibleCast: CompatibleCastPriv {
type Inner;
type Output<U: Sized>: ?Sized;
fn compatible_cast<U>(&self) -> &Self::Output<U>
where
Self::Inner: Compatible<U>;
fn compatible_cast_mut<U>(&mut self) -> &mut Self::Output<U>
where
Self::Inner: Compatible<U>;
}
impl<T: ValidLayout> CompatibleCast for T {
type Inner = T;
type Output<U: Sized> = U;
#[inline]
fn compatible_cast<U>(&self) -> &Self::Output<U>
where
T: Compatible<U>,
{
debug_assert_eq!(std::mem::size_of::<T>(), std::mem::size_of::<U>());
debug_assert_eq!(std::mem::align_of::<T>(), std::mem::align_of::<U>());
unsafe { std::mem::transmute(self) }
}
#[inline]
fn compatible_cast_mut<U>(&mut self) -> &mut Self::Output<U>
where
T: Compatible<U>,
{
debug_assert_eq!(std::mem::size_of::<T>(), std::mem::size_of::<U>());
debug_assert_eq!(std::mem::align_of::<T>(), std::mem::align_of::<U>());
unsafe { std::mem::transmute(self) }
}
}
impl<T: ValidLayout> CompatibleCast for [T] {
type Inner = T;
type Output<U: Sized> = [U];
#[inline]
fn compatible_cast<U>(&self) -> &Self::Output<U>
where
T: Compatible<U>,
{
debug_assert_eq!(std::mem::size_of::<T>(), std::mem::size_of::<U>());
debug_assert_eq!(std::mem::align_of::<T>(), std::mem::align_of::<U>());
unsafe { std::mem::transmute(self) }
}
#[inline]
fn compatible_cast_mut<U>(&mut self) -> &mut Self::Output<U>
where
T: Compatible<U>,
{
debug_assert_eq!(std::mem::size_of::<T>(), std::mem::size_of::<U>());
debug_assert_eq!(std::mem::align_of::<T>(), std::mem::align_of::<U>());
unsafe { std::mem::transmute(self) }
}
}
impl<T: ValidLayout, const N: usize> CompatibleCast for [T; N] {
type Inner = T;
type Output<U: Sized> = [U; N];
#[inline]
fn compatible_cast<U>(&self) -> &Self::Output<U>
where
T: Compatible<U>,
{
debug_assert_eq!(std::mem::size_of::<T>(), std::mem::size_of::<U>());
debug_assert_eq!(std::mem::align_of::<T>(), std::mem::align_of::<U>());
unsafe { std::mem::transmute(self) }
}
#[inline]
fn compatible_cast_mut<U>(&mut self) -> &mut Self::Output<U>
where
T: Compatible<U>,
{
debug_assert_eq!(std::mem::size_of::<T>(), std::mem::size_of::<U>());
debug_assert_eq!(std::mem::align_of::<T>(), std::mem::align_of::<U>());
unsafe { std::mem::transmute(self) }
}
}
mod private {
use crate::data::layout::valid_layout::ValidLayout;
pub trait CompatibleCastPriv {}
impl<T: ValidLayout> CompatibleCastPriv for T {}
impl<T: ValidLayout> CompatibleCastPriv for [T] {}
impl<T: ValidLayout, const N: usize> CompatibleCastPriv for [T; N] {}
}
#[cfg(test)]
mod tests {
use super::{Compatible, CompatibleCast};
use crate::data::{layout::valid_layout::ValidLayout, managed::value::Value};
#[repr(C)]
struct A {
a: f64,
b: f32,
}
#[repr(C)]
struct B {
c: f64,
d: f32,
}
unsafe impl ValidLayout for A {
fn valid_layout(_: Value) -> bool {
unimplemented!()
}
fn type_object<'target, Tgt: crate::prelude::Target<'target>>(
_target: &Tgt,
) -> Value<'target, 'static> {
unimplemented!()
}
}
unsafe impl Compatible<B> for A {}
#[test]
fn compatible_cast_ref() {
let a = &A { a: 1.0, b: 2.0 };
{
let b = a.compatible_cast::<B>();
assert_eq!(b.c, a.a);
assert_eq!(b.d, a.b);
}
}
#[test]
fn compatible_cast_mut() {
let a = &mut A { a: 1.0, b: 2.0 };
{
let b = a.compatible_cast_mut::<B>();
b.c = 2.0;
b.d = 3.0
}
assert_eq!(a.a, 2.0);
assert_eq!(a.b, 3.0);
}
#[test]
fn compatible_cast_slice() {
let a = &[A { a: 1.0, b: 2.0 }][..];
{
let b = a.compatible_cast::<B>();
assert_eq!(b[0].c, a[0].a);
assert_eq!(b[0].d, a[0].b);
}
}
#[test]
fn compatible_cast_slice_mut() {
let a = &mut [A { a: 1.0, b: 2.0 }][..];
{
let b = a.compatible_cast_mut::<B>();
b[0].c = 2.0;
b[0].d = 3.0;
}
assert_eq!(a[0].a, 2.0);
assert_eq!(a[0].b, 3.0);
}
#[test]
fn compatible_cast_sized_slice() {
let a = &[A { a: 1.0, b: 2.0 }];
{
let b = a.compatible_cast::<B>();
assert_eq!(b[0].c, a[0].a);
assert_eq!(b[0].d, a[0].b);
}
}
#[test]
fn compatible_cast_sized_slice_mut() {
let a = &mut [A { a: 1.0, b: 2.0 }];
{
let b = a.compatible_cast_mut::<B>();
b[0].c = 2.0;
b[0].d = 3.0;
}
assert_eq!(a[0].a, 2.0);
assert_eq!(a[0].b, 3.0);
}
}