Reputation: 1439
I am looking at the code of from_raw_parts_mut
:
pub unsafe fn from_raw_parts_mut<'a, T>(p: *mut T, len: usize) -> &'a mut [T] {
mem::transmute(Repr { data: p, len: len })
}
It uses transmute
to reinterpret a Repr
to a &mut [T]
. As far as I understand, Repr
is a 128 bit struct. How does this transmute of differently sized types work?
Upvotes: 2
Views: 810
Reputation: 14051
mem::transmute()
does only work when transmuting to a type of the same size - so that means an &mut[T]
slice is also the same size.
Looking at Repr
:
#[repr(C)]
struct Repr<T> {
pub data: *const T,
pub len: usize,
}
It has a pointer to some data and a length. This is exactly what a slice is - a pointer to an array of items (which might be an actual array, or owned by a Vec<T>
, etc.) with a length to say how many items are valid.
The object which is passed around as a slice is (under the covers) exactly what the Repr
looks like, even though the data it refers to can be anything from 0 to as many T
as will fit into memory.
In Rust, some references are not just implemented as a pointer as in some other languages. Some types are "fat pointers". This might not be obvious at first since, especially if you are familiar with references/pointers in some other languages! Some examples are:
&[T]
and &mut [T]
, which as described above, are actually a pointer and length. The length is needed for bounds checks. For example, you can pass a slice corresponding to part of an array or Vec
to a function.&Trait
or Box<Trait>
, where Trait
is a trait rather than a concrete type, are actually a pointer to the concrete type and a pointer to a vtable — the information needed to call trait methods on the object, given that its concrete type is not known.Upvotes: 5