在JavaScript中,当您需要通过以下方式访问内存块时,将使用DataView
:
uint8
,uint16
,uint32
,float32
等) DataView
通常用于网络代码,解析和创建二进制文件格式以及实现虚拟机。尽管前两个只能使用顺序访问,但是使用DataView
作为其RAM的虚拟机需要能够自由访问(甚至随机!)
Rust中是否有相应的库?我见过bytes和byteorder,但它们似乎更多是为流/顺序访问而不是免费的随机访问而设计的。
答案 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
板条箱提供了这样的抽象:LitteEndian
和BigEndian
类型都实现了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
结构及其对bytes
中Buf
特征的实现。
您可以在内存的任意位置开始,在一片字节(&[u8]
)周围创建光标;从中读取将进行读取,将其放置在下一次读取中,它将处理对齐,字节序和边界检查。
注意:不幸的是,似乎没有返回Option<u16>
的版本;如果担心的话,我可能会扩展它。
因此,我认为列出的板条箱对您有正确的想法,它们可以满足您提出的所有要求。