xref: /aosp_15_r20/external/pigweed/docs/style/protobuf.rst (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1.. _docs-pw-style-protobuf:
2
3==============
4Protobuf style
5==============
6The Pigweed protobuf style guide is closely based on `Google's public
7protobuf style guide <https://protobuf.dev/programming-guides/style/>`_.
8The Google Protobuf Style Guide applies to Pigweed except as described in this
9document.
10
11The Pigweed protobuf style guide only applies to Pigweed itself. It does not
12apply to projects that use Pigweed or to the third-party code included with
13Pigweed.
14
15--------
16Editions
17--------
18Pigweed only allows ``proto3`` (i.e. ``syntax = "proto3";``) at this time.
19``proto2`` is not supported, and the ``edition`` versions (e.g.
20``edition = "2023";``) will be considered when sufficient motivation arises.
21
22------
23Naming
24------
25Protobuf library structure
26==========================
27All protobuf files should live in a ``proto`` subdirectory within their
28respective modules. This produces an ``import`` path that matches the pattern of
29``[module name]/proto/[proto file].proto``\. If a module exposes multiple proto
30libraries that need to be grouped separately from a build/distribution
31perspective, additional directories may be introduced that follow the pattern
32``[module name]/[group name]_proto/[proto file].proto``\.
33
34Examples:
35
36* ``pw_log/proto``
37* ``pw_unit_test/proto``
38* ``pw_snapshot/proto``
39* ``pw_snapshot/metadata_proto``
40
41Rationale: This overlays the include paths of native libraries, but introduces
42``proto`` to the enclosing directory hierarchy to make it clearer that generated
43proto libraries are being introduced.
44
45Protobuf package names
46======================
47Protobuf library packages should append a ``proto`` suffix to package
48namespaces. If a module exposes multiple proto
49libraries that need to be grouped separately from a build/distribution
50perspective, a ``*_proto`` suffix may be used instead.
51
52Example:
53
54.. code-block:: protobuf
55   :emphasize-lines: 3
56
57   // This lives inside of pw_file.
58
59   package pw.file.proto;
60
61   service FileSystem {
62     // ...
63   }
64
65Rationale: This prevents collisions between generated proto types and
66language-native types.
67
68RPC service names
69=================
70Services should strive for simple, intuitive, globally unique names, and should
71**not** be suffixed with ``*Service``.
72
73Example:
74
75.. code-block:: protobuf
76   :emphasize-lines: 1
77
78   service PwEcho {
79     rpc Echo(EchoRequest) returns (EchoResponse) {}
80   }
81
82Rationale: Pigweed's C++ RPC codegen namespaces services differently than
83regular protos (for example, ``pw::file::pw_rpc::raw::FileSystem::Service``),
84which makes it sufficiently clear when a name refers to a service.
85
86------
87Typing
88------
89Using ``optional``
90==================
91When presence or absence of a field's value has a semantic meaning, the field
92should be marked as ``optional`` to signal the distinction. Otherwise,
93``optional`` should be omitted. This causes the field to still be optional, but
94indicates that the default value of zero is semantically equivalent to an
95explicit value of zero.
96
97Example:
98
99.. code-block:: protobuf
100   :emphasize-lines: 6
101
102   message MyRequest {
103     // The maximum number of `foo` entries to return in the response message.
104     // If this is not set, the response may contain as many `foo` entries
105     // as needed. If `max_foo` is zero, no `foo` entries should be included
106     // in the response.
107     optional uint32 max_foo = 1;
108   }
109
110Rationale: ``optional`` is very useful for clarifying cases where an implied
111default value seems ambiguous, and it also signals codegen for ``has_max_foo``
112getters in various languages.
113
114Using ``required``
115==================
116``required`` fields are strictly forbidden within Pigweed.
117
118-----
119Enums
120-----
121Default values
122==============
123All enums must have a safe default zero value. Usually this is ``UNKNOWN`` or
124``NONE``, but may be any other semantically similar default.
125
126Rationale: Enums are default-initialized to zero, which means that a zero value
127that conveys anything beyond "unset" may be misleading.
128
129.. code-block:: protobuf
130   :emphasize-lines: 5
131
132   package pw.chrono.proto;
133
134   message EpochType {
135     enum Enum {
136       UNKNOWN = 0;
137       TIME_SINCE_BOOT = 1;
138       UTC_WALL_CLOCK = 2;
139       GPS_WALL_CLOCK = 3;
140       TAI_WALL_CLOCK = 4;
141     };
142   }
143
144Namespacing
145===========
146Prefer to place ``enum`` definitions within a ``message`` to namespace the
147generated names for the values.
148
149Rationale: Enum value names can easily collide if you don't prefix them (i.e.
150``UNKNOWN`` from one enum will collide with ``UNKNOWN`` from another enum).
151Namespacing them within a message prevents these collisions.
152
153.. code-block:: protobuf
154   :emphasize-lines: 3, 4
155
156   package pw.chrono.proto;
157
158   message EpochType {
159     enum Enum {
160       UNKNOWN = 0;
161       TIME_SINCE_BOOT = 1;
162       UTC_WALL_CLOCK = 2;
163       GPS_WALL_CLOCK = 3;
164       TAI_WALL_CLOCK = 4;
165     };
166   }
167