什么与Rust中JavaScript的DataView等效?

时间:2018-11-04 02:26:40

标签: rust

在JavaScript中,当您需要通过以下方式访问内存块时,将使用DataView

  • 不同的宽度类型(uint8uint16uint32float32等)
  • 未对齐数据
  • 特定字节序

DataView通常用于网络代码,解析和创建二进制文件格式以及实现虚拟机。尽管前两个只能使用顺序访问,但是使用DataView作为其RAM的虚拟机需要能够自由访问(甚至随机!)

Rust中是否有相应的库?我见过bytesbyteorder,但它们似乎更多是为流/顺序访问而不是免费的随机访问而设计的。

1 个答案:

答案 0 :(得分:4)

作为一种系统语言,Rust本身具有与原始内存进行交互的能力,而无需特定的包装器。

因此,从内存中读取u32仅需要撒一些unsafe

fn read_u32(bytes: &[u8]) -> u32 {
    assert!(bytes.as_ptr() as usize % std::mem::align_of::<u32>() == 0);
    assert!(bytes.len() >= 4);

    unsafe { *(bytes.as_ptr() as *const u32) }
}

此原始功能可用于构建更好的抽象。值得注意的是,抽象要注意对齐和尾数。


byteorder板条箱提供了这样的抽象:LitteEndianBigEndian类型都实现了ByteOrder特质。

上述功能可以改进为:

fn read_u32(bytes: &[u8]) -> u32 { LittleEndian::read_u32(bytes) }

它将负责:

  • 执行转化。
  • 平均处理未对齐的访问,而不是惊慌。
  • 具有显着的字节序。

不过,它实际上只说明了原始类型,这就是bytes条板箱插入的位置。

例如,让我们解码一个UDP Header

use std::io::Cursor;
use bytes::buf::Buf;

struct UdpHeader {
    src_port: u16,
    dst_port: u16,
    length: u16,
    checksum: u16,
}

fn read_udp_header<T: AsRef<[u8]>>(bytes: &mut Cursor<T>) -> UdpHeader {
    UdpHeader {
        src_port: bytes.read_u16_be(),
        dst_port: bytes.read_u16_be(),
        length: bytes.read_u16_be(),
        checksum: bytes.read_u16_be(),
    }
}

使用标准库中的Cursor结构及其对bytesBuf特征的实现。

您可以在内存的任意位置开始,在一片字节(&[u8])周围创建光标;从中读取将进行读取,将其放置在下一次读取中,它将处理对齐,字节序和边界检查。

注意:不幸的是,似乎没有返回Option<u16>的版本;如果担心的话,我可能会扩展它。


因此,我认为列出的板条箱对您有正确的想法,它们可以满足您提出的所有要求。