我正在研究在我的嵌入式物联网框架中采用 Protobuf,其中可以从 MQTT/HTTP/等网络源接收消息并将其馈送到系统。
我寻求完全处理传入的数据而不复制它,因此预期用途是将起始地址
std::uint8_t*
和大小提供给protobuf。
消息的基本模式是:
message Message {
optional string str = 1;
optinal bytes raw = 2;
}
数组数据(字符串和原始数据)的预期输出分别是
std::string_view
和 std::span
*,它们将指向接收到的数据。
那么为了避免不必要的副本,这是否适用?如果是这样,怎么办?
* 任何一对
std::uint8_t*
和 size_t
指向相关数据都是可接受的。
我不知道如何使用现有的消息结构通过 Google 的 C++ protobuf 库来实现此目的。可以使用较低级别的函数逐个字段进行解析,但是这样您就无法享受从原始文件自动生成的代码的好处。
看起来应该可以使用 nanopb,尽管我还没有具体尝试过。默认情况下,nanopb 将为字符串生成回调或静态数组,但这可以用生成器选项覆盖。
对于您的示例,
myproto.options
文件将包含:
* include:"span"
msg.raw callback_datatype:"std::span<uint8_t>", callback_function="bytes_to_span"
并且您将提供用于转换的命名回调函数:
bool bytes_to_span(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_iter_t *field)
{
if (istream)
{
// Copy pointer to field contents in input stream into a std::span in message structure.
auto result = static_cast<std::span<uint8_t>*>(field->pData);
*result = std::span<uint8_t>(istream->state, istream->bytes_left);
}
return true;
}