我正在尝试序列化由以下 protobuf 文件指定的数据:
syntax = "proto3";
package efficient_servers.protobuf;
message Request {
oneof msg {
Walk walk = 1;
OneToOne oneToOne = 2;
OneToAll oneToAll = 3;
Reset reset = 4;
}
}
message Walk {
repeated Location locations = 1; // repeated n times, determines edge directions
repeated uint32 lengths = 2; // [mm], repeated n-1 times
}
message OneToOne {
Location origin = 1;
Location destination = 2;
}
message OneToAll {
Location origin = 1;
}
message Reset {}
message Location {
int32 x = 1; // [mm]
int32 y = 2; // [mm]
}
message Response {
enum Status {OK = 0; ERROR = 1;};
Status status = 1; // Always present
string errMsg = 2;
uint64 shortest_path_length = 3; // [mm]
uint64 total_length = 4; // [mm]
}
我需要创建一个Response
,只有状态字段填写有OK
变体,encoded_len()
函数返回 0。对我来说,这似乎是编码器忽略了消息的默认值,这是可以理解的,它想要最小化消息大小。但是,如果我只想发送一条带有单个默认字段的消息怎么办?在这种情况下,消息大小为零并且不会对任何消息进行编码。
有没有办法解决这个废话?请注意,我无法编辑 .proto 规范文件。
我尝试过仅使用ERROR
状态枚举的变体,并且返回一个有效的非零值encoded_len()
,但我还需要序列化为OK
变体。
我正在使用以下代码:
pub fn generate_response(data: Result<RequestResponse, String>) -> BytesMut {
let mut response = Response::default();
match data {
Ok(request_response) => {
match request_response.request {
Msg::Reset(_) => {
response.set_status(Status::Ok);
},
Msg::OneToAll(_) => {
response.set_status(Status::Ok);
response.shortest_path_length = request_response.length;
}
Msg::OneToOne(_) => {
response.set_status(Status::Ok);
response.total_length = request_response.length;
}
Msg::Walk(_) => {
response.set_status(Status::Ok);
},
}
}
Err(msg) => {
response.set_status(Status::Error);
response.err_msg = msg.parse().unwrap();
}
}
let encoded_len = response.encoded_len();
let mut buf = BytesMut::with_capacity(encoded_len);
buf.resize(encoded_len, 0);
response.encode(&mut buf).unwrap();
return buf;
}
总而言之,当 ResponseRequest.request 为 Msg::Reset 或 Msg:Walk 时,encoded_len() 函数返回 0,这意味着我没有序列化数据,因此没有要发送的数据。
因此,您发送长度为 0 的响应,接收方将其解码为
Response
,最终得到一个Response
仅包含默认值的消息实例。这不会造成任何问题,假设您使用的任何传输都能够表示“响应的长度为 X”,因此能够处理空响应。
请注意,如果您
Response
在其他消息类型中有一个字段,那么“此字段填充有默认消息”和“此字段未填充”之间仍然存在差异 - 您最终会得到该字段的标记,并且然后是 0 字节长度前缀的消息。