使用动态大小的数据将 'struct' 序列化为 '&[u8]'
Serialize 'struct' with dynamically sized data to '&[u8]'
我正在尝试为结构创建通用序列化方案。按照类似 给出的答案,我有以下设置:
#[repr(packed)]
struct MyStruct {
bytes: [u8; 4]
}
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() {
let s = MyStruct { bytes: [0u8, 1u8, 2u8, 3u8].to_owned() };
let bytes: &[u8] = unsafe { any_as_u8_slice(&s) };
println!("{:?}", bytes);
}
输出:
[0, 1, 2, 3]
这很好用,但是它没有考虑像 Vec<u8>
这样动态调整大小的结构成员,并且它们的大小需要在运行时确定。理想情况下,我想将 Vec<u8>
中的每个元素编码为字节,并添加一个前缀以指示要读取的字节数。
目前我有这个:
#[repr(packed)]
struct MyStruct {
bytes: Vec<u8>
}
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() {
let s = MyStruct { bytes: [0u8, 1u8, 2u8, 3u8].to_vec() };
let bytes: &[u8] = unsafe { any_as_u8_slice(&s) };
println!("{:?}", bytes);
}
输出:
[208, 25, 156, 239, 136, 85, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0]
我假设上面的输出引用了某种指针,但我不确定。
目前,bincode
crate 与 serde
crate 一起执行此操作,但它将向量的长度序列化为 usize
。我宁愿指定它并将长度编码为 u8
,如 中所述。不幸的是,这里最好的解决方案是重写 Bincode
库,这让我不得不寻找任何替代解决方案。
编辑
使用 serde
和 bincode
的实现:
use serde::{Serialize};
#[derive(Clone, Debug, Serialize)]
struct MyStruct {
bytes: Vec<u8>
}
fn main() {
let s = MyStruct { bytes: [0u8, 1u8, 2u8, 3u8].to_vec() };
let bytes = bincode::serialize(&s).unwrap();
println!("{:?}", bytes);
}
输出:
[4, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3]
想要的输出:
[4, 0, 1, 2, 3]
您看到的 Vec
的输出完全符合预期。一个 Vec
有三个元素,一个指针,长度,和它的容量。这是guaranteed by the standard library。在你的情况下,你有指针,长度和容量都是小端的数字 4。
不可能按照您想要的方式将包含 Vec
的结构转换为 &[u8]
。 &[u8]
切片是一块连续的内存,但是,Vec
从根本上说是一种间接寻址,这意味着它的元素不会与结构的其余部分连续存储。
至少,您需要将字节收集到 Vec<u8>
或类似的文件中,因为您需要从多个地方复制数据。
如果 bincode
的唯一问题是 usize
长度前缀,您可以 configure it to use a variable-length prefix by using the with_varint_encoding
选项。
use bincode::{DefaultOptions, Options};
use serde::Serialize;
#[derive(Clone, Debug, Serialize)]
struct MyStruct {
bytes: Vec<u8>,
}
fn main() {
let s = MyStruct {
bytes: [0u8, 1u8, 2u8, 3u8].to_vec(),
};
let bytes = DefaultOptions::new()
.with_varint_encoding()
.serialize(&s);
println!("{:?}", bytes);
}
输出:
[4, 0, 1, 2, 3]
我正在尝试为结构创建通用序列化方案。按照类似
#[repr(packed)]
struct MyStruct {
bytes: [u8; 4]
}
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() {
let s = MyStruct { bytes: [0u8, 1u8, 2u8, 3u8].to_owned() };
let bytes: &[u8] = unsafe { any_as_u8_slice(&s) };
println!("{:?}", bytes);
}
输出:
[0, 1, 2, 3]
这很好用,但是它没有考虑像 Vec<u8>
这样动态调整大小的结构成员,并且它们的大小需要在运行时确定。理想情况下,我想将 Vec<u8>
中的每个元素编码为字节,并添加一个前缀以指示要读取的字节数。
目前我有这个:
#[repr(packed)]
struct MyStruct {
bytes: Vec<u8>
}
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() {
let s = MyStruct { bytes: [0u8, 1u8, 2u8, 3u8].to_vec() };
let bytes: &[u8] = unsafe { any_as_u8_slice(&s) };
println!("{:?}", bytes);
}
输出:
[208, 25, 156, 239, 136, 85, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0]
我假设上面的输出引用了某种指针,但我不确定。
目前,bincode
crate 与 serde
crate 一起执行此操作,但它将向量的长度序列化为 usize
。我宁愿指定它并将长度编码为 u8
,如 Bincode
库,这让我不得不寻找任何替代解决方案。
编辑
使用 serde
和 bincode
的实现:
use serde::{Serialize};
#[derive(Clone, Debug, Serialize)]
struct MyStruct {
bytes: Vec<u8>
}
fn main() {
let s = MyStruct { bytes: [0u8, 1u8, 2u8, 3u8].to_vec() };
let bytes = bincode::serialize(&s).unwrap();
println!("{:?}", bytes);
}
输出:
[4, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3]
想要的输出:
[4, 0, 1, 2, 3]
您看到的 Vec
的输出完全符合预期。一个 Vec
有三个元素,一个指针,长度,和它的容量。这是guaranteed by the standard library。在你的情况下,你有指针,长度和容量都是小端的数字 4。
不可能按照您想要的方式将包含 Vec
的结构转换为 &[u8]
。 &[u8]
切片是一块连续的内存,但是,Vec
从根本上说是一种间接寻址,这意味着它的元素不会与结构的其余部分连续存储。
至少,您需要将字节收集到 Vec<u8>
或类似的文件中,因为您需要从多个地方复制数据。
如果 bincode
的唯一问题是 usize
长度前缀,您可以 configure it to use a variable-length prefix by using the with_varint_encoding
选项。
use bincode::{DefaultOptions, Options};
use serde::Serialize;
#[derive(Clone, Debug, Serialize)]
struct MyStruct {
bytes: Vec<u8>,
}
fn main() {
let s = MyStruct {
bytes: [0u8, 1u8, 2u8, 3u8].to_vec(),
};
let bytes = DefaultOptions::new()
.with_varint_encoding()
.serialize(&s);
println!("{:?}", bytes);
}
输出:
[4, 0, 1, 2, 3]