How do I use the byteorder crate to read a usize?

2019-07-16 04:14发布

问题:

I'm writing an encoding library and I'd like to convert a slice into a usize.

I see a read_uint method that looks promising, though I'm unsure how to get the register size as a variable so I can put it in the function.

For example I'd like to get 32 on a 32 bit processor, and 64 on a 64 bit processor.

回答1:

One way is to use mem::size_of to get the size of a usize:

use byteorder::{ByteOrder, ReadBytesExt};

fn read_usize<B, R>(mut b: R) -> Result<usize, std::io::Error>
where
    B: ByteOrder,
    R: ReadBytesExt,
{
    b.read_uint::<B>(std::mem::size_of::<usize>()).map(|v| v as usize)
}

Another is to have different functions or function implementations for different architectures:

fn read_usize<B, R>(mut b: R) -> Result<usize, std::io::Error>
where
    B: ByteOrder,
    R: ReadBytesExt,
{
    if cfg!(target_pointer_width = "64") {
        b.read_u64::<B>().map(|v| v as usize)
    } else if cfg!(target_pointer_width = "32") {
        b.read_u32::<B>().map(|v| v as usize)
    } else {
        b.read_u16::<B>().map(|v| v as usize)
    }
}

See also:

  • How to get the size of a user defined struct? (sizeof)
  • How to check in Rust if architecture is 32 or 64 bit?


回答2:

TL;DR there is a good reason for not providing a read_usize function, because it is not consistent on different cpu-architectures.


This is a bad idea. Normally you have some kind of protocol you are trying to deserialize. This format should be independent from the cpu-architecture and therefore you can't read an usize, because it is cpu-dependent.

Let's assume you have a simple protocol where you first have the size of an array and afterwards n elements.

+------+---------+
| size | ....... |
+------+---------+

Let's suppose the protocol says that your size is 4 byte long. Now you want to do the thing Shepmaster suggested and read the usize dependent on your architecture.

On a x86_64 OS you will now read 8 bytes and therefore swallow the first element in your array.
On a Atmega8 your usize would be 2 bytes and therefore only take the first 2 bytes of your size (which might be zero in case there are less than 65k elements and a BigEndian byte-order).

This is the reason why there is no read_usize function and it is correct. You need to decide how long your size is, read the exact amount of bytes from your slice and then us as to convert that into an usize.



标签: rust