Ahojte kolegovia,
Tentokrat sa na Vas obraciam kvoli serializacii/deserializacii struktur(y) - jednoduchych MSG (TCP/IP) medzi serverom(Rust) a klientom C/freeRTOS(32bit MCU, 128kb RAM).
Spravy su vsehovsudy jednoduche, nieje nutne ich balit do msgpack, protobuf, bson a pod.
Na serializaciu/deserializaciu som pouzil serde/bincode, s tym ze vysledna sprava sa sklada z MessageHeader + MessageBody => Message. Na tomto designe sa mi nepacia dve veci, a to:
MessageHeader::message_type je ulozena hodnota z MessageBodyType::{Version, BatteryHealth} a sucastne Message::body obsahuje {enum MessageBody::Version(Version), enum BatteryHealth(BatteryHealth) }
co ma za nasledok ze Serde serializuje Message(Version) nasledovne
0 1 2 3 4
[message_type | _pad0 | body_size ]
[ crc ]
[ enum ] <---- serde vlozil enum
[x1 | x2 | x3 ]
Takze "struct MessageHeader" ma dlzku 8 bajtov, "struct Version" ma dlzku 4 bajty => idealne by "struct Message" mal mat 12 bajtov.
V skutocnosti ma "struct Message" 16 bajtov, a to z dovodu ze serde prida 4 bajty na rozlisenie enum MessageBody::{Version, BatteryHealth}
Serializovany objekt s prihladnutim na kod vyzsie vyzera nasledovne, kde 11/22 je MessageBodyType::{Version, BatteryHealth}, a 0/1 na 9 pozicii je "enum MessageBody::{Version(), BatteryHealth()}"
serialized_version: (16) vec![11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ...]
serialized_battery: (16) vec![22, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, ...]
Preto sa pytam skusenejsich, akceptovat to, ze serde prida 4bajty na rozlisenie enumu a tuto vec zohladit na strane klienta,
Pripadne, napada Vas moznost ako namodelovat kod nizsie, tak, aby serde/bincode serializovalo/deserializovalo iba mne chcenych 12bajtov (MessageHeader + MessageBody)
AD: Pokusal som sa namodelovat "pub fn deserialize<'a>(bytes: &'a [u8]) -> Box<MessageTrait>", toto sa mi nepodarilo skrz (
https://doc.rust-lang.org/error-index.html#E0038)
Rust:
cargo - serde
cargo - bincode
use serde_repr::*;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, PartialEq, Debug)]
pub enum MessageBody {
Version(Version),
BatteryHealth(BatteryHealth),
}
#[derive(Serialize_repr, Deserialize_repr, PartialEq, Debug)]
#[repr(u8)]
pub enum MessageBodyType {
Version = 11,
BatteryHealth = 22,
}
impl MessageBody {
pub fn value(&self) -> MessageBodyType {
match *self {
MessageBody::Version(_) => MessageBodyType::Version,
MessageBody::BatteryHealth(_) => MessageBodyType::BatteryHealth
}
}
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
#[repr(C)]
pub struct MessageHeader {
message_type: MessageBodyType, // 1
_pad0: u8, // 1
body_size: u16, // 2
crc: u32, // 4
}
impl MessageHeader {
pub fn new_as(message_type: MessageBodyType) -> MessageHeader {
MessageHeader {
message_type: message_type,
_pad0: 0,
body_size: 0,
crc: 0,
}
}
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Message {
header: MessageHeader,
body: MessageBody,
}
impl Message {
pub fn serialize(mt: MessageBody) -> Vec<u8> {
let header = MessageHeader::new_as(mt.value());
let header_size_of = std::mem::size_of::<MessageHeader>();
let header_vec = bincode::serialize(&header).unwrap();
let header_vec_len = header_vec.len();
let body_version_size_of = std::mem::size_of::<Version>();
let body_vec: Vec<u8> = bincode::serialize(&mt).unwrap();
let body_vec_vec_len = body_vec.len();
let message: Message = Message { header: header, body: mt };
let message_size_of = std::mem::size_of::<Message>();
let message_vec = bincode::serialize(&message).unwrap();
let message_len = message_vec.len();
message_vec
}
pub fn deserialize<'a>(bytes: &'a [u8]) -> Message {
let message_header_len = std::mem::size_of::<MessageHeader>();
let header_slice: &[u8] = &bytes[0..message_header_len];
let header: MessageHeader = bincode::deserialize(header_slice).unwrap();
let message: Message = bincode::deserialize(bytes).unwrap();
message
}
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
#[repr(C)]
pub struct Version {
pub x1: u8, // 1
pub x2: u8, // 1
pub x3: u16, // 2
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
#[repr(C)]
pub struct BatteryHealth {
pub x1: u8, // 1
pub x2: u8, // 1
pub x3: u16, // 2
}
fn main () -> Result<(), Box<(dyn std::error::Error + 'static)>> {
let serialized_version: Vec<u8> = Message::serialize(MessageBody::Version(Version{x1: 3, x2: 6, x3: 0xFAFA}));
let serialized_battery: Vec<u8> = Message::serialize(MessageBody::BatteryHealth(BatteryHealth{x1: 10, x2: 20, x3: 0x0A0A}));
let deserialized_version: Message = Message::deserialize(&serialized_version);
Ok(())
}
Diky M.