Skip to main content

try_transmute_ref

Macro try_transmute_ref 

Source
macro_rules! try_transmute_ref {
    ($e:expr) => { ... };
}
Expand description

Conditionally transmutes a mutable or immutable reference of one type to an immutable reference of another type of the same size and compatible alignment.

This macro behaves like an invocation of this function:

fn try_transmute_ref<Src, Dst>(src: &Src) -> Result<&Dst, ValidityError<&Src, Dst>>
where
    Src: IntoBytes + Immutable + ?Sized,
    Dst: TryFromBytes + Immutable + ?Sized,
    align_of::<Src>() >= align_of::<Dst>(),
    size_compatible::<Src, Dst>(),
{
    ...
}

The types Src and Dst are inferred from the calling context; they cannot be explicitly specified in the macro invocation.

§Size compatibility

try_transmute_ref! supports transmuting between Sized types, between unsized (i.e., ?Sized) types, and from a Sized type to an unsized type. It supports any transmutation that preserves the number of bytes of the referent, even if doing so requires updating the metadata stored in an unsized “fat” reference:

let src: &[[u8; 2]] = &[[0, 1], [2, 3]][..];
let dst: &[u8] = try_transmute_ref!(src).unwrap();

assert_eq!(src.len(), 2);
assert_eq!(dst.len(), 4);
assert_eq!(dst, [0, 1, 2, 3]);
assert_eq!(size_of_val(src), size_of_val(dst));

§Examples

Transmuting between Sized types:

// 0u8 → bool = false
assert_eq!(try_transmute_ref!(&0u8), Ok(&false));

// 1u8 → bool = true
 assert_eq!(try_transmute_ref!(&1u8), Ok(&true));

// 2u8 → bool = error
assert!(matches!(
    try_transmute_ref!(&2u8),
    Result::<&bool, _>::Err(ValidityError { .. })
));

Transmuting between unsized types:

#[derive(KnownLayout, FromBytes, IntoBytes, Immutable)]
#[repr(C)]
struct SliceDst<T, U> {
    t: T,
    u: [U],
}

type Src = SliceDst<u32, u16>;
type Dst = SliceDst<u16, bool>;

let src = Src::ref_from_bytes(&[0, 1, 0, 1, 0, 1, 0, 1]).unwrap();
let dst: &Dst = try_transmute_ref!(src).unwrap();

assert_eq!(src.t.as_bytes(), [0, 1, 0, 1]);
assert_eq!(src.u.len(), 2);
assert_eq!(src.u.as_bytes(), [0, 1, 0, 1]);

assert_eq!(dst.t.as_bytes(), [0, 1]);
assert_eq!(dst.u, [false, true, false, true, false, true]);