1

I have some byte data stred in a &[u8] I know for a fact the data contained in the slice is float data. I want to do the equivalent of auto float_ptr = (float*)char_ptr;

I tried:

let data_silce = &body[buffer_offset..(buffer_offset + buffer_length)] as &[f32];

But you are not allowed to execute this kind of casting in rust.

1

3 Answers 3

5

Use the bytemuck library; specifically bytemuck::cast_slice(). Underneath, it is just the unsafe conversion that has already been described in other answers, but it uses compile-time (type) and run-time (length and alignment) checks to ensure that you don't have to worry about correctly checking the safety conditions.

let data_slice: &[f32] = bytemuck::cast_slice(
    &body[buffer_offset..(buffer_offset + buffer_length)
];

Note that this will panic if the beginning and end of the slice are not aligned to 4 bytes. There is no way to avoid this requirement in Rust — if the data is not aligned, you must copy it to a new location that is aligned. (Since your goal is to produce f32s, the simplest way to do that while ensuring the alignment would be to iterate with f32::from_ne_bytes(), performing the f32 conversion and the copy.)

Sign up to request clarification or add additional context in comments.

Comments

4

You will need to use unsafe Rust to interpret one type of data as if it is another.

You can do:

let bytes = &body[buffer_offset..(buffer_offset + buffer_length)];

let len = bytes.len();
let ptr = bytes.as_ptr() as *const f32;
let floats: &[f32] = unsafe { std::slice::from_raw_parts(ptr, len / 4)};

Note that this is Undefined Behaviour if any of these are true:

  • the size of the original slice is not a multiple of 4 bytes
  • the alignment of the slice is not a multiple of 4 bytes

All sequences of 4 bytes are valid f32s but, for types without that property, to avoid UB you also need to make sure that all values are valid.

Comments

0

Since Rust 1.30.0, there's also the (unsafe) align_to for slices. This function is unsafe only because of the possibility of invalid types, removing some of the safety burden.

let bytes = &body[buffer_offset..(buffer_offset + buffer_length)];

// SAFETY: f32 can hold any bit pattern
let (prefix, floats, suffix) = unsafe { bytes.align_to::<f32>() };
// catch misalignment, which was Undefined Behaviour in from_raw_parts
assert!(prefix.is_empty());
assert!(suffix.is_empty());
// use floats

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.