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]);