Documentation for pb_ostream_from_buffer says
After writing, you can check stream.bytes_written to find out how much valid data there is in the buffer. This should be passed as the message length on decoding side.
So ideally, when I send the serialized data I need to also send the bytes_written as a parameter separate from the buffer.
The problem is that my interface only allows me to send one variable: the buffer.
QUESTION
How do I specify always serialize the struct with no optimizations so that bufsize in
pb_istream_from_buffer(const pb_byte_t *buf, size_t bufsize)
can be a constant (i.e. the macro that specifies the maximum size) instead of needing to pass stream.bytes_written?
According to the Protocol Buffers encoding specification there are variable size types (like
int32,int64,string, etc) and fixed size types (likefixed32,fixed64,double, etc). Now, this variable size encoding is more than just an optimization, it's a part of the design and specification. So disabling this "optimization" by the means of Protocol Buffers is only possible if your data consists exclusively of fixed length types and has norepeatedfields as long as the number of repetitions is not fixed. I presume that this is not the case, since you're asking this question. So the short answer is no, it's not possible by means of the library because it would violate the encoding specification.But in my opinion the desired effect could be easily achieved by encoding the size into the buffer with little CPU and RAM overhead. I presume you know the maximum size of the message generated by
nanopb, we denote it byMAX_MSG_SIZE. We call this message the payload message. Suppose that thisMAX_MSG_SIZEcan be represented by some integer type, which we denote bywrapped_size_t(e.g.uint16_t).The idea is simple:
MAX_MSG_SIZE;nanopbat some offset into the allocated buffer;MAX_MSG_SIZE + sizeof(wrapped_size_t)to the receiver;pb_istream_from_buffer.I attach the code to illustrate the idea. I used an example from
nanopbrepository:UPD Ok, if, for some reason, you still wish to stick to the original GPB encoding there's another option available: fill the unused part of the buffer (i.e. the part after the last byte written by
nanopb) with some valid data which will be ignored. For instance, you can reserve a field number which doesn't mark any field in your*.protofile but is used to mark the data which will be discarded by the GPB decoder. Let's denote this reserved field number asRESERVED_FIELD_NUMBER. This is used for backward compatibility but you can use it for your purpose as well. Let's call this filling-in the buffer with the dummy data sealing (perhaps there's a better term). This method also requires that you have at least 2 free bytes available to you afterpb_encode.So the idea of sealing is even simpler:
pb_encode;byteswithRESERVED_FIELD_NUMBER.I attach the updated code, the main function is
bool seal_buffer(uint8_t *buffer, size_t size), call it afterpb_encodeto seal the buffer and you're done. Currently, it has a limitation of sealing no more than2 ** 28 + 4bytes, but it could be easily updated to overcome this limitation.