BurntSushi / byteorder

Rust library for reading/writing numbers in big-endian and little-endian.
The Unlicense
984 stars 144 forks source link

Transparently support reading into arrays of types that are byte-compatible with integers #186

Closed ptomato closed 2 years ago

ptomato commented 2 years ago

Hi! :wave: My use case is that I'd like to read a data file into a buffer of Wrapping<u16>. Here's an example program, that doesn't compile:

use byteorder::ReadBytesExt;
fn main() -> Result<(), std::io::Error> {
    let mut file = std::fs::File::open("test")?;
    let mut buffer = [std::num::Wrapping(0); 16];
    file.read_u16_into::<byteorder::NetworkEndian>(&mut buffer)?;
    Ok(())
}

It would be nice if read_NNN_into() would support types that are byte-compatible with integers, such as in this case Wrapping<u16>.

(I'm relatively inexperienced with Rust so maybe there's some existing way to do this that I'm missing, without copying the buffer and without unsafe code!)

BurntSushi commented 2 years ago

I don't think it makes a lot of sense for byteorder to support this on its own. The simplest way would be to add read_wrapping_u16_into APIs (along with the other various integer types), but that bloats the API considerably. We could modify the existing read_u16_into APIs to take a generic parameter, and add traits for performing zero-cost conversions between integer types. But this is a lot of infrastructure, and would ultimately require a byteorder 2.0 release because making APIs generic tends to lead to breaking changes in practice.

Longer term, I think the answer to this will be better support from Rust itself. The "safer transmute" RFC is a good starting point to see what folks are up to in this space currently. For a more immediate answer, your options are to either use unsafe, or use one of the crates that provide the "safer transmute" functionality as a library. For example, bytemuck or zerocopy. Those should let you write the code you want without unsafe.