
[英]using C++ template programming to extract the field types of an arbitrary structure
[英]using a bytes field as proxy for arbitrary messages
你好纳米开发者,
我想实现以下原型:
message container {
enum MessageType {
TYPE_UNKNOWN = 0;
evt_resultStatus = 1;
}
required MessageType mt = 1;
optional bytes cmd_evt_transfer = 2;
}
message evt_resultStatus {
required int32 operationMode = 1;
}
...
点表示,有更多消息带有(多个)原语,其中包含即将到来的数据类型。 枚举也会增长,只是想保持简短。
容器生成为:
typedef struct _container {
container_MessageType mt;
pb_callback_t cmd_evt_transfer;
} container;
evt_resultStatus 是:
typedef struct _evt_resultStatus {
int32_t operationMode;
} evt_resultStatus;
字段cmd_evt_transfer
应该充当后续消息的代理,例如evt_resultStatus
持有原始数据类型。 evt_resultStatus
应编码成字节并放入cmd_evt_transfer
字段中。 然后对容器进行编码,编码结果将用于后续传输。
这样做的背景,是为了缩短proto定义,避免one of thing。 不幸的是语法版本 3 没有得到完全支持,所以我们不能使用any
字段。
第一个问题是:这种方法可行吗?
到目前为止,我得到的是包括似乎表现良好的回调的编码。 但另一方面,解码会以某种方式跳过回调。 我在这里读过问题,当使用oneof
和bytes
字段时也会发生这种情况。
有人可以澄清如何进行吗?
到目前为止我得到的示例代码:
bool encode_msg_test(pb_byte_t* buffer, int32_t sval, size_t* sz, char* err) {
evt_resultStatus rs = evt_resultStatus_init_zero;
rs.operationMode = sval;
pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
/*encode container*/
container msg = container_init_zero;
msg.mt = container_MessageType_evt_resultStatus;
msg.cmd_evt_transfer.arg = &rs;
msg.cmd_evt_transfer.funcs.encode = encode_cb;
if(! pb_encode(&stream, container_fields, &msg)) {
const char* local_err = PB_GET_ERROR(&stream);
sprintf(err, "pb_encode error: %s", local_err);
return false;
}
*sz = stream.bytes_written;
return true;
}
bool encode_cb(pb_ostream_t *stream, const pb_field_t *field, void * const *arg) {
evt_resultStatus* rs = (evt_resultStatus*)(*arg);
//with the below in place a stream full error rises
// if (! pb_encode_tag_for_field(stream, field)) {
// return false;
// }
if(! pb_encode(stream, evt_resultStatus_fields, rs)) {
return false;
}
return true;
}
//buffer holds previously encoded data
bool decode_msg_test(pb_byte_t* buffer, int32_t* sval, size_t msg_len, char* err) {
container msg = container_init_zero;
evt_resultStatus res = evt_resultStatus_init_zero;
msg.cmd_evt_transfer.arg = &res;
msg.cmd_evt_transfer.funcs.decode = decode_cb;
pb_istream_t stream = pb_istream_from_buffer(buffer, msg_len);
if(! pb_decode(&stream, container_fields, &msg)) {
const char* local_err = PB_GET_ERROR(&stream);
sprintf(err, "pb_encode error: %s", local_err);
return false;
}
*sval = res.operationMode;
return true;
}
bool decode_cb(pb_istream_t *istream, const pb_field_t *field, void **arg) {
evt_resultStatus * rs = (evt_resultStatus*)(*arg);
if(! pb_decode(istream, evt_resultStatus_fields, rs)) {
return false;
}
return true;
}
我觉得,我对编码/解码过程没有正确的理解。
假设是否正确:
pb_encode
的第一次调用(在encode_msg_test
中)处理mt
字段cmd_evt_transfer
的第二次调用(在pb_encode
中)处理encode_cb
字段如果我做:
bool encode_cb(pb_ostream_t *stream, const pb_field_t *field, void * const *arg) {
evt_resultStatus* rs = (evt_resultStatus*)(*arg);
if (! pb_encode_tag_for_field(stream, field)) {
return false;
}
if(! pb_encode(stream, evt_resultStatus_fields, rs)) {
return false;
}
return true;
}
然后我在调用pb_encode
时收到 stream 完整错误。
这是为什么?
是的,这种做法是合理的。 Nanopb 回调不关心回调读取或写入的实际数据是什么。
至于为什么你的解码回调不起作用,你需要发布你用于解码的代码。
(顺便说一句, Any
类型确实在 nanopb 中工作,并且包含在这个测试用例中。但是所有Any
消息中包含的type_url
使它们有相当大的开销。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.