chamibuddhika
chamibuddhika

Reputation: 1439

How is from_raw_parts_mut able to transmute between types of different sizes?

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

Answers (1)

Chris Emerson
Chris Emerson

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:

  • Slices &[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 objects like &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

Related Questions