Reputation: 2244
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
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