1*61c4878aSAndroid Build Coastguard Worker.. _seed-0103: 2*61c4878aSAndroid Build Coastguard Worker 3*61c4878aSAndroid Build Coastguard Worker============================================ 4*61c4878aSAndroid Build Coastguard Worker0103: pw_protobuf: Past, present, and future 5*61c4878aSAndroid Build Coastguard Worker============================================ 6*61c4878aSAndroid Build Coastguard Worker.. seed:: 7*61c4878aSAndroid Build Coastguard Worker :number: 0103 8*61c4878aSAndroid Build Coastguard Worker :name: pw_protobuf: Past, present, and future 9*61c4878aSAndroid Build Coastguard Worker :status: Accepted 10*61c4878aSAndroid Build Coastguard Worker :proposal_date: 2023-08-16 11*61c4878aSAndroid Build Coastguard Worker :cl: 133971 12*61c4878aSAndroid Build Coastguard Worker :authors: Alexei Frolov 13*61c4878aSAndroid Build Coastguard Worker :facilitator: Armando Montanez 14*61c4878aSAndroid Build Coastguard Worker 15*61c4878aSAndroid Build Coastguard Worker------- 16*61c4878aSAndroid Build Coastguard WorkerSummary 17*61c4878aSAndroid Build Coastguard Worker------- 18*61c4878aSAndroid Build Coastguard Worker``pw_protobuf`` is one of Pigweed's oldest modules and has become a foundational 19*61c4878aSAndroid Build Coastguard Workercomponent of Pigweed and Pigweed-based projects. At its core, ``pw_protobuf`` 20*61c4878aSAndroid Build Coastguard Workerprovides a compact and efficient `protobuf <https://protobuf.dev>`_ wire format 21*61c4878aSAndroid Build Coastguard Workerencoder and decoder, but as third-party usage has grown, additional higher-level 22*61c4878aSAndroid Build Coastguard WorkerAPIs have sprung up, many of which were contributed by third-party developers to 23*61c4878aSAndroid Build Coastguard Workeraddress use cases within their own projects. 24*61c4878aSAndroid Build Coastguard Worker 25*61c4878aSAndroid Build Coastguard WorkerThe growth of ``pw_protobuf`` was not entirely controlled, which has resulted in 26*61c4878aSAndroid Build Coastguard Workera lack of cohesion among its components, incomplete implementations, and 27*61c4878aSAndroid Build Coastguard Workerimplicit, undocumented limitations. This has made the module difficult to 28*61c4878aSAndroid Build Coastguard Workerapproach for new users and put a lasting maintenance burden on the core Pigweed 29*61c4878aSAndroid Build Coastguard Workerteam. 30*61c4878aSAndroid Build Coastguard Worker 31*61c4878aSAndroid Build Coastguard WorkerThis document explores the state of ``pw_protobuf`` and proposes a plan to 32*61c4878aSAndroid Build Coastguard Workerresolve the issues present in the module, both in the immediate short term and 33*61c4878aSAndroid Build Coastguard Workera longer term vision. 34*61c4878aSAndroid Build Coastguard Worker 35*61c4878aSAndroid Build Coastguard Worker--------------------------- 36*61c4878aSAndroid Build Coastguard WorkerSummary of Proposed Changes 37*61c4878aSAndroid Build Coastguard Worker--------------------------- 38*61c4878aSAndroid Build Coastguard WorkerThe table below summarizes the states of the different ``pw_protobuf`` 39*61c4878aSAndroid Build Coastguard Workercomponents following acceptance of this SEED. The reasoning behind these changes 40*61c4878aSAndroid Build Coastguard Workeris explained in further detail throughout the rest of the SEED. 41*61c4878aSAndroid Build Coastguard Worker 42*61c4878aSAndroid Build Coastguard Worker.. list-table:: 43*61c4878aSAndroid Build Coastguard Worker :header-rows: 1 44*61c4878aSAndroid Build Coastguard Worker 45*61c4878aSAndroid Build Coastguard Worker * - Component 46*61c4878aSAndroid Build Coastguard Worker - Status 47*61c4878aSAndroid Build Coastguard Worker - Details 48*61c4878aSAndroid Build Coastguard Worker * - Wire format encoder/decoder 49*61c4878aSAndroid Build Coastguard Worker - Supported 50*61c4878aSAndroid Build Coastguard Worker - * ``pw_protobuf``'s primary API. 51*61c4878aSAndroid Build Coastguard Worker * Codegen helpers for convenient use. 52*61c4878aSAndroid Build Coastguard Worker * Works with streams and direct buffers. 53*61c4878aSAndroid Build Coastguard Worker * Recommended for compact and efficient protobuf operations. 54*61c4878aSAndroid Build Coastguard Worker * - Find API 55*61c4878aSAndroid Build Coastguard Worker - Supported 56*61c4878aSAndroid Build Coastguard Worker - * Useful for extracting fields from messages without having to set up a 57*61c4878aSAndroid Build Coastguard Worker decoder. 58*61c4878aSAndroid Build Coastguard Worker * Recommended as an alternative for in-memory objects for small, simple 59*61c4878aSAndroid Build Coastguard Worker messages. 60*61c4878aSAndroid Build Coastguard Worker * Will be expanded with better support for repeated fields. 61*61c4878aSAndroid Build Coastguard Worker * - Nanopb integration (build system / RPC) 62*61c4878aSAndroid Build Coastguard Worker - Supported 63*61c4878aSAndroid Build Coastguard Worker - * Recommended for newer projects that want a complete object model for 64*61c4878aSAndroid Build Coastguard Worker their protobuf messages. 65*61c4878aSAndroid Build Coastguard Worker * Recommended by default for RPC services. 66*61c4878aSAndroid Build Coastguard Worker * Can easily be used alongside lower-level ``pw_protobuf`` APIs in cases 67*61c4878aSAndroid Build Coastguard Worker where more control is required. 68*61c4878aSAndroid Build Coastguard Worker * - Message API (``message.h``) 69*61c4878aSAndroid Build Coastguard Worker - Deprecated 70*61c4878aSAndroid Build Coastguard Worker - * Superseded by other APIs. 71*61c4878aSAndroid Build Coastguard Worker * Only used by one project. 72*61c4878aSAndroid Build Coastguard Worker * Code will be removed. 73*61c4878aSAndroid Build Coastguard Worker * - Message structures 74*61c4878aSAndroid Build Coastguard Worker - **Short-term:** Discouraged 75*61c4878aSAndroid Build Coastguard Worker 76*61c4878aSAndroid Build Coastguard Worker **Long-term:** Deprecated 77*61c4878aSAndroid Build Coastguard Worker - * Will remain supported for existing users indefinitely, though no new 78*61c4878aSAndroid Build Coastguard Worker features will be added. 79*61c4878aSAndroid Build Coastguard Worker * Docs will be updated to clearly detail its limitations. 80*61c4878aSAndroid Build Coastguard Worker * Not recommended to new users; Nanopb or the low-level APIs should be 81*61c4878aSAndroid Build Coastguard Worker preferred. 82*61c4878aSAndroid Build Coastguard Worker * Will be replaced with a newer ``pw_protobuf`` object model at an 83*61c4878aSAndroid Build Coastguard Worker unspecified future point. 84*61c4878aSAndroid Build Coastguard Worker * Code will remain until the new model is fully implemented and existing 85*61c4878aSAndroid Build Coastguard Worker users have had time to migrate (with Pigweed assistance for internal 86*61c4878aSAndroid Build Coastguard Worker customers). 87*61c4878aSAndroid Build Coastguard Worker * - ``pwpb_rpc`` 88*61c4878aSAndroid Build Coastguard Worker - **Short-term:** Discouraged 89*61c4878aSAndroid Build Coastguard Worker 90*61c4878aSAndroid Build Coastguard Worker **Long-term:** Deprecated 91*61c4878aSAndroid Build Coastguard Worker - * Will remain supported for existing users indefinitely, though no new 92*61c4878aSAndroid Build Coastguard Worker features will be added. 93*61c4878aSAndroid Build Coastguard Worker * Not recommended to new users; ``nanopb_rpc`` and/or raw methods should 94*61c4878aSAndroid Build Coastguard Worker be preferred. 95*61c4878aSAndroid Build Coastguard Worker * When the new ``pw_protobuf`` object model is added, it will come with 96*61c4878aSAndroid Build Coastguard Worker updated RPC integration. 97*61c4878aSAndroid Build Coastguard Worker * Code will remain until the new model is fully implemented and existing 98*61c4878aSAndroid Build Coastguard Worker users have had time to migrate (with Pigweed assistance for internal 99*61c4878aSAndroid Build Coastguard Worker customers). 100*61c4878aSAndroid Build Coastguard Worker * - New ``pw_protobuf`` object model 101*61c4878aSAndroid Build Coastguard Worker - **Long-term:** Planned 102*61c4878aSAndroid Build Coastguard Worker - * Intended to replace existing message structures as the premier 103*61c4878aSAndroid Build Coastguard Worker in-memory object model, with a more complete implementation of the 104*61c4878aSAndroid Build Coastguard Worker protobuf spec. 105*61c4878aSAndroid Build Coastguard Worker * Investigation and design will be examined in a future SEED. 106*61c4878aSAndroid Build Coastguard Worker 107*61c4878aSAndroid Build Coastguard Worker---------------------------- 108*61c4878aSAndroid Build Coastguard WorkerBackground and Current State 109*61c4878aSAndroid Build Coastguard Worker---------------------------- 110*61c4878aSAndroid Build Coastguard Worker 111*61c4878aSAndroid Build Coastguard WorkerProtobuf Components 112*61c4878aSAndroid Build Coastguard Worker=================== 113*61c4878aSAndroid Build Coastguard Worker``pw_protobuf`` today consists of several different layered APIs, which are 114*61c4878aSAndroid Build Coastguard Workerexplored below. 115*61c4878aSAndroid Build Coastguard Worker 116*61c4878aSAndroid Build Coastguard WorkerCore encoder and decoder 117*61c4878aSAndroid Build Coastguard Worker------------------------ 118*61c4878aSAndroid Build Coastguard Worker``pw_protobuf``'s core low-level APIs interact directly with the 119*61c4878aSAndroid Build Coastguard Worker`Protobuf wire format <https://protobuf.dev/programming-guides/encoding/>`_, 120*61c4878aSAndroid Build Coastguard Workerprocessing each field appearing in a message individually without any notion of 121*61c4878aSAndroid Build Coastguard Workerhigher-level message semantics such as repeated or optional fields. These APIs 122*61c4878aSAndroid Build Coastguard Workerare compact and highly-capable; they are able to construct any valid protobuf 123*61c4878aSAndroid Build Coastguard Workermessage, albeit by pushing much of the burden onto users to ensure that they do 124*61c4878aSAndroid Build Coastguard Workernot encode fields in violation of their messages' schemas. 125*61c4878aSAndroid Build Coastguard Worker 126*61c4878aSAndroid Build Coastguard WorkerOrigin 127*61c4878aSAndroid Build Coastguard Worker^^^^^^ 128*61c4878aSAndroid Build Coastguard WorkerThe idea for direct wire encoding originated prior to the inception of Pigweed, 129*61c4878aSAndroid Build Coastguard Workerwhen the team was setting up crash reporting for a project. Crash diagnostic 130*61c4878aSAndroid Build Coastguard Workerdata was transmitted from each device as a protobuf message, which was encoded 131*61c4878aSAndroid Build Coastguard Workerusing `nanopb <https://jpa.kapsi.fi/nanopb/>`_, a popular lightweight, 132*61c4878aSAndroid Build Coastguard Workerembedded-friendly protobuf library for serializing and deserializing protobuf 133*61c4878aSAndroid Build Coastguard Workerdata to and from C structs. 134*61c4878aSAndroid Build Coastguard Worker 135*61c4878aSAndroid Build Coastguard WorkerTo send crash reports, a single, statically-allocated crash message struct was 136*61c4878aSAndroid Build Coastguard Workerpopulated by the device's various subsystems, before being serialized to a 137*61c4878aSAndroid Build Coastguard Workerbuffer and queued for transmission over the appropriate interface. The fields of 138*61c4878aSAndroid Build Coastguard Workerthis struct ranged from single integers to complex nested messages. The nature 139*61c4878aSAndroid Build Coastguard Workerof nanopb in a static memory environment required each variable-length field in 140*61c4878aSAndroid Build Coastguard Workerthe generated message to be reserved for its maximum allowable size, which 141*61c4878aSAndroid Build Coastguard Workerquickly blew up in the cases of large strings and repeated submessages. All in 142*61c4878aSAndroid Build Coastguard Workerall, the generated crash struct clocked in at around 12KB --- several times 143*61c4878aSAndroid Build Coastguard Workerlarger than its encoded size --- a high price to pay for such a 144*61c4878aSAndroid Build Coastguard Workermemory-constrained device. 145*61c4878aSAndroid Build Coastguard Worker 146*61c4878aSAndroid Build Coastguard WorkerThis large overhead raised the question of whether it was necessary to store the 147*61c4878aSAndroid Build Coastguard Workercrash data in an intermediate format, or if this could be eliminated. By the 148*61c4878aSAndroid Build Coastguard Workernature of the protobuf wire format, it is possible to build up a message in 149*61c4878aSAndroid Build Coastguard Workerparts, writing one field at a time. Due to this, it would be possible for each 150*61c4878aSAndroid Build Coastguard Workersubsystem to be passed some serializer which would allow them to write their 151*61c4878aSAndroid Build Coastguard Workerfields directly to the final output buffer, avoiding any additional in-memory 152*61c4878aSAndroid Build Coastguard Workerstorage. This would be especially beneficial for variable-length fields, where 153*61c4878aSAndroid Build Coastguard Workersystems could write only as much data as they had at the moment, avoiding the 154*61c4878aSAndroid Build Coastguard Workeroverhead of worst-case reservations. ``pw_protobuf`` was conceptualized as this 155*61c4878aSAndroid Build Coastguard Workertype of wire serializer, providing a convenient wrapper around direct 156*61c4878aSAndroid Build Coastguard Workerfield-by-field serialization. 157*61c4878aSAndroid Build Coastguard Worker 158*61c4878aSAndroid Build Coastguard WorkerWhile the project ended up shipping with their original ``nanopb`` setup, a 159*61c4878aSAndroid Build Coastguard Workerprototype of this serializer was written as a proof of concept, and ended up 160*61c4878aSAndroid Build Coastguard Workerbeing refined to support all basic protobuf operations as one of the first 161*61c4878aSAndroid Build Coastguard Workermodules offered by the newly-started Pigweed project. 162*61c4878aSAndroid Build Coastguard Worker 163*61c4878aSAndroid Build Coastguard WorkerImplementation 164*61c4878aSAndroid Build Coastguard Worker^^^^^^^^^^^^^^ 165*61c4878aSAndroid Build Coastguard WorkerThe core encoders have undergone several iterations over time. The 166*61c4878aSAndroid Build Coastguard Worker`original implementation <https://cs.opensource.google/pigweed/pigweed/+/bbf164c985576a348f3bcd4c48b3e9fd8a464a66:pw_protobuf/public/pw_protobuf/encoder.h;l=25>`_ 167*61c4878aSAndroid Build Coastguard Workeroffered a simple API to directly serialize single protobuf fields to an 168*61c4878aSAndroid Build Coastguard Workerin-memory buffer through a series of typed ``Encode`` functions. Message 169*61c4878aSAndroid Build Coastguard Workernesting was handled manually by the user, calling a ``Push`` function to begin 170*61c4878aSAndroid Build Coastguard Workerwriting fields to a submessage, followed by ``Pop`` on completion. 171*61c4878aSAndroid Build Coastguard Worker 172*61c4878aSAndroid Build Coastguard WorkerThe decoder was a 173*61c4878aSAndroid Build Coastguard Worker`later addition <https://cs.opensource.google/pigweed/pigweed/+/6d9b9b447b84afb60e714ebd97523ee55b93c9a6:pw_protobuf/public/pw_protobuf/decoder.h;l=23>`_, 174*61c4878aSAndroid Build Coastguard Workerinitially invoking a callback on each field in the serialized message with its 175*61c4878aSAndroid Build Coastguard Workerfield number, giving the users the ability to extract the field by calling the 176*61c4878aSAndroid Build Coastguard Workerappropriate typed ``Decode`` function. This was implemented via a 177*61c4878aSAndroid Build Coastguard Worker``DecodeHandler`` virtual interface, and it persists to this day as 178*61c4878aSAndroid Build Coastguard Worker``CallbackDecoder``. However, this proved to be too cumbersome to use, so the 179*61c4878aSAndroid Build Coastguard Workermain decoder was `rewritten <https://cs.opensource.google/pigweed/pigweed/+/fe9723cd67796e9236022cde6ef42cda99682d77>`_ 180*61c4878aSAndroid Build Coastguard Workerin the style of an iterator where users manually advanced it through the 181*61c4878aSAndroid Build Coastguard Workerserialized fields, decoding those which they cared about. 182*61c4878aSAndroid Build Coastguard Worker 183*61c4878aSAndroid Build Coastguard WorkerStreaming enhancement 184*61c4878aSAndroid Build Coastguard Worker^^^^^^^^^^^^^^^^^^^^^ 185*61c4878aSAndroid Build Coastguard WorkerThe original encoder and decoder were designed to operate on messages which fit 186*61c4878aSAndroid Build Coastguard Workerinto buffers directly in memory. However, as the ``pw_stream`` interface was 187*61c4878aSAndroid Build Coastguard Workerstabilized and adopted, there was interest in processing protobuf messages whose 188*61c4878aSAndroid Build Coastguard Workerdata was not fully available (for example, reading out of flash 189*61c4878aSAndroid Build Coastguard Workersector-by-sector). This prompted another rewrite of the core classes to make 190*61c4878aSAndroid Build Coastguard Worker``pw::Stream`` the interface to the serialized data. This was done differently 191*61c4878aSAndroid Build Coastguard Workerfor the encoder and decoder: the encoder only operates on streams, with 192*61c4878aSAndroid Build Coastguard Worker``MemoryEncoder`` becoming a shallow wrapper instantiating a ``MemoryWriter`` on 193*61c4878aSAndroid Build Coastguard Workertop of a buffer, whereas the decoder ended up having two separate, parallel 194*61c4878aSAndroid Build Coastguard Worker``StreamDecoder`` and ``MemoryDecoder`` implementations. 195*61c4878aSAndroid Build Coastguard Worker 196*61c4878aSAndroid Build Coastguard WorkerThe reason for this asymmetry has to do with the manner in which the two were 197*61c4878aSAndroid Build Coastguard Workerimplemented. The encoder was 198*61c4878aSAndroid Build Coastguard Worker`rewritten first <https://cs.opensource.google/pigweed/pigweed/+/0ed221cbb8b943205dea4ac315fe1d4b1e6b7371>`_, 199*61c4878aSAndroid Build Coastguard Workerand carefully designed to function on top of the limited semantic guarantees 200*61c4878aSAndroid Build Coastguard Workeroffered by ``pw_stream``. Following this redesign, it seemed obvious and natural 201*61c4878aSAndroid Build Coastguard Workerto use the existing MemoryStream to provide the previous encoding functionality 202*61c4878aSAndroid Build Coastguard Workernearly transparently. However, when reviewing this implementation with the 203*61c4878aSAndroid Build Coastguard Workerlarger team, several potential issues were noted. What was previously a simple 204*61c4878aSAndroid Build Coastguard Workermemory access to write a protobuf field became an expensive virtual call which 205*61c4878aSAndroid Build Coastguard Workercould not be elided. The common use case of serializing a message to a buffer 206*61c4878aSAndroid Build Coastguard Workerhad become significantly less performant, prompting concerns about the impact of 207*61c4878aSAndroid Build Coastguard Workerthe change. Additionally, it was noted that this performance impact would be far 208*61c4878aSAndroid Build Coastguard Workerworse on the decoding side, where serialized varints had to be read one byte at 209*61c4878aSAndroid Build Coastguard Workera time. 210*61c4878aSAndroid Build Coastguard Worker 211*61c4878aSAndroid Build Coastguard WorkerAs a result, it was decided that a larger analysis was required. To aid this, 212*61c4878aSAndroid Build Coastguard Workerthe stream-based decoder would be implemented separately to the existing memory 213*61c4878aSAndroid Build Coastguard Workerdecoder so that direct comparisons could be made between the two 214*61c4878aSAndroid Build Coastguard Workerimplementations. Unfortunately, the performance of the two implementations was 215*61c4878aSAndroid Build Coastguard Workernever properly analyzed as the team became entangled in higher priority 216*61c4878aSAndroid Build Coastguard Workercommitments. 217*61c4878aSAndroid Build Coastguard Worker 218*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 219*61c4878aSAndroid Build Coastguard Worker 220*61c4878aSAndroid Build Coastguard Worker class StreamEncoder { 221*61c4878aSAndroid Build Coastguard Worker public: 222*61c4878aSAndroid Build Coastguard Worker constexpr StreamEncoder(stream::Writer& writer, ByteSpan scratch_buffer); 223*61c4878aSAndroid Build Coastguard Worker 224*61c4878aSAndroid Build Coastguard Worker Status WriteUint32(uint32_t field_number, uint32_t value); 225*61c4878aSAndroid Build Coastguard Worker Status WriteString(uint32_t field_number, std::string_view value); 226*61c4878aSAndroid Build Coastguard Worker }; 227*61c4878aSAndroid Build Coastguard Worker 228*61c4878aSAndroid Build Coastguard Worker*A subset of the StreamEncoder API, demonstrating its low-level field writing 229*61c4878aSAndroid Build Coastguard Workeroperations.* 230*61c4878aSAndroid Build Coastguard Worker 231*61c4878aSAndroid Build Coastguard WorkerWire format code generation 232*61c4878aSAndroid Build Coastguard Worker--------------------------- 233*61c4878aSAndroid Build Coastguard Worker``pw_protobuf`` provides lightweight generated code wrappers on top of its core 234*61c4878aSAndroid Build Coastguard Workerwire format encoder and decoder which eliminate the need to provide the correct 235*61c4878aSAndroid Build Coastguard Workerfield number and type when writing/reading serialized fields. Each generated 236*61c4878aSAndroid Build Coastguard Workerfunction calls directly into the underlying encoder/decoder API, in theory 237*61c4878aSAndroid Build Coastguard Workermaking them zero-overhead wrappers. 238*61c4878aSAndroid Build Coastguard Worker 239*61c4878aSAndroid Build Coastguard WorkerThe encoder codegen was part of the original implementation of ``pw_protobuf``. 240*61c4878aSAndroid Build Coastguard WorkerIt constituted a ``protoc`` plugin written in Python, and several GN build 241*61c4878aSAndroid Build Coastguard Workertemplates to define protobuf libraries and invoke ``protoc`` on them to create 242*61c4878aSAndroid Build Coastguard Workera C++ target which could be depended on by others. The build integration was 243*61c4878aSAndroid Build Coastguard Workeradded separately to the main protobuf module, as ``pw_protobuf_compiler``, and 244*61c4878aSAndroid Build Coastguard Workerhas since expanded to support many different protobuf code generators in various 245*61c4878aSAndroid Build Coastguard Workerlanguages. 246*61c4878aSAndroid Build Coastguard Worker 247*61c4878aSAndroid Build Coastguard WorkerThe decoder codegen was added at a much later date, alongside the struct object 248*61c4878aSAndroid Build Coastguard Workermodel. Like the encoder codegen, it defines wrappers around the underlying 249*61c4878aSAndroid Build Coastguard Workerdecoder functions which populate values for each of a message's fields, though 250*61c4878aSAndroid Build Coastguard Workerusers are still required to manually iterate through the message and extract 251*61c4878aSAndroid Build Coastguard Workereach field. 252*61c4878aSAndroid Build Coastguard Worker 253*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 254*61c4878aSAndroid Build Coastguard Worker 255*61c4878aSAndroid Build Coastguard Worker class FooEncoder : public ::pw::protobuf::StreamEncoder { 256*61c4878aSAndroid Build Coastguard Worker Status WriteBar(uint32_t value) { 257*61c4878aSAndroid Build Coastguard Worker return ::pw::protobuf::StreamEncoder::WriteUint32( 258*61c4878aSAndroid Build Coastguard Worker static_cast<uint32_t>(Fields::kBar), value); 259*61c4878aSAndroid Build Coastguard Worker } 260*61c4878aSAndroid Build Coastguard Worker }; 261*61c4878aSAndroid Build Coastguard Worker 262*61c4878aSAndroid Build Coastguard Worker*An example of how a generated encoder wrapper calls into the underlying 263*61c4878aSAndroid Build Coastguard Workeroperation.* 264*61c4878aSAndroid Build Coastguard Worker 265*61c4878aSAndroid Build Coastguard WorkerMessage API 266*61c4878aSAndroid Build Coastguard Worker----------- 267*61c4878aSAndroid Build Coastguard WorkerThe ``Message`` API was the first attempt at providing higher-level semantic 268*61c4878aSAndroid Build Coastguard Workerwrappers on top of ``pw_protobuf``'s direct wire serialization. It was developed 269*61c4878aSAndroid Build Coastguard Workerin conjunction with the implementation of Pigweed's software update flow for a 270*61c4878aSAndroid Build Coastguard Workerproject and addressed several use cases that came up with the way the project 271*61c4878aSAndroid Build Coastguard Workerstored its update bundle metadata. 272*61c4878aSAndroid Build Coastguard Worker 273*61c4878aSAndroid Build Coastguard WorkerThis API works on the decoding side only, giving users easier access to fields 274*61c4878aSAndroid Build Coastguard Workerof a serialized message. It provides functions which scan a message for a field 275*61c4878aSAndroid Build Coastguard Workerusing its field number (similar to the ``Find`` APIs discussed later). However, 276*61c4878aSAndroid Build Coastguard Workerinstead of deserializing the field and returning its data directly, these APIs 277*61c4878aSAndroid Build Coastguard Workergive the user a typed handle to the field which can be used to read it. 278*61c4878aSAndroid Build Coastguard Worker 279*61c4878aSAndroid Build Coastguard WorkerThese field handles apply protobuf semantics beyond the field-by-field iteration 280*61c4878aSAndroid Build Coastguard Workerof the low level decoder. For example, a field can be accessed as a repeated 281*61c4878aSAndroid Build Coastguard Workerfield, whose handle provides a C++ iterator over each instance of the field in 282*61c4878aSAndroid Build Coastguard Workerthe serialized message. Additionally, ``Message`` is the only API currently in 283*61c4878aSAndroid Build Coastguard Worker``pw_protobuf`` which allows users to work directly with protobuf ``map`` 284*61c4878aSAndroid Build Coastguard Workerfields, reading key-value pairs from a message. 285*61c4878aSAndroid Build Coastguard Worker 286*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 287*61c4878aSAndroid Build Coastguard Worker 288*61c4878aSAndroid Build Coastguard Worker // Parse repeated field `repeated string rep_str = 5;` 289*61c4878aSAndroid Build Coastguard Worker RepeatedStrings rep_str = message.AsRepeatedString(5); 290*61c4878aSAndroid Build Coastguard Worker // Iterate through the entries. For iteration 291*61c4878aSAndroid Build Coastguard Worker for (String element : rep_str) { 292*61c4878aSAndroid Build Coastguard Worker // Process str 293*61c4878aSAndroid Build Coastguard Worker } 294*61c4878aSAndroid Build Coastguard Worker 295*61c4878aSAndroid Build Coastguard Worker // Parse map field `map<string, bytes> str_to_bytes = 7;` 296*61c4878aSAndroid Build Coastguard Worker StringToBytesMap str_to_bytes = message.AsStringToBytesMap(7); 297*61c4878aSAndroid Build Coastguard Worker // Access the entry by a given key value 298*61c4878aSAndroid Build Coastguard Worker Bytes bytes_for_key = str_to_bytes["key"]; 299*61c4878aSAndroid Build Coastguard Worker // Or iterate through map entries 300*61c4878aSAndroid Build Coastguard Worker for (StringToBytesMapEntry entry : str_to_bytes) { 301*61c4878aSAndroid Build Coastguard Worker String key = entry.Key(); 302*61c4878aSAndroid Build Coastguard Worker Bytes value = entry.Value(); 303*61c4878aSAndroid Build Coastguard Worker // Process entry 304*61c4878aSAndroid Build Coastguard Worker } 305*61c4878aSAndroid Build Coastguard Worker 306*61c4878aSAndroid Build Coastguard Worker*Examples of reading repeated and map fields from a serialized protobuf using 307*61c4878aSAndroid Build Coastguard Workerthe Message API.* 308*61c4878aSAndroid Build Coastguard Worker 309*61c4878aSAndroid Build Coastguard WorkerMessage structures 310*61c4878aSAndroid Build Coastguard Worker------------------ 311*61c4878aSAndroid Build Coastguard Worker``pw_protobuf``'s message structure API is its premier high-level, in-memory 312*61c4878aSAndroid Build Coastguard Workerobject model. It was contributed by an external team with some guidance from 313*61c4878aSAndroid Build Coastguard WorkerPigweed developers and was driven largely by a desire to work conveniently with 314*61c4878aSAndroid Build Coastguard Workerprotobufs in RPC methods without the burden of a third-party dependency in 315*61c4878aSAndroid Build Coastguard Worker``nanopb`` (the only officially supported protobuf library in RPC at the time). 316*61c4878aSAndroid Build Coastguard Worker 317*61c4878aSAndroid Build Coastguard WorkerMessage structures function similarly to more conventional protobuf libraries, 318*61c4878aSAndroid Build Coastguard Workerwhere every definition in a ``.proto`` file generates a corresponding C++ 319*61c4878aSAndroid Build Coastguard Workerobject. In the case of ``pw_protobuf``, these objects are defined as structs 320*61c4878aSAndroid Build Coastguard Workercontaining the fields of their protobuf message as members. Functions are 321*61c4878aSAndroid Build Coastguard Workerprovided to encode from or decode to one of these structs, removing the manual 322*61c4878aSAndroid Build Coastguard Workerper-field processing from the lower-level APIs. 323*61c4878aSAndroid Build Coastguard Worker 324*61c4878aSAndroid Build Coastguard WorkerEach field in a protobuf message becomes an inline member of its generated 325*61c4878aSAndroid Build Coastguard Workerstruct. Protobuf types are mapped to C++ types where possible, with special 326*61c4878aSAndroid Build Coastguard Workerhandling of protobuf specifiers and variable-length fields. Fields labeled as 327*61c4878aSAndroid Build Coastguard Workeroptional are wrapped in a ``std::optional`` from the STL. Fields labeled as 328*61c4878aSAndroid Build Coastguard Worker``oneof`` are not supported (in fact, the code generator completely ignores the 329*61c4878aSAndroid Build Coastguard Workerkeyword). Variable-length fields can either be inlined or handled through 330*61c4878aSAndroid Build Coastguard Workercallbacks invoked by the encoder or decoder when processing the message. If 331*61c4878aSAndroid Build Coastguard Workerinlined, a container sized to a user-specified maximum length is generated. For 332*61c4878aSAndroid Build Coastguard Workerstrings, this is a ``pw::InlineString`` while most other fields use a 333*61c4878aSAndroid Build Coastguard Worker``pw::Vector``. 334*61c4878aSAndroid Build Coastguard Worker 335*61c4878aSAndroid Build Coastguard WorkerSimilar to nanopb, users can pass options to the ``pw_protobuf`` generator 336*61c4878aSAndroid Build Coastguard Workerthrough the protobuf compiler to configure their generated message structures. 337*61c4878aSAndroid Build Coastguard WorkerThese allow specifying the maximum size of variable-length fields, setting a 338*61c4878aSAndroid Build Coastguard Workerfixed size, or forcing the use of callbacks for encoding and decoding. Options 339*61c4878aSAndroid Build Coastguard Workermaybe be specified inline in the proto file or listed in a separate file 340*61c4878aSAndroid Build Coastguard Worker(conventionally named ``.options``) to avoid leaking ``pw_protobuf``-specific 341*61c4878aSAndroid Build Coastguard Workermetadata into protobuf files that may be shared across multiple languages and 342*61c4878aSAndroid Build Coastguard Workerprotobuf compiler contexts. 343*61c4878aSAndroid Build Coastguard Worker 344*61c4878aSAndroid Build Coastguard WorkerUnlike the lower-level generated classes which require custom per-field encoding 345*61c4878aSAndroid Build Coastguard Workerand decoding functions, message serialization is handled generically through the 346*61c4878aSAndroid Build Coastguard Workeruse of a field descriptor table. The descriptor table for a message contains an 347*61c4878aSAndroid Build Coastguard Workerentry for each of its fields, storing its type, field number, and other metadata 348*61c4878aSAndroid Build Coastguard Workeralongside its offset within the generated message structure. This table is 349*61c4878aSAndroid Build Coastguard Workergenerated once per message defined in a protobuf file, trading a small 350*61c4878aSAndroid Build Coastguard Workeradditional memory overhead for reduced code size when serializing and 351*61c4878aSAndroid Build Coastguard Workerdeserializing data. 352*61c4878aSAndroid Build Coastguard Worker 353*61c4878aSAndroid Build Coastguard Worker.. code-block:: proto 354*61c4878aSAndroid Build Coastguard Worker 355*61c4878aSAndroid Build Coastguard Worker message Customer { 356*61c4878aSAndroid Build Coastguard Worker int32 age = 1; 357*61c4878aSAndroid Build Coastguard Worker string name = 2; 358*61c4878aSAndroid Build Coastguard Worker optional fixed32 loyalty_id = 3; 359*61c4878aSAndroid Build Coastguard Worker } 360*61c4878aSAndroid Build Coastguard Worker 361*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 362*61c4878aSAndroid Build Coastguard Worker 363*61c4878aSAndroid Build Coastguard Worker struct Customer::Message { 364*61c4878aSAndroid Build Coastguard Worker int32_t age; 365*61c4878aSAndroid Build Coastguard Worker pw::InlineString<32> name; 366*61c4878aSAndroid Build Coastguard Worker std::optional<uint32_t> loyalty_id; 367*61c4878aSAndroid Build Coastguard Worker }; 368*61c4878aSAndroid Build Coastguard Worker 369*61c4878aSAndroid Build Coastguard Worker*Example of how a protobuf message definition is converted as a C++ struct.* 370*61c4878aSAndroid Build Coastguard Worker 371*61c4878aSAndroid Build Coastguard WorkerFind API 372*61c4878aSAndroid Build Coastguard Worker-------- 373*61c4878aSAndroid Build Coastguard Worker``pw_protobuf``'s set of ``Find`` APIs constitute functions for extracting 374*61c4878aSAndroid Build Coastguard Workersingle fields from serialized messages. The functions scan the message for a 375*61c4878aSAndroid Build Coastguard Workerfield number and decode it as a specified protobuf type. Like the core 376*61c4878aSAndroid Build Coastguard Workerserialization APIs, there are two levels to ``Find``: direct low-level typed 377*61c4878aSAndroid Build Coastguard Workerfunctions, and generated code functions that invoke these for named protobuf 378*61c4878aSAndroid Build Coastguard Workerfields. 379*61c4878aSAndroid Build Coastguard Worker 380*61c4878aSAndroid Build Coastguard WorkerExtracting a single field is a common protobuf use case, and was envisioned 381*61c4878aSAndroid Build Coastguard Workerearly in ``pw_protobuf``'s development. An initial version of ``Find`` was 382*61c4878aSAndroid Build Coastguard Workerstarted shortly after the original callback-based decoder was implemented, 383*61c4878aSAndroid Build Coastguard Workerproviding a ``DecodeHandler`` to scan for a specific field number in a message. 384*61c4878aSAndroid Build Coastguard WorkerThis version was never fully completed and did not see any production use. More 385*61c4878aSAndroid Build Coastguard Workerrecently, the ``Find`` APIs were revisited and reimplemented on top of the 386*61c4878aSAndroid Build Coastguard Workeriterative decoder. 387*61c4878aSAndroid Build Coastguard Worker 388*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 389*61c4878aSAndroid Build Coastguard Worker 390*61c4878aSAndroid Build Coastguard Worker pw::Result<uint32_t> age = Customer::FindAge(serialized_customer); 391*61c4878aSAndroid Build Coastguard Worker if (age.ok()) { 392*61c4878aSAndroid Build Coastguard Worker PW_LOG_INFO("Age is %u", age.value()); 393*61c4878aSAndroid Build Coastguard Worker } 394*61c4878aSAndroid Build Coastguard Worker 395*61c4878aSAndroid Build Coastguard Worker*An example of using a generated Find function to extract a field from a 396*61c4878aSAndroid Build Coastguard Workerserialized protobuf message.* 397*61c4878aSAndroid Build Coastguard Worker 398*61c4878aSAndroid Build Coastguard WorkerRPC integration 399*61c4878aSAndroid Build Coastguard Worker--------------- 400*61c4878aSAndroid Build Coastguard WorkerPigweed RPC exchanges data in the form of protobufs and was designed to allow 401*61c4878aSAndroid Build Coastguard Workerusers to implement their services using different protobuf libraries, with some 402*61c4878aSAndroid Build Coastguard Workersupported officially. Supporting the use of ``pw_protobuf`` had been a goal from 403*61c4878aSAndroid Build Coastguard Workerthe beginning, but it was never implemented on top of the direct wire encoders 404*61c4878aSAndroid Build Coastguard Workerand decoders. Despite this, several RPC service implementations in Pigweed and 405*61c4878aSAndroid Build Coastguard Workercustomer projects ended up using ``pw_protobuf`` on top of the raw RPC method 406*61c4878aSAndroid Build Coastguard WorkerAPI, manually decoding and encoding messages. 407*61c4878aSAndroid Build Coastguard Worker 408*61c4878aSAndroid Build Coastguard WorkerWhen message structures were contributed, they came with an expansion of RPC to 409*61c4878aSAndroid Build Coastguard Workerallow their usage in method implementations, becoming the second officially 410*61c4878aSAndroid Build Coastguard Workersupported protobuf library. ``pw_protobuf`` methods are structured and behave 411*61c4878aSAndroid Build Coastguard Workersimilarly to RPC's nanopb-based methods, automatically deserializing requests 412*61c4878aSAndroid Build Coastguard Workerfrom and serializing responses to their generated message structures. 413*61c4878aSAndroid Build Coastguard Worker 414*61c4878aSAndroid Build Coastguard WorkerWhat Works Well 415*61c4878aSAndroid Build Coastguard Worker=============== 416*61c4878aSAndroid Build Coastguard WorkerOverall, ``pw_protobuf`` has been a largely successful module despite its 417*61c4878aSAndroid Build Coastguard Workergrowing pains. It has become an integral part of Pigweed, used widely upstream 418*61c4878aSAndroid Build Coastguard Workeracross major components of the system, including logging and crash reporting. 419*61c4878aSAndroid Build Coastguard WorkerSeveral Pigweed customers have also shown to favor ``pw_protobuf``, choosing it 420*61c4878aSAndroid Build Coastguard Workerover other embedded protobuf libraries like nanopb. 421*61c4878aSAndroid Build Coastguard Worker 422*61c4878aSAndroid Build Coastguard WorkerThe list below summarizes some of ``pw_protobuf``'s successes. 423*61c4878aSAndroid Build Coastguard Worker 424*61c4878aSAndroid Build Coastguard Worker**Overall** 425*61c4878aSAndroid Build Coastguard Worker 426*61c4878aSAndroid Build Coastguard Worker* Widespread adoption across Pigweed and Pigweed-based projects. 427*61c4878aSAndroid Build Coastguard Worker 428*61c4878aSAndroid Build Coastguard Worker* Easy to integrate into a project which uses Pigweed's build system. 429*61c4878aSAndroid Build Coastguard Worker 430*61c4878aSAndroid Build Coastguard Worker* Often comes at a minimal additional cost to projects, as the core of 431*61c4878aSAndroid Build Coastguard Worker ``pw_protobuf`` is already used by popular upstream modules. 432*61c4878aSAndroid Build Coastguard Worker 433*61c4878aSAndroid Build Coastguard Worker**Core wire format encoders/decoders** 434*61c4878aSAndroid Build Coastguard Worker 435*61c4878aSAndroid Build Coastguard Worker* Simple, intuitive APIs which give users a lot of control over the structure 436*61c4878aSAndroid Build Coastguard Worker of their messages. 437*61c4878aSAndroid Build Coastguard Worker 438*61c4878aSAndroid Build Coastguard Worker* Lightweight in terms of code size and memory use. 439*61c4878aSAndroid Build Coastguard Worker 440*61c4878aSAndroid Build Coastguard Worker**Codegen general** 441*61c4878aSAndroid Build Coastguard Worker 442*61c4878aSAndroid Build Coastguard Worker* Build system integration is extensive and generally simple to use. 443*61c4878aSAndroid Build Coastguard Worker 444*61c4878aSAndroid Build Coastguard Worker* Low-level codegen wrappers are convenient to use without sacrificing the 445*61c4878aSAndroid Build Coastguard Worker power of the underlying APIs. 446*61c4878aSAndroid Build Coastguard Worker 447*61c4878aSAndroid Build Coastguard Worker**Message API** 448*61c4878aSAndroid Build Coastguard Worker 449*61c4878aSAndroid Build Coastguard Worker* Though only used by a single project, it works well for their needs and 450*61c4878aSAndroid Build Coastguard Worker gives them extensive semantic processing of serialized messages without the 451*61c4878aSAndroid Build Coastguard Worker overhead of decoding to a full in-memory object. 452*61c4878aSAndroid Build Coastguard Worker 453*61c4878aSAndroid Build Coastguard Worker* More capable processing than the Find APIs: for example, allowing iteration 454*61c4878aSAndroid Build Coastguard Worker over elements of a repeated field. 455*61c4878aSAndroid Build Coastguard Worker 456*61c4878aSAndroid Build Coastguard Worker* As the entire API is stream-based, it permits useful operations such as 457*61c4878aSAndroid Build Coastguard Worker giving the user a bounded stream over a bytes field of the message, 458*61c4878aSAndroid Build Coastguard Worker eliminating the need for an additional copy of data. 459*61c4878aSAndroid Build Coastguard Worker 460*61c4878aSAndroid Build Coastguard Worker* Support for protobuf maps, something which is absent from any other 461*61c4878aSAndroid Build Coastguard Worker ``pw_protobuf`` API. 462*61c4878aSAndroid Build Coastguard Worker 463*61c4878aSAndroid Build Coastguard Worker**Message Structures** 464*61c4878aSAndroid Build Coastguard Worker 465*61c4878aSAndroid Build Coastguard Worker* Message structures work incredibly well for the majority of simple use cases, 466*61c4878aSAndroid Build Coastguard Worker making protobufs easy to use without having to understand the details of the 467*61c4878aSAndroid Build Coastguard Worker wire format. 468*61c4878aSAndroid Build Coastguard Worker 469*61c4878aSAndroid Build Coastguard Worker* Adoption of ``pw_protobuf`` increased following the addition of this API and 470*61c4878aSAndroid Build Coastguard Worker corresponding RPC support, indicating that it is more valuable to a typical 471*61c4878aSAndroid Build Coastguard Worker user who is not concerned with the minor efficiencies offered by the 472*61c4878aSAndroid Build Coastguard Worker lower-level APIs. 473*61c4878aSAndroid Build Coastguard Worker 474*61c4878aSAndroid Build Coastguard Worker* Encoding and decoding messages is efficient due to the struct model's generic 475*61c4878aSAndroid Build Coastguard Worker table-based implementation. Users do not have to write custom code to process 476*61c4878aSAndroid Build Coastguard Worker each message as they would with the lower-level APIs, resulting in reduced 477*61c4878aSAndroid Build Coastguard Worker overall code size in some cases. 478*61c4878aSAndroid Build Coastguard Worker 479*61c4878aSAndroid Build Coastguard Worker* Nested messages are far easier to handle than in any other API, which require 480*61c4878aSAndroid Build Coastguard Worker additional setup creating sub-encoders/decoders. 481*61c4878aSAndroid Build Coastguard Worker 482*61c4878aSAndroid Build Coastguard Worker* The use of containers such as ``pw::Vector`` for repeated fields simplifies 483*61c4878aSAndroid Build Coastguard Worker their use and avoids the issues of similar libraries such as nanopb, where 484*61c4878aSAndroid Build Coastguard Worker users have to remember to manually set their length. 485*61c4878aSAndroid Build Coastguard Worker 486*61c4878aSAndroid Build Coastguard Worker**Find API** 487*61c4878aSAndroid Build Coastguard Worker 488*61c4878aSAndroid Build Coastguard Worker* Eliminates a lot of boilerplate in the common use case where only a single 489*61c4878aSAndroid Build Coastguard Worker field from a message needs to be read. 490*61c4878aSAndroid Build Coastguard Worker 491*61c4878aSAndroid Build Coastguard Worker**RPC integration** 492*61c4878aSAndroid Build Coastguard Worker 493*61c4878aSAndroid Build Coastguard Worker* Has seen a high rate of adoption as it provides a convenient API to read and 494*61c4878aSAndroid Build Coastguard Worker write requests and responses without requiring the management of a third-party 495*61c4878aSAndroid Build Coastguard Worker library dependency. 496*61c4878aSAndroid Build Coastguard Worker 497*61c4878aSAndroid Build Coastguard Worker* ``pw_protobuf``-based RPC services can still fall back on the raw RPC API in 498*61c4878aSAndroid Build Coastguard Worker instances where more flexible handling is required. 499*61c4878aSAndroid Build Coastguard Worker 500*61c4878aSAndroid Build Coastguard WorkerThe Issues 501*61c4878aSAndroid Build Coastguard Worker========== 502*61c4878aSAndroid Build Coastguard Worker 503*61c4878aSAndroid Build Coastguard WorkerOverview 504*61c4878aSAndroid Build Coastguard Worker-------- 505*61c4878aSAndroid Build Coastguard WorkerThis section shows a summary of the known issues present at each layer of the 506*61c4878aSAndroid Build Coastguard Workercurrent ``pw_protobuf`` module. Several of these issues will be explored in 507*61c4878aSAndroid Build Coastguard Workerfurther detail later. 508*61c4878aSAndroid Build Coastguard Worker 509*61c4878aSAndroid Build Coastguard Worker**Overall** 510*61c4878aSAndroid Build Coastguard Worker 511*61c4878aSAndroid Build Coastguard Worker* Lack of an overall vision and cohesive story: What is ``pw_protobuf`` trying 512*61c4878aSAndroid Build Coastguard Worker to be and what kinds of users does it target? Where does it fit into the 513*61c4878aSAndroid Build Coastguard Worker larger protobuf ecosystem? 514*61c4878aSAndroid Build Coastguard Worker 515*61c4878aSAndroid Build Coastguard Worker* Documentation structure doesn't clearly guide users. Should be addressed in 516*61c4878aSAndroid Build Coastguard Worker conjunction with the larger :ref:`SEED-0102 <seed-0102>` effort. 517*61c4878aSAndroid Build Coastguard Worker 518*61c4878aSAndroid Build Coastguard Worker* Too many overlapping implementations. We should focus on one model with a 519*61c4878aSAndroid Build Coastguard Worker clear delineation between its layers. 520*61c4878aSAndroid Build Coastguard Worker 521*61c4878aSAndroid Build Coastguard Worker* Despite describing itself as a lightweight and efficient protobuf library, 522*61c4878aSAndroid Build Coastguard Worker little size reporting and performance statistics are provided to substantiate 523*61c4878aSAndroid Build Coastguard Worker these claims. 524*61c4878aSAndroid Build Coastguard Worker 525*61c4878aSAndroid Build Coastguard Worker**Core wire format encoders/decoders** 526*61c4878aSAndroid Build Coastguard Worker 527*61c4878aSAndroid Build Coastguard Worker* Parallel memory and stream decoder implementations which don't share any code. 528*61c4878aSAndroid Build Coastguard Worker They also have different APIs, e.g. using ``Result`` (stream decoder) vs. a 529*61c4878aSAndroid Build Coastguard Worker ``Status`` and output pointer (memory decoder). 530*61c4878aSAndroid Build Coastguard Worker 531*61c4878aSAndroid Build Coastguard Worker* Effectively-deprecated APIs still exist (e.g. ``CallbackDecoder``). 532*61c4878aSAndroid Build Coastguard Worker 533*61c4878aSAndroid Build Coastguard Worker* Inefficiencies when working with varints and streams. When reading a varint 534*61c4878aSAndroid Build Coastguard Worker from a message, the ``StreamDecoder`` consumes its stream one byte at a time, 535*61c4878aSAndroid Build Coastguard Worker each going through a potentially costly virtual call to the underlying 536*61c4878aSAndroid Build Coastguard Worker implementation. 537*61c4878aSAndroid Build Coastguard Worker 538*61c4878aSAndroid Build Coastguard Worker**Codegen general** 539*61c4878aSAndroid Build Coastguard Worker 540*61c4878aSAndroid Build Coastguard Worker* The headers generated by ``pw_protobuf`` are poorly structured. Some users 541*61c4878aSAndroid Build Coastguard Worker have observed large compiler memory usage parsing them, which may be related. 542*61c4878aSAndroid Build Coastguard Worker 543*61c4878aSAndroid Build Coastguard Worker* Each message in a ``.proto`` file generates a namespace in C++, in which its 544*61c4878aSAndroid Build Coastguard Worker generated classes appear. This is unintuitive and difficult to use, with most 545*61c4878aSAndroid Build Coastguard Worker users resorting to a mess of using statements at the top of each file that 546*61c4878aSAndroid Build Coastguard Worker works with protobufs. 547*61c4878aSAndroid Build Coastguard Worker 548*61c4878aSAndroid Build Coastguard Worker* Due to the way ``pw_protobuf`` appends its own namespace to users' proto 549*61c4878aSAndroid Build Coastguard Worker packages, it is not always possible to deduce where this namespace will exist 550*61c4878aSAndroid Build Coastguard Worker in external compilation units. To work around this, a somewhat hacky approach 551*61c4878aSAndroid Build Coastguard Worker is used where every generated ``pw_protobuf`` namespace is aliased within a 552*61c4878aSAndroid Build Coastguard Worker root-level namespace scope. 553*61c4878aSAndroid Build Coastguard Worker 554*61c4878aSAndroid Build Coastguard Worker* While basic codegen works in all build systems, only the GN build supports 555*61c4878aSAndroid Build Coastguard Worker the full capabilities of ``pw_protobuf``. Several essential features, such as 556*61c4878aSAndroid Build Coastguard Worker options files, are missing from other builds. 557*61c4878aSAndroid Build Coastguard Worker 558*61c4878aSAndroid Build Coastguard Worker* There appear to be issues with how the codegen steps are exposed to the CMake 559*61c4878aSAndroid Build Coastguard Worker build graph, preventing protobuf files from being regenerated as a result of 560*61c4878aSAndroid Build Coastguard Worker some codegen script modifications. 561*61c4878aSAndroid Build Coastguard Worker 562*61c4878aSAndroid Build Coastguard Worker* Protobuf editions, the modern replacement for the proto2 and proto3 syntax 563*61c4878aSAndroid Build Coastguard Worker options, are not supported by the code generator. Files using them fail to 564*61c4878aSAndroid Build Coastguard Worker compile. 565*61c4878aSAndroid Build Coastguard Worker 566*61c4878aSAndroid Build Coastguard Worker**Message API** 567*61c4878aSAndroid Build Coastguard Worker 568*61c4878aSAndroid Build Coastguard Worker* The message API as a whole has been superseded by the structure API, and there 569*61c4878aSAndroid Build Coastguard Worker is no reason for it to be used. 570*61c4878aSAndroid Build Coastguard Worker 571*61c4878aSAndroid Build Coastguard Worker**Message structures** 572*61c4878aSAndroid Build Coastguard Worker 573*61c4878aSAndroid Build Coastguard Worker* Certain types of valid proto messages are impossible to represent due to 574*61c4878aSAndroid Build Coastguard Worker language limitations. For example, as message structs directly embed 575*61c4878aSAndroid Build Coastguard Worker submessages, a circular dependency between nested messages cannot exist. 576*61c4878aSAndroid Build Coastguard Worker 577*61c4878aSAndroid Build Coastguard Worker* Optional proto fields are represented in C++ by ``std::optional``. This has 578*61c4878aSAndroid Build Coastguard Worker several issues: 579*61c4878aSAndroid Build Coastguard Worker 580*61c4878aSAndroid Build Coastguard Worker * Memory overhead as a result of storing each field's presence flag 581*61c4878aSAndroid Build Coastguard Worker individually. 582*61c4878aSAndroid Build Coastguard Worker 583*61c4878aSAndroid Build Coastguard Worker * Inconsistent with how other protobuf libraries function. Typically, field 584*61c4878aSAndroid Build Coastguard Worker presence is exposed through a separate API, with accessors always 585*61c4878aSAndroid Build Coastguard Worker returning a value (the default if absent). 586*61c4878aSAndroid Build Coastguard Worker 587*61c4878aSAndroid Build Coastguard Worker* Not all types of fields are supported. Optional strings and optional 588*61c4878aSAndroid Build Coastguard Worker submessages do not work (the generator effectively ignores the ``optional`` 589*61c4878aSAndroid Build Coastguard Worker specifier). ``oneof`` fields do not work. 590*61c4878aSAndroid Build Coastguard Worker 591*61c4878aSAndroid Build Coastguard Worker* Not all options work for all fields. Fixed/max size specifiers to inline 592*61c4878aSAndroid Build Coastguard Worker repeated fields generally only work for simple field types --- callbacks must 593*61c4878aSAndroid Build Coastguard Worker be used otherwise. 594*61c4878aSAndroid Build Coastguard Worker 595*61c4878aSAndroid Build Coastguard Worker* In cases where the generator does not support something, it often does not 596*61c4878aSAndroid Build Coastguard Worker indicate this to the user, silently outputting incorrect code instead. 597*61c4878aSAndroid Build Coastguard Worker 598*61c4878aSAndroid Build Coastguard Worker* Options files share both a filename and some option names with other protobuf 599*61c4878aSAndroid Build Coastguard Worker libraries, namely Nanopb. This can cause issues when trying to use the same 600*61c4878aSAndroid Build Coastguard Worker protobuf definition in different contexts, as the options do not always work 601*61c4878aSAndroid Build Coastguard Worker the same way in both. 602*61c4878aSAndroid Build Coastguard Worker 603*61c4878aSAndroid Build Coastguard Worker**Find API** 604*61c4878aSAndroid Build Coastguard Worker 605*61c4878aSAndroid Build Coastguard Worker* Lack of support for repeated fields. Only the first element will be found. 606*61c4878aSAndroid Build Coastguard Worker 607*61c4878aSAndroid Build Coastguard Worker* Similarly, does not support recurring non-repeated fields. The protobuf 608*61c4878aSAndroid Build Coastguard Worker specification requires that scalar fields are overridden if they reappear, 609*61c4878aSAndroid Build Coastguard Worker while string, bytes, or submessage fields are merged. 610*61c4878aSAndroid Build Coastguard Worker 611*61c4878aSAndroid Build Coastguard Worker* Only one layer of searching is supported; it is not possible to look up a 612*61c4878aSAndroid Build Coastguard Worker nested field. 613*61c4878aSAndroid Build Coastguard Worker 614*61c4878aSAndroid Build Coastguard Worker* The stream version of the Find API does not allow scanning for submessages due 615*61c4878aSAndroid Build Coastguard Worker to limitations with the ownership and lifetime of its decoder. 616*61c4878aSAndroid Build Coastguard Worker 617*61c4878aSAndroid Build Coastguard Worker**RPC integration** 618*61c4878aSAndroid Build Coastguard Worker 619*61c4878aSAndroid Build Coastguard Worker* RPC creates and runs message encoders and decoders for the user. Therefore, it 620*61c4878aSAndroid Build Coastguard Worker is not possible to use any messages with callback-based fields in RPC method 621*61c4878aSAndroid Build Coastguard Worker implementations. 622*61c4878aSAndroid Build Coastguard Worker 623*61c4878aSAndroid Build Coastguard WorkerDeep dive on selected issues 624*61c4878aSAndroid Build Coastguard Worker---------------------------- 625*61c4878aSAndroid Build Coastguard Worker 626*61c4878aSAndroid Build Coastguard WorkerGenerated namespaces 627*61c4878aSAndroid Build Coastguard Worker^^^^^^^^^^^^^^^^^^^^ 628*61c4878aSAndroid Build Coastguard Worker``pw_protobuf``'s generator was written to output a namespace for each message 629*61c4878aSAndroid Build Coastguard Workerin a file from its first implementation, on top of which all subsequent 630*61c4878aSAndroid Build Coastguard Workergenerated code was added. 631*61c4878aSAndroid Build Coastguard Worker 632*61c4878aSAndroid Build Coastguard WorkerThe reason for this unusual design choice was to work around C++'s 633*61c4878aSAndroid Build Coastguard Workerdeclaration-before-definition rule to allow circularly-referential protobuf 634*61c4878aSAndroid Build Coastguard Workermessages. Each message's associated generated classes are first forward-declared 635*61c4878aSAndroid Build Coastguard Workerat the start of the generated header, and later defined as necessary. 636*61c4878aSAndroid Build Coastguard Worker 637*61c4878aSAndroid Build Coastguard WorkerFor example, given a message ``Foo``, the following code is generated: 638*61c4878aSAndroid Build Coastguard Worker 639*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 640*61c4878aSAndroid Build Coastguard Worker 641*61c4878aSAndroid Build Coastguard Worker namespace Foo { 642*61c4878aSAndroid Build Coastguard Worker 643*61c4878aSAndroid Build Coastguard Worker // Message field numbers. 644*61c4878aSAndroid Build Coastguard Worker enum Fields; 645*61c4878aSAndroid Build Coastguard Worker 646*61c4878aSAndroid Build Coastguard Worker // Generated struct. 647*61c4878aSAndroid Build Coastguard Worker struct Message; 648*61c4878aSAndroid Build Coastguard Worker 649*61c4878aSAndroid Build Coastguard Worker class StreamEncoder; 650*61c4878aSAndroid Build Coastguard Worker class StreamDecoder; 651*61c4878aSAndroid Build Coastguard Worker 652*61c4878aSAndroid Build Coastguard Worker // Some other metadata omitted. 653*61c4878aSAndroid Build Coastguard Worker 654*61c4878aSAndroid Build Coastguard Worker } // namespace Foo 655*61c4878aSAndroid Build Coastguard Worker 656*61c4878aSAndroid Build Coastguard WorkerThe more intuitive approach of generating a struct/class directly for each 657*61c4878aSAndroid Build Coastguard Workermessage is difficult, if not impossible, to cleanly implement under the current 658*61c4878aSAndroid Build Coastguard Worker``pw_protobuf`` object model. There are several reasons why this is, with the 659*61c4878aSAndroid Build Coastguard Workerprimary being that cross-message dependencies cannot easily be generated due to 660*61c4878aSAndroid Build Coastguard Workerthe aforementioned declaration issues. C++ does not allow forward-declaring a 661*61c4878aSAndroid Build Coastguard Workersubclass, so certain types of nested message relationships are not directly 662*61c4878aSAndroid Build Coastguard Workerrepresentable. Some potential workarounds have been suggested for this, such as 663*61c4878aSAndroid Build Coastguard Workerdefining struct members as aliases to internally-generated types, but we have 664*61c4878aSAndroid Build Coastguard Workerbeen unable to get this correctly working following a timeboxed prototyping 665*61c4878aSAndroid Build Coastguard Workersession. 666*61c4878aSAndroid Build Coastguard Worker 667*61c4878aSAndroid Build Coastguard WorkerMessage structures 668*61c4878aSAndroid Build Coastguard Worker^^^^^^^^^^^^^^^^^^ 669*61c4878aSAndroid Build Coastguard WorkerMany of the issues with message structs stem from the same language limitations 670*61c4878aSAndroid Build Coastguard Workeras those described above with namespacing. As the generated structures' members 671*61c4878aSAndroid Build Coastguard Workerare embedded directly within them and publicly exposed, it is not possible to 672*61c4878aSAndroid Build Coastguard Workerrepresent certain types of valid protobuf messages. Additionally, the way 673*61c4878aSAndroid Build Coastguard Workercertain types of fields are generated is problematic, as described below. 674*61c4878aSAndroid Build Coastguard Worker 675*61c4878aSAndroid Build Coastguard Worker**Optional fields** 676*61c4878aSAndroid Build Coastguard Worker 677*61c4878aSAndroid Build Coastguard WorkerA field labeled as ``optional`` in a proto file generates a struct member 678*61c4878aSAndroid Build Coastguard Workerwrapped in a ``std::optional`` from the C++ STL. This choice is semantically 679*61c4878aSAndroid Build Coastguard Workerinconsistent with how the official protobuf libraries in other languages are 680*61c4878aSAndroid Build Coastguard Workerdesigned. Typically, accessing a field will always return a valid value. In the 681*61c4878aSAndroid Build Coastguard Workercase of absence, the field is populated with its default value (the zero value 682*61c4878aSAndroid Build Coastguard Workerunless otherwise specified). Presence checking is implemented as a parallel API 683*61c4878aSAndroid Build Coastguard Workerfor users who require it. 684*61c4878aSAndroid Build Coastguard Worker 685*61c4878aSAndroid Build Coastguard WorkerThis choice also results in additional memory overhead, as each field's presence 686*61c4878aSAndroid Build Coastguard Workerflag is stored within its optional wrapper, padding what could otherwise be a 687*61c4878aSAndroid Build Coastguard Workersingle bit to a much larger aligned size. In the conventional disconnected model 688*61c4878aSAndroid Build Coastguard Workerof field presence, the generated object could instead store a bitfield with an 689*61c4878aSAndroid Build Coastguard Workerentry for each of its members, compacting its overall size. 690*61c4878aSAndroid Build Coastguard Worker 691*61c4878aSAndroid Build Coastguard WorkerOptional fields are not supported for all types. The compiler ignores the 692*61c4878aSAndroid Build Coastguard Worker``optional`` specifier when it is set on string fields, as well as on nested 693*61c4878aSAndroid Build Coastguard Workermessages, generating the member as a regular field and serializing it per 694*61c4878aSAndroid Build Coastguard Workerstandard ``proto3`` rules, omitting a zero-valued entry. 695*61c4878aSAndroid Build Coastguard Worker 696*61c4878aSAndroid Build Coastguard WorkerImplementing ``optional`` the typical way would require hiding the members of 697*61c4878aSAndroid Build Coastguard Workereach generated message, instead providing accessor functions to modify them, 698*61c4878aSAndroid Build Coastguard Workerchecking for presence and inserting default values where appropriate. 699*61c4878aSAndroid Build Coastguard Worker 700*61c4878aSAndroid Build Coastguard Worker**Oneof fields** 701*61c4878aSAndroid Build Coastguard Worker 702*61c4878aSAndroid Build Coastguard WorkerThe ``pw_protobuf`` code generator completely ignores the ``oneof`` specifier 703*61c4878aSAndroid Build Coastguard Workerwhen processing a message. When multiple fields are listed within a ``oneof`` 704*61c4878aSAndroid Build Coastguard Workerblock in a ``.proto`` file, the generated struct will contain all of them as 705*61c4878aSAndroid Build Coastguard Workerdirect members without any notion of exclusivity. This permits ``pw_protobuf`` 706*61c4878aSAndroid Build Coastguard Workerto encode semantically invalid protobuf messages: if multiple members of a 707*61c4878aSAndroid Build Coastguard Worker``oneof`` are set, the encoder will serialize all of them, creating a message 708*61c4878aSAndroid Build Coastguard Workerthat is unprocessable by other protobuf libraries. 709*61c4878aSAndroid Build Coastguard Worker 710*61c4878aSAndroid Build Coastguard WorkerFor example, given the following protobuf definition: 711*61c4878aSAndroid Build Coastguard Worker 712*61c4878aSAndroid Build Coastguard Worker.. code-block:: proto 713*61c4878aSAndroid Build Coastguard Worker 714*61c4878aSAndroid Build Coastguard Worker message Foo { 715*61c4878aSAndroid Build Coastguard Worker oneof variant { 716*61c4878aSAndroid Build Coastguard Worker uint32 a = 1; 717*61c4878aSAndroid Build Coastguard Worker uint32 b = 2; 718*61c4878aSAndroid Build Coastguard Worker } 719*61c4878aSAndroid Build Coastguard Worker } 720*61c4878aSAndroid Build Coastguard Worker 721*61c4878aSAndroid Build Coastguard WorkerThe generator will output the following struct, allowing invalid messages to be 722*61c4878aSAndroid Build Coastguard Workerwritten. 723*61c4878aSAndroid Build Coastguard Worker 724*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 725*61c4878aSAndroid Build Coastguard Worker 726*61c4878aSAndroid Build Coastguard Worker struct Foo::Message { 727*61c4878aSAndroid Build Coastguard Worker uint32_t a; 728*61c4878aSAndroid Build Coastguard Worker uint32_t b; 729*61c4878aSAndroid Build Coastguard Worker }; 730*61c4878aSAndroid Build Coastguard Worker 731*61c4878aSAndroid Build Coastguard Worker // This will work and create a semantically invalid message. 732*61c4878aSAndroid Build Coastguard Worker Foo::StreamEncoder encoder; 733*61c4878aSAndroid Build Coastguard Worker encoder.Write({.a = 32, .b = 100}); 734*61c4878aSAndroid Build Coastguard Worker 735*61c4878aSAndroid Build Coastguard WorkerSimilarly to ``optional``, the best approach to support ``oneof`` would be to 736*61c4878aSAndroid Build Coastguard Workerhide the members of each message and provide accessors. This would avoid the 737*61c4878aSAndroid Build Coastguard Workerrisk of incorrectly reading memory (such as a wrong ``union`` member) and not 738*61c4878aSAndroid Build Coastguard Workerrequire manual bookkeeping as in nanopb. 739*61c4878aSAndroid Build Coastguard Worker 740*61c4878aSAndroid Build Coastguard Worker-------- 741*61c4878aSAndroid Build Coastguard WorkerProposal 742*61c4878aSAndroid Build Coastguard Worker-------- 743*61c4878aSAndroid Build Coastguard Worker 744*61c4878aSAndroid Build Coastguard WorkerShort-term Plan 745*61c4878aSAndroid Build Coastguard Worker=============== 746*61c4878aSAndroid Build Coastguard WorkerA full rework of ``pw_protobuf`` does not seem feasible at this point in time 747*61c4878aSAndroid Build Coastguard Workerdue to limited resourcing. As a result, the most reasonable course of action is 748*61c4878aSAndroid Build Coastguard Workerto tie up the loose ends of the existing code, and leave the module in a state 749*61c4878aSAndroid Build Coastguard Workerwhere it functions properly in every supported use case, with unsupported use 750*61c4878aSAndroid Build Coastguard Workercases made explicit. 751*61c4878aSAndroid Build Coastguard Worker 752*61c4878aSAndroid Build Coastguard WorkerThe important steps to making this happen are listed below. 753*61c4878aSAndroid Build Coastguard Worker 754*61c4878aSAndroid Build Coastguard Worker* Restructure the module documentation to help users select which protobuf API 755*61c4878aSAndroid Build Coastguard Worker is best suited for them, and add a section explicitly detailing the 756*61c4878aSAndroid Build Coastguard Worker limitations of each. 757*61c4878aSAndroid Build Coastguard Worker 758*61c4878aSAndroid Build Coastguard Worker* Deprecate and hide the ``Message`` API, as it has been superseded by the 759*61c4878aSAndroid Build Coastguard Worker ``Find`` APIs. 760*61c4878aSAndroid Build Coastguard Worker 761*61c4878aSAndroid Build Coastguard Worker* Discourage usage of message structures in new code, while providing a 762*61c4878aSAndroid Build Coastguard Worker comprehensive upfront explanation of their limitations and unsupported use 763*61c4878aSAndroid Build Coastguard Worker cases, including: 764*61c4878aSAndroid Build Coastguard Worker 765*61c4878aSAndroid Build Coastguard Worker * ``oneof`` cannot be used. 766*61c4878aSAndroid Build Coastguard Worker 767*61c4878aSAndroid Build Coastguard Worker * Inlining some types of repeated fields such as submessages is not possible. 768*61c4878aSAndroid Build Coastguard Worker Callbacks must be used to encode and decode them. 769*61c4878aSAndroid Build Coastguard Worker 770*61c4878aSAndroid Build Coastguard Worker * The use of ``optional`` only generates optional struct members for simple 771*61c4878aSAndroid Build Coastguard Worker scalar fields. More complex optional fields must be processed through 772*61c4878aSAndroid Build Coastguard Worker callbacks. 773*61c4878aSAndroid Build Coastguard Worker 774*61c4878aSAndroid Build Coastguard Worker* Update the code generator to loudly fail when it encounters an unsupported 775*61c4878aSAndroid Build Coastguard Worker message or field structure. 776*61c4878aSAndroid Build Coastguard Worker 777*61c4878aSAndroid Build Coastguard Worker* Discourage the use of the automatic ``pw_protobuf`` RPC generator due to the 778*61c4878aSAndroid Build Coastguard Worker limitations with message structures. ``nanopb`` or manually processed ``raw`` 779*61c4878aSAndroid Build Coastguard Worker methods should be used instead. 780*61c4878aSAndroid Build Coastguard Worker 781*61c4878aSAndroid Build Coastguard Worker Similarly, clearly document the limitations around callback-based messages in 782*61c4878aSAndroid Build Coastguard Worker RPCs methods, and provide examples of how to fall back to raw RPC encoding and 783*61c4878aSAndroid Build Coastguard Worker decoding. 784*61c4878aSAndroid Build Coastguard Worker 785*61c4878aSAndroid Build Coastguard Worker* Move all upstream usage of ``pw_protobuf`` away from message structures and 786*61c4878aSAndroid Build Coastguard Worker ``pwpb_rpc`` to the lower-level direct wire APIs, or rarely Nanopb. 787*61c4878aSAndroid Build Coastguard Worker 788*61c4878aSAndroid Build Coastguard Worker* Rename the options files used by ``pw_protobuf``'s message structs to 789*61c4878aSAndroid Build Coastguard Worker distinguish them from Nanopb options. 790*61c4878aSAndroid Build Coastguard Worker 791*61c4878aSAndroid Build Coastguard Worker* Make the ``pw_protobuf`` code generator aware of the protobuf edition option 792*61c4878aSAndroid Build Coastguard Worker so that message definitions using it can be compiled. 793*61c4878aSAndroid Build Coastguard Worker 794*61c4878aSAndroid Build Coastguard Worker* Extend full protobuf code generation support to the Bazel and CMake builds, as 795*61c4878aSAndroid Build Coastguard Worker well as the Android build integration. 796*61c4878aSAndroid Build Coastguard Worker 797*61c4878aSAndroid Build Coastguard Worker* Minimize the amount of duplication in the code generator to clean up generated 798*61c4878aSAndroid Build Coastguard Worker header files and attempt to reduce compiler memory usage. 799*61c4878aSAndroid Build Coastguard Worker 800*61c4878aSAndroid Build Coastguard Worker* Extend the ``Find`` APIs with support for repeated fields to bring them closer 801*61c4878aSAndroid Build Coastguard Worker to the Message API's utility. 802*61c4878aSAndroid Build Coastguard Worker 803*61c4878aSAndroid Build Coastguard WorkerLong-term Plan 804*61c4878aSAndroid Build Coastguard Worker============== 805*61c4878aSAndroid Build Coastguard WorkerThis section lays out a long term design vision for ``pw_protobuf``. There is no 806*61c4878aSAndroid Build Coastguard Workerestimated timeframe on when this work will happen, but the ideas are collected 807*61c4878aSAndroid Build Coastguard Workerhere for future reference. 808*61c4878aSAndroid Build Coastguard Worker 809*61c4878aSAndroid Build Coastguard WorkerReplace message structures 810*61c4878aSAndroid Build Coastguard Worker-------------------------- 811*61c4878aSAndroid Build Coastguard WorkerAs discussed above, most issues with message structures stem from having members 812*61c4878aSAndroid Build Coastguard Workerexposed directly. Obscuring the internal details of messages and providing 813*61c4878aSAndroid Build Coastguard Workerpublic accessor APIs gives the flexibility to fix the existing problems without 814*61c4878aSAndroid Build Coastguard Workerrunning against language limitations or exposing additional complexity to users. 815*61c4878aSAndroid Build Coastguard Worker 816*61c4878aSAndroid Build Coastguard WorkerBy doing so, the internal representation of a message is no longer directly tied 817*61c4878aSAndroid Build Coastguard Workerto C++'s type system. Instead of defining typed members for each field in a 818*61c4878aSAndroid Build Coastguard Workermessage, the entire message structure could consist of an intermediate binary 819*61c4878aSAndroid Build Coastguard Workerrepresentation, with fields located at known offsets alongside necessary 820*61c4878aSAndroid Build Coastguard Workermetadata. This avoids the declaration and aliasing issues, as types are now only 821*61c4878aSAndroid Build Coastguard Workerrequired to be defined at access rather than storage. 822*61c4878aSAndroid Build Coastguard Worker 823*61c4878aSAndroid Build Coastguard WorkerThis would require a complete rewrite which would be incompatible with the 824*61c4878aSAndroid Build Coastguard Workercurrent APIs. The least invasive way to handle it would be to create an entirely 825*61c4878aSAndroid Build Coastguard Workernew code generator, port over the core lower level generator functionality, and 826*61c4878aSAndroid Build Coastguard Workerbuild the new messages on top of it. The old API would then be fully deprecated, 827*61c4878aSAndroid Build Coastguard Workerand users could migrate over one message at a time, with assistance from the 828*61c4878aSAndroid Build Coastguard WorkerPigweed team for internal customers. 829*61c4878aSAndroid Build Coastguard Worker 830*61c4878aSAndroid Build Coastguard WorkerInvestigate standardization of wire format operations 831*61c4878aSAndroid Build Coastguard Worker----------------------------------------------------- 832*61c4878aSAndroid Build Coastguard Worker``pw_protobuf`` is one of many libraries, both within Google and externally, 833*61c4878aSAndroid Build Coastguard Workerthat re-implements protobuf wire format processing. At the time it was written, 834*61c4878aSAndroid Build Coastguard Workerthis made sense, as there was no convenient option that fit the niche that 835*61c4878aSAndroid Build Coastguard Worker``pw_protobuf`` targeted. However, since then, the core protobuf team has 836*61c4878aSAndroid Build Coastguard Workerheavily invested in the development of `upb <https://github.com/protocolbuffers/upb>`_: 837*61c4878aSAndroid Build Coastguard Workera compact, low-level protobuf backend intended to be wrapped by higher-level 838*61c4878aSAndroid Build Coastguard Workerlibraries in various languages. Many of upb's core design goals align with the 839*61c4878aSAndroid Build Coastguard Workerinitial vision for ``pw_protobuf``, making it worthwhile to coordinate with its 840*61c4878aSAndroid Build Coastguard Workerdevelopers to see it may be suitable for use in Pigweed. 841*61c4878aSAndroid Build Coastguard Worker 842*61c4878aSAndroid Build Coastguard WorkerPreliminary investigations into upb have shown that, while small in size, it is 843*61c4878aSAndroid Build Coastguard Workerstill larger than the core of ``pw_protobuf`` as it is a complete protobuf 844*61c4878aSAndroid Build Coastguard Workerlibrary supporting the entire protobuf specification. Not all of that is 845*61c4878aSAndroid Build Coastguard Workerrequired for Pigweed or its customers, so any potential reuse would likely be 846*61c4878aSAndroid Build Coastguard Workercontingent on the ability to selectively remove unnecessary parts. 847*61c4878aSAndroid Build Coastguard Worker 848*61c4878aSAndroid Build Coastguard WorkerAt the time of writing, upb does not have a stable API or ABI. While this is 849*61c4878aSAndroid Build Coastguard Workerokay for first-party consumers, shipping it as part of Pigweed may present 850*61c4878aSAndroid Build Coastguard Workeradditional maintenance issues. 851*61c4878aSAndroid Build Coastguard Worker 852*61c4878aSAndroid Build Coastguard WorkerNonetheless, synchronizing with upb to share learnings and potentially reduce 853*61c4878aSAndroid Build Coastguard Workerduplicated effort should be an essential step in any future ``pw_protobuf`` 854*61c4878aSAndroid Build Coastguard Workerwork. 855