xref: /aosp_15_r20/external/pigweed/seed/0103.rst (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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