aboutsummaryrefslogtreecommitdiff
path: root/pw_protobuf/docs.rst
diff options
context:
space:
mode:
Diffstat (limited to 'pw_protobuf/docs.rst')
-rw-r--r--pw_protobuf/docs.rst292
1 files changed, 191 insertions, 101 deletions
diff --git a/pw_protobuf/docs.rst b/pw_protobuf/docs.rst
index cbc1792fa..ecc3f5593 100644
--- a/pw_protobuf/docs.rst
+++ b/pw_protobuf/docs.rst
@@ -10,7 +10,7 @@ the Protocol Buffer wire format.
The protobuf module is a work in progress. Wire format encoding and decoding
is supported, though the APIs are not final. C++ code generation exists for
- encoding, but not decoding.
+ encoding and decoding, but does not cover all message types.
------
Design
@@ -166,107 +166,34 @@ space to allocate to account for nested submessage encoding overhead.
created the nested encoder will trigger a crash. To resume using the parent
encoder, destroy the submessage encoder first.
+Repeated Fields
+===============
+Repeated fields can be encoded a value at a time by repeatedly calling
+`WriteInt32` etc., or as a packed field by calling e.g. `WritePackedInt32` with
+a `std::span<Type>` or `WriteRepeatedInt32` with a `pw::Vector<Type>` (see
+:ref:`module-pw_containers` for details).
+
Error Handling
==============
While individual write calls on a proto encoder return pw::Status objects, the
encoder tracks all status returns and "latches" onto the first error
encountered. This status can be accessed via ``StreamEncoder::status()``.
-Codegen
-=======
-pw_protobuf encoder codegen integration is supported in GN, Bazel, and CMake.
-The codegen is just a light wrapper around the ``StreamEncoder`` and
-``MemoryEncoder`` objects, providing named helper functions to write proto
-fields rather than requiring that field numbers are directly passed to an
-encoder. Namespaced proto enums are also generated, and used as the arguments
-when writing enum fields of a proto message.
-
-All generated messages provide a ``Fields`` enum that can be used directly for
-out-of-band encoding, or with the ``pw::protobuf::Decoder``.
-
-This module's codegen is available through the ``*.pwpb`` sub-target of a
-``pw_proto_library`` in GN, CMake, and Bazel. See :ref:`pw_protobuf_compiler's
-documentation <module-pw_protobuf_compiler>` for more information on build
-system integration for pw_protobuf codegen.
-
-Example ``BUILD.gn``:
-
-.. Code:: none
-
- import("//build_overrides/pigweed.gni")
-
- import("$dir_pw_build/target_types.gni")
- import("$dir_pw_protobuf_compiler/proto.gni")
-
- # This target controls where the *.pwpb.h headers end up on the include path.
- # In this example, it's at "pet_daycare_protos/client.pwpb.h".
- pw_proto_library("pet_daycare_protos") {
- sources = [
- "pet_daycare_protos/client.proto",
- ]
- }
-
- pw_source_set("example_client") {
- sources = [ "example_client.cc" ]
- deps = [
- ":pet_daycare_protos.pwpb",
- dir_pw_bytes,
- dir_pw_stream,
- ]
- }
-
-Example ``pet_daycare_protos/client.proto``:
-
-.. Code:: none
-
- syntax = "proto3";
- // The proto package controls the namespacing of the codegen. If this package
- // were fuzzy.friends, the namespace for codegen would be fuzzy::friends::*.
- package fuzzy_friends;
-
- message Pet {
- string name = 1;
- string pet_type = 2;
- }
-
- message Client {
- repeated Pet pets = 1;
- }
-
-Example ``example_client.cc``:
-
-.. Code:: cpp
-
- #include "pet_daycare_protos/client.pwpb.h"
- #include "pw_protobuf/encoder.h"
- #include "pw_stream/sys_io_stream.h"
- #include "pw_bytes/span.h"
-
- pw::stream::SysIoWriter sys_io_writer;
- std::byte submessage_scratch_buffer[64];
- // The constructor is the same as a pw::protobuf::StreamEncoder.
- fuzzy_friends::Client::StreamEncoder client(sys_io_writer,
- submessage_scratch_buffer);
- {
- fuzzy_friends::Pet::StreamEncoder pet1 = client.GetPetsEncoder();
- pet1.WriteName("Spot");
- pet1.WritePetType("dog");
- }
+Proto map encoding utils
+========================
- {
- fuzzy_friends::Pet::StreamEncoder pet2 = client.GetPetsEncoder();
- pet2.WriteName("Slippers");
- pet2.WritePetType("rabbit");
- }
+Some additional helpers for encoding more complex but common protobuf
+submessages (e.g. map<string, bytes>) are provided in
+``pw_protobuf/map_utils.h``.
- if (!client.status().ok()) {
- PW_LOG_INFO("Failed to encode proto; %s", client.status().str());
- }
+.. Note::
+ The helper API are currently in-development and may not remain stable.
--------
Decoding
--------
-``pw_protobuf`` provides two decoder implementations, which are described below.
+``pw_protobuf`` provides three decoder implementations, which are described
+below.
Decoder
=======
@@ -425,15 +352,17 @@ its parent decoder cannot be used.
// parent decoder can be used again.
}
-Proto map encoding utils
-========================
-
-Some additional helpers for encoding more complex but common protobuf
-submessages (e.g. map<string, bytes>) are provided in
-``pw_protobuf/map_utils.h``.
+Repeated Fields
+---------------
+The ``StreamDecoder`` supports two encoded forms of repeated fields: value at a
+time, by repeatedly calling `ReadInt32` etc., and packed fields by calling
+e.g. `ReadPackedInt32`.
-.. Note::
- The helper API are currently in-development and may not remain stable.
+Since protobuf encoders are permitted to choose either format, including
+splitting repeated fields up into multiple packed fields, ``StreamDecoder``
+also provides method `ReadRepeatedInt32` etc. methods that accept a
+``pw::Vector`` (see :ref:`module-pw_containers` for details). These methods
+correctly extend the vector for either encoding.
Message
=======
@@ -599,11 +528,172 @@ single fields directly.
.. Note::
The helper API are currently in-development and may not remain stable.
+-------
+Codegen
+-------
+
+pw_protobuf codegen integration is supported in GN, Bazel, and CMake.
+The codegen is a light wrapper around the ``StreamEncoder``, ``MemoryEncoder``,
+and ``StreamDecoder`` objects, providing named helper functions to write and
+read proto fields rather than requiring that field numbers are directly passed
+to an encoder.
+
+All generated messages provide a ``Fields`` enum that can be used directly for
+out-of-band encoding, or with the ``pw::protobuf::Decoder``.
+
+This module's codegen is available through the ``*.pwpb`` sub-target of a
+``pw_proto_library`` in GN, CMake, and Bazel. See :ref:`pw_protobuf_compiler's
+documentation <module-pw_protobuf_compiler>` for more information on build
+system integration for pw_protobuf codegen.
+
+Example ``BUILD.gn``:
+
+.. Code:: none
+
+ import("//build_overrides/pigweed.gni")
+
+ import("$dir_pw_build/target_types.gni")
+ import("$dir_pw_protobuf_compiler/proto.gni")
+
+ # This target controls where the *.pwpb.h headers end up on the include path.
+ # In this example, it's at "pet_daycare_protos/client.pwpb.h".
+ pw_proto_library("pet_daycare_protos") {
+ sources = [
+ "pet_daycare_protos/client.proto",
+ ]
+ }
+
+ pw_source_set("example_client") {
+ sources = [ "example_client.cc" ]
+ deps = [
+ ":pet_daycare_protos.pwpb",
+ dir_pw_bytes,
+ dir_pw_stream,
+ ]
+ }
+
+ pw_source_set("example_server") {
+ sources = [ "example_server.cc" ]
+ deps = [
+ ":pet_daycare_protos.pwpb",
+ dir_pw_bytes,
+ dir_pw_stream,
+ ]
+ }
+
+Example ``pet_daycare_protos/client.proto``:
+
+.. Code:: none
+
+ syntax = "proto3";
+ // The proto package controls the namespacing of the codegen. If this package
+ // were fuzzy.friends, the namespace for codegen would be fuzzy::friends::*.
+ package fuzzy_friends;
+
+ message Pet {
+ string name = 1;
+ string pet_type = 2;
+ }
+
+ message Client {
+ repeated Pet pets = 1;
+ }
+
+Example ``example_client.cc``:
+
+.. Code:: cpp
+
+ #include "pet_daycare_protos/client.pwpb.h"
+ #include "pw_protobuf/encoder.h"
+ #include "pw_stream/sys_io_stream.h"
+ #include "pw_bytes/span.h"
+
+ pw::stream::SysIoWriter sys_io_writer;
+ std::byte submessage_scratch_buffer[64];
+ // The constructor is the same as a pw::protobuf::StreamEncoder.
+ fuzzy_friends::Client::StreamEncoder client(sys_io_writer,
+ submessage_scratch_buffer);
+ {
+ fuzzy_friends::Pet::StreamEncoder pet1 = client.GetPetsEncoder();
+ pet1.WriteName("Spot");
+ pet1.WritePetType("dog");
+ }
+
+ {
+ fuzzy_friends::Pet::StreamEncoder pet2 = client.GetPetsEncoder();
+ pet2.WriteName("Slippers");
+ pet2.WritePetType("rabbit");
+ }
+
+ if (!client.status().ok()) {
+ PW_LOG_INFO("Failed to encode proto; %s", client.status().str());
+ }
+
+Example ``example_server.cc``:
+
+.. Code:: cpp
+
+ #include "pet_daycare_protos/client.pwpb.h"
+ #include "pw_protobuf/stream_decoder.h"
+ #include "pw_stream/sys_io_stream.h"
+ #include "pw_bytes/span.h"
+
+ pw::stream::SysIoReader sys_io_reader;
+ // The constructor is the same as a pw::protobuf::StreamDecoder.
+ fuzzy_friends::Client::StreamDecoder client(sys_io_reader);
+ while (client.Next().ok()) {
+ switch (client.Field().value) {
+ case fuzzy_friends::Client::Fields::PET: {
+ std::array<char, 32> name{};
+ std::array<char, 32> pet_type{};
+
+ fuzzy_friends::Pet::StreamDecoder pet = client.GetPetsDecoder();
+ while (pet.Next().ok()) {
+ switch (pet.Field().value) {
+ case fuzzy_friends::Pet::NAME:
+ pet.ReadName(name);
+ break;
+ case fuzzy_friends::Pet::TYPE:
+ pet.ReadPetType(pet_type);
+ break;
+ }
+ }
+
+ break;
+ }
+ }
+ }
+
+ if (!client.status().ok()) {
+ PW_LOG_INFO("Failed to decode proto; %s", client.status().str());
+ }
+
+Enums
+=====
+Namespaced proto enums are generated, and used as the arguments when writing
+enum fields of a proto message. When reading enum fields of a proto message,
+the enum value is validated and returned as the correct type, or
+``Status::DataLoss()`` if the decoded enum value was not given in the proto.
+
+Repeated Fields
+===============
+For encoding, the wrappers provide a `WriteFieldName` method with three
+signatures. One that encodes a single value at a time, one that encodes a packed
+field from a `std::span<Type>`, and one that encodes a packed field from a
+`pw::Vector<Type>`. All three return `Status`.
+
+For decoding, the wrappers provide a `ReadFieldName` method with three
+signatures. One that reads a single value at a time, returning a `Result<Type>`,
+one that reads a packed field into a `std::span<Type>` and returning a
+`StatusWithSize`, and one that supports all formats reading into a
+`pw::Vector<Type>` and returning `Status`.
+
+-----------
Size report
-===========
+-----------
Full size report
-----------------
+================
This report demonstrates the size of using the entire decoder with all of its
decode methods and a decode callback for a proto message containing each of the
@@ -613,7 +703,7 @@ protobuf field types.
Incremental size report
------------------------
+=======================
This report is generated using the full report as a base and adding some int32
fields to the decode callback to demonstrate the incremental cost of decoding