Есть ли способ превратить себя в кусочек? [dубликат]

Я хочу отправить свою структуру через TcpStream. Я мог бы отправить String или u8, но я не могу отправить произвольную структуру. Например:

struct MyStruct {
    id: u8,
    data: [u8; 1024],
}

let my_struct = MyStruct { id: 0, data: [1; 1024] };
let bytes: &[u8] = convert_struct(my_struct); // how??
tcp_stream.write(bytes);

После получения данных я хочу преобразовать &[u8] обратно в MyStruct. Как я могу конвертировать между этими двумя представлениями?

Я знаю, что у Rust есть модуль JSON для сериализации данных, но я не хочу использовать JSON, потому что хочу отправлять данные как можно быстрее и малым, поэтому Я хочу, чтобы не было слишком больших накладных расходов.

11
задан 8 March 2017 в 18:33

1 ответ

Структура с правильными размерами в виде нулевых копий может быть выполнена с использованием stdlib и общей функции.

В приведенном ниже примере существует функция многократного использования, называемая any_as_u8_slice вместо convert_struct , так как это утилита для обертывания создания и создания срезов.

Обратите внимание, что вопрос задает вопрос о преобразовании, этот пример создает только для чтения срез, поэтому имеет преимущество в том, что не нужно копировать память. [ ! d2]

Вот пример, основанный на вопросе:

unsafe fn any_as_u8_slice<T: Sized>(p: &T) -> &[u8] {
    ::std::slice::from_raw_parts(
        (p as *const T) as *const u8,
        ::std::mem::size_of::<T>(),
    )
}

fn main() {
    struct MyStruct {
        id: u8,
        data: [u8; 1024],
    }
    let my_struct = MyStruct { id: 0, data: [1; 1024] };
    let bytes: &[u8] = unsafe { any_as_u8_slice(&my_struct) };
    // tcp_stream.write(bytes);
    println!("{:?}", bytes);
}

Примечание 1), хотя в некоторых случаях ящики с третьей стороной могут быть лучше, это примитивная операция, полезная для того, чтобы знать, как это сделать в Rust.

Примечание 1) во время записи (Rust 1.15), поддержка функций const отсутствует. После того, как это будет возможно, можно будет добавить в массив фиксированного размера вместо среза.

Примечание 3) функция any_as_u8_slice отмечена unsafe, поскольку любые байты заполнения в struct могут быть неинициализированной памятью (давая неопределенное поведение). Если был способ обеспечить, чтобы входные аргументы использовали только структуры, которые были #[repr(packed)], тогда это могло быть безопасным.

В противном случае функция достаточно безопасна, поскольку она предотвращает переполнение буфера, поскольку выход считывается, только фиксированное количество байтов и его время жизни привязаны к вводу. Если вам нужна версия, которая вернула &mut [u8], это было бы очень опасно, так как модификация могла легко создавать противоречивые / поврежденные данные.

13
ответ дан 15 August 2018 в 15:36
  • 1
    Как указано в ответе: "он предотвращает переполнение буфера, поскольку выход доступен только для чтения, фиксированное количество байтов и его время жизни привязано к входу. & Quot; – ideasman42 21 June 2018 в 12:44

Другие вопросы по тегам:

Похожие вопросы: