xrl
xrl

Reputation: 2244

Casting slice of values to a slice of bytes

I am experimenting with an API where the callers provide a Vec<Point> which they want me to fill in with data. They can allocate room in the vector by creating it with with_capacity then push out its size by doing push(Point{...}). Then I will fill the underlying buffer with bytes from the disk, switch their endian representation as necessary, and then provide it back as a Vec<Point>.

Here is the function which takes their vector and fills it with data. The problem is that transmute only works when the types are of the same size, a Point is 12 bytes and transmute throws away 11 of those bytes.

fn read_points(&self, offset: u64, points: &mut [point::Point]) {
    let mut file = self.handle.borrow_mut();
    file.seek(SeekFrom::Start(offset)).unwrap();

    // bleep bloorp. danger!
    let points_buf : &mut [u8] = unsafe { mem::transmute(points) };
    file.read(points_buf).unwrap();

    // should take the 12 bytes and do the endian swaps
    for mut chunk in points_buf.chunks_mut(point::POINT_SIZE) {
        let point = point::buf_to_point(chunk);
        let buf : &mut [u8] = &mut chunk;
        point::fill_buf(buf, point.timestamp, point.value);
    }
}

Can this API be done in Rust or should I should I switch to doing safer but slower copy operations?

Upvotes: 2

Views: 4214

Answers (1)

Simon Sapin
Simon Sapin

Reputation: 10180

The memory representation of &mut [T] is (*mut T, usize) where usize is the number of T elements in the slice, not the number of bytes. So transmuting a slice of say 20 points gives you a slice of 20 bytes.

You have to compute the correct number of bytes:

let n_bytes = points.len() * std::mem::size_of::<Point>();
let points_buf = std::slice::from_raw_parts_mut(points.as_mut_ptr(), n_bytes);

(Then of course deal of all the rest of the unsafety.)

Upvotes: 5

Related Questions