Я хочу отправить свою структуру через 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, потому что хочу отправлять данные как можно быстрее и малым, поэтому Я хочу, чтобы не было слишком больших накладных расходов.
Структура с правильными размерами в виде нулевых копий может быть выполнена с использованием 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], это было бы очень опасно, так как модификация могла легко создавать противоречивые / поврежденные данные.