Created
August 22, 2019 09:57
-
-
Save vpetrigo/df85bbb8197e3be76f644bb8290444c4 to your computer and use it in GitHub Desktop.
Pack repeated fields with Nanopb library
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <pb_decode.h> | |
#include <pb_encode.h> | |
#include <stdbool.h> | |
#include <stddef.h> | |
#include <stdio.h> | |
#include "Test.pb.h" | |
bool str_encode(pb_ostream_t *stream, const pb_field_t *field, | |
void *const *arg) { | |
const char *str = *arg; | |
if (!pb_encode_tag_for_field(stream, field)) { | |
return false; | |
} | |
return pb_encode_string(stream, (unsigned char *)str, strlen(str)); | |
} | |
struct repeated { | |
void **repeated_f; | |
int index; | |
size_t max_size; | |
}; | |
bool req_encode(pb_ostream_t *stream, const pb_field_t *field, | |
void *const *arg) { | |
struct repeated *req = *arg; | |
while (req->index < req->max_size) { | |
SearchRequest *sreq = ((SearchRequest **)req->repeated_f)[req->index]; | |
printf("%s: Try to encode: %s\n", __func__, sreq->query.arg); | |
++req->index; | |
if (!pb_encode_tag(stream, PB_WT_STRING, field->tag)) { | |
return false; | |
} | |
if (!pb_encode_submessage(stream, SearchRequest_fields, sreq)) { | |
return false; | |
} | |
} | |
return true; | |
} | |
int main(void) { | |
const char *str1 = "Hello"; | |
const char *str2 = "World"; | |
unsigned char buffer[128]; | |
size_t message_length; | |
bool status; | |
Result result_msg = Result_init_default; | |
pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof buffer); | |
SearchRequest first = { | |
.query = {.funcs = {.encode = str_encode}, .arg = str1}}; | |
SearchRequest second = { | |
.query = {.funcs = {.encode = str_encode}, .arg = str2}}; | |
SearchRequest *requests[] = {&first, &second}; | |
struct repeated r1 = {.repeated_f = requests, .index = 0, .max_size = 2}; | |
result_msg.requests.funcs.encode = req_encode; | |
result_msg.requests.arg = &r1; | |
status = pb_encode(&stream, Result_fields, &result_msg); | |
message_length = stream.bytes_written; | |
if (!status) { | |
printf("Encoding failed: %s\n", PB_GET_ERROR(&stream)); | |
return -1; | |
} | |
printf("Success: %zu written\n", message_length); | |
for (size_t i = 0; i < message_length; ++i) { | |
printf("%02hhx", buffer[i]); | |
} | |
puts(""); | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
syntax = "proto3"; | |
message SearchRequest { | |
string query = 1; | |
} | |
message Result { | |
repeated SearchRequest requests = 1; | |
} |
@ssevans87 would you tell whether snippet above was helpful?
@vpetrigo Hello. I can tell, the snippet above was very helpful for me.
due to your example I was able to pack and unpack something more complex. Thanks!
Thanks a lot for the snippet!!! it was very helpful for me.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@ssevans87, sorry misunderstood your question at first. Here is the snippet:
•
Repeated.proto
• dummy app:
So, for submessages you have the following steps:
• encode tag with
pb_encode_tag_for_field()
• encode payload with
pb_encode_submessage()
For decoding you just decode the submessage one by one. No need to iterate manually, since Protobuf knows the field type (by tag encoded) and length that was put by submessage encoding call. That should be it.