Using the `byteorder` crate on large buffers

Hey all, I'm writing a torrent client which involves reading bytes over a UdpSocket/TcpStream. I'm using the byteorder crate to read values in BigEndian order, as specified by the bittorrent protocol. The crate defines these in a trait named ReadBytesExt and provides examples like:

let mut rdr = Cursor::new(vec![2, 5, 3, 0]);
assert_eq!(517, rdr.read_u16::<BigEndian>().unwrap());

I myself am using an array rather than a vector to read messages from the connection. I tried using a [u8; 512], like so:

fn error() {
    let buffer = [0u8; 64];
    let c = Cursor::new(buffer);
    let msg = c.read_u32::<BigEndian>();
}
error[E0599]: no method named `read_u32` found for struct `std::io::Cursor<&[u8; 64]>` in the current scope

It seems I can get around this with two different strategies:

  1. Use a vector instead, which seems a bit wasteful as the data is copied (right?)
let c = Cursor::new(buffer.to_vec());
let msg = c.read_u32::<BigEndian>();
  1. Pass the buffer to a function which expects a reference to an unsized array
fn workaround(buffer: &[u8]) -> u32 {
  let c = Cursor::new(buffer)
  let msg = c.read_u32::<BigEndian>();
  msg
}

If there is an implementation for std::io::Cursor<&[u8]>, why are there also implementations for fixed size arrays? Is this for optimization reasons? Something I'm missing about arrays?

How can I use this implementation without having to construct another function to "omit" the size from the reference? Or is there something idiomatic I am missing when it comes to reading "large" (>32), non-fixed size payloads? I was planning on using a vector to build messages that are larger than the buffer (when needed)

(Rust Playground Example)

Seems I just confused arrays and slices, oops.

The latest code I now have is:

  let buf = [0u8; 512];
  // fill buffer from udp/tcp

  let buf: &[u8] = &buf[..]; // convert to slice
  let c = Cursor::new(&buf);
  c.read_u32::<BigEndian>();

Is this idiomatic?

That is fine.

1 Like