仅包含枚举字段的消息的编码长度为 0

问题描述 投票:0回答:1

我正在尝试序列化数据,该数据由以下 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,这意味着我没有序列化数据,因此没有要发送的数据。

rust protocol-buffers prost
1个回答
0
投票

但是如果我只想发送一条带有单个默认字段的消息怎么办?在这种情况下,消息大小为零,并且不会对消息进行编码。

因此,您发送长度为 0 的响应,接收方将其解码为

Response
,最终得到一个仅包含默认值的
Response
消息实例。

不应该导致任何问题,假设您使用的任何传输都能够说“响应的长度为X”,因此能够处理空响应。

请注意,如果您在其他消息类型中有

Response
字段,“此字段填充有默认消息”和“此字段未填充”之间仍然存在差异 - 您最终会得到标签对于该字段,然后是 0 字节长度前缀的消息。

© www.soinside.com 2019 - 2024. All rights reserved.