1*61c4878aSAndroid Build Coastguard Worker.. _module-pw_protobuf: 2*61c4878aSAndroid Build Coastguard Worker 3*61c4878aSAndroid Build Coastguard Worker=========== 4*61c4878aSAndroid Build Coastguard Workerpw_protobuf 5*61c4878aSAndroid Build Coastguard Worker=========== 6*61c4878aSAndroid Build Coastguard Worker.. pigweed-module:: 7*61c4878aSAndroid Build Coastguard Worker :name: pw_protobuf 8*61c4878aSAndroid Build Coastguard Worker 9*61c4878aSAndroid Build Coastguard Worker``pw_protobuf`` provides an expressive interface for encoding and decoding 10*61c4878aSAndroid Build Coastguard Workerthe Protocol Buffer wire format with a lightweight code and data footprint. 11*61c4878aSAndroid Build Coastguard Worker 12*61c4878aSAndroid Build Coastguard Worker.. note:: 13*61c4878aSAndroid Build Coastguard Worker 14*61c4878aSAndroid Build Coastguard Worker The protobuf module is a work in progress. Wire format encoding and decoding 15*61c4878aSAndroid Build Coastguard Worker is supported, though the APIs are not final. C++ code generation exists for 16*61c4878aSAndroid Build Coastguard Worker encoding and decoding, but not yet optimized for in-memory decoding. 17*61c4878aSAndroid Build Coastguard Worker 18*61c4878aSAndroid Build Coastguard Worker-------- 19*61c4878aSAndroid Build Coastguard WorkerOverview 20*61c4878aSAndroid Build Coastguard Worker-------- 21*61c4878aSAndroid Build Coastguard WorkerUnlike protobuf libraries which require protobuf messages be represented by 22*61c4878aSAndroid Build Coastguard Workerin-memory data structures, ``pw_protobuf`` provides a progressive flexible API 23*61c4878aSAndroid Build Coastguard Workerthat allows the user to choose the data storage format and tradeoffs most 24*61c4878aSAndroid Build Coastguard Workersuitable for their product on top of the implementation. 25*61c4878aSAndroid Build Coastguard Worker 26*61c4878aSAndroid Build Coastguard WorkerThe API is designed in three layers, which can be freely intermixed with each 27*61c4878aSAndroid Build Coastguard Workerother in your code, depending on point of use requirements: 28*61c4878aSAndroid Build Coastguard Worker 29*61c4878aSAndroid Build Coastguard Worker1. Message Structures, 30*61c4878aSAndroid Build Coastguard Worker2. Per-Field Writers and Readers, 31*61c4878aSAndroid Build Coastguard Worker3. Direct Writers and Readers. 32*61c4878aSAndroid Build Coastguard Worker 33*61c4878aSAndroid Build Coastguard WorkerThis has a few benefits. The primary one is that it allows the core proto 34*61c4878aSAndroid Build Coastguard Workerserialization and deserialization libraries to be relatively small. 35*61c4878aSAndroid Build Coastguard Worker 36*61c4878aSAndroid Build Coastguard Worker.. include:: size_report/protobuf_overview 37*61c4878aSAndroid Build Coastguard Worker 38*61c4878aSAndroid Build Coastguard WorkerTo demonstrate these layers, we use the following protobuf message definition 39*61c4878aSAndroid Build Coastguard Workerin the examples: 40*61c4878aSAndroid Build Coastguard Worker 41*61c4878aSAndroid Build Coastguard Worker.. code-block:: protobuf 42*61c4878aSAndroid Build Coastguard Worker 43*61c4878aSAndroid Build Coastguard Worker message Customer { 44*61c4878aSAndroid Build Coastguard Worker enum Status { 45*61c4878aSAndroid Build Coastguard Worker NEW = 1; 46*61c4878aSAndroid Build Coastguard Worker ACTIVE = 2; 47*61c4878aSAndroid Build Coastguard Worker INACTIVE = 3; 48*61c4878aSAndroid Build Coastguard Worker } 49*61c4878aSAndroid Build Coastguard Worker int32 age = 1; 50*61c4878aSAndroid Build Coastguard Worker string name = 2; 51*61c4878aSAndroid Build Coastguard Worker Status status = 3; 52*61c4878aSAndroid Build Coastguard Worker } 53*61c4878aSAndroid Build Coastguard Worker 54*61c4878aSAndroid Build Coastguard WorkerAnd the following accompanying options file: 55*61c4878aSAndroid Build Coastguard Worker 56*61c4878aSAndroid Build Coastguard Worker.. code-block:: text 57*61c4878aSAndroid Build Coastguard Worker 58*61c4878aSAndroid Build Coastguard Worker Customer.name max_size:32 59*61c4878aSAndroid Build Coastguard Worker 60*61c4878aSAndroid Build Coastguard Worker.. toctree:: 61*61c4878aSAndroid Build Coastguard Worker :maxdepth: 1 62*61c4878aSAndroid Build Coastguard Worker 63*61c4878aSAndroid Build Coastguard Worker size_report 64*61c4878aSAndroid Build Coastguard Worker 65*61c4878aSAndroid Build Coastguard WorkerMessage Structures 66*61c4878aSAndroid Build Coastguard Worker================== 67*61c4878aSAndroid Build Coastguard WorkerThe highest level API is based around message structures created through C++ 68*61c4878aSAndroid Build Coastguard Workercode generation, integrated with Pigweed's build system. 69*61c4878aSAndroid Build Coastguard Worker 70*61c4878aSAndroid Build Coastguard Worker.. warning:: 71*61c4878aSAndroid Build Coastguard Worker 72*61c4878aSAndroid Build Coastguard Worker Message structures only support a subset of protobuf field types. Before 73*61c4878aSAndroid Build Coastguard Worker continuing, refer to :ref:`pw_protobuf-message-limitations` to understand 74*61c4878aSAndroid Build Coastguard Worker what types of protobuf messages can and cannot be represented, and whether 75*61c4878aSAndroid Build Coastguard Worker or not message structures are a suitable choice. 76*61c4878aSAndroid Build Coastguard Worker 77*61c4878aSAndroid Build Coastguard WorkerThis results in the following generated structure: 78*61c4878aSAndroid Build Coastguard Worker 79*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 80*61c4878aSAndroid Build Coastguard Worker 81*61c4878aSAndroid Build Coastguard Worker enum class Customer::Status : uint32_t { 82*61c4878aSAndroid Build Coastguard Worker NEW = 1, 83*61c4878aSAndroid Build Coastguard Worker ACTIVE = 2, 84*61c4878aSAndroid Build Coastguard Worker INACTIVE = 3, 85*61c4878aSAndroid Build Coastguard Worker 86*61c4878aSAndroid Build Coastguard Worker kNew = NEW, 87*61c4878aSAndroid Build Coastguard Worker kActive = ACTIVE, 88*61c4878aSAndroid Build Coastguard Worker kInactive = INACTIVE, 89*61c4878aSAndroid Build Coastguard Worker }; 90*61c4878aSAndroid Build Coastguard Worker 91*61c4878aSAndroid Build Coastguard Worker struct Customer::Message { 92*61c4878aSAndroid Build Coastguard Worker int32_t age; 93*61c4878aSAndroid Build Coastguard Worker pw::InlineString<32> name; 94*61c4878aSAndroid Build Coastguard Worker Customer::Status status; 95*61c4878aSAndroid Build Coastguard Worker }; 96*61c4878aSAndroid Build Coastguard Worker 97*61c4878aSAndroid Build Coastguard WorkerWhich can be encoded with the code: 98*61c4878aSAndroid Build Coastguard Worker 99*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 100*61c4878aSAndroid Build Coastguard Worker 101*61c4878aSAndroid Build Coastguard Worker #include "example_protos/customer.pwpb.h" 102*61c4878aSAndroid Build Coastguard Worker 103*61c4878aSAndroid Build Coastguard Worker pw::Status EncodeCustomer(Customer::StreamEncoder& encoder) { 104*61c4878aSAndroid Build Coastguard Worker return encoder.Write({ 105*61c4878aSAndroid Build Coastguard Worker age = 33, 106*61c4878aSAndroid Build Coastguard Worker name = "Joe Bloggs", 107*61c4878aSAndroid Build Coastguard Worker status = Customer::Status::INACTIVE 108*61c4878aSAndroid Build Coastguard Worker }); 109*61c4878aSAndroid Build Coastguard Worker } 110*61c4878aSAndroid Build Coastguard Worker 111*61c4878aSAndroid Build Coastguard WorkerAnd decoded into a struct with the code: 112*61c4878aSAndroid Build Coastguard Worker 113*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 114*61c4878aSAndroid Build Coastguard Worker 115*61c4878aSAndroid Build Coastguard Worker #include "example_protos/customer.pwpb.h" 116*61c4878aSAndroid Build Coastguard Worker 117*61c4878aSAndroid Build Coastguard Worker pw::Status DecodeCustomer(Customer::StreamDecoder& decoder) { 118*61c4878aSAndroid Build Coastguard Worker Customer::Message customer{}; 119*61c4878aSAndroid Build Coastguard Worker PW_TRY(decoder.Read(customer)); 120*61c4878aSAndroid Build Coastguard Worker // Read fields from customer 121*61c4878aSAndroid Build Coastguard Worker return pw::OkStatus(); 122*61c4878aSAndroid Build Coastguard Worker } 123*61c4878aSAndroid Build Coastguard Worker 124*61c4878aSAndroid Build Coastguard WorkerThese structures can be moved, copied, and compared with each other for 125*61c4878aSAndroid Build Coastguard Workerequality. 126*61c4878aSAndroid Build Coastguard Worker 127*61c4878aSAndroid Build Coastguard WorkerThe encoder and decoder code is generic and implemented in the core C++ module. 128*61c4878aSAndroid Build Coastguard WorkerA small overhead for each message type used in your code describes the structure 129*61c4878aSAndroid Build Coastguard Workerto the generic encoder and decoders. 130*61c4878aSAndroid Build Coastguard Worker 131*61c4878aSAndroid Build Coastguard WorkerMessage comparison 132*61c4878aSAndroid Build Coastguard Worker------------------ 133*61c4878aSAndroid Build Coastguard WorkerMessage structures implement ``operator==`` and ``operator!=`` for equality and 134*61c4878aSAndroid Build Coastguard Workerinequality comparisons. However, these can only work on trivial scalar fields 135*61c4878aSAndroid Build Coastguard Workerand fixed-size strings within the message. Fields using a callback are not 136*61c4878aSAndroid Build Coastguard Workerconsidered in the comparison. 137*61c4878aSAndroid Build Coastguard Worker 138*61c4878aSAndroid Build Coastguard WorkerTo check if the equality operator of a generated message covers all fields, 139*61c4878aSAndroid Build Coastguard Worker``pw_protobuf`` provides an ``IsTriviallyComparable`` function. 140*61c4878aSAndroid Build Coastguard Worker 141*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 142*61c4878aSAndroid Build Coastguard Worker 143*61c4878aSAndroid Build Coastguard Worker template <typename Message> 144*61c4878aSAndroid Build Coastguard Worker constexpr bool IsTriviallyComparable<Message>(); 145*61c4878aSAndroid Build Coastguard Worker 146*61c4878aSAndroid Build Coastguard WorkerFor example, given the following protobuf definitions: 147*61c4878aSAndroid Build Coastguard Worker 148*61c4878aSAndroid Build Coastguard Worker.. code-block:: protobuf 149*61c4878aSAndroid Build Coastguard Worker 150*61c4878aSAndroid Build Coastguard Worker message Point { 151*61c4878aSAndroid Build Coastguard Worker int32 x = 1; 152*61c4878aSAndroid Build Coastguard Worker int32 y = 2; 153*61c4878aSAndroid Build Coastguard Worker } 154*61c4878aSAndroid Build Coastguard Worker 155*61c4878aSAndroid Build Coastguard Worker message Label { 156*61c4878aSAndroid Build Coastguard Worker Point point = 1; 157*61c4878aSAndroid Build Coastguard Worker string label = 2; 158*61c4878aSAndroid Build Coastguard Worker } 159*61c4878aSAndroid Build Coastguard Worker 160*61c4878aSAndroid Build Coastguard WorkerAnd the accompanying options file: 161*61c4878aSAndroid Build Coastguard Worker 162*61c4878aSAndroid Build Coastguard Worker.. code-block:: text 163*61c4878aSAndroid Build Coastguard Worker 164*61c4878aSAndroid Build Coastguard Worker Label.label use_callback:true 165*61c4878aSAndroid Build Coastguard Worker 166*61c4878aSAndroid Build Coastguard WorkerThe ``Point`` message can be fully compared for equality, but ``Label`` cannot. 167*61c4878aSAndroid Build Coastguard Worker``Label`` still defines an ``operator==``, but it ignores the ``label`` string. 168*61c4878aSAndroid Build Coastguard Worker 169*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 170*61c4878aSAndroid Build Coastguard Worker 171*61c4878aSAndroid Build Coastguard Worker Point::Message one = {.x = 5, .y = 11}; 172*61c4878aSAndroid Build Coastguard Worker Point::Message two = {.x = 5, .y = 11}; 173*61c4878aSAndroid Build Coastguard Worker 174*61c4878aSAndroid Build Coastguard Worker static_assert(pw::protobuf::IsTriviallyComparable<Point::Message>()); 175*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(one, two); 176*61c4878aSAndroid Build Coastguard Worker static_assert(!pw::protobuf::IsTriviallyComparable<Label::Message>()); 177*61c4878aSAndroid Build Coastguard Worker 178*61c4878aSAndroid Build Coastguard WorkerBuffer Sizes 179*61c4878aSAndroid Build Coastguard Worker------------ 180*61c4878aSAndroid Build Coastguard WorkerInitializing a ``MemoryEncoder`` requires that you specify the size of the 181*61c4878aSAndroid Build Coastguard Workerbuffer to encode to. The code generation includes a ``kMaxEncodedSizeBytes`` 182*61c4878aSAndroid Build Coastguard Workerconstant that represents the maximum encoded size of the protobuf message, 183*61c4878aSAndroid Build Coastguard Workerexcluding the contents of any field values which require a callback. 184*61c4878aSAndroid Build Coastguard Worker 185*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 186*61c4878aSAndroid Build Coastguard Worker 187*61c4878aSAndroid Build Coastguard Worker #include "example_protos/customer.pwpb.h" 188*61c4878aSAndroid Build Coastguard Worker 189*61c4878aSAndroid Build Coastguard Worker std::byte buffer[Customer::kMaxEncodedSizeBytes]; 190*61c4878aSAndroid Build Coastguard Worker Customer::MemoryEncoder encoder(buffer); 191*61c4878aSAndroid Build Coastguard Worker const auto status = encoder.Write({ 192*61c4878aSAndroid Build Coastguard Worker age = 22, 193*61c4878aSAndroid Build Coastguard Worker name = "Wolfgang Bjornson", 194*61c4878aSAndroid Build Coastguard Worker status = Customer::Status::ACTIVE 195*61c4878aSAndroid Build Coastguard Worker }); 196*61c4878aSAndroid Build Coastguard Worker 197*61c4878aSAndroid Build Coastguard Worker // Always check the encoder status or return values from Write calls. 198*61c4878aSAndroid Build Coastguard Worker if (!status.ok()) { 199*61c4878aSAndroid Build Coastguard Worker PW_LOG_INFO("Failed to encode proto; %s", encoder.status().str()); 200*61c4878aSAndroid Build Coastguard Worker } 201*61c4878aSAndroid Build Coastguard Worker 202*61c4878aSAndroid Build Coastguard WorkerIn the above example, because the ``name`` field has a ``max_size`` specified 203*61c4878aSAndroid Build Coastguard Workerin the accompanying options file, ``kMaxEncodedSizeBytes`` includes the maximum 204*61c4878aSAndroid Build Coastguard Workerlength of the value for that field. 205*61c4878aSAndroid Build Coastguard Worker 206*61c4878aSAndroid Build Coastguard WorkerWhere the maximum length of a field value is not known, indicated by the 207*61c4878aSAndroid Build Coastguard Workerstructure requiring a callback for that field, the constant includes 208*61c4878aSAndroid Build Coastguard Workerall relevant overhead and only requires that you add the length of the field 209*61c4878aSAndroid Build Coastguard Workervalues. 210*61c4878aSAndroid Build Coastguard Worker 211*61c4878aSAndroid Build Coastguard WorkerFor example if a ``bytes`` field length is not specified in the options file, 212*61c4878aSAndroid Build Coastguard Workerbut is known to your code (``kMaxImageDataSize`` in this example being a 213*61c4878aSAndroid Build Coastguard Workerconstant in your own code), you can simply add it to the generated constant: 214*61c4878aSAndroid Build Coastguard Worker 215*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 216*61c4878aSAndroid Build Coastguard Worker 217*61c4878aSAndroid Build Coastguard Worker #include "example_protos/store.pwpb.h" 218*61c4878aSAndroid Build Coastguard Worker 219*61c4878aSAndroid Build Coastguard Worker const std::byte image_data[kMaxImageDataSize] = { ... }; 220*61c4878aSAndroid Build Coastguard Worker 221*61c4878aSAndroid Build Coastguard Worker Store::Message store{}; 222*61c4878aSAndroid Build Coastguard Worker // Calling SetEncoder means we must always extend the buffer size. 223*61c4878aSAndroid Build Coastguard Worker store.image_data.SetEncoder([](Store::StreamEncoder& encoder) { 224*61c4878aSAndroid Build Coastguard Worker return encoder.WriteImageData(image_data); 225*61c4878aSAndroid Build Coastguard Worker }); 226*61c4878aSAndroid Build Coastguard Worker 227*61c4878aSAndroid Build Coastguard Worker std::byte buffer[Store::kMaxEncodedSizeBytes + kMaxImageDataSize]; 228*61c4878aSAndroid Build Coastguard Worker Store::MemoryEncoder encoder(buffer); 229*61c4878aSAndroid Build Coastguard Worker const auto status = encoder.Write(store); 230*61c4878aSAndroid Build Coastguard Worker 231*61c4878aSAndroid Build Coastguard Worker // Always check the encoder status or return values from Write calls. 232*61c4878aSAndroid Build Coastguard Worker if (!status.ok()) { 233*61c4878aSAndroid Build Coastguard Worker PW_LOG_INFO("Failed to encode proto; %s", encoder.status().str()); 234*61c4878aSAndroid Build Coastguard Worker } 235*61c4878aSAndroid Build Coastguard Worker 236*61c4878aSAndroid Build Coastguard WorkerOr when using a variable number of repeated submessages, where the maximum 237*61c4878aSAndroid Build Coastguard Workernumber is known to your code but not to the proto, you can add the constants 238*61c4878aSAndroid Build Coastguard Workerfrom one message type to another: 239*61c4878aSAndroid Build Coastguard Worker 240*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 241*61c4878aSAndroid Build Coastguard Worker 242*61c4878aSAndroid Build Coastguard Worker #include "example_protos/person.pwpb.h" 243*61c4878aSAndroid Build Coastguard Worker 244*61c4878aSAndroid Build Coastguard Worker Person::Message grandchild{}; 245*61c4878aSAndroid Build Coastguard Worker // Calling SetEncoder means we must always extend the buffer size. 246*61c4878aSAndroid Build Coastguard Worker grandchild.grandparent.SetEncoder([](Person::StreamEncoder& encoder) { 247*61c4878aSAndroid Build Coastguard Worker PW_TRY(encoder.GetGrandparentEncoder().Write(maternal_grandma)); 248*61c4878aSAndroid Build Coastguard Worker PW_TRY(encoder.GetGrandparentEncoder().Write(maternal_grandpa)); 249*61c4878aSAndroid Build Coastguard Worker PW_TRY(encoder.GetGrandparentEncoder().Write(paternal_grandma)); 250*61c4878aSAndroid Build Coastguard Worker PW_TRY(encoder.GetGrandparentEncoder().Write(paternal_grandpa)); 251*61c4878aSAndroid Build Coastguard Worker return pw::OkStatus(); 252*61c4878aSAndroid Build Coastguard Worker }); 253*61c4878aSAndroid Build Coastguard Worker 254*61c4878aSAndroid Build Coastguard Worker std::byte buffer[Person::kMaxEncodedSizeBytes + 255*61c4878aSAndroid Build Coastguard Worker Grandparent::kMaxEncodedSizeBytes * 4]; 256*61c4878aSAndroid Build Coastguard Worker Person::MemoryEncoder encoder(buffer); 257*61c4878aSAndroid Build Coastguard Worker const auto status = encoder.Write(grandchild); 258*61c4878aSAndroid Build Coastguard Worker 259*61c4878aSAndroid Build Coastguard Worker // Always check the encoder status or return values from Write calls. 260*61c4878aSAndroid Build Coastguard Worker if (!status.ok()) { 261*61c4878aSAndroid Build Coastguard Worker PW_LOG_INFO("Failed to encode proto; %s", encoder.status().str()); 262*61c4878aSAndroid Build Coastguard Worker } 263*61c4878aSAndroid Build Coastguard Worker 264*61c4878aSAndroid Build Coastguard Worker.. warning:: 265*61c4878aSAndroid Build Coastguard Worker Encoding to a buffer that is insufficiently large will return 266*61c4878aSAndroid Build Coastguard Worker ``Status::ResourceExhausted()`` from ``Write`` calls, and from the 267*61c4878aSAndroid Build Coastguard Worker encoder's ``status()`` call. Always check the status of calls or the encoder, 268*61c4878aSAndroid Build Coastguard Worker as in the case of error, the encoded data will be invalid. 269*61c4878aSAndroid Build Coastguard Worker 270*61c4878aSAndroid Build Coastguard Worker.. _pw_protobuf-message-limitations: 271*61c4878aSAndroid Build Coastguard Worker 272*61c4878aSAndroid Build Coastguard WorkerLimitations 273*61c4878aSAndroid Build Coastguard Worker----------- 274*61c4878aSAndroid Build Coastguard Worker``pw_protobuf``'s message structure API is incomplete. Generally speaking, it is 275*61c4878aSAndroid Build Coastguard Workerreasonable to use for basic messages containing simple inline fields (scalar 276*61c4878aSAndroid Build Coastguard Workertypes, bytes, and strings) and nested messages of similar form. Beyond this, 277*61c4878aSAndroid Build Coastguard Workercertain other types of protobuf specifiers can be used, but may be limited in 278*61c4878aSAndroid Build Coastguard Workerhow and when they are supported. These cases are described below. 279*61c4878aSAndroid Build Coastguard Worker 280*61c4878aSAndroid Build Coastguard WorkerIf an object representation of protobuf messages is desired, the Pigweed team 281*61c4878aSAndroid Build Coastguard Workerrecommends using `Nanopb`_, which is fully supported within Pigweed's build and 282*61c4878aSAndroid Build Coastguard WorkerRPC systems. 283*61c4878aSAndroid Build Coastguard Worker 284*61c4878aSAndroid Build Coastguard WorkerMessage structures are eventually intended to be replaced with an alternative 285*61c4878aSAndroid Build Coastguard Workerobject model. See `SEED-0103 <http://pwrev.dev/133971>`_ for additional 286*61c4878aSAndroid Build Coastguard Workerinformation about how message structures came to be and our future plans. 287*61c4878aSAndroid Build Coastguard Worker 288*61c4878aSAndroid Build Coastguard WorkerProtobuf versioning 289*61c4878aSAndroid Build Coastguard Worker^^^^^^^^^^^^^^^^^^^ 290*61c4878aSAndroid Build Coastguard WorkerMessage structures are generated in accordance to ``proto3`` semantics only. 291*61c4878aSAndroid Build Coastguard WorkerUnset fields default to their zero values. Explicit field presence is supported 292*61c4878aSAndroid Build Coastguard Workerthrough the use of the ``optional`` specifier. Proto2-only keywords such as 293*61c4878aSAndroid Build Coastguard Worker``required`` have no effect. 294*61c4878aSAndroid Build Coastguard Worker 295*61c4878aSAndroid Build Coastguard WorkerThere is limited preliminary support for Protobuf editions, primarily to allow 296*61c4878aSAndroid Build Coastguard Workereditions-based proto files to compile. At this time, the only editions feature 297*61c4878aSAndroid Build Coastguard Workersupported by the code generator is ``field_presence``. 298*61c4878aSAndroid Build Coastguard Worker 299*61c4878aSAndroid Build Coastguard Worker``oneof`` fields 300*61c4878aSAndroid Build Coastguard Worker^^^^^^^^^^^^^^^^ 301*61c4878aSAndroid Build Coastguard Worker``oneof`` protobuf fields cannot be inlined within a message structure: they 302*61c4878aSAndroid Build Coastguard Workermust be encoded and decoded using callbacks. 303*61c4878aSAndroid Build Coastguard Worker 304*61c4878aSAndroid Build Coastguard Worker``optional`` fields 305*61c4878aSAndroid Build Coastguard Worker^^^^^^^^^^^^^^^^^^^ 306*61c4878aSAndroid Build Coastguard WorkerOnly scalar fields generate a ``std::optional`` wrapper in the resulting message 307*61c4878aSAndroid Build Coastguard Workerstructure. Optional submessages or variable-length fields 308*61c4878aSAndroid Build Coastguard Worker(``string`` / ``bytes``) must be processed through callbacks, requiring manual 309*61c4878aSAndroid Build Coastguard Workertracking of presence depending on whether or not the callback is invoked. 310*61c4878aSAndroid Build Coastguard Worker 311*61c4878aSAndroid Build Coastguard Worker.. _pw_protobuf-per-field-apis: 312*61c4878aSAndroid Build Coastguard Worker 313*61c4878aSAndroid Build Coastguard WorkerPer-Field Writers and Readers 314*61c4878aSAndroid Build Coastguard Worker============================= 315*61c4878aSAndroid Build Coastguard WorkerThe middle level API is based around typed methods to write and read each 316*61c4878aSAndroid Build Coastguard Workerfield of the message directly to the final serialized form, again created 317*61c4878aSAndroid Build Coastguard Workerthrough C++ code generation. 318*61c4878aSAndroid Build Coastguard Worker 319*61c4878aSAndroid Build Coastguard WorkerEncoding 320*61c4878aSAndroid Build Coastguard Worker-------- 321*61c4878aSAndroid Build Coastguard WorkerGiven the same message structure, in addition to the ``Write()`` method that 322*61c4878aSAndroid Build Coastguard Workeraccepts a message structure, the following additional methods are also 323*61c4878aSAndroid Build Coastguard Workergenerated in the typed ``StreamEncoder`` class. 324*61c4878aSAndroid Build Coastguard Worker 325*61c4878aSAndroid Build Coastguard WorkerThere are lightweight wrappers around the core implementation, calling the 326*61c4878aSAndroid Build Coastguard Workerunderlying methods with the correct field numbers and value types, and result 327*61c4878aSAndroid Build Coastguard Workerin no additional binary code over correctly using the core implementation. 328*61c4878aSAndroid Build Coastguard Worker 329*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 330*61c4878aSAndroid Build Coastguard Worker 331*61c4878aSAndroid Build Coastguard Worker class Customer::StreamEncoder : pw::protobuf::StreamEncoder { 332*61c4878aSAndroid Build Coastguard Worker public: 333*61c4878aSAndroid Build Coastguard Worker // Message Structure Writer. 334*61c4878aSAndroid Build Coastguard Worker pw::Status Write(const Customer::Message&); 335*61c4878aSAndroid Build Coastguard Worker 336*61c4878aSAndroid Build Coastguard Worker // Per-Field Typed Writers. 337*61c4878aSAndroid Build Coastguard Worker pw::Status WriteAge(int32_t); 338*61c4878aSAndroid Build Coastguard Worker 339*61c4878aSAndroid Build Coastguard Worker pw::Status WriteName(std::string_view); 340*61c4878aSAndroid Build Coastguard Worker pw::Status WriteName(const char*, size_t); 341*61c4878aSAndroid Build Coastguard Worker 342*61c4878aSAndroid Build Coastguard Worker pw::Status WriteStatus(Customer::Status); 343*61c4878aSAndroid Build Coastguard Worker }; 344*61c4878aSAndroid Build Coastguard Worker 345*61c4878aSAndroid Build Coastguard WorkerSo the same encoding method could be written as: 346*61c4878aSAndroid Build Coastguard Worker 347*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 348*61c4878aSAndroid Build Coastguard Worker 349*61c4878aSAndroid Build Coastguard Worker #include "example_protos/customer.pwpb.h" 350*61c4878aSAndroid Build Coastguard Worker 351*61c4878aSAndroid Build Coastguard Worker Status EncodeCustomer(Customer::StreamEncoder& encoder) { 352*61c4878aSAndroid Build Coastguard Worker PW_TRY(encoder.WriteAge(33)); 353*61c4878aSAndroid Build Coastguard Worker PW_TRY(encoder.WriteName("Joe Bloggs"sv)); 354*61c4878aSAndroid Build Coastguard Worker PW_TRY(encoder.WriteStatus(Customer::Status::INACTIVE)); 355*61c4878aSAndroid Build Coastguard Worker } 356*61c4878aSAndroid Build Coastguard Worker 357*61c4878aSAndroid Build Coastguard WorkerPigweed's protobuf encoders encode directly to the wire format of a proto rather 358*61c4878aSAndroid Build Coastguard Workerthan staging information to a mutable datastructure. This means any writes of a 359*61c4878aSAndroid Build Coastguard Workervalue are final, and can't be referenced or modified as a later step in the 360*61c4878aSAndroid Build Coastguard Workerencode process. 361*61c4878aSAndroid Build Coastguard Worker 362*61c4878aSAndroid Build Coastguard WorkerCasting between generated StreamEncoder types 363*61c4878aSAndroid Build Coastguard Worker^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 364*61c4878aSAndroid Build Coastguard Workerpw_protobuf guarantees that all generated ``StreamEncoder`` classes can be 365*61c4878aSAndroid Build Coastguard Workerconverted among each other. It's also safe to convert any ``MemoryEncoder`` to 366*61c4878aSAndroid Build Coastguard Workerany other ``StreamEncoder``. 367*61c4878aSAndroid Build Coastguard Worker 368*61c4878aSAndroid Build Coastguard WorkerThis guarantee exists to facilitate usage of protobuf overlays. Protobuf 369*61c4878aSAndroid Build Coastguard Workeroverlays are protobuf message definitions that deliberately ensure that 370*61c4878aSAndroid Build Coastguard Workerfields defined in one message will not conflict with fields defined in other 371*61c4878aSAndroid Build Coastguard Workermessages. 372*61c4878aSAndroid Build Coastguard Worker 373*61c4878aSAndroid Build Coastguard WorkerFor example: 374*61c4878aSAndroid Build Coastguard Worker 375*61c4878aSAndroid Build Coastguard Worker.. code-block:: protobuf 376*61c4878aSAndroid Build Coastguard Worker 377*61c4878aSAndroid Build Coastguard Worker // The first half of the overlaid message. 378*61c4878aSAndroid Build Coastguard Worker message BaseMessage { 379*61c4878aSAndroid Build Coastguard Worker uint32 length = 1; 380*61c4878aSAndroid Build Coastguard Worker reserved 2; // Reserved for Overlay 381*61c4878aSAndroid Build Coastguard Worker } 382*61c4878aSAndroid Build Coastguard Worker 383*61c4878aSAndroid Build Coastguard Worker // OK: The second half of the overlaid message. 384*61c4878aSAndroid Build Coastguard Worker message Overlay { 385*61c4878aSAndroid Build Coastguard Worker reserved 1; // Reserved for BaseMessage 386*61c4878aSAndroid Build Coastguard Worker uint32 height = 2; 387*61c4878aSAndroid Build Coastguard Worker } 388*61c4878aSAndroid Build Coastguard Worker 389*61c4878aSAndroid Build Coastguard Worker // OK: A message that overlays and bundles both types together. 390*61c4878aSAndroid Build Coastguard Worker message Both { 391*61c4878aSAndroid Build Coastguard Worker uint32 length = 1; // Defined independently by BaseMessage 392*61c4878aSAndroid Build Coastguard Worker uint32 height = 2; // Defined independently by Overlay 393*61c4878aSAndroid Build Coastguard Worker } 394*61c4878aSAndroid Build Coastguard Worker 395*61c4878aSAndroid Build Coastguard Worker // BAD: Diverges from BaseMessage's definition, and can cause decode 396*61c4878aSAndroid Build Coastguard Worker // errors/corruption. 397*61c4878aSAndroid Build Coastguard Worker message InvalidOverlay { 398*61c4878aSAndroid Build Coastguard Worker fixed32 length = 1; 399*61c4878aSAndroid Build Coastguard Worker } 400*61c4878aSAndroid Build Coastguard Worker 401*61c4878aSAndroid Build Coastguard WorkerThe ``StreamEncoderCast<>()`` helper template reduces very messy casting into 402*61c4878aSAndroid Build Coastguard Workera much easier to read syntax: 403*61c4878aSAndroid Build Coastguard Worker 404*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 405*61c4878aSAndroid Build Coastguard Worker 406*61c4878aSAndroid Build Coastguard Worker #include "pw_protobuf/encoder.h" 407*61c4878aSAndroid Build Coastguard Worker #include "pw_protobuf_test_protos/full_test.pwpb.h" 408*61c4878aSAndroid Build Coastguard Worker 409*61c4878aSAndroid Build Coastguard Worker Result<ConstByteSpan> EncodeOverlaid(uint32_t height, 410*61c4878aSAndroid Build Coastguard Worker uint32_t length, 411*61c4878aSAndroid Build Coastguard Worker ConstByteSpan encode_buffer) { 412*61c4878aSAndroid Build Coastguard Worker BaseMessage::MemoryEncoder base(encode_buffer); 413*61c4878aSAndroid Build Coastguard Worker 414*61c4878aSAndroid Build Coastguard Worker // Without StreamEncoderCast<>(), this line would be: 415*61c4878aSAndroid Build Coastguard Worker // Overlay::StreamEncoder& overlay = 416*61c4878aSAndroid Build Coastguard Worker // *static_cast<Overlay::StreamEncoder*>( 417*61c4878aSAndroid Build Coastguard Worker // static_cast<pw::protobuf::StreamEncoder*>(&base) 418*61c4878aSAndroid Build Coastguard Worker Overlay::StreamEncoder& overlay = 419*61c4878aSAndroid Build Coastguard Worker StreamEncoderCast<Overlay::StreamEncoder>(base); 420*61c4878aSAndroid Build Coastguard Worker if (!overlay.WriteHeight(height).ok()) { 421*61c4878aSAndroid Build Coastguard Worker return overlay.status(); 422*61c4878aSAndroid Build Coastguard Worker } 423*61c4878aSAndroid Build Coastguard Worker if (!base.WriteLength(length).ok()) { 424*61c4878aSAndroid Build Coastguard Worker return base.status(); 425*61c4878aSAndroid Build Coastguard Worker } 426*61c4878aSAndroid Build Coastguard Worker return ConstByteSpan(base); 427*61c4878aSAndroid Build Coastguard Worker } 428*61c4878aSAndroid Build Coastguard Worker 429*61c4878aSAndroid Build Coastguard WorkerWhile this use case is somewhat uncommon, it's a core supported use case of 430*61c4878aSAndroid Build Coastguard Workerpw_protobuf. 431*61c4878aSAndroid Build Coastguard Worker 432*61c4878aSAndroid Build Coastguard Worker.. warning:: 433*61c4878aSAndroid Build Coastguard Worker 434*61c4878aSAndroid Build Coastguard Worker Using this to convert one stream encoder to another when the messages 435*61c4878aSAndroid Build Coastguard Worker themselves do not safely overlay will result in corrupt protos. Be careful 436*61c4878aSAndroid Build Coastguard Worker when doing this as there's no compile-time way to detect whether or not two 437*61c4878aSAndroid Build Coastguard Worker messages are meant to overlay. 438*61c4878aSAndroid Build Coastguard Worker 439*61c4878aSAndroid Build Coastguard WorkerDecoding 440*61c4878aSAndroid Build Coastguard Worker-------- 441*61c4878aSAndroid Build Coastguard WorkerFor decoding, in addition to the ``Read()`` method that populates a message 442*61c4878aSAndroid Build Coastguard Workerstructure, the following additional methods are also generated in the typed 443*61c4878aSAndroid Build Coastguard Worker``StreamDecoder`` class. 444*61c4878aSAndroid Build Coastguard Worker 445*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 446*61c4878aSAndroid Build Coastguard Worker 447*61c4878aSAndroid Build Coastguard Worker class Customer::StreamDecoder : pw::protobuf::StreamDecoder { 448*61c4878aSAndroid Build Coastguard Worker public: 449*61c4878aSAndroid Build Coastguard Worker // Message Structure Reader. 450*61c4878aSAndroid Build Coastguard Worker pw::Status Read(Customer::Message&); 451*61c4878aSAndroid Build Coastguard Worker 452*61c4878aSAndroid Build Coastguard Worker // Returns the identity of the current field. 453*61c4878aSAndroid Build Coastguard Worker ::pw::Result<Fields> Field(); 454*61c4878aSAndroid Build Coastguard Worker 455*61c4878aSAndroid Build Coastguard Worker // Per-Field Typed Readers. 456*61c4878aSAndroid Build Coastguard Worker pw::Result<int32_t> ReadAge(); 457*61c4878aSAndroid Build Coastguard Worker 458*61c4878aSAndroid Build Coastguard Worker pw::StatusWithSize ReadName(pw::span<char>); 459*61c4878aSAndroid Build Coastguard Worker BytesReader GetNameReader(); // Read name as a stream of bytes. 460*61c4878aSAndroid Build Coastguard Worker 461*61c4878aSAndroid Build Coastguard Worker pw::Result<Customer::Status> ReadStatus(); 462*61c4878aSAndroid Build Coastguard Worker }; 463*61c4878aSAndroid Build Coastguard Worker 464*61c4878aSAndroid Build Coastguard WorkerComplete and correct decoding requires looping through the fields, so is more 465*61c4878aSAndroid Build Coastguard Workercomplex than encoding or using the message structure. 466*61c4878aSAndroid Build Coastguard Worker 467*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 468*61c4878aSAndroid Build Coastguard Worker 469*61c4878aSAndroid Build Coastguard Worker pw::Status DecodeCustomer(Customer::StreamDecoder& decoder) { 470*61c4878aSAndroid Build Coastguard Worker uint32_t age; 471*61c4878aSAndroid Build Coastguard Worker char name[32]; 472*61c4878aSAndroid Build Coastguard Worker Customer::Status status; 473*61c4878aSAndroid Build Coastguard Worker 474*61c4878aSAndroid Build Coastguard Worker while ((status = decoder.Next()).ok()) { 475*61c4878aSAndroid Build Coastguard Worker switch (decoder.Field().value()) { 476*61c4878aSAndroid Build Coastguard Worker case Customer::Fields::kAge: { 477*61c4878aSAndroid Build Coastguard Worker PW_TRY_ASSIGN(age, decoder.ReadAge()); 478*61c4878aSAndroid Build Coastguard Worker break; 479*61c4878aSAndroid Build Coastguard Worker } 480*61c4878aSAndroid Build Coastguard Worker case Customer::Fields::kName: { 481*61c4878aSAndroid Build Coastguard Worker PW_TRY(decoder.ReadName(name)); 482*61c4878aSAndroid Build Coastguard Worker break; 483*61c4878aSAndroid Build Coastguard Worker } 484*61c4878aSAndroid Build Coastguard Worker case Customer::Fields::kStatus: { 485*61c4878aSAndroid Build Coastguard Worker PW_TRY_ASSIGN(status, decoder.ReadStatus()); 486*61c4878aSAndroid Build Coastguard Worker break; 487*61c4878aSAndroid Build Coastguard Worker } 488*61c4878aSAndroid Build Coastguard Worker } 489*61c4878aSAndroid Build Coastguard Worker } 490*61c4878aSAndroid Build Coastguard Worker 491*61c4878aSAndroid Build Coastguard Worker return status.IsOutOfRange() ? OkStatus() : status; 492*61c4878aSAndroid Build Coastguard Worker } 493*61c4878aSAndroid Build Coastguard Worker 494*61c4878aSAndroid Build Coastguard Worker.. warning:: ``Fields::SNAKE_CASE`` is deprecated. Use ``Fields::kCamelCase``. 495*61c4878aSAndroid Build Coastguard Worker 496*61c4878aSAndroid Build Coastguard Worker Transitional support for ``Fields::SNAKE_CASE`` will soon only be available by 497*61c4878aSAndroid Build Coastguard Worker explicitly setting the following GN variable in your project: 498*61c4878aSAndroid Build Coastguard Worker ``pw_protobuf_compiler_GENERATE_LEGACY_ENUM_SNAKE_CASE_NAMES=true`` 499*61c4878aSAndroid Build Coastguard Worker 500*61c4878aSAndroid Build Coastguard Worker This support will be removed after downstream projects have been migrated. 501*61c4878aSAndroid Build Coastguard Worker 502*61c4878aSAndroid Build Coastguard Worker.. _module-pw_protobuf-read: 503*61c4878aSAndroid Build Coastguard Worker 504*61c4878aSAndroid Build Coastguard WorkerReading a single field 505*61c4878aSAndroid Build Coastguard Worker---------------------- 506*61c4878aSAndroid Build Coastguard WorkerSometimes, only a single field from a serialized message needs to be read. In 507*61c4878aSAndroid Build Coastguard Workerthese cases, setting up a decoder and iterating through the message is a lot of 508*61c4878aSAndroid Build Coastguard Workerboilerplate. ``pw_protobuf`` generates convenient ``Find*()`` functions for 509*61c4878aSAndroid Build Coastguard Workermost fields in a message which handle this for you. 510*61c4878aSAndroid Build Coastguard Worker 511*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 512*61c4878aSAndroid Build Coastguard Worker 513*61c4878aSAndroid Build Coastguard Worker pw::Status ReadCustomerData(pw::ConstByteSpan serialized_customer) { 514*61c4878aSAndroid Build Coastguard Worker pw::Result<uint32_t> age = Customer::FindAge(serialized_customer); 515*61c4878aSAndroid Build Coastguard Worker if (!age.ok()) { 516*61c4878aSAndroid Build Coastguard Worker return age.status(); 517*61c4878aSAndroid Build Coastguard Worker } 518*61c4878aSAndroid Build Coastguard Worker 519*61c4878aSAndroid Build Coastguard Worker // This will scan the buffer again from the start, which is less efficient 520*61c4878aSAndroid Build Coastguard Worker // than writing a custom decoder loop. 521*61c4878aSAndroid Build Coastguard Worker pw::Result<std::string_view> name = Customer::FindName(serialized_customer); 522*61c4878aSAndroid Build Coastguard Worker if (!age.ok()) { 523*61c4878aSAndroid Build Coastguard Worker return age.status(); 524*61c4878aSAndroid Build Coastguard Worker } 525*61c4878aSAndroid Build Coastguard Worker 526*61c4878aSAndroid Build Coastguard Worker DoStuff(age, name); 527*61c4878aSAndroid Build Coastguard Worker return pw::OkStatus(); 528*61c4878aSAndroid Build Coastguard Worker } 529*61c4878aSAndroid Build Coastguard Worker 530*61c4878aSAndroid Build Coastguard WorkerThe ``Find`` APIs also work with streamed data, as shown below. 531*61c4878aSAndroid Build Coastguard Worker 532*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 533*61c4878aSAndroid Build Coastguard Worker 534*61c4878aSAndroid Build Coastguard Worker pw::Status ReadCustomerData(pw::stream::Reader& customer_stream) { 535*61c4878aSAndroid Build Coastguard Worker pw::Result<uint32_t> age = Customer::FindAge(customer_stream); 536*61c4878aSAndroid Build Coastguard Worker if (!age.ok()) { 537*61c4878aSAndroid Build Coastguard Worker return age.status(); 538*61c4878aSAndroid Build Coastguard Worker } 539*61c4878aSAndroid Build Coastguard Worker 540*61c4878aSAndroid Build Coastguard Worker // This will begin scanning for `name` from the current position of the 541*61c4878aSAndroid Build Coastguard Worker // stream (following the `age` field). If `name` appeared before `age` in 542*61c4878aSAndroid Build Coastguard Worker // the serialized data, it will not be found. 543*61c4878aSAndroid Build Coastguard Worker // 544*61c4878aSAndroid Build Coastguard Worker // Note that unlike with the buffer APIs, stream Find methods copy `string` 545*61c4878aSAndroid Build Coastguard Worker // and `bytes` fields into a user-provided buffer. 546*61c4878aSAndroid Build Coastguard Worker char name[32]; 547*61c4878aSAndroid Build Coastguard Worker pw::StatusWithSize sws = Customer::FindName(serialized_customer, name); 548*61c4878aSAndroid Build Coastguard Worker if (!sws.ok()) { 549*61c4878aSAndroid Build Coastguard Worker return sws.status(); 550*61c4878aSAndroid Build Coastguard Worker } 551*61c4878aSAndroid Build Coastguard Worker if (sws.size() >= sizeof(name)) { 552*61c4878aSAndroid Build Coastguard Worker return pw::Status::OutOfRange(); 553*61c4878aSAndroid Build Coastguard Worker } 554*61c4878aSAndroid Build Coastguard Worker name[sws.size()] = '\0'; 555*61c4878aSAndroid Build Coastguard Worker 556*61c4878aSAndroid Build Coastguard Worker DoStuff(age, name); 557*61c4878aSAndroid Build Coastguard Worker return pw::OkStatus(); 558*61c4878aSAndroid Build Coastguard Worker } 559*61c4878aSAndroid Build Coastguard Worker 560*61c4878aSAndroid Build Coastguard Worker``Find`` APIs can also be used to iterate over occurrences of a repeated field. 561*61c4878aSAndroid Build Coastguard WorkerFor example, given the protobuf definition: 562*61c4878aSAndroid Build Coastguard Worker 563*61c4878aSAndroid Build Coastguard Worker.. code-block:: proto 564*61c4878aSAndroid Build Coastguard Worker 565*61c4878aSAndroid Build Coastguard Worker message Samples { 566*61c4878aSAndroid Build Coastguard Worker repeated uint32 raw_values = 1; 567*61c4878aSAndroid Build Coastguard Worker } 568*61c4878aSAndroid Build Coastguard Worker 569*61c4878aSAndroid Build Coastguard WorkerThe ``raw_values`` field can be iterated over as follows: 570*61c4878aSAndroid Build Coastguard Worker 571*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 572*61c4878aSAndroid Build Coastguard Worker 573*61c4878aSAndroid Build Coastguard Worker pw::Status ReadSamples(pw::ConstByteSpan serialized_samples) { 574*61c4878aSAndroid Build Coastguard Worker pw::protobuf::Uint32Finder raw_values = 575*61c4878aSAndroid Build Coastguard Worker Samples::FindRawValues(serialized_samples); 576*61c4878aSAndroid Build Coastguard Worker for (Result<int32_t> val = finder.Next(); val.ok(); val = finder.Next()) { 577*61c4878aSAndroid Build Coastguard Worker ConsumeValue(*val); 578*61c4878aSAndroid Build Coastguard Worker } 579*61c4878aSAndroid Build Coastguard Worker } 580*61c4878aSAndroid Build Coastguard Worker 581*61c4878aSAndroid Build Coastguard Worker.. note:: 582*61c4878aSAndroid Build Coastguard Worker 583*61c4878aSAndroid Build Coastguard Worker Each call to ``Find*()`` linearly scans through the message. If you have to 584*61c4878aSAndroid Build Coastguard Worker read multiple fields, it is more efficient to instantiate your own decoder as 585*61c4878aSAndroid Build Coastguard Worker described above. 586*61c4878aSAndroid Build Coastguard Worker 587*61c4878aSAndroid Build Coastguard Worker 588*61c4878aSAndroid Build Coastguard WorkerDirect Writers and Readers 589*61c4878aSAndroid Build Coastguard Worker========================== 590*61c4878aSAndroid Build Coastguard WorkerThe lowest level API is provided by the core C++ implementation, and requires 591*61c4878aSAndroid Build Coastguard Workerthe caller to provide the correct field number and value types for encoding, or 592*61c4878aSAndroid Build Coastguard Workercheck the same when decoding. 593*61c4878aSAndroid Build Coastguard Worker 594*61c4878aSAndroid Build Coastguard WorkerEncoding 595*61c4878aSAndroid Build Coastguard Worker-------- 596*61c4878aSAndroid Build Coastguard WorkerThe two fundamental classes are ``MemoryEncoder`` which directly encodes a proto 597*61c4878aSAndroid Build Coastguard Workerto an in-memory buffer, and ``StreamEncoder`` that operates on 598*61c4878aSAndroid Build Coastguard Worker``pw::stream::Writer`` objects to serialize proto data. 599*61c4878aSAndroid Build Coastguard Worker 600*61c4878aSAndroid Build Coastguard Worker``StreamEncoder`` allows you encode a proto to something like ``pw::sys_io`` 601*61c4878aSAndroid Build Coastguard Workerwithout needing to build the complete message in memory 602*61c4878aSAndroid Build Coastguard Worker 603*61c4878aSAndroid Build Coastguard WorkerTo encode the same message we've used in the examples thus far, we would use 604*61c4878aSAndroid Build Coastguard Workerthe following parts of the core API: 605*61c4878aSAndroid Build Coastguard Worker 606*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 607*61c4878aSAndroid Build Coastguard Worker 608*61c4878aSAndroid Build Coastguard Worker class pw::protobuf::StreamEncoder { 609*61c4878aSAndroid Build Coastguard Worker public: 610*61c4878aSAndroid Build Coastguard Worker Status WriteInt32(uint32_t field_number, int32_t); 611*61c4878aSAndroid Build Coastguard Worker Status WriteUint32(uint32_t field_number, uint32_t); 612*61c4878aSAndroid Build Coastguard Worker 613*61c4878aSAndroid Build Coastguard Worker Status WriteString(uint32_t field_number, std::string_view); 614*61c4878aSAndroid Build Coastguard Worker Status WriteString(uint32_t field_number, const char*, size_t); 615*61c4878aSAndroid Build Coastguard Worker 616*61c4878aSAndroid Build Coastguard Worker // And many other methods, see pw_protobuf/encoder.h 617*61c4878aSAndroid Build Coastguard Worker }; 618*61c4878aSAndroid Build Coastguard Worker 619*61c4878aSAndroid Build Coastguard WorkerEncoding the same message requires that we specify the field numbers, which we 620*61c4878aSAndroid Build Coastguard Workercan hardcode, or supplement using the C++ code generated ``Fields`` enum, and 621*61c4878aSAndroid Build Coastguard Workercast the enumerated type. 622*61c4878aSAndroid Build Coastguard Worker 623*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 624*61c4878aSAndroid Build Coastguard Worker 625*61c4878aSAndroid Build Coastguard Worker #include "pw_protobuf/encoder.h" 626*61c4878aSAndroid Build Coastguard Worker #include "example_protos/customer.pwpb.h" 627*61c4878aSAndroid Build Coastguard Worker 628*61c4878aSAndroid Build Coastguard Worker Status EncodeCustomer(pw::protobuf::StreamEncoder& encoder) { 629*61c4878aSAndroid Build Coastguard Worker PW_TRY(encoder.WriteInt32(static_cast<uint32_t>(Customer::Fields::kAge), 630*61c4878aSAndroid Build Coastguard Worker 33)); 631*61c4878aSAndroid Build Coastguard Worker PW_TRY(encoder.WriteString(static_cast<uint32_t>(Customer::Fields::kName), 632*61c4878aSAndroid Build Coastguard Worker "Joe Bloggs"sv)); 633*61c4878aSAndroid Build Coastguard Worker PW_TRY(encoder.WriteUint32( 634*61c4878aSAndroid Build Coastguard Worker static_cast<uint32_t>(Customer::Fields::kStatus), 635*61c4878aSAndroid Build Coastguard Worker static_cast<uint32_t>(Customer::Status::INACTIVE))); 636*61c4878aSAndroid Build Coastguard Worker } 637*61c4878aSAndroid Build Coastguard Worker 638*61c4878aSAndroid Build Coastguard WorkerDecoding 639*61c4878aSAndroid Build Coastguard Worker-------- 640*61c4878aSAndroid Build Coastguard Worker``StreamDecoder`` reads data from a ``pw::stream::Reader`` and mirrors the API 641*61c4878aSAndroid Build Coastguard Workerof the encoders. 642*61c4878aSAndroid Build Coastguard Worker 643*61c4878aSAndroid Build Coastguard WorkerTo decode the same message we would use the following parts of the core API: 644*61c4878aSAndroid Build Coastguard Worker 645*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 646*61c4878aSAndroid Build Coastguard Worker 647*61c4878aSAndroid Build Coastguard Worker class pw::protobuf::StreamDecoder { 648*61c4878aSAndroid Build Coastguard Worker public: 649*61c4878aSAndroid Build Coastguard Worker // Returns the identity of the current field. 650*61c4878aSAndroid Build Coastguard Worker ::pw::Result<uint32_t> FieldNumber(); 651*61c4878aSAndroid Build Coastguard Worker 652*61c4878aSAndroid Build Coastguard Worker Result<int32_t> ReadInt32(); 653*61c4878aSAndroid Build Coastguard Worker Result<uint32_t> ReadUint32(); 654*61c4878aSAndroid Build Coastguard Worker 655*61c4878aSAndroid Build Coastguard Worker StatusWithSize ReadString(pw::span<char>); 656*61c4878aSAndroid Build Coastguard Worker 657*61c4878aSAndroid Build Coastguard Worker // And many other methods, see pw_protobuf/stream_decoder.h 658*61c4878aSAndroid Build Coastguard Worker }; 659*61c4878aSAndroid Build Coastguard Worker 660*61c4878aSAndroid Build Coastguard WorkerAs with the typed per-field API, complete and correct decoding requires looping 661*61c4878aSAndroid Build Coastguard Workerthrough the fields and checking the field numbers, along with casting types. 662*61c4878aSAndroid Build Coastguard Worker 663*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 664*61c4878aSAndroid Build Coastguard Worker 665*61c4878aSAndroid Build Coastguard Worker pw::Status DecodeCustomer(pw::protobuf::StreamDecoder& decoder) { 666*61c4878aSAndroid Build Coastguard Worker uint32_t age; 667*61c4878aSAndroid Build Coastguard Worker char name[32]; 668*61c4878aSAndroid Build Coastguard Worker Customer::Status status; 669*61c4878aSAndroid Build Coastguard Worker 670*61c4878aSAndroid Build Coastguard Worker while ((status = decoder.Next()).ok()) { 671*61c4878aSAndroid Build Coastguard Worker switch (decoder.FieldNumber().value()) { 672*61c4878aSAndroid Build Coastguard Worker case static_cast<uint32_t>(Customer::Fields::kAge): { 673*61c4878aSAndroid Build Coastguard Worker PW_TRY_ASSIGN(age, decoder.ReadInt32()); 674*61c4878aSAndroid Build Coastguard Worker break; 675*61c4878aSAndroid Build Coastguard Worker } 676*61c4878aSAndroid Build Coastguard Worker case static_cast<uint32_t>(Customer::Fields::kName): { 677*61c4878aSAndroid Build Coastguard Worker PW_TRY(decoder.ReadString(name)); 678*61c4878aSAndroid Build Coastguard Worker break; 679*61c4878aSAndroid Build Coastguard Worker } 680*61c4878aSAndroid Build Coastguard Worker case static_cast<uint32_t>(Customer::Fields::kStatus): { 681*61c4878aSAndroid Build Coastguard Worker uint32_t status_value; 682*61c4878aSAndroid Build Coastguard Worker PW_TRY_ASSIGN(status_value, decoder.ReadUint32()); 683*61c4878aSAndroid Build Coastguard Worker status = static_cast<Customer::Status>(status_value); 684*61c4878aSAndroid Build Coastguard Worker break; 685*61c4878aSAndroid Build Coastguard Worker } 686*61c4878aSAndroid Build Coastguard Worker } 687*61c4878aSAndroid Build Coastguard Worker } 688*61c4878aSAndroid Build Coastguard Worker 689*61c4878aSAndroid Build Coastguard Worker return status.IsOutOfRange() ? OkStatus() : status; 690*61c4878aSAndroid Build Coastguard Worker } 691*61c4878aSAndroid Build Coastguard Worker 692*61c4878aSAndroid Build Coastguard WorkerFind APIs 693*61c4878aSAndroid Build Coastguard Worker--------- 694*61c4878aSAndroid Build Coastguard Worker 695*61c4878aSAndroid Build Coastguard Worker.. doxygenfile:: pw_protobuf/public/pw_protobuf/find.h 696*61c4878aSAndroid Build Coastguard Worker 697*61c4878aSAndroid Build Coastguard Worker 698*61c4878aSAndroid Build Coastguard WorkerHandling of packages 699*61c4878aSAndroid Build Coastguard Worker==================== 700*61c4878aSAndroid Build Coastguard Worker 701*61c4878aSAndroid Build Coastguard WorkerPackage declarations in ``.proto`` files are converted to namespace 702*61c4878aSAndroid Build Coastguard Workerdeclarations. Unlike ``protoc``'s native C++ codegen, pw_protobuf appends an 703*61c4878aSAndroid Build Coastguard Workeradditional ``::pwpb`` namespace after the user-specified package name: for 704*61c4878aSAndroid Build Coastguard Workerexample, ``package my.cool.project`` becomes ``namespace 705*61c4878aSAndroid Build Coastguard Workermy::cool::project::pwpb``. We emit a different package name than stated, in 706*61c4878aSAndroid Build Coastguard Workerorder to avoid clashes for projects that link against multiple C++ proto 707*61c4878aSAndroid Build Coastguard Workerlibraries in the same library. 708*61c4878aSAndroid Build Coastguard Worker 709*61c4878aSAndroid Build Coastguard Worker.. 710*61c4878aSAndroid Build Coastguard Worker TODO: b/258832150 - Remove this section, if possible 711*61c4878aSAndroid Build Coastguard Worker 712*61c4878aSAndroid Build Coastguard WorkerIn some cases, pw_protobuf codegen may encounter external message references 713*61c4878aSAndroid Build Coastguard Workerduring parsing, where it is unable to resolve the package name of the message. 714*61c4878aSAndroid Build Coastguard WorkerIn these situations, the codegen is instead forced to emit the package name as 715*61c4878aSAndroid Build Coastguard Worker``pw::pwpb_xxx::my::cool::project``, where "pwpb_xxx" is the name of some 716*61c4878aSAndroid Build Coastguard Workerunspecified private namespace. Users are expected to manually identify the 717*61c4878aSAndroid Build Coastguard Workerintended namespace name of that symbol, as described above, and must not rely 718*61c4878aSAndroid Build Coastguard Workeron any such private namespaces, even if they appear in codegen output. 719*61c4878aSAndroid Build Coastguard Worker 720*61c4878aSAndroid Build Coastguard Worker------- 721*61c4878aSAndroid Build Coastguard WorkerCodegen 722*61c4878aSAndroid Build Coastguard Worker------- 723*61c4878aSAndroid Build Coastguard Workerpw_protobuf codegen integration is supported in GN, Bazel, and CMake. 724*61c4878aSAndroid Build Coastguard Worker 725*61c4878aSAndroid Build Coastguard Worker``pw_protobuf`` only supports targeting ``proto3`` syntax and its semantics. 726*61c4878aSAndroid Build Coastguard WorkerFiles which specify ``syntax = "proto2"`` will be treated as proto3, and any 727*61c4878aSAndroid Build Coastguard Workerproto2-specific options will be ignored. 728*61c4878aSAndroid Build Coastguard Worker 729*61c4878aSAndroid Build Coastguard Worker.. admonition:: Protobuf edition support 730*61c4878aSAndroid Build Coastguard Worker 731*61c4878aSAndroid Build Coastguard Worker `Protobuf editions <https://protobuf.dev/editions/overview>`_ are the future 732*61c4878aSAndroid Build Coastguard Worker of Protobuf versioning, replacing proto2 and proto3 with more granular code 733*61c4878aSAndroid Build Coastguard Worker generation options. ``pw_protobuf`` has some basic support for editions, but 734*61c4878aSAndroid Build Coastguard Worker it is still a work in progress. 735*61c4878aSAndroid Build Coastguard Worker 736*61c4878aSAndroid Build Coastguard WorkerThis module's codegen is available through the ``*.pwpb`` sub-target of a 737*61c4878aSAndroid Build Coastguard Worker``pw_proto_library`` in GN, CMake, and Bazel. See :ref:`pw_protobuf_compiler's 738*61c4878aSAndroid Build Coastguard Workerdocumentation <module-pw_protobuf_compiler>` for more information on build 739*61c4878aSAndroid Build Coastguard Workersystem integration for pw_protobuf codegen. 740*61c4878aSAndroid Build Coastguard Worker 741*61c4878aSAndroid Build Coastguard WorkerExample ``BUILD.gn``: 742*61c4878aSAndroid Build Coastguard Worker 743*61c4878aSAndroid Build Coastguard Worker.. code-block:: 744*61c4878aSAndroid Build Coastguard Worker 745*61c4878aSAndroid Build Coastguard Worker import("//build_overrides/pigweed.gni") 746*61c4878aSAndroid Build Coastguard Worker 747*61c4878aSAndroid Build Coastguard Worker import("$dir_pw_build/target_types.gni") 748*61c4878aSAndroid Build Coastguard Worker import("$dir_pw_protobuf_compiler/proto.gni") 749*61c4878aSAndroid Build Coastguard Worker 750*61c4878aSAndroid Build Coastguard Worker # This target controls where the *.pwpb.h headers end up on the include path. 751*61c4878aSAndroid Build Coastguard Worker # In this example, it's at "pet_daycare_protos/client.pwpb.h". 752*61c4878aSAndroid Build Coastguard Worker pw_proto_library("pet_daycare_protos") { 753*61c4878aSAndroid Build Coastguard Worker sources = [ 754*61c4878aSAndroid Build Coastguard Worker "pet_daycare_protos/client.proto", 755*61c4878aSAndroid Build Coastguard Worker ] 756*61c4878aSAndroid Build Coastguard Worker } 757*61c4878aSAndroid Build Coastguard Worker 758*61c4878aSAndroid Build Coastguard Worker pw_source_set("example_client") { 759*61c4878aSAndroid Build Coastguard Worker sources = [ "example_client.cc" ] 760*61c4878aSAndroid Build Coastguard Worker deps = [ 761*61c4878aSAndroid Build Coastguard Worker ":pet_daycare_protos.pwpb", 762*61c4878aSAndroid Build Coastguard Worker dir_pw_bytes, 763*61c4878aSAndroid Build Coastguard Worker dir_pw_stream, 764*61c4878aSAndroid Build Coastguard Worker ] 765*61c4878aSAndroid Build Coastguard Worker } 766*61c4878aSAndroid Build Coastguard Worker 767*61c4878aSAndroid Build Coastguard Worker------------- 768*61c4878aSAndroid Build Coastguard WorkerConfiguration 769*61c4878aSAndroid Build Coastguard Worker------------- 770*61c4878aSAndroid Build Coastguard Worker``pw_protobuf`` supports the following configuration options. 771*61c4878aSAndroid Build Coastguard Worker 772*61c4878aSAndroid Build Coastguard Worker* ``PW_PROTOBUF_CFG_MAX_VARINT_SIZE``: 773*61c4878aSAndroid Build Coastguard Worker When encoding nested messages, the number of bytes to reserve for the varint 774*61c4878aSAndroid Build Coastguard Worker submessage length. Nested messages are limited in size to the maximum value 775*61c4878aSAndroid Build Coastguard Worker that can be varint-encoded into this reserved space. 776*61c4878aSAndroid Build Coastguard Worker 777*61c4878aSAndroid Build Coastguard Worker The values that can be set, and their corresponding maximum submessage 778*61c4878aSAndroid Build Coastguard Worker lengths, are outlined below. 779*61c4878aSAndroid Build Coastguard Worker 780*61c4878aSAndroid Build Coastguard Worker +-------------------+----------------------------------------+ 781*61c4878aSAndroid Build Coastguard Worker | MAX_VARINT_SIZE | Maximum submessage length | 782*61c4878aSAndroid Build Coastguard Worker +===================+========================================+ 783*61c4878aSAndroid Build Coastguard Worker | 1 byte | 127 | 784*61c4878aSAndroid Build Coastguard Worker +-------------------+----------------------------------------+ 785*61c4878aSAndroid Build Coastguard Worker | 2 bytes | 16,383 or < 16KiB | 786*61c4878aSAndroid Build Coastguard Worker +-------------------+----------------------------------------+ 787*61c4878aSAndroid Build Coastguard Worker | 3 bytes | 2,097,151 or < 2048KiB | 788*61c4878aSAndroid Build Coastguard Worker +-------------------+----------------------------------------+ 789*61c4878aSAndroid Build Coastguard Worker | 4 bytes (default) | 268,435,455 or < 256MiB | 790*61c4878aSAndroid Build Coastguard Worker +-------------------+----------------------------------------+ 791*61c4878aSAndroid Build Coastguard Worker | 5 bytes | 4,294,967,295 or < 4GiB (max uint32_t) | 792*61c4878aSAndroid Build Coastguard Worker +-------------------+----------------------------------------+ 793*61c4878aSAndroid Build Coastguard Worker 794*61c4878aSAndroid Build Coastguard WorkerField Options 795*61c4878aSAndroid Build Coastguard Worker============= 796*61c4878aSAndroid Build Coastguard Worker``pw_protobuf`` supports the following field options for specifying 797*61c4878aSAndroid Build Coastguard Workerprotocol-level limitations, rather than code generation parameters (although 798*61c4878aSAndroid Build Coastguard Workerthey do influence code generation): 799*61c4878aSAndroid Build Coastguard Worker 800*61c4878aSAndroid Build Coastguard Worker 801*61c4878aSAndroid Build Coastguard Worker* ``max_count``: 802*61c4878aSAndroid Build Coastguard Worker Maximum number of entries for repeated fields. 803*61c4878aSAndroid Build Coastguard Worker 804*61c4878aSAndroid Build Coastguard Worker* ``max_size``: 805*61c4878aSAndroid Build Coastguard Worker Maximum size of `bytes` or `string` fields. 806*61c4878aSAndroid Build Coastguard Worker 807*61c4878aSAndroid Build Coastguard WorkerEven though other proto codegen implementations do not respect these field 808*61c4878aSAndroid Build Coastguard Workeroptions, they can still compile protos which use these options. This is 809*61c4878aSAndroid Build Coastguard Workerespecially useful for host builds using upstream protoc code generation, where 810*61c4878aSAndroid Build Coastguard Workerhost software can use the reflection API to query for the options and validate 811*61c4878aSAndroid Build Coastguard Workermessages comply with the specified limitations. 812*61c4878aSAndroid Build Coastguard Worker 813*61c4878aSAndroid Build Coastguard Worker.. code-block:: text 814*61c4878aSAndroid Build Coastguard Worker 815*61c4878aSAndroid Build Coastguard Worker import "pw_protobuf_protos/field_options.proto"; 816*61c4878aSAndroid Build Coastguard Worker 817*61c4878aSAndroid Build Coastguard Worker message Demo { 818*61c4878aSAndroid Build Coastguard Worker string size_limited_string = 1 [(pw.protobuf.pwpb).max_size = 16]; 819*61c4878aSAndroid Build Coastguard Worker }; 820*61c4878aSAndroid Build Coastguard Worker 821*61c4878aSAndroid Build Coastguard WorkerOptions Files 822*61c4878aSAndroid Build Coastguard Worker============= 823*61c4878aSAndroid Build Coastguard WorkerCode generation can be configured using a separate ``.pwpb_options`` file placed 824*61c4878aSAndroid Build Coastguard Workeralongside the relevant ``.proto`` file. 825*61c4878aSAndroid Build Coastguard Worker 826*61c4878aSAndroid Build Coastguard WorkerThe format of this file is a series of fully qualified field names, or patterns, 827*61c4878aSAndroid Build Coastguard Workerfollowed by one or more options. Lines starting with ``#`` or ``//`` are 828*61c4878aSAndroid Build Coastguard Workercomments, and blank lines are ignored. 829*61c4878aSAndroid Build Coastguard Worker 830*61c4878aSAndroid Build Coastguard WorkerExample: 831*61c4878aSAndroid Build Coastguard Worker 832*61c4878aSAndroid Build Coastguard Worker.. code-block:: 833*61c4878aSAndroid Build Coastguard Worker 834*61c4878aSAndroid Build Coastguard Worker // Set an option for a specific field. 835*61c4878aSAndroid Build Coastguard Worker fuzzy_friends.Client.visit_dates max_count:16 836*61c4878aSAndroid Build Coastguard Worker 837*61c4878aSAndroid Build Coastguard Worker // Set options for multiple fields by wildcard matching. 838*61c4878aSAndroid Build Coastguard Worker fuzzy_friends.Pet.* max_size:32 839*61c4878aSAndroid Build Coastguard Worker 840*61c4878aSAndroid Build Coastguard Worker // Set multiple options in one go. 841*61c4878aSAndroid Build Coastguard Worker fuzzy_friends.Dog.paws max_count:4 fixed_count:true 842*61c4878aSAndroid Build Coastguard Worker 843*61c4878aSAndroid Build Coastguard WorkerOptions files should be listed as ``inputs`` when defining ``pw_proto_library``, 844*61c4878aSAndroid Build Coastguard Workere.g. 845*61c4878aSAndroid Build Coastguard Worker 846*61c4878aSAndroid Build Coastguard Worker.. code-block:: 847*61c4878aSAndroid Build Coastguard Worker 848*61c4878aSAndroid Build Coastguard Worker pw_proto_library("pet_daycare_protos") { 849*61c4878aSAndroid Build Coastguard Worker sources = [ 850*61c4878aSAndroid Build Coastguard Worker "pet_daycare_protos/client.proto", 851*61c4878aSAndroid Build Coastguard Worker ] 852*61c4878aSAndroid Build Coastguard Worker inputs = [ 853*61c4878aSAndroid Build Coastguard Worker "pet_daycare_protos/client.pwpb_options", 854*61c4878aSAndroid Build Coastguard Worker ] 855*61c4878aSAndroid Build Coastguard Worker } 856*61c4878aSAndroid Build Coastguard Worker 857*61c4878aSAndroid Build Coastguard WorkerValid options are: 858*61c4878aSAndroid Build Coastguard Worker 859*61c4878aSAndroid Build Coastguard Worker* ``max_count``: 860*61c4878aSAndroid Build Coastguard Worker Maximum number of entries for repeated fields. When set, repeated scalar 861*61c4878aSAndroid Build Coastguard Worker fields will use the ``pw::Vector`` container type instead of a callback. 862*61c4878aSAndroid Build Coastguard Worker 863*61c4878aSAndroid Build Coastguard Worker* ``fixed_count``: 864*61c4878aSAndroid Build Coastguard Worker Specified with ``max_count`` to use a fixed length ``std::array`` container 865*61c4878aSAndroid Build Coastguard Worker instead of ``pw::Vector``. 866*61c4878aSAndroid Build Coastguard Worker 867*61c4878aSAndroid Build Coastguard Worker* ``max_size``: 868*61c4878aSAndroid Build Coastguard Worker Maximum size of `bytes` or `string` fields. When set, `bytes` fields use 869*61c4878aSAndroid Build Coastguard Worker ``pw::Vector`` and `string` fields use ``pw::InlineString`` instead of a 870*61c4878aSAndroid Build Coastguard Worker callback. 871*61c4878aSAndroid Build Coastguard Worker 872*61c4878aSAndroid Build Coastguard Worker* ``fixed_size``: 873*61c4878aSAndroid Build Coastguard Worker Specified with ``max_size`` to use a fixed length ``std::array`` container 874*61c4878aSAndroid Build Coastguard Worker instead of ``pw::Vector`` for `bytes` fields. 875*61c4878aSAndroid Build Coastguard Worker 876*61c4878aSAndroid Build Coastguard Worker* ``use_callback``: 877*61c4878aSAndroid Build Coastguard Worker Replaces the structure member for the field with a callback function even 878*61c4878aSAndroid Build Coastguard Worker where a simpler type could be used. This can be useful to ignore fields, to 879*61c4878aSAndroid Build Coastguard Worker stop decoding of complex structures if certain values are not as expected, or 880*61c4878aSAndroid Build Coastguard Worker to provide special handling for nested messages. 881*61c4878aSAndroid Build Coastguard Worker 882*61c4878aSAndroid Build Coastguard Worker.. admonition:: Rationale 883*61c4878aSAndroid Build Coastguard Worker 884*61c4878aSAndroid Build Coastguard Worker The choice of a separate options file, over embedding options within the proto 885*61c4878aSAndroid Build Coastguard Worker file, are driven by the need for proto files to be shared across multiple 886*61c4878aSAndroid Build Coastguard Worker contexts. 887*61c4878aSAndroid Build Coastguard Worker 888*61c4878aSAndroid Build Coastguard Worker A typical product would require the same proto be used on a hardware 889*61c4878aSAndroid Build Coastguard Worker component, running Pigweed; a server-side component, running on a cloud 890*61c4878aSAndroid Build Coastguard Worker platform; and an app component, running on a Phone OS. 891*61c4878aSAndroid Build Coastguard Worker 892*61c4878aSAndroid Build Coastguard Worker While related, each of these will likely have different source projects and 893*61c4878aSAndroid Build Coastguard Worker build systems. 894*61c4878aSAndroid Build Coastguard Worker 895*61c4878aSAndroid Build Coastguard Worker Were the Pigweed options embedded in the protos, it would be necessary for 896*61c4878aSAndroid Build Coastguard Worker both the cloud platform and Phone OS to be able to ``"import pigweed"`` --- 897*61c4878aSAndroid Build Coastguard Worker and equivalently for options relevant to their platforms in the embedded 898*61c4878aSAndroid Build Coastguard Worker software project. 899*61c4878aSAndroid Build Coastguard Worker 900*61c4878aSAndroid Build Coastguard Worker------------------ 901*61c4878aSAndroid Build Coastguard WorkerMessage Structures 902*61c4878aSAndroid Build Coastguard Worker------------------ 903*61c4878aSAndroid Build Coastguard WorkerThe C++ code generator creates a ``struct Message`` for each protobuf message 904*61c4878aSAndroid Build Coastguard Workerthat can hold the set of values encoded by it, following these rules. 905*61c4878aSAndroid Build Coastguard Worker 906*61c4878aSAndroid Build Coastguard Worker* Scalar fields are represented by their appropriate C++ type. 907*61c4878aSAndroid Build Coastguard Worker 908*61c4878aSAndroid Build Coastguard Worker .. code-block:: protobuf 909*61c4878aSAndroid Build Coastguard Worker 910*61c4878aSAndroid Build Coastguard Worker message Customer { 911*61c4878aSAndroid Build Coastguard Worker int32 age = 1; 912*61c4878aSAndroid Build Coastguard Worker uint32 birth_year = 2; 913*61c4878aSAndroid Build Coastguard Worker sint64 rating = 3; 914*61c4878aSAndroid Build Coastguard Worker bool is_active = 4; 915*61c4878aSAndroid Build Coastguard Worker } 916*61c4878aSAndroid Build Coastguard Worker 917*61c4878aSAndroid Build Coastguard Worker .. code-block:: c++ 918*61c4878aSAndroid Build Coastguard Worker 919*61c4878aSAndroid Build Coastguard Worker struct Customer::Message { 920*61c4878aSAndroid Build Coastguard Worker int32_t age; 921*61c4878aSAndroid Build Coastguard Worker uint32_t birth_year; 922*61c4878aSAndroid Build Coastguard Worker int64_t rating; 923*61c4878aSAndroid Build Coastguard Worker bool is_active; 924*61c4878aSAndroid Build Coastguard Worker }; 925*61c4878aSAndroid Build Coastguard Worker 926*61c4878aSAndroid Build Coastguard Worker* Enumerations are represented by a code generated namespaced proto enum. 927*61c4878aSAndroid Build Coastguard Worker 928*61c4878aSAndroid Build Coastguard Worker .. code-block:: protobuf 929*61c4878aSAndroid Build Coastguard Worker 930*61c4878aSAndroid Build Coastguard Worker message Award { 931*61c4878aSAndroid Build Coastguard Worker enum Service { 932*61c4878aSAndroid Build Coastguard Worker BRONZE = 1; 933*61c4878aSAndroid Build Coastguard Worker SILVER = 2; 934*61c4878aSAndroid Build Coastguard Worker GOLD = 3; 935*61c4878aSAndroid Build Coastguard Worker } 936*61c4878aSAndroid Build Coastguard Worker Service service = 1; 937*61c4878aSAndroid Build Coastguard Worker } 938*61c4878aSAndroid Build Coastguard Worker 939*61c4878aSAndroid Build Coastguard Worker .. code-block:: c++ 940*61c4878aSAndroid Build Coastguard Worker 941*61c4878aSAndroid Build Coastguard Worker enum class Award::Service : uint32_t { 942*61c4878aSAndroid Build Coastguard Worker BRONZE = 1, 943*61c4878aSAndroid Build Coastguard Worker SILVER = 2, 944*61c4878aSAndroid Build Coastguard Worker GOLD = 3, 945*61c4878aSAndroid Build Coastguard Worker 946*61c4878aSAndroid Build Coastguard Worker kBronze = BRONZE, 947*61c4878aSAndroid Build Coastguard Worker kSilver = SILVER, 948*61c4878aSAndroid Build Coastguard Worker kGold = GOLD, 949*61c4878aSAndroid Build Coastguard Worker }; 950*61c4878aSAndroid Build Coastguard Worker 951*61c4878aSAndroid Build Coastguard Worker struct Award::Message { 952*61c4878aSAndroid Build Coastguard Worker Award::Service service; 953*61c4878aSAndroid Build Coastguard Worker }; 954*61c4878aSAndroid Build Coastguard Worker 955*61c4878aSAndroid Build Coastguard Worker Aliases to the enum values are also included in the "constant" style to match 956*61c4878aSAndroid Build Coastguard Worker your preferred coding style. These aliases have any common prefix to the 957*61c4878aSAndroid Build Coastguard Worker enumeration values removed, such that: 958*61c4878aSAndroid Build Coastguard Worker 959*61c4878aSAndroid Build Coastguard Worker .. code-block:: protobuf 960*61c4878aSAndroid Build Coastguard Worker 961*61c4878aSAndroid Build Coastguard Worker enum Activity { 962*61c4878aSAndroid Build Coastguard Worker ACTIVITY_CYCLING = 1; 963*61c4878aSAndroid Build Coastguard Worker ACTIVITY_RUNNING = 2; 964*61c4878aSAndroid Build Coastguard Worker ACTIVITY_SWIMMING = 3; 965*61c4878aSAndroid Build Coastguard Worker } 966*61c4878aSAndroid Build Coastguard Worker 967*61c4878aSAndroid Build Coastguard Worker .. code-block:: c++ 968*61c4878aSAndroid Build Coastguard Worker 969*61c4878aSAndroid Build Coastguard Worker enum class Activity : uint32_t { 970*61c4878aSAndroid Build Coastguard Worker ACTIVITY_CYCLING = 1, 971*61c4878aSAndroid Build Coastguard Worker ACTIVITY_RUNNING = 2, 972*61c4878aSAndroid Build Coastguard Worker ACTIVITY_SWIMMING = 3, 973*61c4878aSAndroid Build Coastguard Worker 974*61c4878aSAndroid Build Coastguard Worker kCycling = ACTIVITY_CYCLING, 975*61c4878aSAndroid Build Coastguard Worker kRunning = ACTIVITY_RUNNING, 976*61c4878aSAndroid Build Coastguard Worker kSwimming = ACTIVITY_SWIMMING, 977*61c4878aSAndroid Build Coastguard Worker }; 978*61c4878aSAndroid Build Coastguard Worker 979*61c4878aSAndroid Build Coastguard Worker 980*61c4878aSAndroid Build Coastguard Worker* Nested messages are represented by their own ``struct Message`` provided that 981*61c4878aSAndroid Build Coastguard Worker a reference cycle does not exist. 982*61c4878aSAndroid Build Coastguard Worker 983*61c4878aSAndroid Build Coastguard Worker .. code-block:: protobuf 984*61c4878aSAndroid Build Coastguard Worker 985*61c4878aSAndroid Build Coastguard Worker message Sale { 986*61c4878aSAndroid Build Coastguard Worker Customer customer = 1; 987*61c4878aSAndroid Build Coastguard Worker Product product = 2; 988*61c4878aSAndroid Build Coastguard Worker } 989*61c4878aSAndroid Build Coastguard Worker 990*61c4878aSAndroid Build Coastguard Worker .. code-block:: c++ 991*61c4878aSAndroid Build Coastguard Worker 992*61c4878aSAndroid Build Coastguard Worker struct Sale::Message { 993*61c4878aSAndroid Build Coastguard Worker Customer::Message customer; 994*61c4878aSAndroid Build Coastguard Worker Product::Message product; 995*61c4878aSAndroid Build Coastguard Worker }; 996*61c4878aSAndroid Build Coastguard Worker 997*61c4878aSAndroid Build Coastguard Worker* Optional scalar fields are represented by the appropriate C++ type wrapped in 998*61c4878aSAndroid Build Coastguard Worker ``std::optional``. Optional fields are not encoded when the value is not 999*61c4878aSAndroid Build Coastguard Worker present. 1000*61c4878aSAndroid Build Coastguard Worker 1001*61c4878aSAndroid Build Coastguard Worker .. code-block:: protobuf 1002*61c4878aSAndroid Build Coastguard Worker 1003*61c4878aSAndroid Build Coastguard Worker message Loyalty { 1004*61c4878aSAndroid Build Coastguard Worker optional int32 points = 1; 1005*61c4878aSAndroid Build Coastguard Worker } 1006*61c4878aSAndroid Build Coastguard Worker 1007*61c4878aSAndroid Build Coastguard Worker .. code-block:: c++ 1008*61c4878aSAndroid Build Coastguard Worker 1009*61c4878aSAndroid Build Coastguard Worker struct Loyalty::Message { 1010*61c4878aSAndroid Build Coastguard Worker std::optional<int32_t> points; 1011*61c4878aSAndroid Build Coastguard Worker }; 1012*61c4878aSAndroid Build Coastguard Worker 1013*61c4878aSAndroid Build Coastguard Worker* Repeated scalar fields are represented by ``pw::Vector`` when the 1014*61c4878aSAndroid Build Coastguard Worker ``max_count`` option is set for that field, or by ``std::array`` when both 1015*61c4878aSAndroid Build Coastguard Worker ``max_count`` and ``fixed_count:true`` are set. 1016*61c4878aSAndroid Build Coastguard Worker 1017*61c4878aSAndroid Build Coastguard Worker The max count is exposed as an UpperCamelCase constant ``k{FieldName}MaxSize``. 1018*61c4878aSAndroid Build Coastguard Worker 1019*61c4878aSAndroid Build Coastguard Worker .. code-block:: protobuf 1020*61c4878aSAndroid Build Coastguard Worker 1021*61c4878aSAndroid Build Coastguard Worker message Register { 1022*61c4878aSAndroid Build Coastguard Worker repeated int32 cash_in = 1; 1023*61c4878aSAndroid Build Coastguard Worker repeated int32 cash_out = 2; 1024*61c4878aSAndroid Build Coastguard Worker } 1025*61c4878aSAndroid Build Coastguard Worker 1026*61c4878aSAndroid Build Coastguard Worker .. code-block:: text 1027*61c4878aSAndroid Build Coastguard Worker 1028*61c4878aSAndroid Build Coastguard Worker Register.cash_in max_count:32 fixed_count:true 1029*61c4878aSAndroid Build Coastguard Worker Register.cash_out max_count:64 1030*61c4878aSAndroid Build Coastguard Worker 1031*61c4878aSAndroid Build Coastguard Worker .. code-block:: c++ 1032*61c4878aSAndroid Build Coastguard Worker 1033*61c4878aSAndroid Build Coastguard Worker namespace Register { 1034*61c4878aSAndroid Build Coastguard Worker static constexpr size_t kCashInMaxSize = 32; 1035*61c4878aSAndroid Build Coastguard Worker static constexpr size_t kCashOutMaxSize = 64; 1036*61c4878aSAndroid Build Coastguard Worker } 1037*61c4878aSAndroid Build Coastguard Worker 1038*61c4878aSAndroid Build Coastguard Worker struct Register::Message { 1039*61c4878aSAndroid Build Coastguard Worker std::array<int32_t, kCashInMaxSize> cash_in; 1040*61c4878aSAndroid Build Coastguard Worker pw::Vector<int32_t, kCashOutMaxSize> cash_out; 1041*61c4878aSAndroid Build Coastguard Worker }; 1042*61c4878aSAndroid Build Coastguard Worker 1043*61c4878aSAndroid Build Coastguard Worker* `bytes` fields are represented by ``pw::Vector`` when the ``max_size`` option 1044*61c4878aSAndroid Build Coastguard Worker is set for that field, or by ``std::array`` when both ``max_size`` and 1045*61c4878aSAndroid Build Coastguard Worker ``fixed_size:true`` are set. 1046*61c4878aSAndroid Build Coastguard Worker 1047*61c4878aSAndroid Build Coastguard Worker The max size is exposed as an UpperCamelCase constant ``k{FieldName}MaxSize``. 1048*61c4878aSAndroid Build Coastguard Worker 1049*61c4878aSAndroid Build Coastguard Worker .. code-block:: protobuf 1050*61c4878aSAndroid Build Coastguard Worker 1051*61c4878aSAndroid Build Coastguard Worker message Product { 1052*61c4878aSAndroid Build Coastguard Worker bytes sku = 1; 1053*61c4878aSAndroid Build Coastguard Worker bytes serial_number = 2; 1054*61c4878aSAndroid Build Coastguard Worker } 1055*61c4878aSAndroid Build Coastguard Worker 1056*61c4878aSAndroid Build Coastguard Worker .. code-block:: text 1057*61c4878aSAndroid Build Coastguard Worker 1058*61c4878aSAndroid Build Coastguard Worker Product.sku max_size:8 fixed_size:true 1059*61c4878aSAndroid Build Coastguard Worker Product.serial_number max_size:64 1060*61c4878aSAndroid Build Coastguard Worker 1061*61c4878aSAndroid Build Coastguard Worker .. code-block:: c++ 1062*61c4878aSAndroid Build Coastguard Worker 1063*61c4878aSAndroid Build Coastguard Worker namespace Product { 1064*61c4878aSAndroid Build Coastguard Worker static constexpr size_t kSkuMaxSize = 8; 1065*61c4878aSAndroid Build Coastguard Worker static constexpr size_t kSerialNumberMaxSize = 64; 1066*61c4878aSAndroid Build Coastguard Worker } 1067*61c4878aSAndroid Build Coastguard Worker 1068*61c4878aSAndroid Build Coastguard Worker struct Product::Message { 1069*61c4878aSAndroid Build Coastguard Worker std::array<std::byte, kSkuMaxSize> sku; 1070*61c4878aSAndroid Build Coastguard Worker pw::Vector<std::byte, kSerialNumberMaxSize> serial_number; 1071*61c4878aSAndroid Build Coastguard Worker }; 1072*61c4878aSAndroid Build Coastguard Worker 1073*61c4878aSAndroid Build Coastguard Worker* `string` fields are represented by a :cpp:type:`pw::InlineString` when the 1074*61c4878aSAndroid Build Coastguard Worker ``max_size`` option is set for that field. The string can hold up to 1075*61c4878aSAndroid Build Coastguard Worker ``max_size`` characters, and is always null terminated. The null terminator is 1076*61c4878aSAndroid Build Coastguard Worker not counted in ``max_size``. 1077*61c4878aSAndroid Build Coastguard Worker 1078*61c4878aSAndroid Build Coastguard Worker The max size is exposed as an UpperCamelCase constant ``k{FieldName}MaxSize``. 1079*61c4878aSAndroid Build Coastguard Worker 1080*61c4878aSAndroid Build Coastguard Worker .. code-block:: protobuf 1081*61c4878aSAndroid Build Coastguard Worker 1082*61c4878aSAndroid Build Coastguard Worker message Employee { 1083*61c4878aSAndroid Build Coastguard Worker string name = 1; 1084*61c4878aSAndroid Build Coastguard Worker } 1085*61c4878aSAndroid Build Coastguard Worker 1086*61c4878aSAndroid Build Coastguard Worker .. code-block:: text 1087*61c4878aSAndroid Build Coastguard Worker 1088*61c4878aSAndroid Build Coastguard Worker Employee.name max_size:128 1089*61c4878aSAndroid Build Coastguard Worker 1090*61c4878aSAndroid Build Coastguard Worker .. code-block:: c++ 1091*61c4878aSAndroid Build Coastguard Worker 1092*61c4878aSAndroid Build Coastguard Worker namespace Employee { 1093*61c4878aSAndroid Build Coastguard Worker static constexpr size_t kNameMaxSize = 128; 1094*61c4878aSAndroid Build Coastguard Worker } 1095*61c4878aSAndroid Build Coastguard Worker 1096*61c4878aSAndroid Build Coastguard Worker struct Employee::Message { 1097*61c4878aSAndroid Build Coastguard Worker pw::InlineString<kNameMaxSize> name; 1098*61c4878aSAndroid Build Coastguard Worker }; 1099*61c4878aSAndroid Build Coastguard Worker 1100*61c4878aSAndroid Build Coastguard Worker* Nested messages with a dependency cycle, repeated scalar fields without a 1101*61c4878aSAndroid Build Coastguard Worker ``max_count`` option set, `bytes` and `strings` fields without a ``max_size`` 1102*61c4878aSAndroid Build Coastguard Worker option set, and repeated nested messages, repeated `bytes`, and repeated 1103*61c4878aSAndroid Build Coastguard Worker `strings` fields, are represented by a callback. 1104*61c4878aSAndroid Build Coastguard Worker 1105*61c4878aSAndroid Build Coastguard Worker You set the callback to a custom function for encoding or decoding 1106*61c4878aSAndroid Build Coastguard Worker before passing the structure to ``Write()`` or ``Read()`` appropriately. 1107*61c4878aSAndroid Build Coastguard Worker 1108*61c4878aSAndroid Build Coastguard Worker .. code-block:: protobuf 1109*61c4878aSAndroid Build Coastguard Worker 1110*61c4878aSAndroid Build Coastguard Worker message Store { 1111*61c4878aSAndroid Build Coastguard Worker Store nearest_store = 1; 1112*61c4878aSAndroid Build Coastguard Worker repeated int32 employee_numbers = 2; 1113*61c4878aSAndroid Build Coastguard Worker string directions = 3; 1114*61c4878aSAndroid Build Coastguard Worker repeated string address = 4; 1115*61c4878aSAndroid Build Coastguard Worker repeated Employee employees = 5; 1116*61c4878aSAndroid Build Coastguard Worker } 1117*61c4878aSAndroid Build Coastguard Worker 1118*61c4878aSAndroid Build Coastguard Worker .. code-block:: 1119*61c4878aSAndroid Build Coastguard Worker 1120*61c4878aSAndroid Build Coastguard Worker // No options set. 1121*61c4878aSAndroid Build Coastguard Worker 1122*61c4878aSAndroid Build Coastguard Worker .. code-block:: c++ 1123*61c4878aSAndroid Build Coastguard Worker 1124*61c4878aSAndroid Build Coastguard Worker struct Store::Message { 1125*61c4878aSAndroid Build Coastguard Worker pw::protobuf::Callback<Store::StreamEncoder, Store::StreamDecoder> nearest_store; 1126*61c4878aSAndroid Build Coastguard Worker pw::protobuf::Callback<Store::StreamEncoder, Store::StreamDecoder> employee_numbers; 1127*61c4878aSAndroid Build Coastguard Worker pw::protobuf::Callback<Store::StreamEncoder, Store::StreamDecoder> directions; 1128*61c4878aSAndroid Build Coastguard Worker pw::protobuf::Callback<Store::StreamEncoder, Store::StreamDecoder> address; 1129*61c4878aSAndroid Build Coastguard Worker pw::protobuf::Callback<Store::StreamEncoder, Store::StreamDecoder> employees; 1130*61c4878aSAndroid Build Coastguard Worker }; 1131*61c4878aSAndroid Build Coastguard Worker 1132*61c4878aSAndroid Build Coastguard Worker A Callback object can be converted to a ``bool`` indicating whether a callback 1133*61c4878aSAndroid Build Coastguard Worker is set. 1134*61c4878aSAndroid Build Coastguard Worker 1135*61c4878aSAndroid Build Coastguard Worker* Fields defined within a ``oneof`` group are represented by a ``OneOf`` 1136*61c4878aSAndroid Build Coastguard Worker callback. 1137*61c4878aSAndroid Build Coastguard Worker 1138*61c4878aSAndroid Build Coastguard Worker .. code-block:: protobuf 1139*61c4878aSAndroid Build Coastguard Worker 1140*61c4878aSAndroid Build Coastguard Worker message OnlineOrder { 1141*61c4878aSAndroid Build Coastguard Worker Product product = 1; 1142*61c4878aSAndroid Build Coastguard Worker Customer customer = 2; 1143*61c4878aSAndroid Build Coastguard Worker 1144*61c4878aSAndroid Build Coastguard Worker oneof delivery { 1145*61c4878aSAndroid Build Coastguard Worker Address shipping_address = 3; 1146*61c4878aSAndroid Build Coastguard Worker Date pickup_date = 4; 1147*61c4878aSAndroid Build Coastguard Worker } 1148*61c4878aSAndroid Build Coastguard Worker } 1149*61c4878aSAndroid Build Coastguard Worker 1150*61c4878aSAndroid Build Coastguard Worker .. code-block:: 1151*61c4878aSAndroid Build Coastguard Worker 1152*61c4878aSAndroid Build Coastguard Worker // No options set. 1153*61c4878aSAndroid Build Coastguard Worker 1154*61c4878aSAndroid Build Coastguard Worker .. code-block:: c++ 1155*61c4878aSAndroid Build Coastguard Worker 1156*61c4878aSAndroid Build Coastguard Worker struct OnlineOrder::Message { 1157*61c4878aSAndroid Build Coastguard Worker Product::Message product; 1158*61c4878aSAndroid Build Coastguard Worker Customer::Message customer; 1159*61c4878aSAndroid Build Coastguard Worker pw::protobuf::OneOf<OnlineOrder::StreamEncoder, 1160*61c4878aSAndroid Build Coastguard Worker OnlineOrder::StreamDecoder, 1161*61c4878aSAndroid Build Coastguard Worker OnlineOrder::Fields> 1162*61c4878aSAndroid Build Coastguard Worker delivery; 1163*61c4878aSAndroid Build Coastguard Worker }; 1164*61c4878aSAndroid Build Coastguard Worker 1165*61c4878aSAndroid Build Coastguard Worker Encoding a ``oneof`` field is identical to using a regular field callback. 1166*61c4878aSAndroid Build Coastguard Worker The encode callback will be invoked once when the message is written. Users 1167*61c4878aSAndroid Build Coastguard Worker must ensure that only a single field is written to the encoder within the 1168*61c4878aSAndroid Build Coastguard Worker callback. 1169*61c4878aSAndroid Build Coastguard Worker 1170*61c4878aSAndroid Build Coastguard Worker .. code-block:: c++ 1171*61c4878aSAndroid Build Coastguard Worker 1172*61c4878aSAndroid Build Coastguard Worker OnlineOrder::Message message; 1173*61c4878aSAndroid Build Coastguard Worker message.delivery.SetEncoder( 1174*61c4878aSAndroid Build Coastguard Worker [&pickup_date](OnlineOrder::StreamEncoder& encoder) { 1175*61c4878aSAndroid Build Coastguard Worker return encoder.GetPickupDateEncoder().Write(pickup_date); 1176*61c4878aSAndroid Build Coastguard Worker }); 1177*61c4878aSAndroid Build Coastguard Worker 1178*61c4878aSAndroid Build Coastguard Worker The ``OneOf`` decoder callback is invoked when reading a message structure 1179*61c4878aSAndroid Build Coastguard Worker when a field within the ``oneof`` group is encountered. The found field is 1180*61c4878aSAndroid Build Coastguard Worker passed to the callback. 1181*61c4878aSAndroid Build Coastguard Worker 1182*61c4878aSAndroid Build Coastguard Worker If multiple fields from the ``oneof`` group are encountered within a ``Read``, 1183*61c4878aSAndroid Build Coastguard Worker it will fail with a ``DATA_LOSS`` status. 1184*61c4878aSAndroid Build Coastguard Worker 1185*61c4878aSAndroid Build Coastguard Worker .. code-block:: c++ 1186*61c4878aSAndroid Build Coastguard Worker 1187*61c4878aSAndroid Build Coastguard Worker OnlineOrder::Message message; 1188*61c4878aSAndroid Build Coastguard Worker message.delivery.SetDecoder( 1189*61c4878aSAndroid Build Coastguard Worker [this](OnlineOrder::Fields field, OnlineOrder::StreamDecoder& decoder) { 1190*61c4878aSAndroid Build Coastguard Worker switch (field) { 1191*61c4878aSAndroid Build Coastguard Worker case OnlineOrder::Fields::kShippingAddress: 1192*61c4878aSAndroid Build Coastguard Worker PW_TRY(decoder.GetShippingAddressDecoder().Read(&this->shipping_address)); 1193*61c4878aSAndroid Build Coastguard Worker break; 1194*61c4878aSAndroid Build Coastguard Worker case OnlineOrder::Fields::kPickupDate: 1195*61c4878aSAndroid Build Coastguard Worker PW_TRY(decoder.GetPickupDateDecoder().Read(&this->pickup_date)); 1196*61c4878aSAndroid Build Coastguard Worker break; 1197*61c4878aSAndroid Build Coastguard Worker default: 1198*61c4878aSAndroid Build Coastguard Worker return pw::Status::DataLoss(); 1199*61c4878aSAndroid Build Coastguard Worker } 1200*61c4878aSAndroid Build Coastguard Worker 1201*61c4878aSAndroid Build Coastguard Worker return pw::OkStatus(); 1202*61c4878aSAndroid Build Coastguard Worker }); 1203*61c4878aSAndroid Build Coastguard Worker 1204*61c4878aSAndroid Build Coastguard WorkerMessage structures can be copied, but doing so will clear any assigned 1205*61c4878aSAndroid Build Coastguard Workercallbacks. To preserve functions applied to callbacks, ensure that the message 1206*61c4878aSAndroid Build Coastguard Workerstructure is moved. 1207*61c4878aSAndroid Build Coastguard Worker 1208*61c4878aSAndroid Build Coastguard WorkerMessage structures can also be compared with each other for equality. This 1209*61c4878aSAndroid Build Coastguard Workerincludes all repeated and nested fields represented by value types, but does not 1210*61c4878aSAndroid Build Coastguard Workercompare any field represented by a callback. 1211*61c4878aSAndroid Build Coastguard Worker 1212*61c4878aSAndroid Build Coastguard WorkerReserved-Word Conflicts 1213*61c4878aSAndroid Build Coastguard Worker======================= 1214*61c4878aSAndroid Build Coastguard WorkerGenerated symbols whose names conflict with reserved C++ keywords or 1215*61c4878aSAndroid Build Coastguard Workerstandard-library macros are suffixed with underscores to avoid compilation 1216*61c4878aSAndroid Build Coastguard Workerfailures. This can be seen below in ``Channel.operator``, which is mapped to 1217*61c4878aSAndroid Build Coastguard Worker``Channel::Message::operator_`` to avoid conflicting with the ``operator`` 1218*61c4878aSAndroid Build Coastguard Workerkeyword. 1219*61c4878aSAndroid Build Coastguard Worker 1220*61c4878aSAndroid Build Coastguard Worker.. code-block:: protobuf 1221*61c4878aSAndroid Build Coastguard Worker 1222*61c4878aSAndroid Build Coastguard Worker message Channel { 1223*61c4878aSAndroid Build Coastguard Worker int32 bitrate = 1; 1224*61c4878aSAndroid Build Coastguard Worker float signal_to_noise_ratio = 2; 1225*61c4878aSAndroid Build Coastguard Worker Company operator = 3; 1226*61c4878aSAndroid Build Coastguard Worker } 1227*61c4878aSAndroid Build Coastguard Worker 1228*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 1229*61c4878aSAndroid Build Coastguard Worker 1230*61c4878aSAndroid Build Coastguard Worker struct Channel::Message { 1231*61c4878aSAndroid Build Coastguard Worker int32_t bitrate; 1232*61c4878aSAndroid Build Coastguard Worker float signal_to_noise_ratio; 1233*61c4878aSAndroid Build Coastguard Worker Company::Message operator_; 1234*61c4878aSAndroid Build Coastguard Worker }; 1235*61c4878aSAndroid Build Coastguard Worker 1236*61c4878aSAndroid Build Coastguard WorkerSimilarly, as shown in the example below, some POSIX-signal names conflict with 1237*61c4878aSAndroid Build Coastguard Workermacros defined by the standard-library header ``<csignal>`` and therefore 1238*61c4878aSAndroid Build Coastguard Workerrequire underscore suffixes in the generated code. Note, however, that some 1239*61c4878aSAndroid Build Coastguard Workersignal names are left alone. This is because ``<csignal>`` only defines a subset 1240*61c4878aSAndroid Build Coastguard Workerof the POSIX signals as macros; the rest are perfectly valid identifiers that 1241*61c4878aSAndroid Build Coastguard Workerwon't cause any problems unless the user defines custom macros for them. Any 1242*61c4878aSAndroid Build Coastguard Workernaming conflicts caused by user-defined macros are the user's responsibility 1243*61c4878aSAndroid Build Coastguard Worker(https://google.github.io/styleguide/cppguide.html#Preprocessor_Macros). 1244*61c4878aSAndroid Build Coastguard Worker 1245*61c4878aSAndroid Build Coastguard Worker.. code-block:: protobuf 1246*61c4878aSAndroid Build Coastguard Worker 1247*61c4878aSAndroid Build Coastguard Worker enum PosixSignal { 1248*61c4878aSAndroid Build Coastguard Worker NONE = 0; 1249*61c4878aSAndroid Build Coastguard Worker SIGHUP = 1; 1250*61c4878aSAndroid Build Coastguard Worker SIGINT = 2; 1251*61c4878aSAndroid Build Coastguard Worker SIGQUIT = 3; 1252*61c4878aSAndroid Build Coastguard Worker SIGILL = 4; 1253*61c4878aSAndroid Build Coastguard Worker SIGTRAP = 5; 1254*61c4878aSAndroid Build Coastguard Worker SIGABRT = 6; 1255*61c4878aSAndroid Build Coastguard Worker SIGFPE = 8; 1256*61c4878aSAndroid Build Coastguard Worker SIGKILL = 9; 1257*61c4878aSAndroid Build Coastguard Worker SIGSEGV = 11; 1258*61c4878aSAndroid Build Coastguard Worker SIGPIPE = 13; 1259*61c4878aSAndroid Build Coastguard Worker SIGALRM = 14; 1260*61c4878aSAndroid Build Coastguard Worker SIGTERM = 15; 1261*61c4878aSAndroid Build Coastguard Worker } 1262*61c4878aSAndroid Build Coastguard Worker 1263*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 1264*61c4878aSAndroid Build Coastguard Worker 1265*61c4878aSAndroid Build Coastguard Worker enum class PosixSignal : uint32_t { 1266*61c4878aSAndroid Build Coastguard Worker NONE = 0, 1267*61c4878aSAndroid Build Coastguard Worker SIGHUP = 1, 1268*61c4878aSAndroid Build Coastguard Worker SIGINT_ = 2, 1269*61c4878aSAndroid Build Coastguard Worker SIGQUIT = 3, 1270*61c4878aSAndroid Build Coastguard Worker SIGILL_ = 4, 1271*61c4878aSAndroid Build Coastguard Worker SIGTRAP = 5, 1272*61c4878aSAndroid Build Coastguard Worker SIGABRT_ = 6, 1273*61c4878aSAndroid Build Coastguard Worker SIGFPE_ = 8, 1274*61c4878aSAndroid Build Coastguard Worker SIGKILL = 9, 1275*61c4878aSAndroid Build Coastguard Worker SIGSEGV_ = 11, 1276*61c4878aSAndroid Build Coastguard Worker SIGPIPE = 13, 1277*61c4878aSAndroid Build Coastguard Worker SIGALRM = 14, 1278*61c4878aSAndroid Build Coastguard Worker SIGTERM_ = 15, 1279*61c4878aSAndroid Build Coastguard Worker 1280*61c4878aSAndroid Build Coastguard Worker kNone = NONE, 1281*61c4878aSAndroid Build Coastguard Worker kSighup = SIGHUP, 1282*61c4878aSAndroid Build Coastguard Worker kSigint = SIGINT_, 1283*61c4878aSAndroid Build Coastguard Worker kSigquit = SIGQUIT, 1284*61c4878aSAndroid Build Coastguard Worker kSigill = SIGILL_, 1285*61c4878aSAndroid Build Coastguard Worker kSigtrap = SIGTRAP, 1286*61c4878aSAndroid Build Coastguard Worker kSigabrt = SIGABRT_, 1287*61c4878aSAndroid Build Coastguard Worker kSigfpe = SIGFPE_, 1288*61c4878aSAndroid Build Coastguard Worker kSigkill = SIGKILL, 1289*61c4878aSAndroid Build Coastguard Worker kSigsegv = SIGSEGV_, 1290*61c4878aSAndroid Build Coastguard Worker kSigpipe = SIGPIPE, 1291*61c4878aSAndroid Build Coastguard Worker kSigalrm = SIGALRM, 1292*61c4878aSAndroid Build Coastguard Worker kSigterm = SIGTERM_, 1293*61c4878aSAndroid Build Coastguard Worker }; 1294*61c4878aSAndroid Build Coastguard Worker 1295*61c4878aSAndroid Build Coastguard WorkerMuch like reserved words and macros, the names ``Message`` and ``Fields`` are 1296*61c4878aSAndroid Build Coastguard Workersuffixed with underscores in generated C++ code. This is to prevent name 1297*61c4878aSAndroid Build Coastguard Workerconflicts with the codegen internals if they're used in a nested context as in 1298*61c4878aSAndroid Build Coastguard Workerthe example below. 1299*61c4878aSAndroid Build Coastguard Worker 1300*61c4878aSAndroid Build Coastguard Worker.. code-block:: protobuf 1301*61c4878aSAndroid Build Coastguard Worker 1302*61c4878aSAndroid Build Coastguard Worker message Function { 1303*61c4878aSAndroid Build Coastguard Worker message Message { 1304*61c4878aSAndroid Build Coastguard Worker string content = 1; 1305*61c4878aSAndroid Build Coastguard Worker } 1306*61c4878aSAndroid Build Coastguard Worker 1307*61c4878aSAndroid Build Coastguard Worker enum Fields { 1308*61c4878aSAndroid Build Coastguard Worker NONE = 0; 1309*61c4878aSAndroid Build Coastguard Worker COMPLEX_NUMBERS = 1; 1310*61c4878aSAndroid Build Coastguard Worker INTEGERS_MOD_5 = 2; 1311*61c4878aSAndroid Build Coastguard Worker MEROMORPHIC_FUNCTIONS_ON_COMPLEX_PLANE = 3; 1312*61c4878aSAndroid Build Coastguard Worker OTHER = 4; 1313*61c4878aSAndroid Build Coastguard Worker } 1314*61c4878aSAndroid Build Coastguard Worker 1315*61c4878aSAndroid Build Coastguard Worker Message description = 1; 1316*61c4878aSAndroid Build Coastguard Worker Fields domain = 2; 1317*61c4878aSAndroid Build Coastguard Worker Fields codomain = 3; 1318*61c4878aSAndroid Build Coastguard Worker } 1319*61c4878aSAndroid Build Coastguard Worker 1320*61c4878aSAndroid Build Coastguard Worker.. code-block:: 1321*61c4878aSAndroid Build Coastguard Worker 1322*61c4878aSAndroid Build Coastguard Worker Function.Message.content max_size:128 1323*61c4878aSAndroid Build Coastguard Worker 1324*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 1325*61c4878aSAndroid Build Coastguard Worker 1326*61c4878aSAndroid Build Coastguard Worker struct Function::Message_::Message { 1327*61c4878aSAndroid Build Coastguard Worker pw::InlineString<128> content; 1328*61c4878aSAndroid Build Coastguard Worker }; 1329*61c4878aSAndroid Build Coastguard Worker 1330*61c4878aSAndroid Build Coastguard Worker enum class Function::Message_::Fields : uint32_t { 1331*61c4878aSAndroid Build Coastguard Worker CONTENT = 1, 1332*61c4878aSAndroid Build Coastguard Worker }; 1333*61c4878aSAndroid Build Coastguard Worker 1334*61c4878aSAndroid Build Coastguard Worker enum class Function::Fields_ uint32_t { 1335*61c4878aSAndroid Build Coastguard Worker NONE = 0, 1336*61c4878aSAndroid Build Coastguard Worker COMPLEX_NUMBERS = 1, 1337*61c4878aSAndroid Build Coastguard Worker INTEGERS_MOD_5 = 2, 1338*61c4878aSAndroid Build Coastguard Worker MEROMORPHIC_FUNCTIONS_ON_COMPLEX_PLANE = 3, 1339*61c4878aSAndroid Build Coastguard Worker OTHER = 4, 1340*61c4878aSAndroid Build Coastguard Worker 1341*61c4878aSAndroid Build Coastguard Worker kNone = NONE, 1342*61c4878aSAndroid Build Coastguard Worker kComplexNumbers = COMPLEX_NUMBERS, 1343*61c4878aSAndroid Build Coastguard Worker kIntegersMod5 = INTEGERS_MOD_5, 1344*61c4878aSAndroid Build Coastguard Worker kMeromorphicFunctionsOnComplexPlane = 1345*61c4878aSAndroid Build Coastguard Worker MEROMORPHIC_FUNCTIONS_ON_COMPLEX_PLANE, 1346*61c4878aSAndroid Build Coastguard Worker kOther = OTHER, 1347*61c4878aSAndroid Build Coastguard Worker }; 1348*61c4878aSAndroid Build Coastguard Worker 1349*61c4878aSAndroid Build Coastguard Worker struct Function::Message { 1350*61c4878aSAndroid Build Coastguard Worker Function::Message_::Message description; 1351*61c4878aSAndroid Build Coastguard Worker Function::Fields_ domain; 1352*61c4878aSAndroid Build Coastguard Worker Function::Fields_ codomain; 1353*61c4878aSAndroid Build Coastguard Worker }; 1354*61c4878aSAndroid Build Coastguard Worker 1355*61c4878aSAndroid Build Coastguard Worker enum class Function::Fields : uint32_t { 1356*61c4878aSAndroid Build Coastguard Worker DESCRIPTION = 1, 1357*61c4878aSAndroid Build Coastguard Worker DOMAIN = 2, 1358*61c4878aSAndroid Build Coastguard Worker CODOMAIN = 3, 1359*61c4878aSAndroid Build Coastguard Worker }; 1360*61c4878aSAndroid Build Coastguard Worker 1361*61c4878aSAndroid Build Coastguard Worker.. warning:: 1362*61c4878aSAndroid Build Coastguard Worker Note that the C++ spec also reserves two categories of identifiers for the 1363*61c4878aSAndroid Build Coastguard Worker compiler to use in ways that may conflict with generated code: 1364*61c4878aSAndroid Build Coastguard Worker 1365*61c4878aSAndroid Build Coastguard Worker * Any identifier that contains two consecutive underscores anywhere in it. 1366*61c4878aSAndroid Build Coastguard Worker * Any identifier that starts with an underscore followed by a capital letter. 1367*61c4878aSAndroid Build Coastguard Worker 1368*61c4878aSAndroid Build Coastguard Worker Appending underscores to symbols in these categories wouldn't change the fact 1369*61c4878aSAndroid Build Coastguard Worker that they match patterns reserved for the compiler, so the codegen does not 1370*61c4878aSAndroid Build Coastguard Worker currently attempt to fix them. Such names will therefore result in 1371*61c4878aSAndroid Build Coastguard Worker non-portable code that may or may not work depending on the compiler. These 1372*61c4878aSAndroid Build Coastguard Worker naming patterns are of course strongly discouraged in any protobufs that will 1373*61c4878aSAndroid Build Coastguard Worker be used with ``pw_protobuf`` codegen. 1374*61c4878aSAndroid Build Coastguard Worker 1375*61c4878aSAndroid Build Coastguard WorkerOverhead 1376*61c4878aSAndroid Build Coastguard Worker======== 1377*61c4878aSAndroid Build Coastguard WorkerA single encoder and decoder is used for these structures, with a one-time code 1378*61c4878aSAndroid Build Coastguard Workercost. When the code generator creates the ``struct Message``, it also creates 1379*61c4878aSAndroid Build Coastguard Workera description of this structure that the shared encoder and decoder use. 1380*61c4878aSAndroid Build Coastguard Worker 1381*61c4878aSAndroid Build Coastguard WorkerThe cost of this description is a shared table for each protobuf message 1382*61c4878aSAndroid Build Coastguard Workerdefinition used, with four words per field within the protobuf message, and an 1383*61c4878aSAndroid Build Coastguard Workeraddition word to store the size of the table. 1384*61c4878aSAndroid Build Coastguard Worker 1385*61c4878aSAndroid Build Coastguard Worker-------- 1386*61c4878aSAndroid Build Coastguard WorkerEncoding 1387*61c4878aSAndroid Build Coastguard Worker-------- 1388*61c4878aSAndroid Build Coastguard WorkerThe simplest way to use ``MemoryEncoder`` to encode a proto is from its code 1389*61c4878aSAndroid Build Coastguard Workergenerated ``Message`` structure into an in-memory buffer. 1390*61c4878aSAndroid Build Coastguard Worker 1391*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 1392*61c4878aSAndroid Build Coastguard Worker 1393*61c4878aSAndroid Build Coastguard Worker #include "my_protos/my_proto.pwpb.h" 1394*61c4878aSAndroid Build Coastguard Worker #include "pw_bytes/span.h" 1395*61c4878aSAndroid Build Coastguard Worker #include "pw_protobuf/encoder.h" 1396*61c4878aSAndroid Build Coastguard Worker #include "pw_status/status_with_size.h" 1397*61c4878aSAndroid Build Coastguard Worker 1398*61c4878aSAndroid Build Coastguard Worker // Writes a proto response to the provided buffer, returning the encode 1399*61c4878aSAndroid Build Coastguard Worker // status and number of bytes written. 1400*61c4878aSAndroid Build Coastguard Worker pw::StatusWithSize WriteProtoResponse(pw::ByteSpan response) { 1401*61c4878aSAndroid Build Coastguard Worker MyProto::Message message{} 1402*61c4878aSAndroid Build Coastguard Worker message.magic_number = 0x1a1a2b2b; 1403*61c4878aSAndroid Build Coastguard Worker message.favorite_food = "cookies"; 1404*61c4878aSAndroid Build Coastguard Worker message.calories = 600; 1405*61c4878aSAndroid Build Coastguard Worker 1406*61c4878aSAndroid Build Coastguard Worker // All proto writes are directly written to the `response` buffer. 1407*61c4878aSAndroid Build Coastguard Worker MyProto::MemoryEncoder encoder(response); 1408*61c4878aSAndroid Build Coastguard Worker encoder.Write(message); 1409*61c4878aSAndroid Build Coastguard Worker 1410*61c4878aSAndroid Build Coastguard Worker return pw::StatusWithSize(encoder.status(), encoder.size()); 1411*61c4878aSAndroid Build Coastguard Worker } 1412*61c4878aSAndroid Build Coastguard Worker 1413*61c4878aSAndroid Build Coastguard WorkerAll fields of a message are written, including those initialized to their 1414*61c4878aSAndroid Build Coastguard Workerdefault values. 1415*61c4878aSAndroid Build Coastguard Worker 1416*61c4878aSAndroid Build Coastguard WorkerAlternatively, for example if only a subset of fields are required to be 1417*61c4878aSAndroid Build Coastguard Workerencoded, fields can be written a field at a time through the code generated 1418*61c4878aSAndroid Build Coastguard Workeror lower-level APIs. This can be more convenient if finer grained control or 1419*61c4878aSAndroid Build Coastguard Workerother custom handling is required. 1420*61c4878aSAndroid Build Coastguard Worker 1421*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 1422*61c4878aSAndroid Build Coastguard Worker 1423*61c4878aSAndroid Build Coastguard Worker #include "my_protos/my_proto.pwpb.h" 1424*61c4878aSAndroid Build Coastguard Worker #include "pw_bytes/span.h" 1425*61c4878aSAndroid Build Coastguard Worker #include "pw_protobuf/encoder.h" 1426*61c4878aSAndroid Build Coastguard Worker #include "pw_status/status_with_size.h" 1427*61c4878aSAndroid Build Coastguard Worker 1428*61c4878aSAndroid Build Coastguard Worker // Writes a proto response to the provided buffer, returning the encode 1429*61c4878aSAndroid Build Coastguard Worker // status and number of bytes written. 1430*61c4878aSAndroid Build Coastguard Worker pw::StatusWithSize WriteProtoResponse(pw::ByteSpan response) { 1431*61c4878aSAndroid Build Coastguard Worker // All proto writes are directly written to the `response` buffer. 1432*61c4878aSAndroid Build Coastguard Worker MyProto::MemoryEncoder encoder(response); 1433*61c4878aSAndroid Build Coastguard Worker encoder.WriteMagicNumber(0x1a1a2b2b); 1434*61c4878aSAndroid Build Coastguard Worker encoder.WriteFavoriteFood("cookies"); 1435*61c4878aSAndroid Build Coastguard Worker // Only conditionally write calories. 1436*61c4878aSAndroid Build Coastguard Worker if (on_diet) { 1437*61c4878aSAndroid Build Coastguard Worker encoder.WriteCalories(600); 1438*61c4878aSAndroid Build Coastguard Worker } 1439*61c4878aSAndroid Build Coastguard Worker return pw::StatusWithSize(encoder.status(), encoder.size()); 1440*61c4878aSAndroid Build Coastguard Worker } 1441*61c4878aSAndroid Build Coastguard Worker 1442*61c4878aSAndroid Build Coastguard WorkerStreamEncoder 1443*61c4878aSAndroid Build Coastguard Worker============= 1444*61c4878aSAndroid Build Coastguard Worker``StreamEncoder`` is constructed with the destination stream, and a scratch 1445*61c4878aSAndroid Build Coastguard Workerbuffer used to handle nested submessages. 1446*61c4878aSAndroid Build Coastguard Worker 1447*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 1448*61c4878aSAndroid Build Coastguard Worker 1449*61c4878aSAndroid Build Coastguard Worker #include "my_protos/my_proto.pwpb.h" 1450*61c4878aSAndroid Build Coastguard Worker #include "pw_bytes/span.h" 1451*61c4878aSAndroid Build Coastguard Worker #include "pw_protobuf/encoder.h" 1452*61c4878aSAndroid Build Coastguard Worker #include "pw_stream/sys_io_stream.h" 1453*61c4878aSAndroid Build Coastguard Worker 1454*61c4878aSAndroid Build Coastguard Worker pw::stream::SysIoWriter sys_io_writer; 1455*61c4878aSAndroid Build Coastguard Worker MyProto::StreamEncoder encoder(sys_io_writer, pw::ByteSpan()); 1456*61c4878aSAndroid Build Coastguard Worker 1457*61c4878aSAndroid Build Coastguard Worker // Once this line returns, the field has been written to the Writer. 1458*61c4878aSAndroid Build Coastguard Worker encoder.WriteTimestamp(system::GetUnixEpoch()); 1459*61c4878aSAndroid Build Coastguard Worker 1460*61c4878aSAndroid Build Coastguard Worker // There's no intermediate buffering when writing a string directly to a 1461*61c4878aSAndroid Build Coastguard Worker // StreamEncoder. 1462*61c4878aSAndroid Build Coastguard Worker encoder.WriteWelcomeMessage("Welcome to Pigweed!"); 1463*61c4878aSAndroid Build Coastguard Worker 1464*61c4878aSAndroid Build Coastguard Worker if (!encoder.status().ok()) { 1465*61c4878aSAndroid Build Coastguard Worker PW_LOG_INFO("Failed to encode proto; %s", encoder.status().str()); 1466*61c4878aSAndroid Build Coastguard Worker } 1467*61c4878aSAndroid Build Coastguard Worker 1468*61c4878aSAndroid Build Coastguard WorkerCallbacks 1469*61c4878aSAndroid Build Coastguard Worker========= 1470*61c4878aSAndroid Build Coastguard WorkerWhen using the ``Write()`` method with a ``struct Message``, certain fields may 1471*61c4878aSAndroid Build Coastguard Workerrequire a callback function be set to encode the values for those fields. 1472*61c4878aSAndroid Build Coastguard WorkerOtherwise the values will be treated as an empty repeated field and not encoded. 1473*61c4878aSAndroid Build Coastguard Worker 1474*61c4878aSAndroid Build Coastguard WorkerThe callback is called with the cursor at the field in question, and passed 1475*61c4878aSAndroid Build Coastguard Workera reference to the typed encoder that can write the required values to the 1476*61c4878aSAndroid Build Coastguard Workerstream or buffer. 1477*61c4878aSAndroid Build Coastguard Worker 1478*61c4878aSAndroid Build Coastguard WorkerCallback implementations may use any level of API. For example a callback for a 1479*61c4878aSAndroid Build Coastguard Workernested submessage (with a dependency cycle, or repeated) can be implemented by 1480*61c4878aSAndroid Build Coastguard Workercalling ``Write()`` on a nested encoder. 1481*61c4878aSAndroid Build Coastguard Worker 1482*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 1483*61c4878aSAndroid Build Coastguard Worker 1484*61c4878aSAndroid Build Coastguard Worker Store::Message store{}; 1485*61c4878aSAndroid Build Coastguard Worker store.employees.SetEncoder([](Store::StreamEncoder& encoder) { 1486*61c4878aSAndroid Build Coastguard Worker Employee::Message employee{}; 1487*61c4878aSAndroid Build Coastguard Worker // Populate `employee`. 1488*61c4878aSAndroid Build Coastguard Worker return encoder.GetEmployeesEncoder().Write(employee); 1489*61c4878aSAndroid Build Coastguard Worker )); 1490*61c4878aSAndroid Build Coastguard Worker 1491*61c4878aSAndroid Build Coastguard WorkerNested submessages 1492*61c4878aSAndroid Build Coastguard Worker================== 1493*61c4878aSAndroid Build Coastguard WorkerCode generated ``GetFieldEncoder`` methods are provided that return a correctly 1494*61c4878aSAndroid Build Coastguard Workertyped ``StreamEncoder`` or ``MemoryEncoder`` for the message. 1495*61c4878aSAndroid Build Coastguard Worker 1496*61c4878aSAndroid Build Coastguard Worker.. code-block:: protobuf 1497*61c4878aSAndroid Build Coastguard Worker 1498*61c4878aSAndroid Build Coastguard Worker message Owner { 1499*61c4878aSAndroid Build Coastguard Worker Animal pet = 1; 1500*61c4878aSAndroid Build Coastguard Worker } 1501*61c4878aSAndroid Build Coastguard Worker 1502*61c4878aSAndroid Build Coastguard WorkerNote that the accessor method is named for the field, while the returned encoder 1503*61c4878aSAndroid Build Coastguard Workeris named for the message type. 1504*61c4878aSAndroid Build Coastguard Worker 1505*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Animal::StreamEncoder Owner::StreamEncoder::GetPetEncoder() 1506*61c4878aSAndroid Build Coastguard Worker 1507*61c4878aSAndroid Build Coastguard WorkerA lower-level API method returns an untyped encoder, which only provides the 1508*61c4878aSAndroid Build Coastguard Workerlower-level API methods. This can be cast to a typed encoder if needed. 1509*61c4878aSAndroid Build Coastguard Worker 1510*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: pw::protobuf::StreamEncoder pw::protobuf::StreamEncoder::GetNestedEncoder(uint32_t field_number, EmptyEncoderBehavior empty_encoder_behavior = EmptyEncoderBehavior::kWriteFieldNumber) 1511*61c4878aSAndroid Build Coastguard Worker 1512*61c4878aSAndroid Build Coastguard Worker(The optional `empty_encoder_behavior` parameter allows the user to disable 1513*61c4878aSAndroid Build Coastguard Workerwriting the tag number for the nested encoder, if no data was written to 1514*61c4878aSAndroid Build Coastguard Workerthat nested decoder.) 1515*61c4878aSAndroid Build Coastguard Worker 1516*61c4878aSAndroid Build Coastguard Worker.. warning:: 1517*61c4878aSAndroid Build Coastguard Worker When a nested submessage is created, any use of the parent encoder that 1518*61c4878aSAndroid Build Coastguard Worker created the nested encoder will trigger a crash. To resume using the parent 1519*61c4878aSAndroid Build Coastguard Worker encoder, destroy the submessage encoder first. 1520*61c4878aSAndroid Build Coastguard Worker 1521*61c4878aSAndroid Build Coastguard WorkerBuffering 1522*61c4878aSAndroid Build Coastguard Worker--------- 1523*61c4878aSAndroid Build Coastguard WorkerWriting proto messages with nested submessages requires buffering due to 1524*61c4878aSAndroid Build Coastguard Workerlimitations of the proto format. Every proto submessage must know the size of 1525*61c4878aSAndroid Build Coastguard Workerthe submessage before its final serialization can begin. A streaming encoder can 1526*61c4878aSAndroid Build Coastguard Workerbe passed a scratch buffer to use when constructing nested messages. All 1527*61c4878aSAndroid Build Coastguard Workersubmessage data is buffered to this scratch buffer until the submessage is 1528*61c4878aSAndroid Build Coastguard Workerfinalized. Note that the contents of this scratch buffer is not necessarily 1529*61c4878aSAndroid Build Coastguard Workervalid proto data, so don't try to use it directly. 1530*61c4878aSAndroid Build Coastguard Worker 1531*61c4878aSAndroid Build Coastguard WorkerThe code generation includes a ``kScratchBufferSizeBytes`` constant that 1532*61c4878aSAndroid Build Coastguard Workerrepresents the size of the largest submessage and all necessary overhead, 1533*61c4878aSAndroid Build Coastguard Workerexcluding the contents of any field values which require a callback. 1534*61c4878aSAndroid Build Coastguard Worker 1535*61c4878aSAndroid Build Coastguard WorkerIf a submessage field requires a callback, due to a dependency cycle, or a 1536*61c4878aSAndroid Build Coastguard Workerrepeated field of unknown length, the size of the submessage cannot be included 1537*61c4878aSAndroid Build Coastguard Workerin the ``kScratchBufferSizeBytes`` constant. If you encode a submessage of this 1538*61c4878aSAndroid Build Coastguard Workertype (which you'll know you're doing because you set an encoder callback for it) 1539*61c4878aSAndroid Build Coastguard Workersimply add the appropriate structure's ``kMaxEncodedSizeBytes`` constant to the 1540*61c4878aSAndroid Build Coastguard Workerscratch buffer size to guarantee enough space. 1541*61c4878aSAndroid Build Coastguard Worker 1542*61c4878aSAndroid Build Coastguard WorkerWhen calculating yourself, the ``MaxScratchBufferSize()`` helper function can 1543*61c4878aSAndroid Build Coastguard Workeralso be useful in estimating how much space to allocate to account for nested 1544*61c4878aSAndroid Build Coastguard Workersubmessage encoding overhead. 1545*61c4878aSAndroid Build Coastguard Worker 1546*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 1547*61c4878aSAndroid Build Coastguard Worker 1548*61c4878aSAndroid Build Coastguard Worker #include "my_protos/pets.pwpb.h" 1549*61c4878aSAndroid Build Coastguard Worker #include "pw_bytes/span.h" 1550*61c4878aSAndroid Build Coastguard Worker #include "pw_protobuf/encoder.h" 1551*61c4878aSAndroid Build Coastguard Worker #include "pw_stream/sys_io_stream.h" 1552*61c4878aSAndroid Build Coastguard Worker 1553*61c4878aSAndroid Build Coastguard Worker pw::stream::SysIoWriter sys_io_writer; 1554*61c4878aSAndroid Build Coastguard Worker // The scratch buffer should be at least as big as the largest nested 1555*61c4878aSAndroid Build Coastguard Worker // submessage. It's a good idea to be a little generous. 1556*61c4878aSAndroid Build Coastguard Worker std::byte submessage_scratch_buffer[Owner::kScratchBufferSizeBytes]; 1557*61c4878aSAndroid Build Coastguard Worker 1558*61c4878aSAndroid Build Coastguard Worker // Provide the scratch buffer to the proto encoder. The buffer's lifetime must 1559*61c4878aSAndroid Build Coastguard Worker // match the lifetime of the encoder. 1560*61c4878aSAndroid Build Coastguard Worker Owner::StreamEncoder owner_encoder(sys_io_writer, submessage_scratch_buffer); 1561*61c4878aSAndroid Build Coastguard Worker 1562*61c4878aSAndroid Build Coastguard Worker { 1563*61c4878aSAndroid Build Coastguard Worker // Note that the parent encoder, owner_encoder, cannot be used until the 1564*61c4878aSAndroid Build Coastguard Worker // nested encoder, pet_encoder, has been destroyed. 1565*61c4878aSAndroid Build Coastguard Worker Animal::StreamEncoder pet_encoder = owner_encoder.GetPetEncoder(); 1566*61c4878aSAndroid Build Coastguard Worker 1567*61c4878aSAndroid Build Coastguard Worker // There's intermediate buffering when writing to a nested encoder. 1568*61c4878aSAndroid Build Coastguard Worker pet_encoder.WriteName("Spot"); 1569*61c4878aSAndroid Build Coastguard Worker pet_encoder.WriteType(Pet::Type::DOG); 1570*61c4878aSAndroid Build Coastguard Worker 1571*61c4878aSAndroid Build Coastguard Worker // When this scope ends, the nested encoder is serialized to the Writer. 1572*61c4878aSAndroid Build Coastguard Worker // In addition, the parent encoder, owner_encoder, can be used again. 1573*61c4878aSAndroid Build Coastguard Worker } 1574*61c4878aSAndroid Build Coastguard Worker 1575*61c4878aSAndroid Build Coastguard Worker // If an encode error occurs when encoding the nested messages, it will be 1576*61c4878aSAndroid Build Coastguard Worker // reflected at the root encoder. 1577*61c4878aSAndroid Build Coastguard Worker if (!owner_encoder.status().ok()) { 1578*61c4878aSAndroid Build Coastguard Worker PW_LOG_INFO("Failed to encode proto; %s", owner_encoder.status().str()); 1579*61c4878aSAndroid Build Coastguard Worker } 1580*61c4878aSAndroid Build Coastguard Worker 1581*61c4878aSAndroid Build Coastguard WorkerMemoryEncoder objects use the final destination buffer rather than relying on a 1582*61c4878aSAndroid Build Coastguard Workerscratch buffer. The ``kMaxEncodedSizeBytes`` constant takes into account the 1583*61c4878aSAndroid Build Coastguard Workeroverhead required for nesting submessages. If you calculate the buffer size 1584*61c4878aSAndroid Build Coastguard Workeryourself, your destination buffer might need additional space. 1585*61c4878aSAndroid Build Coastguard Worker 1586*61c4878aSAndroid Build Coastguard Worker.. warning:: 1587*61c4878aSAndroid Build Coastguard Worker If the scratch buffer size is not sufficient, the encoding will fail with 1588*61c4878aSAndroid Build Coastguard Worker ``Status::ResourceExhausted()``. Always check the results of ``Write`` calls 1589*61c4878aSAndroid Build Coastguard Worker or the encoder status to ensure success, as otherwise the encoded data will 1590*61c4878aSAndroid Build Coastguard Worker be invalid. 1591*61c4878aSAndroid Build Coastguard Worker 1592*61c4878aSAndroid Build Coastguard WorkerScalar Fields 1593*61c4878aSAndroid Build Coastguard Worker============= 1594*61c4878aSAndroid Build Coastguard WorkerAs shown, scalar fields are written using code generated ``WriteFoo`` 1595*61c4878aSAndroid Build Coastguard Workermethods that accept the appropriate type and automatically writes the correct 1596*61c4878aSAndroid Build Coastguard Workerfield number. 1597*61c4878aSAndroid Build Coastguard Worker 1598*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status MyProto::StreamEncoder::WriteFoo(T) 1599*61c4878aSAndroid Build Coastguard Worker 1600*61c4878aSAndroid Build Coastguard WorkerThese can be freely intermixed with the lower-level API that provides a method 1601*61c4878aSAndroid Build Coastguard Workerper field type, requiring that the field number be passed in. The code 1602*61c4878aSAndroid Build Coastguard Workergeneration includes a ``Fields`` enum to provide the field number values. 1603*61c4878aSAndroid Build Coastguard Worker 1604*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamEncoder::WriteUint64(uint32_t field_number, uint64_t) 1605*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamEncoder::WriteSint64(uint32_t field_number, int64_t) 1606*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamEncoder::WriteInt64(uint32_t field_number, int64_t) 1607*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamEncoder::WriteUint32(uint32_t field_number, uint32_t) 1608*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamEncoder::WriteSint32(uint32_t field_number, int32_t) 1609*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamEncoder::WriteInt32(uint32_t field_number, int32_t) 1610*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamEncoder::WriteFixed64(uint32_t field_number, uint64_t) 1611*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamEncoder::WriteFixed32(uint32_t field_number, uint64_t) 1612*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamEncoder::WriteDouble(uint32_t field_number, double) 1613*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamEncoder::WriteFloat(uint32_t field_number, float) 1614*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamEncoder::WriteBool(uint32_t field_number, bool) 1615*61c4878aSAndroid Build Coastguard Worker 1616*61c4878aSAndroid Build Coastguard WorkerThe following two method calls are equivalent, where the first is using the 1617*61c4878aSAndroid Build Coastguard Workercode generated API, and the second implemented by hand. 1618*61c4878aSAndroid Build Coastguard Worker 1619*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 1620*61c4878aSAndroid Build Coastguard Worker 1621*61c4878aSAndroid Build Coastguard Worker my_proto_encoder.WriteAge(42); 1622*61c4878aSAndroid Build Coastguard Worker my_proto_encoder.WriteInt32(static_cast<uint32_t>(MyProto::Fields::kAge), 42); 1623*61c4878aSAndroid Build Coastguard Worker 1624*61c4878aSAndroid Build Coastguard WorkerRepeated Fields 1625*61c4878aSAndroid Build Coastguard Worker--------------- 1626*61c4878aSAndroid Build Coastguard WorkerFor repeated scalar fields, multiple code generated ``WriteFoos`` methods 1627*61c4878aSAndroid Build Coastguard Workerare provided. 1628*61c4878aSAndroid Build Coastguard Worker 1629*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status MyProto::StreamEncoder::WriteFoos(T) 1630*61c4878aSAndroid Build Coastguard Worker 1631*61c4878aSAndroid Build Coastguard Worker This writes a single unpacked value. 1632*61c4878aSAndroid Build Coastguard Worker 1633*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status MyProto::StreamEncoder::WriteFoos(pw::span<const T>) 1634*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status MyProto::StreamEncoder::WriteFoos(const pw::Vector<T>&) 1635*61c4878aSAndroid Build Coastguard Worker 1636*61c4878aSAndroid Build Coastguard Worker These write a packed field containing all of the values in the provided span 1637*61c4878aSAndroid Build Coastguard Worker or vector. 1638*61c4878aSAndroid Build Coastguard Worker 1639*61c4878aSAndroid Build Coastguard WorkerThese too can be freely intermixed with the lower-level API methods, both to 1640*61c4878aSAndroid Build Coastguard Workerwrite a single value, or to write packed values from either a ``pw::span`` or 1641*61c4878aSAndroid Build Coastguard Worker``pw::Vector`` source. 1642*61c4878aSAndroid Build Coastguard Worker 1643*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamEncoder::WritePackedUint64(uint32_t field_number, pw::span<const uint64_t>) 1644*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamEncoder::WriteRepeatedUint64(uint32_t field_number, const pw::Vector<uint64_t>&) 1645*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamEncoder::WritePackedSint64(uint32_t field_number, pw::span<const int64_t>) 1646*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamEncoder::WriteRepeatedSint64(uint32_t field_number, const pw::Vector<int64_t>&) 1647*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamEncoder::WritePackedInt64(uint32_t field_number, pw::span<const int64_t>) 1648*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamEncoder::WriteRepeatedInt64(uint32_t field_number, const pw::Vector<int64_t>&) 1649*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamEncoder::WritePackedUint32(uint32_t field_number, pw::span<const uint32_t>) 1650*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamEncoder::WriteRepeatedUint32(uint32_t field_number, const pw::Vector<uint32_t>&) 1651*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamEncoder::WritePackedSint32(uint32_t field_number, pw::span<const int32_t>) 1652*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamEncoder::WriteRepeatedSint32(uint32_t field_number, const pw::Vector<int32_t>&) 1653*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamEncoder::WritePackedInt32(uint32_t field_number, pw::span<const int32_t>) 1654*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamEncoder::WriteRepeatedInt32(uint32_t field_number, const pw::Vector<int32_t>&) 1655*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamEncoder::WritePackedFixed64(uint32_t field_number, pw::span<const uint64_t>) 1656*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamEncoder::WriteRepeatedFixed64(uint32_t field_number, const pw::Vector<uint64_t>&) 1657*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamEncoder::WritePackedFixed32(uint32_t field_number, pw::span<const uint64_t>) 1658*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamEncoder::WriteRepeatedFixed32(uint32_t field_number, const pw::Vector<uint64_t>&) 1659*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamEncoder::WritePackedDouble(uint32_t field_number, pw::span<const double>) 1660*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamEncoder::WriteRepeatedDouble(uint32_t field_number, const pw::Vector<double>&) 1661*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamEncoder::WritePackedFloat(uint32_t field_number, pw::span<const float>) 1662*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamEncoder::WriteRepeatedFloat(uint32_t field_number, const pw::Vector<float>&) 1663*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamEncoder::WritePackedBool(uint32_t field_number, pw::span<const bool>) 1664*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamEncoder::WriteRepeatedBool(uint32_t field_number, const pw::Vector<bool>&) 1665*61c4878aSAndroid Build Coastguard Worker 1666*61c4878aSAndroid Build Coastguard WorkerThe following two method calls are equivalent, where the first is using the 1667*61c4878aSAndroid Build Coastguard Workercode generated API, and the second implemented by hand. 1668*61c4878aSAndroid Build Coastguard Worker 1669*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 1670*61c4878aSAndroid Build Coastguard Worker 1671*61c4878aSAndroid Build Coastguard Worker constexpr std::array<int32_t, 5> numbers = { 4, 8, 15, 16, 23, 42 }; 1672*61c4878aSAndroid Build Coastguard Worker 1673*61c4878aSAndroid Build Coastguard Worker my_proto_encoder.WriteNumbers(numbers); 1674*61c4878aSAndroid Build Coastguard Worker my_proto_encoder.WritePackedInt32( 1675*61c4878aSAndroid Build Coastguard Worker static_cast<uint32_t>(MyProto::Fields::kNumbers), 1676*61c4878aSAndroid Build Coastguard Worker numbers); 1677*61c4878aSAndroid Build Coastguard Worker 1678*61c4878aSAndroid Build Coastguard WorkerEnumerations 1679*61c4878aSAndroid Build Coastguard Worker============ 1680*61c4878aSAndroid Build Coastguard WorkerEnumerations are written using code generated ``WriteEnum`` methods that 1681*61c4878aSAndroid Build Coastguard Workeraccept the code generated enumeration as the appropriate type and automatically 1682*61c4878aSAndroid Build Coastguard Workerwrites both the correct field number and corresponding value. 1683*61c4878aSAndroid Build Coastguard Worker 1684*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status MyProto::StreamEncoder::WriteEnum(MyProto::Enum) 1685*61c4878aSAndroid Build Coastguard Worker 1686*61c4878aSAndroid Build Coastguard WorkerTo write enumerations with the lower-level API, you would need to cast both 1687*61c4878aSAndroid Build Coastguard Workerthe field number and value to the ``uint32_t`` type. 1688*61c4878aSAndroid Build Coastguard Worker 1689*61c4878aSAndroid Build Coastguard WorkerThe following two methods are equivalent, where the first is code generated, 1690*61c4878aSAndroid Build Coastguard Workerand the second implemented by hand. 1691*61c4878aSAndroid Build Coastguard Worker 1692*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 1693*61c4878aSAndroid Build Coastguard Worker 1694*61c4878aSAndroid Build Coastguard Worker my_proto_encoder.WriteAward(MyProto::Award::SILVER); 1695*61c4878aSAndroid Build Coastguard Worker my_proto_encoder.WriteUint32( 1696*61c4878aSAndroid Build Coastguard Worker static_cast<uint32_t>(MyProto::Fields::kAward), 1697*61c4878aSAndroid Build Coastguard Worker static_cast<uint32_t>(MyProto::Award::SILVER)); 1698*61c4878aSAndroid Build Coastguard Worker 1699*61c4878aSAndroid Build Coastguard WorkerRepeated Fields 1700*61c4878aSAndroid Build Coastguard Worker--------------- 1701*61c4878aSAndroid Build Coastguard WorkerFor repeated enum fields, multiple code generated ``WriteEnums`` methods 1702*61c4878aSAndroid Build Coastguard Workerare provided. 1703*61c4878aSAndroid Build Coastguard Worker 1704*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status MyProto::StreamEncoder::WriteEnums(MyProto::Enums) 1705*61c4878aSAndroid Build Coastguard Worker 1706*61c4878aSAndroid Build Coastguard Worker This writes a single unpacked value. 1707*61c4878aSAndroid Build Coastguard Worker 1708*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status MyProto::StreamEncoder::WriteEnums(pw::span<const MyProto::Enums>) 1709*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status MyProto::StreamEncoder::WriteEnums(const pw::Vector<MyProto::Enums>&) 1710*61c4878aSAndroid Build Coastguard Worker 1711*61c4878aSAndroid Build Coastguard Worker These write a packed field containing all of the values in the provided span 1712*61c4878aSAndroid Build Coastguard Worker or vector. 1713*61c4878aSAndroid Build Coastguard Worker 1714*61c4878aSAndroid Build Coastguard WorkerTheir use is as scalar fields. 1715*61c4878aSAndroid Build Coastguard Worker 1716*61c4878aSAndroid Build Coastguard WorkerStrings 1717*61c4878aSAndroid Build Coastguard Worker======= 1718*61c4878aSAndroid Build Coastguard WorkerStrings fields have multiple code generated methods provided. 1719*61c4878aSAndroid Build Coastguard Worker 1720*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status MyProto::StreamEncoder::WriteName(std::string_view) 1721*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status MyProto::StreamEncoder::WriteName(const char*, size_t) 1722*61c4878aSAndroid Build Coastguard Worker 1723*61c4878aSAndroid Build Coastguard WorkerThese can be freely intermixed with the lower-level API methods. 1724*61c4878aSAndroid Build Coastguard Worker 1725*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamEncoder::WriteString(uint32_t field_number, std::string_view) 1726*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamEncoder::WriteString(uint32_t field_number, const char*, size_t) 1727*61c4878aSAndroid Build Coastguard Worker 1728*61c4878aSAndroid Build Coastguard WorkerA lower level API method is provided that can write a string from another 1729*61c4878aSAndroid Build Coastguard Workerstream. 1730*61c4878aSAndroid Build Coastguard Worker 1731*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamEncoder::WriteStringFromStream(uint32_t field_number, stream::Reader& bytes_reader, size_t num_bytes, ByteSpan stream_pipe_buffer) 1732*61c4878aSAndroid Build Coastguard Worker 1733*61c4878aSAndroid Build Coastguard Worker The payload for the value is provided through the stream::Reader 1734*61c4878aSAndroid Build Coastguard Worker ``bytes_reader``. The method reads a chunk of the data from the reader using 1735*61c4878aSAndroid Build Coastguard Worker the ``stream_pipe_buffer`` and writes it to the encoder. 1736*61c4878aSAndroid Build Coastguard Worker 1737*61c4878aSAndroid Build Coastguard WorkerBytes 1738*61c4878aSAndroid Build Coastguard Worker===== 1739*61c4878aSAndroid Build Coastguard WorkerBytes fields provide the ``WriteData`` code generated method. 1740*61c4878aSAndroid Build Coastguard Worker 1741*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status MyProto::StreamEncoder::WriteData(ConstByteSpan) 1742*61c4878aSAndroid Build Coastguard Worker 1743*61c4878aSAndroid Build Coastguard WorkerThis can be freely intermixed with the lower-level API method. 1744*61c4878aSAndroid Build Coastguard Worker 1745*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamEncoder::WriteBytes(uint32_t field_number, ConstByteSpan) 1746*61c4878aSAndroid Build Coastguard Worker 1747*61c4878aSAndroid Build Coastguard WorkerAnd with the API method that can write bytes from another stream. 1748*61c4878aSAndroid Build Coastguard Worker 1749*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamEncoder::WriteBytesFromStream(uint32_t field_number, stream::Reader& bytes_reader, size_t num_bytes, ByteSpan stream_pipe_buffer) 1750*61c4878aSAndroid Build Coastguard Worker 1751*61c4878aSAndroid Build Coastguard Worker The payload for the value is provided through the stream::Reader 1752*61c4878aSAndroid Build Coastguard Worker ``bytes_reader``. The method reads a chunk of the data from the reader using 1753*61c4878aSAndroid Build Coastguard Worker the ``stream_pipe_buffer`` and writes it to the encoder. 1754*61c4878aSAndroid Build Coastguard Worker 1755*61c4878aSAndroid Build Coastguard WorkerError Handling 1756*61c4878aSAndroid Build Coastguard Worker============== 1757*61c4878aSAndroid Build Coastguard WorkerWhile individual write calls on a proto encoder return ``pw::Status`` objects, 1758*61c4878aSAndroid Build Coastguard Workerthe encoder tracks all status returns and "latches" onto the first error 1759*61c4878aSAndroid Build Coastguard Workerencountered. This status can be accessed via ``StreamEncoder::status()``. 1760*61c4878aSAndroid Build Coastguard Worker 1761*61c4878aSAndroid Build Coastguard WorkerProto map encoding utils 1762*61c4878aSAndroid Build Coastguard Worker======================== 1763*61c4878aSAndroid Build Coastguard WorkerSome additional helpers for encoding more complex but common protobuf 1764*61c4878aSAndroid Build Coastguard Workersubmessages (e.g. ``map<string, bytes>``) are provided in 1765*61c4878aSAndroid Build Coastguard Worker``pw_protobuf/map_utils.h``. 1766*61c4878aSAndroid Build Coastguard Worker 1767*61c4878aSAndroid Build Coastguard Worker.. note:: 1768*61c4878aSAndroid Build Coastguard Worker The helper API are currently in-development and may not remain stable. 1769*61c4878aSAndroid Build Coastguard Worker 1770*61c4878aSAndroid Build Coastguard Worker-------- 1771*61c4878aSAndroid Build Coastguard WorkerDecoding 1772*61c4878aSAndroid Build Coastguard Worker-------- 1773*61c4878aSAndroid Build Coastguard WorkerThe simplest way to use ``StreamDecoder`` is to decode a proto from the stream 1774*61c4878aSAndroid Build Coastguard Workerinto its code generated ``Message`` structure. 1775*61c4878aSAndroid Build Coastguard Worker 1776*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 1777*61c4878aSAndroid Build Coastguard Worker 1778*61c4878aSAndroid Build Coastguard Worker #include "my_protos/my_proto.pwpb.h" 1779*61c4878aSAndroid Build Coastguard Worker #include "pw_protobuf/stream_decoder.h" 1780*61c4878aSAndroid Build Coastguard Worker #include "pw_status/status.h" 1781*61c4878aSAndroid Build Coastguard Worker #include "pw_stream/stream.h" 1782*61c4878aSAndroid Build Coastguard Worker 1783*61c4878aSAndroid Build Coastguard Worker pw::Status DecodeProtoFromStream(pw::stream::Reader& reader) { 1784*61c4878aSAndroid Build Coastguard Worker MyProto::Message message{}; 1785*61c4878aSAndroid Build Coastguard Worker MyProto::StreamDecoder decoder(reader); 1786*61c4878aSAndroid Build Coastguard Worker decoder.Read(message); 1787*61c4878aSAndroid Build Coastguard Worker return decoder.status(); 1788*61c4878aSAndroid Build Coastguard Worker } 1789*61c4878aSAndroid Build Coastguard Worker 1790*61c4878aSAndroid Build Coastguard WorkerIn the case of errors, the decoding will stop and return with the cursor on the 1791*61c4878aSAndroid Build Coastguard Workerfield that caused the error. It is valid in some cases to inspect the error and 1792*61c4878aSAndroid Build Coastguard Workercontinue decoding by calling ``Read()`` again on the same structure, or fall 1793*61c4878aSAndroid Build Coastguard Workerback to using the lower-level APIs. 1794*61c4878aSAndroid Build Coastguard Worker 1795*61c4878aSAndroid Build Coastguard WorkerUnknown fields in the wire encoding are skipped. 1796*61c4878aSAndroid Build Coastguard Worker 1797*61c4878aSAndroid Build Coastguard WorkerIf finer-grained control is required, the ``StreamDecoder`` class provides an 1798*61c4878aSAndroid Build Coastguard Workeriterator-style API for processing a message a field at a time where calling 1799*61c4878aSAndroid Build Coastguard Worker``Next()`` advances the decoder to the next proto field. 1800*61c4878aSAndroid Build Coastguard Worker 1801*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamDecoder::Next() 1802*61c4878aSAndroid Build Coastguard Worker 1803*61c4878aSAndroid Build Coastguard WorkerIn the code generated classes the ``Field()`` method returns the current field 1804*61c4878aSAndroid Build Coastguard Workeras a typed ``Fields`` enumeration member, while the lower-level API provides a 1805*61c4878aSAndroid Build Coastguard Worker``FieldNumber()`` method that returns the number of the field. 1806*61c4878aSAndroid Build Coastguard Worker 1807*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Result<MyProto::Fields> MyProto::StreamDecoder::Field() 1808*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Result<uint32_t> pw::protobuf::StreamDecoder::FieldNumber() 1809*61c4878aSAndroid Build Coastguard Worker 1810*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 1811*61c4878aSAndroid Build Coastguard Worker 1812*61c4878aSAndroid Build Coastguard Worker #include "my_protos/my_proto.pwpb.h" 1813*61c4878aSAndroid Build Coastguard Worker #include "pw_protobuf/strema_decoder.h" 1814*61c4878aSAndroid Build Coastguard Worker #include "pw_status/status.h" 1815*61c4878aSAndroid Build Coastguard Worker #include "pw_status/try.h" 1816*61c4878aSAndroid Build Coastguard Worker #include "pw_stream/stream.h" 1817*61c4878aSAndroid Build Coastguard Worker 1818*61c4878aSAndroid Build Coastguard Worker pw::Status DecodeProtoFromStream(pw::stream::Reader& reader) { 1819*61c4878aSAndroid Build Coastguard Worker MyProto::StreamDecoder decoder(reader); 1820*61c4878aSAndroid Build Coastguard Worker pw::Status status; 1821*61c4878aSAndroid Build Coastguard Worker 1822*61c4878aSAndroid Build Coastguard Worker uint32_t age; 1823*61c4878aSAndroid Build Coastguard Worker char name[16]; 1824*61c4878aSAndroid Build Coastguard Worker 1825*61c4878aSAndroid Build Coastguard Worker // Iterate over the fields in the message. A return value of OK indicates 1826*61c4878aSAndroid Build Coastguard Worker // that a valid field has been found and can be read. When the decoder 1827*61c4878aSAndroid Build Coastguard Worker // reaches the end of the message, Next() will return OUT_OF_RANGE. 1828*61c4878aSAndroid Build Coastguard Worker // Other return values indicate an error trying to decode the message. 1829*61c4878aSAndroid Build Coastguard Worker while ((status = decoder.Next()).ok()) { 1830*61c4878aSAndroid Build Coastguard Worker // Field() returns a Result<Fields> as it may fail sometimes. 1831*61c4878aSAndroid Build Coastguard Worker // However, Field() is guaranteed to be valid after a call to Next() 1832*61c4878aSAndroid Build Coastguard Worker // that returns OK, so the value can be used directly here. 1833*61c4878aSAndroid Build Coastguard Worker switch (decoder.Field().value()) { 1834*61c4878aSAndroid Build Coastguard Worker case MyProto::Fields::kAge: { 1835*61c4878aSAndroid Build Coastguard Worker PW_TRY_ASSIGN(age, decoder.ReadAge()); 1836*61c4878aSAndroid Build Coastguard Worker break; 1837*61c4878aSAndroid Build Coastguard Worker } 1838*61c4878aSAndroid Build Coastguard Worker case MyProto::Fields::kName: 1839*61c4878aSAndroid Build Coastguard Worker // The string field is copied into the provided buffer. If the buffer 1840*61c4878aSAndroid Build Coastguard Worker // is too small to fit the string, RESOURCE_EXHAUSTED is returned and 1841*61c4878aSAndroid Build Coastguard Worker // the decoder is not advanced, allowing the field to be re-read. 1842*61c4878aSAndroid Build Coastguard Worker PW_TRY(decoder.ReadName(name)); 1843*61c4878aSAndroid Build Coastguard Worker break; 1844*61c4878aSAndroid Build Coastguard Worker } 1845*61c4878aSAndroid Build Coastguard Worker } 1846*61c4878aSAndroid Build Coastguard Worker 1847*61c4878aSAndroid Build Coastguard Worker // Do something with the fields... 1848*61c4878aSAndroid Build Coastguard Worker 1849*61c4878aSAndroid Build Coastguard Worker return status.IsOutOfRange() ? OkStatus() : status; 1850*61c4878aSAndroid Build Coastguard Worker } 1851*61c4878aSAndroid Build Coastguard Worker 1852*61c4878aSAndroid Build Coastguard WorkerCallbacks 1853*61c4878aSAndroid Build Coastguard Worker========= 1854*61c4878aSAndroid Build Coastguard WorkerWhen using the ``Read()`` method with a ``struct Message``, certain fields may 1855*61c4878aSAndroid Build Coastguard Workerrequire a callback function be set, otherwise a ``DataLoss`` error will be 1856*61c4878aSAndroid Build Coastguard Workerreturned should that field be encountered in the wire encoding. 1857*61c4878aSAndroid Build Coastguard Worker 1858*61c4878aSAndroid Build Coastguard WorkerThe callback is called with the cursor at the field in question, and passed 1859*61c4878aSAndroid Build Coastguard Workera reference to the typed decoder that can examine the field and be used to 1860*61c4878aSAndroid Build Coastguard Workerdecode it. 1861*61c4878aSAndroid Build Coastguard Worker 1862*61c4878aSAndroid Build Coastguard WorkerCallback implementations may use any level of API. For example a callback for a 1863*61c4878aSAndroid Build Coastguard Workernested submessage (with a dependency cycle, or repeated) can be implemented by 1864*61c4878aSAndroid Build Coastguard Workercalling ``Read()`` on a nested decoder. 1865*61c4878aSAndroid Build Coastguard Worker 1866*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 1867*61c4878aSAndroid Build Coastguard Worker 1868*61c4878aSAndroid Build Coastguard Worker Store::Message store{}; 1869*61c4878aSAndroid Build Coastguard Worker store.employees.SetDecoder([](Store::StreamDecoder& decoder) { 1870*61c4878aSAndroid Build Coastguard Worker PW_ASSERT(decoder.Field().value() == Store::Fields::kEmployees); 1871*61c4878aSAndroid Build Coastguard Worker 1872*61c4878aSAndroid Build Coastguard Worker Employee::Message employee{}; 1873*61c4878aSAndroid Build Coastguard Worker // Set any callbacks on `employee`. 1874*61c4878aSAndroid Build Coastguard Worker PW_TRY(decoder.GetEmployeesDecoder().Read(employee)); 1875*61c4878aSAndroid Build Coastguard Worker // Do things with `employee`. 1876*61c4878aSAndroid Build Coastguard Worker return OkStatus(); 1877*61c4878aSAndroid Build Coastguard Worker )); 1878*61c4878aSAndroid Build Coastguard Worker 1879*61c4878aSAndroid Build Coastguard WorkerNested submessages 1880*61c4878aSAndroid Build Coastguard Worker================== 1881*61c4878aSAndroid Build Coastguard WorkerCode generated ``GetFieldDecoder`` methods are provided that return a correctly 1882*61c4878aSAndroid Build Coastguard Workertyped ``StreamDecoder`` for the message. 1883*61c4878aSAndroid Build Coastguard Worker 1884*61c4878aSAndroid Build Coastguard Worker.. code-block:: protobuf 1885*61c4878aSAndroid Build Coastguard Worker 1886*61c4878aSAndroid Build Coastguard Worker message Owner { 1887*61c4878aSAndroid Build Coastguard Worker Animal pet = 1; 1888*61c4878aSAndroid Build Coastguard Worker } 1889*61c4878aSAndroid Build Coastguard Worker 1890*61c4878aSAndroid Build Coastguard WorkerAs with encoding, note that the accessor method is named for the field, while 1891*61c4878aSAndroid Build Coastguard Workerthe returned decoder is named for the message type. 1892*61c4878aSAndroid Build Coastguard Worker 1893*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Animal::StreamDecoder Owner::StreamDecoder::GetPetDecoder() 1894*61c4878aSAndroid Build Coastguard Worker 1895*61c4878aSAndroid Build Coastguard WorkerA lower-level API method returns an untyped decoder, which only provides the 1896*61c4878aSAndroid Build Coastguard Workerlower-level API methods. This can be moved to a typed decoder later. 1897*61c4878aSAndroid Build Coastguard Worker 1898*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: pw::protobuf::StreamDecoder pw::protobuf::StreamDecoder::GetNestedDecoder() 1899*61c4878aSAndroid Build Coastguard Worker 1900*61c4878aSAndroid Build Coastguard Worker.. warning:: 1901*61c4878aSAndroid Build Coastguard Worker When a nested submessage is being decoded, any use of the parent decoder that 1902*61c4878aSAndroid Build Coastguard Worker created the nested decoder will trigger a crash. To resume using the parent 1903*61c4878aSAndroid Build Coastguard Worker decoder, destroy the submessage decoder first. 1904*61c4878aSAndroid Build Coastguard Worker 1905*61c4878aSAndroid Build Coastguard Worker 1906*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 1907*61c4878aSAndroid Build Coastguard Worker 1908*61c4878aSAndroid Build Coastguard Worker case Owner::Fields::kPet: { 1909*61c4878aSAndroid Build Coastguard Worker // Note that the parent decoder, owner_decoder, cannot be used until the 1910*61c4878aSAndroid Build Coastguard Worker // nested decoder, pet_decoder, has been destroyed. 1911*61c4878aSAndroid Build Coastguard Worker Animal::StreamDecoder pet_decoder = owner_decoder.GetPetDecoder(); 1912*61c4878aSAndroid Build Coastguard Worker 1913*61c4878aSAndroid Build Coastguard Worker while ((status = pet_decoder.Next()).ok()) { 1914*61c4878aSAndroid Build Coastguard Worker switch (pet_decoder.Field().value()) { 1915*61c4878aSAndroid Build Coastguard Worker // Decode pet fields... 1916*61c4878aSAndroid Build Coastguard Worker } 1917*61c4878aSAndroid Build Coastguard Worker } 1918*61c4878aSAndroid Build Coastguard Worker 1919*61c4878aSAndroid Build Coastguard Worker // When this scope ends, the nested decoder is destroyed and the 1920*61c4878aSAndroid Build Coastguard Worker // parent decoder, owner_decoder, can be used again. 1921*61c4878aSAndroid Build Coastguard Worker break; 1922*61c4878aSAndroid Build Coastguard Worker } 1923*61c4878aSAndroid Build Coastguard Worker 1924*61c4878aSAndroid Build Coastguard WorkerScalar Fields 1925*61c4878aSAndroid Build Coastguard Worker============= 1926*61c4878aSAndroid Build Coastguard WorkerScalar fields are read using code generated ``ReadFoo`` methods that return the 1927*61c4878aSAndroid Build Coastguard Workerappropriate type and assert that the correct field number ie being read. 1928*61c4878aSAndroid Build Coastguard Worker 1929*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Result<T> MyProto::StreamDecoder::ReadFoo() 1930*61c4878aSAndroid Build Coastguard Worker 1931*61c4878aSAndroid Build Coastguard WorkerThese can be freely intermixed with the lower-level API that provides a method 1932*61c4878aSAndroid Build Coastguard Workerper field type, requiring that the caller first check the field number. 1933*61c4878aSAndroid Build Coastguard Worker 1934*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Result<uint64_t> pw::protobuf::StreamDecoder::ReadUint64() 1935*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Result<int64_t> pw::protobuf::StreamDecoder::ReadSint64() 1936*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Result<int64_t> pw::protobuf::StreamDecoder::ReadInt64() 1937*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Result<uint32_t> pw::protobuf::StreamDecoder::ReadUint32() 1938*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Result<int32_t> pw::protobuf::StreamDecoder::ReadSint32() 1939*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Result<int32_t> pw::protobuf::StreamDecoder::ReadInt32() 1940*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Result<uint64_t> pw::protobuf::StreamDecoder::ReadFixed64() 1941*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Result<uint64_t> pw::protobuf::StreamDecoder::ReadFixed32() 1942*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Result<double> pw::protobuf::StreamDecoder::ReadDouble() 1943*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Result<float> pw::protobuf::StreamDecoder::ReadFloat() 1944*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Result<bool> pw::protobuf::StreamDecoder::ReadBool() 1945*61c4878aSAndroid Build Coastguard Worker 1946*61c4878aSAndroid Build Coastguard WorkerThe following two code snippets are equivalent, where the first uses the code 1947*61c4878aSAndroid Build Coastguard Workergenerated API, and the second implemented by hand. 1948*61c4878aSAndroid Build Coastguard Worker 1949*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 1950*61c4878aSAndroid Build Coastguard Worker 1951*61c4878aSAndroid Build Coastguard Worker pw::Result<int32_t> age = my_proto_decoder.ReadAge(); 1952*61c4878aSAndroid Build Coastguard Worker 1953*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 1954*61c4878aSAndroid Build Coastguard Worker 1955*61c4878aSAndroid Build Coastguard Worker PW_ASSERT(my_proto_decoder.FieldNumber().value() == 1956*61c4878aSAndroid Build Coastguard Worker static_cast<uint32_t>(MyProto::Fields::kAge)); 1957*61c4878aSAndroid Build Coastguard Worker pw::Result<int32_t> my_proto_decoder.ReadInt32(); 1958*61c4878aSAndroid Build Coastguard Worker 1959*61c4878aSAndroid Build Coastguard WorkerRepeated Fields 1960*61c4878aSAndroid Build Coastguard Worker--------------- 1961*61c4878aSAndroid Build Coastguard WorkerFor repeated scalar fields, multiple code generated ``ReadFoos`` methods 1962*61c4878aSAndroid Build Coastguard Workerare provided. 1963*61c4878aSAndroid Build Coastguard Worker 1964*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Result<T> MyProto::StreamDecoder::ReadFoos() 1965*61c4878aSAndroid Build Coastguard Worker 1966*61c4878aSAndroid Build Coastguard Worker This reads a single unpacked value. 1967*61c4878aSAndroid Build Coastguard Worker 1968*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: StatusWithSize MyProto::StreamDecoder::ReadFoos(pw::span<T>) 1969*61c4878aSAndroid Build Coastguard Worker 1970*61c4878aSAndroid Build Coastguard Worker This reads a packed field containing all of the values into the provided span. 1971*61c4878aSAndroid Build Coastguard Worker 1972*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status MyProto::StreamDecoder::ReadFoos(pw::Vector<T>&) 1973*61c4878aSAndroid Build Coastguard Worker 1974*61c4878aSAndroid Build Coastguard Worker Protobuf encoders are permitted to choose either repeating single unpacked 1975*61c4878aSAndroid Build Coastguard Worker values, or a packed field, including splitting repeated fields up into 1976*61c4878aSAndroid Build Coastguard Worker multiple packed fields. 1977*61c4878aSAndroid Build Coastguard Worker 1978*61c4878aSAndroid Build Coastguard Worker This method supports either format, appending values to the provided 1979*61c4878aSAndroid Build Coastguard Worker ``pw::Vector``. 1980*61c4878aSAndroid Build Coastguard Worker 1981*61c4878aSAndroid Build Coastguard WorkerThese too can be freely intermixed with the lower-level API methods, to read a 1982*61c4878aSAndroid Build Coastguard Workersingle value, a field of packed values into a ``pw::span``, or support both 1983*61c4878aSAndroid Build Coastguard Workerformats appending to a ``pw::Vector`` source. 1984*61c4878aSAndroid Build Coastguard Worker 1985*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: StatusWithSize pw::protobuf::StreamDecoder::ReadPackedUint64(pw::span<uint64_t>) 1986*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamDecoder::ReadRepeatedUint64(pw::Vector<uint64_t>&) 1987*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: StatusWithSize pw::protobuf::StreamDecoder::ReadPackedSint64(pw::span<int64_t>) 1988*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamDecoder::ReadRepeatedSint64(pw::Vector<int64_t>&) 1989*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: StatusWithSize pw::protobuf::StreamDecoder::ReadPackedInt64(pw::span<int64_t>) 1990*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamDecoder::ReadRepeatedInt64(pw::Vector<int64_t>&) 1991*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: StatusWithSize pw::protobuf::StreamDecoder::ReadPackedUint32(pw::span<uint32_t>) 1992*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamDecoder::ReadRepeatedUint32(pw::Vector<uint32_t>&) 1993*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: StatusWithSize pw::protobuf::StreamDecoder::ReadPackedSint32(pw::span<int32_t>) 1994*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamDecoder::ReadRepeatedSint32(pw::Vector<int32_t>&) 1995*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: StatusWithSize pw::protobuf::StreamDecoder::ReadPackedInt32(pw::span<int32_t>) 1996*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamDecoder::ReadRepeatedInt32(pw::Vector<int32_t>&) 1997*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: StatusWithSize pw::protobuf::StreamDecoder::ReadPackedFixed64(pw::span<uint64_t>) 1998*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamDecoder::ReadRepeatedFixed64(pw::Vector<uint64_t>&) 1999*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: StatusWithSize pw::protobuf::StreamDecoder::ReadPackedFixed32(pw::span<uint64_t>) 2000*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamDecoder::ReadRepeatedFixed32(pw::Vector<uint64_t>&) 2001*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: StatusWithSize pw::protobuf::StreamDecoder::ReadPackedDouble(pw::span<double>) 2002*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamDecoder::ReadRepeatedDouble(pw::Vector<double>&) 2003*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: StatusWithSize pw::protobuf::StreamDecoder::ReadPackedFloat(pw::span<float>) 2004*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamDecoder::ReadRepeatedFloat(pw::Vector<float>&) 2005*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: StatusWithSize pw::protobuf::StreamDecoder::ReadPackedBool(pw::span<bool>) 2006*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status pw::protobuf::StreamDecoder::ReadRepeatedBool(pw::Vector<bool>&) 2007*61c4878aSAndroid Build Coastguard Worker 2008*61c4878aSAndroid Build Coastguard WorkerThe following two code blocks are equivalent, where the first uses the code 2009*61c4878aSAndroid Build Coastguard Workergenerated API, and the second is implemented by hand. 2010*61c4878aSAndroid Build Coastguard Worker 2011*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 2012*61c4878aSAndroid Build Coastguard Worker 2013*61c4878aSAndroid Build Coastguard Worker pw::Vector<int32_t, 8> numbers; 2014*61c4878aSAndroid Build Coastguard Worker 2015*61c4878aSAndroid Build Coastguard Worker my_proto_decoder.ReadNumbers(numbers); 2016*61c4878aSAndroid Build Coastguard Worker 2017*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 2018*61c4878aSAndroid Build Coastguard Worker 2019*61c4878aSAndroid Build Coastguard Worker pw::Vector<int32_t, 8> numbers; 2020*61c4878aSAndroid Build Coastguard Worker 2021*61c4878aSAndroid Build Coastguard Worker PW_ASSERT(my_proto_decoder.FieldNumber().value() == 2022*61c4878aSAndroid Build Coastguard Worker static_cast<uint32_t>(MyProto::Fields::kNumbers)); 2023*61c4878aSAndroid Build Coastguard Worker my_proto_decoder.ReadRepeatedInt32(numbers); 2024*61c4878aSAndroid Build Coastguard Worker 2025*61c4878aSAndroid Build Coastguard WorkerEnumerations 2026*61c4878aSAndroid Build Coastguard Worker============ 2027*61c4878aSAndroid Build Coastguard Worker``pw_protobuf`` generates a few functions for working with enumerations. 2028*61c4878aSAndroid Build Coastguard WorkerMost importantly, enumerations are read using generated ``ReadEnum`` methods 2029*61c4878aSAndroid Build Coastguard Workerthat return the enumeration as the appropriate generated type. 2030*61c4878aSAndroid Build Coastguard Worker 2031*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Result<MyProto::Enum> MyProto::StreamDecoder::ReadEnum() 2032*61c4878aSAndroid Build Coastguard Worker 2033*61c4878aSAndroid Build Coastguard Worker Decodes an enum from the stream. 2034*61c4878aSAndroid Build Coastguard Worker 2035*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: constexpr bool MyProto::IsValidEnum(MyProto::Enum value) 2036*61c4878aSAndroid Build Coastguard Worker 2037*61c4878aSAndroid Build Coastguard Worker Validates the value encoded in the wire format against the known set of 2038*61c4878aSAndroid Build Coastguard Worker enumerates. 2039*61c4878aSAndroid Build Coastguard Worker 2040*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: constexpr const char* MyProto::EnumToString(MyProto::Enum value) 2041*61c4878aSAndroid Build Coastguard Worker 2042*61c4878aSAndroid Build Coastguard Worker Returns the string representation of the enum value. For example, 2043*61c4878aSAndroid Build Coastguard Worker ``FooToString(Foo::kBarBaz)`` returns ``"BAR_BAZ"``. Returns the empty string 2044*61c4878aSAndroid Build Coastguard Worker if the value is not a valid value. 2045*61c4878aSAndroid Build Coastguard Worker 2046*61c4878aSAndroid Build Coastguard WorkerTo read enumerations with the lower-level API, you would need to cast the 2047*61c4878aSAndroid Build Coastguard Workerretured value from the ``uint32_t``. 2048*61c4878aSAndroid Build Coastguard Worker 2049*61c4878aSAndroid Build Coastguard WorkerThe following two code blocks are equivalent, where the first is using the code 2050*61c4878aSAndroid Build Coastguard Workergenerated API, and the second implemented by hand. 2051*61c4878aSAndroid Build Coastguard Worker 2052*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 2053*61c4878aSAndroid Build Coastguard Worker 2054*61c4878aSAndroid Build Coastguard Worker pw::Result<MyProto::Award> award = my_proto_decoder.ReadAward(); 2055*61c4878aSAndroid Build Coastguard Worker if (!MyProto::IsValidAward(award)) { 2056*61c4878aSAndroid Build Coastguard Worker PW_LOG_DBG("Unknown award"); 2057*61c4878aSAndroid Build Coastguard Worker } 2058*61c4878aSAndroid Build Coastguard Worker 2059*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 2060*61c4878aSAndroid Build Coastguard Worker 2061*61c4878aSAndroid Build Coastguard Worker PW_ASSERT(my_proto_decoder.FieldNumber().value() == 2062*61c4878aSAndroid Build Coastguard Worker static_cast<uint32_t>(MyProto::Fields::kAward)); 2063*61c4878aSAndroid Build Coastguard Worker pw::Result<uint32_t> award_value = my_proto_decoder.ReadUint32(); 2064*61c4878aSAndroid Build Coastguard Worker if (award_value.ok()) { 2065*61c4878aSAndroid Build Coastguard Worker MyProto::Award award = static_cast<MyProto::Award>(award_value); 2066*61c4878aSAndroid Build Coastguard Worker } 2067*61c4878aSAndroid Build Coastguard Worker 2068*61c4878aSAndroid Build Coastguard WorkerRepeated Fields 2069*61c4878aSAndroid Build Coastguard Worker--------------- 2070*61c4878aSAndroid Build Coastguard WorkerFor repeated enum fields, multiple code generated ``ReadEnums`` methods 2071*61c4878aSAndroid Build Coastguard Workerare provided. 2072*61c4878aSAndroid Build Coastguard Worker 2073*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Result<MyProto::Enums> MyProto::StreamDecoder::ReadEnums() 2074*61c4878aSAndroid Build Coastguard Worker 2075*61c4878aSAndroid Build Coastguard Worker This reads a single unpacked value. 2076*61c4878aSAndroid Build Coastguard Worker 2077*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: StatusWithSize MyProto::StreamDecoder::ReadEnums(pw::span<MyProto::Enums>) 2078*61c4878aSAndroid Build Coastguard Worker 2079*61c4878aSAndroid Build Coastguard Worker This reads a packed field containing all of the checked values into the 2080*61c4878aSAndroid Build Coastguard Worker provided span. 2081*61c4878aSAndroid Build Coastguard Worker 2082*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Status MyProto::StreamDecoder::ReadEnums(pw::Vector<MyProto::Enums>&) 2083*61c4878aSAndroid Build Coastguard Worker 2084*61c4878aSAndroid Build Coastguard Worker This method supports either repeated unpacked or packed formats, appending 2085*61c4878aSAndroid Build Coastguard Worker checked values to the provided ``pw::Vector``. 2086*61c4878aSAndroid Build Coastguard Worker 2087*61c4878aSAndroid Build Coastguard WorkerTheir use is as scalar fields. 2088*61c4878aSAndroid Build Coastguard Worker 2089*61c4878aSAndroid Build Coastguard WorkerStrings 2090*61c4878aSAndroid Build Coastguard Worker======= 2091*61c4878aSAndroid Build Coastguard WorkerStrings fields provide a code generated method to read the string into the 2092*61c4878aSAndroid Build Coastguard Workerprovided span. Since the span is updated with the size of the string, the string 2093*61c4878aSAndroid Build Coastguard Workeris not automatically null-terminated. :ref:`module-pw_string` provides utility 2094*61c4878aSAndroid Build Coastguard Workermethods to copy string data from spans into other targets. 2095*61c4878aSAndroid Build Coastguard Worker 2096*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: StatusWithSize MyProto::StreamDecoder::ReadName(pw::span<char>) 2097*61c4878aSAndroid Build Coastguard Worker 2098*61c4878aSAndroid Build Coastguard WorkerAn additional code generated method is provided to return a nested 2099*61c4878aSAndroid Build Coastguard Worker``BytesReader`` to access the data as a stream. As with nested submessage 2100*61c4878aSAndroid Build Coastguard Workerdecoders, any use of the parent decoder that created the bytes reader will 2101*61c4878aSAndroid Build Coastguard Workertrigger a crash. To resume using the parent decoder, destroy the bytes reader 2102*61c4878aSAndroid Build Coastguard Workerfirst. 2103*61c4878aSAndroid Build Coastguard Worker 2104*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: pw::protobuf::StreamDecoder::BytesReader MyProto::StreamDecoder::GetNameReader() 2105*61c4878aSAndroid Build Coastguard Worker 2106*61c4878aSAndroid Build Coastguard WorkerThese can be freely intermixed with the lower-level API method: 2107*61c4878aSAndroid Build Coastguard Worker 2108*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: StatusWithSize pw::protobuf::StreamDecoder::ReadString(pw::span<char>) 2109*61c4878aSAndroid Build Coastguard Worker 2110*61c4878aSAndroid Build Coastguard WorkerThe lower-level ``GetBytesReader()`` method can also be used to read string data 2111*61c4878aSAndroid Build Coastguard Workeras bytes. 2112*61c4878aSAndroid Build Coastguard Worker 2113*61c4878aSAndroid Build Coastguard WorkerBytes 2114*61c4878aSAndroid Build Coastguard Worker===== 2115*61c4878aSAndroid Build Coastguard WorkerBytes fields provide the ``WriteData`` code generated method to read the bytes 2116*61c4878aSAndroid Build Coastguard Workerinto the provided span. 2117*61c4878aSAndroid Build Coastguard Worker 2118*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: StatusWithSize MyProto::StreamDecoder::ReadData(ByteSpan) 2119*61c4878aSAndroid Build Coastguard Worker 2120*61c4878aSAndroid Build Coastguard WorkerAn additional code generated method is provided to return a nested 2121*61c4878aSAndroid Build Coastguard Worker``BytesReader`` to access the data as a stream. As with nested submessage 2122*61c4878aSAndroid Build Coastguard Workerdecoders, any use of the parent decoder that created the bytes reader will 2123*61c4878aSAndroid Build Coastguard Workertrigger a crash. To resume using the parent decoder, destroy the bytes reader 2124*61c4878aSAndroid Build Coastguard Workerfirst. 2125*61c4878aSAndroid Build Coastguard Worker 2126*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: pw::protobuf::StreamDecoder::BytesReader MyProto::StreamDecoder::GetDataReader() 2127*61c4878aSAndroid Build Coastguard Worker 2128*61c4878aSAndroid Build Coastguard WorkerThese can be freely intermixed with the lower-level API methods. 2129*61c4878aSAndroid Build Coastguard Worker 2130*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: StatusWithSize pw::protobuf::StreamDecoder::ReadBytes(ByteSpan) 2131*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: pw::protobuf::StreamDecoder::BytesReader pw::protobuf::StreamDecoder::GetBytesReader() 2132*61c4878aSAndroid Build Coastguard Worker 2133*61c4878aSAndroid Build Coastguard WorkerThe ``BytesReader`` supports seeking only if the ``StreamDecoder``'s reader 2134*61c4878aSAndroid Build Coastguard Workersupports seeking. 2135*61c4878aSAndroid Build Coastguard Worker 2136*61c4878aSAndroid Build Coastguard WorkerError Handling 2137*61c4878aSAndroid Build Coastguard Worker============== 2138*61c4878aSAndroid Build Coastguard WorkerWhile individual read calls on a proto decoder return ``pw::Result``, 2139*61c4878aSAndroid Build Coastguard Worker``pw::StatusWithSize``, or ``pw::Status`` objects, the decoder tracks all status 2140*61c4878aSAndroid Build Coastguard Workerreturns and "latches" onto the first error encountered. This status can be 2141*61c4878aSAndroid Build Coastguard Workeraccessed via ``StreamDecoder::status()``. 2142*61c4878aSAndroid Build Coastguard Worker 2143*61c4878aSAndroid Build Coastguard WorkerLength Limited Decoding 2144*61c4878aSAndroid Build Coastguard Worker======================= 2145*61c4878aSAndroid Build Coastguard WorkerWhere the length of the protobuf message is known in advance, the decoder can 2146*61c4878aSAndroid Build Coastguard Workerbe prevented from reading from the stream beyond the known bounds by specifying 2147*61c4878aSAndroid Build Coastguard Workerthe known length to the decoder: 2148*61c4878aSAndroid Build Coastguard Worker 2149*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 2150*61c4878aSAndroid Build Coastguard Worker 2151*61c4878aSAndroid Build Coastguard Worker pw::protobuf::StreamDecoder decoder(reader, message_length); 2152*61c4878aSAndroid Build Coastguard Worker 2153*61c4878aSAndroid Build Coastguard WorkerWhen a decoder constructed in this way goes out of scope, it will consume any 2154*61c4878aSAndroid Build Coastguard Workerremaining bytes in ``message_length`` allowing the next ``Read()`` on the stream 2155*61c4878aSAndroid Build Coastguard Workerto be data after the protobuf, even when it was not fully parsed. 2156*61c4878aSAndroid Build Coastguard Worker 2157*61c4878aSAndroid Build Coastguard Worker----------------- 2158*61c4878aSAndroid Build Coastguard WorkerIn-memory Decoder 2159*61c4878aSAndroid Build Coastguard Worker----------------- 2160*61c4878aSAndroid Build Coastguard WorkerThe separate ``Decoder`` class operates on an protobuf message located in a 2161*61c4878aSAndroid Build Coastguard Workerbuffer in memory. It is more efficient than the ``StreamDecoder`` in cases 2162*61c4878aSAndroid Build Coastguard Workerwhere the complete protobuf data can be stored in memory. The tradeoff of this 2163*61c4878aSAndroid Build Coastguard Workerefficiency is that no code generation is provided, so all decoding must be 2164*61c4878aSAndroid Build Coastguard Workerperformed by hand. 2165*61c4878aSAndroid Build Coastguard Worker 2166*61c4878aSAndroid Build Coastguard WorkerAs ``StreamDecoder``, it provides an iterator-style API for processing a 2167*61c4878aSAndroid Build Coastguard Workermessage. Calling ``Next()`` advances the decoder to the next proto field, which 2168*61c4878aSAndroid Build Coastguard Workercan then be read by calling the appropriate ``Read*`` function for the field 2169*61c4878aSAndroid Build Coastguard Workernumber. 2170*61c4878aSAndroid Build Coastguard Worker 2171*61c4878aSAndroid Build Coastguard WorkerWhen reading ``bytes`` and ``string`` fields, the decoder returns a view of that 2172*61c4878aSAndroid Build Coastguard Workerfield within the buffer; no data is copied out. 2173*61c4878aSAndroid Build Coastguard Worker 2174*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 2175*61c4878aSAndroid Build Coastguard Worker 2176*61c4878aSAndroid Build Coastguard Worker #include "pw_protobuf/decoder.h" 2177*61c4878aSAndroid Build Coastguard Worker #include "pw_status/try.h" 2178*61c4878aSAndroid Build Coastguard Worker 2179*61c4878aSAndroid Build Coastguard Worker pw::Status DecodeProtoFromBuffer(pw::span<const std::byte> buffer) { 2180*61c4878aSAndroid Build Coastguard Worker pw::protobuf::Decoder decoder(buffer); 2181*61c4878aSAndroid Build Coastguard Worker pw::Status status; 2182*61c4878aSAndroid Build Coastguard Worker 2183*61c4878aSAndroid Build Coastguard Worker uint32_t uint32_field; 2184*61c4878aSAndroid Build Coastguard Worker std::string_view string_field; 2185*61c4878aSAndroid Build Coastguard Worker 2186*61c4878aSAndroid Build Coastguard Worker // Iterate over the fields in the message. A return value of OK indicates 2187*61c4878aSAndroid Build Coastguard Worker // that a valid field has been found and can be read. When the decoder 2188*61c4878aSAndroid Build Coastguard Worker // reaches the end of the message, Next() will return OUT_OF_RANGE. 2189*61c4878aSAndroid Build Coastguard Worker // Other return values indicate an error trying to decode the message. 2190*61c4878aSAndroid Build Coastguard Worker while ((status = decoder.Next()).ok()) { 2191*61c4878aSAndroid Build Coastguard Worker switch (decoder.FieldNumber()) { 2192*61c4878aSAndroid Build Coastguard Worker case 1: 2193*61c4878aSAndroid Build Coastguard Worker PW_TRY(decoder.ReadUint32(&uint32_field)); 2194*61c4878aSAndroid Build Coastguard Worker break; 2195*61c4878aSAndroid Build Coastguard Worker case 2: 2196*61c4878aSAndroid Build Coastguard Worker // The passed-in string_view will point to the contents of the string 2197*61c4878aSAndroid Build Coastguard Worker // field within the buffer. 2198*61c4878aSAndroid Build Coastguard Worker PW_TRY(decoder.ReadString(&string_field)); 2199*61c4878aSAndroid Build Coastguard Worker break; 2200*61c4878aSAndroid Build Coastguard Worker } 2201*61c4878aSAndroid Build Coastguard Worker } 2202*61c4878aSAndroid Build Coastguard Worker 2203*61c4878aSAndroid Build Coastguard Worker // Do something with the fields... 2204*61c4878aSAndroid Build Coastguard Worker 2205*61c4878aSAndroid Build Coastguard Worker return status.IsOutOfRange() ? OkStatus() : status; 2206*61c4878aSAndroid Build Coastguard Worker } 2207*61c4878aSAndroid Build Coastguard Worker 2208*61c4878aSAndroid Build Coastguard Worker--------------- 2209*61c4878aSAndroid Build Coastguard WorkerMessage Decoder 2210*61c4878aSAndroid Build Coastguard Worker--------------- 2211*61c4878aSAndroid Build Coastguard Worker 2212*61c4878aSAndroid Build Coastguard Worker.. note:: 2213*61c4878aSAndroid Build Coastguard Worker 2214*61c4878aSAndroid Build Coastguard Worker ``pw::protobuf::Message`` is unrelated to the codegen ``struct Message`` 2215*61c4878aSAndroid Build Coastguard Worker used with ``StreamDecoder``. 2216*61c4878aSAndroid Build Coastguard Worker 2217*61c4878aSAndroid Build Coastguard WorkerThe module implements a message parsing helper class ``Message``, in 2218*61c4878aSAndroid Build Coastguard Worker``pw_protobuf/message.h``, to faciliate proto message parsing and field access. 2219*61c4878aSAndroid Build Coastguard WorkerThe class provides interfaces for searching fields in a proto message and 2220*61c4878aSAndroid Build Coastguard Workercreating helper classes for it according to its interpreted field type, i.e. 2221*61c4878aSAndroid Build Coastguard Workeruint32, bytes, string, map<>, repeated etc. The class works on top of 2222*61c4878aSAndroid Build Coastguard Worker``StreamDecoder`` and thus requires a ``pw::stream::SeekableReader`` for proto 2223*61c4878aSAndroid Build Coastguard Workermessage access. The following gives examples for using the class to process 2224*61c4878aSAndroid Build Coastguard Workerdifferent fields in a proto message: 2225*61c4878aSAndroid Build Coastguard Worker 2226*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 2227*61c4878aSAndroid Build Coastguard Worker 2228*61c4878aSAndroid Build Coastguard Worker // Consider the proto messages defined as follows: 2229*61c4878aSAndroid Build Coastguard Worker // 2230*61c4878aSAndroid Build Coastguard Worker // message Nested { 2231*61c4878aSAndroid Build Coastguard Worker // string nested_str = 1; 2232*61c4878aSAndroid Build Coastguard Worker // bytes nested_bytes = 2; 2233*61c4878aSAndroid Build Coastguard Worker // } 2234*61c4878aSAndroid Build Coastguard Worker // 2235*61c4878aSAndroid Build Coastguard Worker // message { 2236*61c4878aSAndroid Build Coastguard Worker // uint32 integer = 1; 2237*61c4878aSAndroid Build Coastguard Worker // string str = 2; 2238*61c4878aSAndroid Build Coastguard Worker // bytes bytes = 3; 2239*61c4878aSAndroid Build Coastguard Worker // Nested nested = 4; 2240*61c4878aSAndroid Build Coastguard Worker // repeated string rep_str = 5; 2241*61c4878aSAndroid Build Coastguard Worker // repeated Nested rep_nested = 6; 2242*61c4878aSAndroid Build Coastguard Worker // map<string, bytes> str_to_bytes = 7; 2243*61c4878aSAndroid Build Coastguard Worker // map<string, Nested> str_to_nested = 8; 2244*61c4878aSAndroid Build Coastguard Worker // } 2245*61c4878aSAndroid Build Coastguard Worker 2246*61c4878aSAndroid Build Coastguard Worker // Given a seekable `reader` that reads the top-level proto message, and 2247*61c4878aSAndroid Build Coastguard Worker // a <proto_size> that gives the size of the proto message: 2248*61c4878aSAndroid Build Coastguard Worker Message message(reader, proto_size); 2249*61c4878aSAndroid Build Coastguard Worker 2250*61c4878aSAndroid Build Coastguard Worker // Parse a proto integer field 2251*61c4878aSAndroid Build Coastguard Worker Uint32 integer = messasge_parser.AsUint32(1); 2252*61c4878aSAndroid Build Coastguard Worker if (!integer.ok()) { 2253*61c4878aSAndroid Build Coastguard Worker // handle parsing error. i.e. return integer.status(). 2254*61c4878aSAndroid Build Coastguard Worker } 2255*61c4878aSAndroid Build Coastguard Worker uint32_t integer_value = integer.value(); // obtained the value 2256*61c4878aSAndroid Build Coastguard Worker 2257*61c4878aSAndroid Build Coastguard Worker // Parse a string field 2258*61c4878aSAndroid Build Coastguard Worker String str = message.AsString(2); 2259*61c4878aSAndroid Build Coastguard Worker if (!str.ok()) { 2260*61c4878aSAndroid Build Coastguard Worker // handle parsing error. i.e. return str.status(); 2261*61c4878aSAndroid Build Coastguard Worker } 2262*61c4878aSAndroid Build Coastguard Worker 2263*61c4878aSAndroid Build Coastguard Worker // check string equal 2264*61c4878aSAndroid Build Coastguard Worker Result<bool> str_check = str.Equal("foo"); 2265*61c4878aSAndroid Build Coastguard Worker 2266*61c4878aSAndroid Build Coastguard Worker // Parse a bytes field 2267*61c4878aSAndroid Build Coastguard Worker Bytes bytes = message.AsBytes(3); 2268*61c4878aSAndroid Build Coastguard Worker if (!bytes.ok()) { 2269*61c4878aSAndroid Build Coastguard Worker // handle parsing error. i.e. return bytes.status(); 2270*61c4878aSAndroid Build Coastguard Worker } 2271*61c4878aSAndroid Build Coastguard Worker 2272*61c4878aSAndroid Build Coastguard Worker // Get a reader to the bytes. 2273*61c4878aSAndroid Build Coastguard Worker stream::IntervalReader bytes_reader = bytes.GetBytesReader(); 2274*61c4878aSAndroid Build Coastguard Worker 2275*61c4878aSAndroid Build Coastguard Worker // Parse nested message `Nested nested = 4;` 2276*61c4878aSAndroid Build Coastguard Worker Message nested = message.AsMessage(4). 2277*61c4878aSAndroid Build Coastguard Worker // Get the fields in the nested message. 2278*61c4878aSAndroid Build Coastguard Worker String nested_str = nested.AsString(1); 2279*61c4878aSAndroid Build Coastguard Worker Bytes nested_bytes = nested.AsBytes(2); 2280*61c4878aSAndroid Build Coastguard Worker 2281*61c4878aSAndroid Build Coastguard Worker // Parse repeated field `repeated string rep_str = 5;` 2282*61c4878aSAndroid Build Coastguard Worker RepeatedStrings rep_str = message.AsRepeatedString(5); 2283*61c4878aSAndroid Build Coastguard Worker // Iterate through the entries. If proto is malformed when 2284*61c4878aSAndroid Build Coastguard Worker // iterating, the next element (`str` in this case) will be invalid 2285*61c4878aSAndroid Build Coastguard Worker // and loop will end in the iteration after. 2286*61c4878aSAndroid Build Coastguard Worker for (String element : rep_str) { 2287*61c4878aSAndroid Build Coastguard Worker // Check status 2288*61c4878aSAndroid Build Coastguard Worker if (!str.ok()) { 2289*61c4878aSAndroid Build Coastguard Worker // In the case of error, loop will end in the next iteration if 2290*61c4878aSAndroid Build Coastguard Worker // continues. This is the chance for code to catch the error. 2291*61c4878aSAndroid Build Coastguard Worker } 2292*61c4878aSAndroid Build Coastguard Worker // Process str 2293*61c4878aSAndroid Build Coastguard Worker } 2294*61c4878aSAndroid Build Coastguard Worker 2295*61c4878aSAndroid Build Coastguard Worker // Parse repeated field `repeated Nested rep_nested = 6;` 2296*61c4878aSAndroid Build Coastguard Worker RepeatedStrings rep_str = message.AsRepeatedString(6); 2297*61c4878aSAndroid Build Coastguard Worker // Iterate through the entries. For iteration 2298*61c4878aSAndroid Build Coastguard Worker for (Message element : rep_rep_nestedstr) { 2299*61c4878aSAndroid Build Coastguard Worker // Check status 2300*61c4878aSAndroid Build Coastguard Worker if (!element.ok()) { 2301*61c4878aSAndroid Build Coastguard Worker // In the case of error, loop will end in the next iteration if 2302*61c4878aSAndroid Build Coastguard Worker // continues. This is the chance for code to catch the error. 2303*61c4878aSAndroid Build Coastguard Worker } 2304*61c4878aSAndroid Build Coastguard Worker // Process element 2305*61c4878aSAndroid Build Coastguard Worker } 2306*61c4878aSAndroid Build Coastguard Worker 2307*61c4878aSAndroid Build Coastguard Worker // Parse map field `map<string, bytes> str_to_bytes = 7;` 2308*61c4878aSAndroid Build Coastguard Worker StringToBytesMap str_to_bytes = message.AsStringToBytesMap(7); 2309*61c4878aSAndroid Build Coastguard Worker // Access the entry by a given key value 2310*61c4878aSAndroid Build Coastguard Worker Bytes bytes_for_key = str_to_bytes["key"]; 2311*61c4878aSAndroid Build Coastguard Worker // Or iterate through map entries 2312*61c4878aSAndroid Build Coastguard Worker for (StringToBytesMapEntry entry : str_to_bytes) { 2313*61c4878aSAndroid Build Coastguard Worker // Check status 2314*61c4878aSAndroid Build Coastguard Worker if (!entry.ok()) { 2315*61c4878aSAndroid Build Coastguard Worker // In the case of error, loop will end in the next iteration if 2316*61c4878aSAndroid Build Coastguard Worker // continues. This is the chance for code to catch the error. 2317*61c4878aSAndroid Build Coastguard Worker } 2318*61c4878aSAndroid Build Coastguard Worker String key = entry.Key(); 2319*61c4878aSAndroid Build Coastguard Worker Bytes value = entry.Value(); 2320*61c4878aSAndroid Build Coastguard Worker // process entry 2321*61c4878aSAndroid Build Coastguard Worker } 2322*61c4878aSAndroid Build Coastguard Worker 2323*61c4878aSAndroid Build Coastguard Worker // Parse map field `map<string, Nested> str_to_nested = 8;` 2324*61c4878aSAndroid Build Coastguard Worker StringToMessageMap str_to_nested = message.AsStringToBytesMap(8); 2325*61c4878aSAndroid Build Coastguard Worker // Access the entry by a given key value 2326*61c4878aSAndroid Build Coastguard Worker Message nested_for_key = str_to_nested["key"]; 2327*61c4878aSAndroid Build Coastguard Worker // Or iterate through map entries 2328*61c4878aSAndroid Build Coastguard Worker for (StringToMessageMapEntry entry : str_to_nested) { 2329*61c4878aSAndroid Build Coastguard Worker // Check status 2330*61c4878aSAndroid Build Coastguard Worker if (!entry.ok()) { 2331*61c4878aSAndroid Build Coastguard Worker // In the case of error, loop will end in the next iteration if 2332*61c4878aSAndroid Build Coastguard Worker // continues. This is the chance for code to catch the error. 2333*61c4878aSAndroid Build Coastguard Worker // However it is still recommended that the user breaks here. 2334*61c4878aSAndroid Build Coastguard Worker break; 2335*61c4878aSAndroid Build Coastguard Worker } 2336*61c4878aSAndroid Build Coastguard Worker String key = entry.Key(); 2337*61c4878aSAndroid Build Coastguard Worker Message value = entry.Value(); 2338*61c4878aSAndroid Build Coastguard Worker // process entry 2339*61c4878aSAndroid Build Coastguard Worker } 2340*61c4878aSAndroid Build Coastguard Worker 2341*61c4878aSAndroid Build Coastguard WorkerThe methods in ``Message`` for parsing a single field, i.e. everty `AsXXX()` 2342*61c4878aSAndroid Build Coastguard Workermethod except AsRepeatedXXX() and AsStringMapXXX(), internally performs a 2343*61c4878aSAndroid Build Coastguard Workerlinear scan of the entire proto message to find the field with the given 2344*61c4878aSAndroid Build Coastguard Workerfield number. This can be expensive if performed multiple times, especially 2345*61c4878aSAndroid Build Coastguard Workeron slow reader. The same applies to the ``operator[]`` of StringToXXXXMap 2346*61c4878aSAndroid Build Coastguard Workerhelper class. Therefore, for performance consideration, whenever possible, it 2347*61c4878aSAndroid Build Coastguard Workeris recommended to use the following for-range style to iterate and process 2348*61c4878aSAndroid Build Coastguard Workersingle fields directly. 2349*61c4878aSAndroid Build Coastguard Worker 2350*61c4878aSAndroid Build Coastguard Worker 2351*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 2352*61c4878aSAndroid Build Coastguard Worker 2353*61c4878aSAndroid Build Coastguard Worker for (Message::Field field : message) { 2354*61c4878aSAndroid Build Coastguard Worker // Check status 2355*61c4878aSAndroid Build Coastguard Worker if (!field.ok()) { 2356*61c4878aSAndroid Build Coastguard Worker // In the case of error, loop will end in the next iteration if 2357*61c4878aSAndroid Build Coastguard Worker // continues. This is the chance for code to catch the error. 2358*61c4878aSAndroid Build Coastguard Worker } 2359*61c4878aSAndroid Build Coastguard Worker if (field.field_number() == 1) { 2360*61c4878aSAndroid Build Coastguard Worker Uint32 integer = field.As<Uint32>(); 2361*61c4878aSAndroid Build Coastguard Worker ... 2362*61c4878aSAndroid Build Coastguard Worker } else if (field.field_number() == 2) { 2363*61c4878aSAndroid Build Coastguard Worker String str = field.As<String>(); 2364*61c4878aSAndroid Build Coastguard Worker ... 2365*61c4878aSAndroid Build Coastguard Worker } else if (field.field_number() == 3) { 2366*61c4878aSAndroid Build Coastguard Worker Bytes bytes = field.As<Bytes>(); 2367*61c4878aSAndroid Build Coastguard Worker ... 2368*61c4878aSAndroid Build Coastguard Worker } else if (field.field_number() == 4) { 2369*61c4878aSAndroid Build Coastguard Worker Message nested = field.As<Message>(); 2370*61c4878aSAndroid Build Coastguard Worker ... 2371*61c4878aSAndroid Build Coastguard Worker } 2372*61c4878aSAndroid Build Coastguard Worker } 2373*61c4878aSAndroid Build Coastguard Worker 2374*61c4878aSAndroid Build Coastguard Worker 2375*61c4878aSAndroid Build Coastguard Worker.. Note:: 2376*61c4878aSAndroid Build Coastguard Worker The helper API are currently in-development and may not remain stable. 2377*61c4878aSAndroid Build Coastguard Worker 2378*61c4878aSAndroid Build Coastguard Worker----------- 2379*61c4878aSAndroid Build Coastguard WorkerSize report 2380*61c4878aSAndroid Build Coastguard Worker----------- 2381*61c4878aSAndroid Build Coastguard Worker 2382*61c4878aSAndroid Build Coastguard WorkerFull size report 2383*61c4878aSAndroid Build Coastguard Worker================ 2384*61c4878aSAndroid Build Coastguard Worker 2385*61c4878aSAndroid Build Coastguard WorkerThis report demonstrates the size of using the entire decoder with all of its 2386*61c4878aSAndroid Build Coastguard Workerdecode methods and a decode callback for a proto message containing each of the 2387*61c4878aSAndroid Build Coastguard Workerprotobuf field types. 2388*61c4878aSAndroid Build Coastguard Worker 2389*61c4878aSAndroid Build Coastguard Worker.. include:: size_report/decoder_partial 2390*61c4878aSAndroid Build Coastguard Worker 2391*61c4878aSAndroid Build Coastguard Worker 2392*61c4878aSAndroid Build Coastguard WorkerIncremental size report 2393*61c4878aSAndroid Build Coastguard Worker======================= 2394*61c4878aSAndroid Build Coastguard Worker 2395*61c4878aSAndroid Build Coastguard WorkerThis report is generated using the full report as a base and adding some int32 2396*61c4878aSAndroid Build Coastguard Workerfields to the decode callback to demonstrate the incremental cost of decoding 2397*61c4878aSAndroid Build Coastguard Workerfields in a message. 2398*61c4878aSAndroid Build Coastguard Worker 2399*61c4878aSAndroid Build Coastguard Worker.. include:: size_report/decoder_incremental 2400*61c4878aSAndroid Build Coastguard Worker 2401*61c4878aSAndroid Build Coastguard Worker--------------------------- 2402*61c4878aSAndroid Build Coastguard WorkerSerialized size calculation 2403*61c4878aSAndroid Build Coastguard Worker--------------------------- 2404*61c4878aSAndroid Build Coastguard Worker``pw_protobuf/serialized_size.h`` provides a set of functions for calculating 2405*61c4878aSAndroid Build Coastguard Workerhow much memory serialized protocol buffer fields require. The 2406*61c4878aSAndroid Build Coastguard Worker``kMaxSizeBytes*`` variables provide the maximum encoded sizes of each field 2407*61c4878aSAndroid Build Coastguard Workertype. The ``SizeOfField*()`` functions calculate the encoded size of a field of 2408*61c4878aSAndroid Build Coastguard Workerthe specified type, given a particular key and, for variable length fields 2409*61c4878aSAndroid Build Coastguard Worker(varint or delimited), a value. The ``SizeOf*Field`` functions calculate the 2410*61c4878aSAndroid Build Coastguard Workerencoded size of fields with a particular wire format (delimited, varint). 2411*61c4878aSAndroid Build Coastguard Worker 2412*61c4878aSAndroid Build Coastguard WorkerIn the rare event that you need to know the serialized size of a field's tag 2413*61c4878aSAndroid Build Coastguard Worker(field number and wire type), you can use ``TagSizeBytes()`` to calculate the 2414*61c4878aSAndroid Build Coastguard Workertag size for a given field number. 2415*61c4878aSAndroid Build Coastguard Worker 2416*61c4878aSAndroid Build Coastguard Worker-------------------------- 2417*61c4878aSAndroid Build Coastguard WorkerAvailable protobuf modules 2418*61c4878aSAndroid Build Coastguard Worker-------------------------- 2419*61c4878aSAndroid Build Coastguard WorkerThere are a handful of messages ready to be used in Pigweed projects. These are 2420*61c4878aSAndroid Build Coastguard Workerlocated in ``pw_protobuf/pw_protobuf_protos``. 2421*61c4878aSAndroid Build Coastguard Worker 2422*61c4878aSAndroid Build Coastguard Workercommon.proto 2423*61c4878aSAndroid Build Coastguard Worker============ 2424*61c4878aSAndroid Build Coastguard WorkerContains Empty message proto used in many RPC calls. 2425*61c4878aSAndroid Build Coastguard Worker 2426*61c4878aSAndroid Build Coastguard Worker 2427*61c4878aSAndroid Build Coastguard Workerstatus.proto 2428*61c4878aSAndroid Build Coastguard Worker============ 2429*61c4878aSAndroid Build Coastguard WorkerContains the enum for pw::Status. 2430*61c4878aSAndroid Build Coastguard Worker 2431*61c4878aSAndroid Build Coastguard Worker.. note:: 2432*61c4878aSAndroid Build Coastguard Worker ``pw::protobuf::StatusCode`` values should not be used outside of a .proto 2433*61c4878aSAndroid Build Coastguard Worker file. Instead, the StatusCodes should be converted to the Status type in the 2434*61c4878aSAndroid Build Coastguard Worker language. In C++, this would be: 2435*61c4878aSAndroid Build Coastguard Worker 2436*61c4878aSAndroid Build Coastguard Worker .. code-block:: c++ 2437*61c4878aSAndroid Build Coastguard Worker 2438*61c4878aSAndroid Build Coastguard Worker // Reading from a proto 2439*61c4878aSAndroid Build Coastguard Worker pw::Status status = static_cast<pw::Status::Code>(proto.status_field)); 2440*61c4878aSAndroid Build Coastguard Worker // Writing to a proto 2441*61c4878aSAndroid Build Coastguard Worker proto.status_field = static_cast<pw::protobuf::StatusCode>(status.code())); 2442*61c4878aSAndroid Build Coastguard Worker 2443*61c4878aSAndroid Build Coastguard Worker---------------------------------------- 2444*61c4878aSAndroid Build Coastguard WorkerComparison with other protobuf libraries 2445*61c4878aSAndroid Build Coastguard Worker---------------------------------------- 2446*61c4878aSAndroid Build Coastguard Worker 2447*61c4878aSAndroid Build Coastguard Workerprotobuf-lite 2448*61c4878aSAndroid Build Coastguard Worker============= 2449*61c4878aSAndroid Build Coastguard Workerprotobuf-lite is the official reduced-size C++ implementation of protobuf. It 2450*61c4878aSAndroid Build Coastguard Workeruses a restricted subset of the protobuf library's features to minimize code 2451*61c4878aSAndroid Build Coastguard Workersize. However, is is still around 150K in size and requires dynamic memory 2452*61c4878aSAndroid Build Coastguard Workerallocation, making it unsuitable for many embedded systems. 2453*61c4878aSAndroid Build Coastguard Worker 2454*61c4878aSAndroid Build Coastguard Workernanopb 2455*61c4878aSAndroid Build Coastguard Worker====== 2456*61c4878aSAndroid Build Coastguard Worker`Nanopb`_ is a commonly used embedded protobuf library with very small code size 2457*61c4878aSAndroid Build Coastguard Workerand full code generation. It provides both encoding/decoding functionality and 2458*61c4878aSAndroid Build Coastguard Workerin-memory C structs representing protobuf messages. 2459*61c4878aSAndroid Build Coastguard Worker 2460*61c4878aSAndroid Build Coastguard Workernanopb works well for many embedded products; however, using its generated code 2461*61c4878aSAndroid Build Coastguard Workercan run into RAM usage issues when processing nontrivial protobuf messages due 2462*61c4878aSAndroid Build Coastguard Workerto the necessity of defining a struct capable of storing all configurations of 2463*61c4878aSAndroid Build Coastguard Workerthe message, which can grow incredibly large. In one project, Pigweed developers 2464*61c4878aSAndroid Build Coastguard Workerencountered an 11K struct statically allocated for a single message---over twice 2465*61c4878aSAndroid Build Coastguard Workerthe size of the final encoded output! (This was what prompted the development of 2466*61c4878aSAndroid Build Coastguard Worker``pw_protobuf``.) 2467*61c4878aSAndroid Build Coastguard Worker 2468*61c4878aSAndroid Build Coastguard WorkerTo avoid this issue, it is possible to use nanopb's low-level encode/decode 2469*61c4878aSAndroid Build Coastguard Workerfunctions to process individual message fields directly, but this loses all of 2470*61c4878aSAndroid Build Coastguard Workerthe useful semantics of code generation. ``pw_protobuf`` is designed to optimize 2471*61c4878aSAndroid Build Coastguard Workerfor this use case; it allows for efficient operations on the wire format with an 2472*61c4878aSAndroid Build Coastguard Workerintuitive user interface. 2473*61c4878aSAndroid Build Coastguard Worker 2474*61c4878aSAndroid Build Coastguard WorkerDepending on the requirements of a project, either of these libraries could be 2475*61c4878aSAndroid Build Coastguard Workersuitable. 2476*61c4878aSAndroid Build Coastguard Worker 2477*61c4878aSAndroid Build Coastguard Worker.. _Nanopb: https://jpa.kapsi.fi/nanopb/ 2478