@@ -43,13 +43,28 @@ std::map<std::string, FieldValue> DecodeObject(pb_istream_t* stream);
43
43
44
44
/* *
45
45
* Docs TODO(rsgowman). But currently, this just wraps the underlying nanopb
46
- * pb_ostream_t. Eventually, this might use static factory methods to create the
47
- * underlying pb_ostream_t rather than directly passing it in.
46
+ * pb_ostream_t.
48
47
*/
49
48
// TODO(rsgowman): Encode* -> Write*
50
49
class Writer {
51
50
public:
52
- explicit Writer (pb_ostream_t * stream) : stream_(stream) {
51
+ /* *
52
+ * Creates an output stream that writes to the specified vector. Note that
53
+ * this vector pointer must remain valid for the lifetime of this Writer.
54
+ *
55
+ * (This is roughly equivalent to the nanopb function
56
+ * pb_ostream_from_buffer())
57
+ *
58
+ * @param out_bytes where the output should be serialized to.
59
+ */
60
+ static Writer Wrap (std::vector<uint8_t >* out_bytes);
61
+
62
+ /* *
63
+ * Creates a non-writing output stream used to calculate the size of
64
+ * the serialized output.
65
+ */
66
+ static Writer SizingStream () {
67
+ return Writer (PB_OSTREAM_SIZING);
53
68
}
54
69
55
70
/* *
@@ -89,10 +104,18 @@ class Writer {
89
104
const std::function<void (Writer*)>& encode_message_fn);
90
105
91
106
size_t bytes_written () const {
92
- return stream_-> bytes_written ;
107
+ return stream_. bytes_written ;
93
108
}
94
109
95
110
private:
111
+ /* *
112
+ * Creates a new Writer, based on the given nanopb pb_ostream_t. Note that
113
+ * a shallow copy will be taken. (Non-null pointers within this struct must
114
+ * remain valid for the lifetime of this Writer.)
115
+ */
116
+ explicit Writer (const pb_ostream_t & stream) : stream_(stream) {
117
+ }
118
+
96
119
/* *
97
120
* Encodes a "varint" to the output stream.
98
121
*
@@ -108,17 +131,44 @@ class Writer {
108
131
*/
109
132
void EncodeVarint (uint64_t value);
110
133
111
- pb_ostream_t * stream_;
134
+ pb_ostream_t stream_;
112
135
};
113
136
137
+ Writer Writer::Wrap (std::vector<uint8_t >* out_bytes) {
138
+ // TODO(rsgowman): find a better home for this constant.
139
+ // A document is defined to have a max size of 1MiB - 4 bytes.
140
+ static const size_t kMaxDocumentSize = 1 * 1024 * 1024 - 4 ;
141
+
142
+ // Construct a nanopb output stream.
143
+ //
144
+ // Set the max_size to be the max document size (as an upper bound; one would
145
+ // expect individual FieldValue's to be smaller than this).
146
+ //
147
+ // bytes_written is (always) initialized to 0. (NB: nanopb does not know or
148
+ // care about the underlying output vector, so where we are in the vector
149
+ // itself is irrelevant. i.e. don't use out_bytes->size())
150
+ pb_ostream_t raw_stream = {
151
+ /* callback=*/ [](pb_ostream_t * stream, const pb_byte_t * buf,
152
+ size_t count) -> bool {
153
+ auto * out_bytes = static_cast <std::vector<uint8_t >*>(stream->state );
154
+ out_bytes->insert (out_bytes->end (), buf, buf + count);
155
+ return true ;
156
+ },
157
+ /* state=*/ out_bytes,
158
+ /* max_size=*/ kMaxDocumentSize ,
159
+ /* bytes_written=*/ 0 ,
160
+ /* errmsg=*/ nullptr };
161
+ return Writer (raw_stream);
162
+ }
163
+
114
164
// TODO(rsgowman): I've left the methods as near as possible to where they were
115
165
// before, which implies that the Writer methods are interspersed with the
116
166
// PbIstream methods (or what will become the PbIstream methods). This should
117
167
// make it a bit easier to review. Refactor these to group the related methods
118
168
// together (probably within their own file rather than here).
119
169
120
170
void Writer::EncodeTag (pb_wire_type_t wiretype, uint32_t field_number) {
121
- bool status = pb_encode_tag (stream_, wiretype, field_number);
171
+ bool status = pb_encode_tag (& stream_, wiretype, field_number);
122
172
if (!status) {
123
173
// TODO(rsgowman): figure out error handling
124
174
abort ();
@@ -130,7 +180,7 @@ void Writer::EncodeSize(size_t size) {
130
180
}
131
181
132
182
void Writer::EncodeVarint (uint64_t value) {
133
- bool status = pb_encode_varint (stream_, value);
183
+ bool status = pb_encode_varint (& stream_, value);
134
184
if (!status) {
135
185
// TODO(rsgowman): figure out error handling
136
186
abort ();
@@ -195,7 +245,7 @@ int64_t DecodeInteger(pb_istream_t* stream) {
195
245
196
246
void Writer::EncodeString (const std::string& string_value) {
197
247
bool status = pb_encode_string (
198
- stream_, reinterpret_cast <const pb_byte_t *>(string_value.c_str ()),
248
+ & stream_, reinterpret_cast <const pb_byte_t *>(string_value.c_str ()),
199
249
string_value.length ());
200
250
if (!status) {
201
251
// TODO(rsgowman): figure out error handling
@@ -332,8 +382,7 @@ FieldValue DecodeFieldValueImpl(pb_istream_t* stream) {
332
382
void Writer::EncodeNestedMessage (
333
383
const std::function<void (Writer*)>& encode_message_fn) {
334
384
// First calculate the message size using a non-writing substream.
335
- pb_ostream_t raw_sizing_substream = PB_OSTREAM_SIZING;
336
- Writer sizing_substream (&raw_sizing_substream);
385
+ Writer sizing_substream = Writer::SizingStream ();
337
386
encode_message_fn (&sizing_substream);
338
387
size_t size = sizing_substream.bytes_written ();
339
388
@@ -344,8 +393,8 @@ void Writer::EncodeNestedMessage(
344
393
// parse field_value a second time; just update the bytes_written via a call
345
394
// to pb_write. (If we try to write the contents into a sizing stream, it'll
346
395
// fail since sizing streams don't actually have any buffer space.)
347
- if (stream_-> callback == nullptr ) {
348
- bool status = pb_write (stream_, nullptr , size);
396
+ if (stream_. callback == nullptr ) {
397
+ bool status = pb_write (& stream_, nullptr , size);
349
398
if (!status) {
350
399
// TODO(rsgowman): figure out error handling
351
400
abort ();
@@ -354,7 +403,7 @@ void Writer::EncodeNestedMessage(
354
403
}
355
404
356
405
// Ensure the output stream has enough space
357
- if (stream_-> bytes_written + size > stream_-> max_size ) {
406
+ if (stream_. bytes_written + size > stream_. max_size ) {
358
407
// TODO(rsgowman): figure out error handling
359
408
abort ();
360
409
}
@@ -363,18 +412,16 @@ void Writer::EncodeNestedMessage(
363
412
// did the first time. (Use an initializer rather than setting fields
364
413
// individually like nanopb does. This gives us a *chance* of noticing if
365
414
// nanopb adds new fields.)
366
- pb_ostream_t raw_writing_substream = {stream_->callback , stream_->state ,
367
- /* max_size=*/ size,
368
- /* bytes_written=*/ 0 ,
369
- /* errmsg=*/ nullptr };
370
- Writer writing_substream (&raw_writing_substream);
415
+ Writer writing_substream ({stream_.callback , stream_.state ,
416
+ /* max_size=*/ size, /* bytes_written=*/ 0 ,
417
+ /* errmsg=*/ nullptr });
371
418
encode_message_fn (&writing_substream);
372
419
373
- stream_-> bytes_written += raw_writing_substream .bytes_written ;
374
- stream_-> state = raw_writing_substream .state ;
375
- stream_-> errmsg = raw_writing_substream .errmsg ;
420
+ stream_. bytes_written += writing_substream. stream_ .bytes_written ;
421
+ stream_. state = writing_substream. stream_ .state ;
422
+ stream_. errmsg = writing_substream. stream_ .errmsg ;
376
423
377
- if (raw_writing_substream .bytes_written != size) {
424
+ if (writing_substream .bytes_written () != size) {
378
425
// submsg size changed
379
426
// TODO(rsgowman): figure out error handling
380
427
abort ();
@@ -520,30 +567,7 @@ std::map<std::string, FieldValue> DecodeObject(pb_istream_t* stream) {
520
567
521
568
void Serializer::EncodeFieldValue (const FieldValue& field_value,
522
569
std::vector<uint8_t >* out_bytes) {
523
- // TODO(rsgowman): find a better home for this constant.
524
- // A document is defined to have a max size of 1MiB - 4 bytes.
525
- static const size_t kMaxDocumentSize = 1 * 1024 * 1024 - 4 ;
526
-
527
- // Construct a nanopb output stream.
528
- //
529
- // Set the max_size to be the max document size (as an upper bound; one would
530
- // expect individual FieldValue's to be smaller than this).
531
- //
532
- // bytes_written is (always) initialized to 0. (NB: nanopb does not know or
533
- // care about the underlying output vector, so where we are in the vector
534
- // itself is irrelevant. i.e. don't use out_bytes->size())
535
- pb_ostream_t raw_stream = {
536
- /* callback=*/ [](pb_ostream_t * stream, const pb_byte_t * buf,
537
- size_t count) -> bool {
538
- auto * out_bytes = static_cast <std::vector<uint8_t >*>(stream->state );
539
- out_bytes->insert (out_bytes->end (), buf, buf + count);
540
- return true ;
541
- },
542
- /* state=*/ out_bytes,
543
- /* max_size=*/ kMaxDocumentSize ,
544
- /* bytes_written=*/ 0 ,
545
- /* errmsg=*/ NULL };
546
- Writer stream (&raw_stream);
570
+ Writer stream = Writer::Wrap (out_bytes);
547
571
EncodeFieldValueImpl (&stream, field_value);
548
572
}
549
573
0 commit comments