Что эквивалентно JavaScript DataView в Rust? - PullRequest
0 голосов
/ 04 ноября 2018

В JavaScript DataView используется, когда вам нужно получить доступ к блоку памяти с помощью:

  • различные типы ширины (uint8, uint16, uint32, float32 и т. Д.)
  • данные без выравнивания
  • специфический порядок байтов

DataView s обычно используются для сетевого кода, анализа и создания двоичных форматов файлов, а также для реализации виртуальных машин. В то время как первые два могут обойтись только последовательным доступом, виртуальные машины, использующие DataView в качестве ОЗУ, должны иметь свободный доступ к нему (даже в произвольном порядке!)

Есть ли соответствующая библиотека в Rust? Я видел байтов и метеорологов , но они, кажется, больше предназначены для потокового / последовательного доступа, а не для произвольного доступа.

1 Ответ

0 голосов
/ 04 ноября 2018

Как системный язык, 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 :

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 из стандартной библиотеки и реализацию черты Buf из bytes.

Вы можете создать курсор вокруг части байта (&[u8]), начиная с любой точки памяти; чтение из него продвигает его, помещая его для следующего чтения, и оно будет обрабатывать выравнивание, порядковый номер и проверку границ.

Примечание: к сожалению, не существует версии, возвращающей Option<u16>; Я бы, вероятно, продлил бы это, если бы это было проблемой.


Таким образом, я думаю, что у вас есть правильная идея с перечисленными ящиками, они охватывают все требования, которые вы изложили.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...