Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(87)

Side by Side Diff: mojo/public/c/docs/bindings/TUTORIAL.md

Issue 2250183003: Make the fuchsia mojo/public repo the source of truth. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « mojo/public/c/docs/bindings/INTERNALS.md ('k') | mojo/public/c/include/GLES2/gl2.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 # C bindings guide
2
3 The Mojo C bindings are a way to talk the Mojom protocol, the canonical protocol
4 for communication between Mojo programs. The library under `bindings/` provides
5 functionality for encoding, decoding and other computation, so it needs to be
6 linked together with C code generated from .mojom files. These C bindings are
7 lower-level than the C++ bindings (or any other language, for that matter),
8 are more error-prone, and require some knowledge of the C Mojo API and the
9 mojom encoding format. This document assumes the reader knows about (or knows
10 how to look up) this relevant information. Consequently, C bindings can also
11 be faster; generated bindings are smaller than the C++ equivalent, while
12 encoding and decoding is faster. The intention is to use them only when you
13 require speed and flexibility.
14
15 ## Structs
16
17 Let's look at what the generated code looks like for the following struct:
18
19 ``` mojom
20 module example;
21
22 enum Gender { MALE, FEMALE };
23 struct Person {
24 uint32 age;
25 string name;
26 Gender gender;
27 };
28 ```
29
30 A small snippet of the generated C code for the struct and enum:
31
32 ```C
33 // Generated code for mojom enum 'example.Gender'.
34 typedef uint32_t example_Gender;
35 enum example_Gender_Enum {
36 examples_Gender_MALE = 0,
37 examples_Gender_MALE = 1,
38 };
39
40 // Generated code for mojom struct 'example.Person'.
41 union example_PersonPtr {
42 struct example_Person* ptr;
43 uint64_t offset;
44 };
45 struct example_Person {
46 struct MojomStructHeader header_;
47 uint32_t age;
48 example_Gender gender;
49 union MojomStringHeaderPtr name;
50 };
51 ```
52
53 The mojom wire format of a struct is comparable to the C memory model of a
54 struct, with some restrictions; in the example above, we see that the order of
55 the fields is different between the mojom and C structs, since the generated C
56 structs are in packing order, not ordinal order. Although not applicable in this
57 example, there may be additional fields inserted in the generated C struct for
58 padding purposes -- since 4-byte data types need to be 4-byte aligned, the
59 generated C bindings may include some fields not explicitly present in the
60 mojom. Since it's not immediately obvious where padding fields could be
61 inserted, it helps to examine the generated C struct to make sure what the
62 fields are, and if possible, set them using field initializers. The
63 `example_PersonPtr` union is used to represent an offset in the encoded form, or
64 a pointer in the unencoded form.
65
66 Since mojom objects appear in depth-first order relative to their parent object,
67 we can use a `struct MojomBuffer` and calls to `MojomBuffer_Allocate(..)` to
68 linearly allocate space. The struct needs to be constructed and provided by the
69 user, and it contains 3 fields: A pointer to the buffer, size of the buffer in
70 bytes, and the byte-position of the next allocation, typically set to 0.
71
72 For instance, to allocate space for the `name` parameter of an `example_Person`,
73 we can do so this way:
74 ```C
75 char byte_buffer[512] = {0};
76 struct MojomBuffer buf = {byte_buffer, sizeof(byte_buffer), 0};
77
78 // First allocate space for the example_Person struct:
79 struct example_Person* person =
80 (struct example_Person*)MojomBuffer_Allocate(&buf, sizeof(struct example_Pers on));
81
82 // Allocate enough space for a 10 character string.
83 person->name.ptr = (struct MojomStringHeader*)MojomBuffer_Allocate(
84 &buf,
85 sizeof(struct MojomStringHeader) + 10);
86 ```
87
88 We can extract how much buffer space was used by reading `buf.num_byes_used`.
89
90 Along with the C struct, there are some functions generated that help encode and
91 decode mojom structs, amongst other things. For the `example.Person` mojom
92 struct, the following functions are generated:
93
94 ```c
95 struct example_Person* example_Person_DeepCopy(
96 struct MojomBuffer* in_buffer,
97 struct example_Person* in_data);
98
99 void example_Person_EncodePointersAndHandles(
100 struct example_Person* inout_struct, uint32_t in_struct_size,
101 struct MojomHandleBuffer* inout_handle_buffer);
102
103 void example_Person_DecodePointersAndHandles(
104 struct example_Person* inout_struct, uint32_t in_struct_size,
105 MojomHandle inout_handles[], uin32_t in_num_handles);
106
107 MojomValidationResult example_Person_Validate(
108 const struct example_Person* in_struct, uint32_t in_struct_size,
109 uint32_t in_num_handles);
110 ```
111
112 The generated `example_Person_DeepCopy(..)` function is used to copy over the
113 `in_data` into another buffer, specified by `MojomBuffer`. The primary purpose
114 of this function is "linearize" a given `struct example_Person` and its
115 referenced objects into the new buffer. This essentially recursively copies all
116 objects in encoding order. The returned copy can then be encoded.
117
118 Example usage copying a struct example_Person `person`:
119 ```c
120 ...
121 char byte_buffer[512] = {0};
122 struct MojomBuffer buf = {byte_buffer, sizeof(byte_buffer), 0};
123 struct example_Person* new_person = example_Person_DeepCopy(&buf, person);
124 assert(new_person != NULL);
125 ...
126 ```
127
128 The generated `example_Person_EncodePointersAndHandles(..)` is used to encode
129 a given C struct so that it's in wire-format, ready to send over a message pipe.
130 This encoding process involves translating pointers into relative offsets, and
131 extracting handles out of the struct into a separate handle array (and replacing
132 the handle values in the struct with references into the handle array). The
133 supplied `struct MojomHandleBuffer` needs to be constructed and provided by the
134 user and contains 3 fields: pointer to a handles array, the size of the array
135 (number of elements), and the starting offset into the array where handles can
136 be moved into (typically set to 0).
137
138 The generated `example_Person_DecodePointersAndHandles(..)` does the inverse --
139 it translates relative offsets into pointers, and moves handles out of the
140 handle array and into the struct (based on the encoded offset into the array).
141 In practice, before decoding a mojom struct into a usable C struct, it should be
142 first validated; this function may crash on invalid encoded data.
143
144 The generated `example_Person_Validate(..)` validates an encoded `struct
145 example_Person`. The function returns `MOJOM_VALIDATION_ERROR_NONE` if the
146 struct is valid, in which case the struct can be decoded. See
147 `bindings/validation.h` for more error codes.
148
149 ## Interfaces
150
151 It isn't enough to talk to other mojo applications by encoding structs and
152 referenced objects alone; communication happens via interface message calls
153 (i.e., sending mojom messages), so we need to frame our structs this way. The
154 following example describes what's generated for interfaces. Consider an
155 interface `Population` with a message `GetPerson()` that returns a `Person`
156 object given their name:
157
158 ```mojom
159 module example;
160
161 [ServiceName="example.EmployeeRegistry"]
162 interface EmployeeRegistry {
163 GetPerson(string name) => (Person person);
164 };
165 ```
166
167 The generated code:
168 ```C
169 #define example_EmployeeRegistry__ServiceName \
170 ((const char*)"example::EmployeeRegistry")
171 #define example_EmployeeRegistry__CurrentVersion ((uint32_t)0)
172
173 // For message GetPerson:
174 #define example_EmployeeRegistry_GetPerson__Ordinal ((uint32_t)0)
175 #define example_EmployeeRegistry_GetPerson__MinVersion ((uint32_t)0)
176
177 // Request struct for GetPerson():
178 struct example_EmployeeRegistry_GetPerson_Request {
179 struct MojomStructHeader header_;
180 struct MojomStringHeaderPtr name;
181 };
182
183 // Response struct for GetPerson():
184 struct example_EmployeeRegistry_GetPerson_Response {
185 struct MojomStructHeader header_;
186 struct example_PersonPtr person;
187 };
188 ```
189
190 We see that the parameters (and return value) of the `GetPerson(..)` message are
191 contained within mojom structs. To send a `GetPerson(..)` request, an interface
192 request message must be constructed. An interface request message for
193 `GetPerson(..)` consists of the following data in the following order:
194
195 1. `struct MojomMessageWithRequestId`. This contains:
196 - the message ordinal (generated above) which represents which message it is.
197 - flags that say if it's a request or response.
198 - a request ID, since this message is expecting a response.
199 - (see `bindings/message.h`)
200 2. `struct examples_EmployeeRegistry_GetPerson_Request`. This contains the
201 actual parameters for GetPerson().
202
203 Since the request parameters are just a mojom struct, all relevant functions for
204 structs are also generated (see above), e.g, ` void
205 examples_EmployeeRegistry_GetPerson_Request_EncodePointersAndHandles()`. Once
206 the request struct has been encoded, the buffer containing the above two structs
207 can be written to a message pipe.
208
209 On the other hand, when reading an incoming message, the message header must
210 first be validated using
211 ```
212 MojomValidationResult MojomMessage_ValidateHeader(const void* in_buf,
213 uint32_t in_buf_size);
214 ```
215 - If the message arrives on the client side:
216 1. It must be validated as a response message.
217 2. You must check that the message ordinal is known and expects a response
218 message.
219 - If the message arrives on the server side:
220 1. It must be validated as a request message, and that it's a known ordinal.
221 2. If the message's ordinal is known to expect a response, the request message
222 must be validated as expecting a response.
223
224 If valid, it is safe to look at the `request_id` in `struct MojomMessage`, and
225 the `ordinal` describing the message. By checking if it's any of
226 `example_EmployeeRegistry_*__Ordinal`, you can further validate that it is a
227 request or expects a response. See `bindings/message.h` for more functions that
228 help validate message headers. Once the message header is fully validated, you
229 must also validate the request or response mojom struct following the message
230 header using the generated `*_Validate(..)` function.
231
232 Note that validation is run on encoded messages and structs on the wire --
233 decoding a struct without validating it first is dangerous.
234
235 ## Enums and Constants
236
237 Example mojom code:
238 ``` mojom
239 module example;
240
241 enum MyEnum { Zero, One, Four = 4, Five };
242 const uint64 kMyConst = 34;
243 ```
244
245 Generated C code:
246 ``` C
247 typedef uint32_t example_MyEnum;
248 enum example_MyEnum_Enum {
249 examples_MyEnum_Zero = 0,
250 examples_MyEnum_One = 1,
251 examples_MyEnum_Four = 4,
252 examples_MyEnum_Five = 5,
253 };
254
255 #define example_kMyConst ((uint64_t)34)
256 ```
257
258 ## Tagged Unions
259
260 Example mojom code:
261 ``` mojom
262 module example;
263
264 union MyUnion {
265 int8 f0;
266 string f1;
267 MyUnion f2;
268 };
269
270 struct StructWithUnion {
271 MyUnion u;
272 }
273 ```
274 Generated C code:
275 ```C
276 // Generated code for the Tags enum for |MyUnion|.
277 typedef uint32_t example_MyUnion_Tag;
278 enum example_MyUnion_Tag_Enum {
279 example_MyUnion_Tag_f0 = 0,
280 example_MyUnion_Tag_f1 = 1,
281 example_MyUnion_Tag_f2 = 2,
282 example_MyUnion_Tag__UNKNOWN__ = 0xFFFFFFFF,
283 };
284
285 // Generated code for |MyUnion|.
286 union example_MyUnionPtr {
287 struct example_MyUnion* ptr;
288 uint64_t offset;
289 };
290 struct example_MyUnion {
291 uint32_t size;
292 example_MyUnion_Tag tag;
293 union {
294 int8_t f_f0;
295 union MojomStringHeaderPtr f_f1;
296 union example_MyUnionPtr f_f2;
297 uint64_t unknown;
298 } data;
299 };
300
301 // Snippet of generated code for |StructWithUnion|.
302 struct example_StructWithUnion {
303 struct MojomStructHeader header_;
304 struct example_MyUnion u;
305 };
306 ```
307
308 Note that the `MyUnion` inside the `MyUnion` is a pointer object, whereas the
309 `MyUnion` inside `StructWithUnion` is inlined. The only case when unions are
310 pointer objects are when they are inside another union, otherwise they are
311 inlined. Unions are initialized by setting their size and their tag. The size is
312 always 16 bytes if the union is not null (4 for the size field, 4 for the tag,
313 and 8 for the data). The tag must be set to one defined in the generated enum of
314 tags. The unknown tag isn't meant to be encoded over the wire, and exists as an
315 initial value for a union's tag, but the tag should be set to a valid tag
316 before being written to wire. A union whose size is 0 is considered null. Unlike
317 for structs, there are no functions generated for unions, since unions are never
318 encoded as a top-level object type on the wire.
319
320 ## Arrays and Strings
321
322 Arrays and strings (which are just arrays of characters) are not top-level data
323 types; they can only be defined within a struct, union or interface message.
324 Arrays inside structs are pointers to an array object. The array object's byte
325 layout is as follow:
326 1. `struct MojomArrayHeader`. This contains:
327 - Number of bytes in the array (this includes the header and the data
328 following the array header; see `2.`)
329 - Number of elements in the array.
330 - (see `bindings/array.h` for more details)
331 2. The contents of the array (the size of this is accounted for in the number
332 of bytes specified in the array header).
333
334 Note that if the array contains pointer objects (structs, arrays, maps), the
335 array contains only the 8-byte pointers (or offsets in its encoded form) -- the
336 objects' data follow the array contents, and their size is not accounted for in
337 the array header.
338
339 Example of how to allocate and initialize a new array of 5 int32s, and set each
340 one:
341 ```C
342 ...
343 struct MojomArrayHeader* int32_array = MojomArray_New(&buf, 5, sizeof(int32_t));
344 *MOJOM_ARRAY_INDEX(int32_array, int32_t, 0) = 10;
345 *MOJOM_ARRAY_INDEX(int32_array, int32_t, 1) = 20;
346 *MOJOM_ARRAY_INDEX(int32_array, int32_t, 2) = 30;
347 *MOJOM_ARRAY_INDEX(int32_array, int32_t, 3) = 40;
348 *MOJOM_ARRAY_INDEX(int32_array, int32_t, 4) = 50;
349 ```
350
351 Here, `MojomArray_New(..)` allocates space for the buffer and initializes the
352 header, while the `MOJOM_ARRAY_INDEX(.., i)` macro returns the address of the
353 `i`th element.
354
355 TODO(vardhan): Explain how to make an array of bools.
356
357 Since a mojom string is an array of UTF-8 encoded characters, you can use
358 `MojomArray_New(&buf, NUM_CHARACTERS, sizeof(uint8_t))` if they are ASCII
359 characters. Otherwise, since UTF-8 characters may be variable-sized, you must be
360 careful to set the number of characters appropriately, as it may not be the same
361 as the number of bytes (minus the header). By convention, mojom strings are not
362 null-terminated.
363
364 ## Maps
365
366 Maps on the wire are mojom structs with two arrays; one for the keys, and one
367 for the values. The `i`th element in the keys array corresponds to the `i`th
368 element in the values array. As such, both arrays must have the same number
369 of elements, and neither may be null.
370
371 # Additional Readings
372 * [Internals of the generated bindings](INTERNALS.md)
OLDNEW
« no previous file with comments | « mojo/public/c/docs/bindings/INTERNALS.md ('k') | mojo/public/c/include/GLES2/gl2.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698