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

Side by Side Diff: mojo/public/c/bindings/README.md

Issue 2234823005: Initial docs on using the C bindings. (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: spacing 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 | « no previous file | no next file » | 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 Lets look at what the generated code looks like for the following struct:
viettrungluu 2016/08/11 17:15:38 Let's
vardhan 2016/08/11 21:48:33 Done.
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; we see that the order of the fields is
55 different between the mojom and C structs, since the generated C structs are in
56 packing order, not ordinal order. The `example_PersonPtr` union is used to
57 represent an offset in the encoded form, or a pointer in the unencoded form.
58 Although not applicable in this example, there may be additional fields for
59 padding purposes -- since is required since 4-byte datatypes need to be 4-byte
60 aligned, so the generated bindings may include some fields not explicitly
61 present in the mojom. It is important to read the generated struct to make sure
viettrungluu 2016/08/11 17:15:39 The sentence beginning "It is important" doesn't m
vardhan 2016/08/11 21:48:33 clarified.
62 what the fields are, and if possible, use field initializers.
63
64 Since mojom objects appear in the order of when they are referenced, we can use
viettrungluu 2016/08/11 17:15:38 "when" doesn't really make sense.
vardhan 2016/08/11 21:48:33 I changed this to "appear in depth-first order rel
65 a `struct MojomBuffer` and calls to `MojomBuffer_Allocate(..)` to linearly
66 allocate space. The struct needs to be constructed and provided by the user, and
67 it contains 3 fields: A pointer to the buffer, size of the buffer in bytes, and
68 the byte-position of the next allocation, typically set to 0.
69
70 For instance, to allocate space for the `name` parameter of an `example_Person`,
71 we can do so this way:
72 ```C
73 char byte_buffer[512] = {0};
74 struct MojomBuffer buf = {byte_buffer, sizeof(byte_buffer), 0};
75
76 // First allocate space for the exmaple_Person struct:
77 struct example_Person* person =
78 (struct example_Person*)MojomBuffer_Allocate(&buf, sizeof(struct example_Pers on));
79
80 // Allocate enough space for a 10 character string.
81 person->name.ptr = (struct MojomStringHeader*)MojomBuffer_Allocate(
82 &buf,
83 sizeof(struct MojomStringHeader) + 10);
84 ```
85
86 We can extract how much buffer space was used by reading `buf.num_byes_used`.
87
88 Along with the C struct, there are some functions generated that help encode and
89 decode mojom structs, amongst other things. For the `example.Person` mojom
90 struct, the following functions are generated:
91
92 ```c
93 struct example_Person* example_Person_DeepCopy(
94 struct MojomBuffer* in_buffer,
95 struct example_Person* in_data);
96
97 void example_Person_EncodePointersAndHandles(
98 struct example_Person* inout_struct, uint32_t in_struct_size,
99 struct MojomHandleBuffer* inout_handle_buffer);
100
101 void example_Person_DecodePointersAndHandles(
102 struct example_Person* inout_struct, uint32_t in_struct_size,
103 MojomHandle inout_handles[], uin32_t in_num_handles);
104
105 MojomValidationResult example_Person_Validate(
106 const struct example_Person* in_struct, uint32_t in_struct_size,
107 uint32_t in_num_handles);
108 ```
109
110 The generated `example_Person_DeepCopy(..)` function is used to copy over the
111 `in_data` into another buffer, specified by `MojomBuffer`. The primary purpose
112 of this function is "linearize" a given `struct example_Person` and its
113 referenced objects into the new buffer. This essentially recursively copies all
114 objects in encoding order. The new returned copy can then be encoded.
115
116 Example usage copying a struct example_Person `person` :
117 ```c
118 ...
119 char byte_buffer[512] = {0};
120 struct MojomBuffer buf = {byte_buffer, sizeof(byte_buffer), 0};
121 struct example_Person* new_person = example_Person_DeepCopy(&buf, person);
122 assert(new_person != NULL);
123 ...
124 ```
125
126 The generated `example_Person_EncodePointersAndHandles(..)` is used to encode
viettrungluu 2016/08/11 17:15:38 You really love the passive voice, don't you?
vardhan 2016/08/11 21:48:33 Maybe rephrasing this to be "C structs can be enco
viettrungluu 2016/08/11 22:02:41 It is not particularly bothersome to me, but it is
127 the given C struct so that it's in wire-format. This involves translating
128 pointers into relative offsets, and extracting handles out of the struct into a
129 separate handle array (and replacing the handle values in the struct with
130 references into the handle array). The supplied `struct MojomHandleBuffer`
131 needs to be constructed and provided by the user and contains 3 fields: pointer
132 to a handles array, the size of the array (number of elements), and the starting
133 offset into the array where handles can be moved into (typically set to 0).
134
135 The generated `example_Person_DecodePointersAndHandles(..)` does the inverse --
136 it translates relative offsets into pointers, and moves handles out of the
137 handle array and into the struct (based on the encoded offset into the array).
138 In practice, before decoding a mojom struct into a usable C struct, it should be
139 validated.
140
141 The generated `example_Person_Validate(..)` validates an encoded `struct
142 example_Person`. If valid, returns `MOJOM_VALIDATION_ERROR_NONE`, or the
143 relevant error (see `bindings/validation.h` for more error codes).
144
145 ## Interfaces
146
147 It isn't enough to talk to other mojo applications by encoding structs and
148 referenced objects alone; communication happens via interface calls, so we need
149 to frame our structs this way. The following example describes what's generated
150 for interfaces. Consider an interface `Population` with a method `GetPerson()`
151 that returns a `Person` object given their name:
152
153 ```mojom
154 module example;
155
156 [ServiceName="example::EmployeeRegistry"]
157 interface EmployeeRegistry {
158 GetPerson(string name) => (Person person);
159 };
160 ```
161
162 The generated code:
163 ```C
164 #define example_EmployeeRegistry__ServiceName \
165 ((const char*)"example::EmployeeRegistry")
166 #define example_EmployeeRegistry__CurrentVersion ((uint32_t)0)
167
168 // For message GetPerson:
169 #define example_EmployeeRegistry_GetPerson__Ordinal ((uint32_t)0)
170 #define example_EmployeeRegistry_GetPerson__MinVersion ((uint32_t)0)
171
172 // Request struct for GetPerson():
173 struct example_EmployeeRegistry_GetPerson_Request {
174 struct MojomStructHeader header_;
175 struct MojomStringHeaderPtr name;
176 };
177
178 // Response struct for GetPerson():
179 struct example_EmployeeRegistry_GetPerson_Response {
180 struct MojomStructHeader header_;
181 struct example_PersonPtr person;
182 };
183 ```
184
185 We see that the parameters (and return values) of the `GetPerson(..)` message
186 are just mojom structs. To send a `GetPerson(..)` request, an interface request
187 message needs to be constructed. An interface request message for
188 `GetPerson(..)` consists of the following data in the following order:
189
190 1. `struct MojomMessageWithRequestId`. This contains:
191 - the message ordinal (generated above) which represents which message it is.
192 - flags that say if it's a request or response.
193 - a request ID, since this message is expecting a response.
194 - (see `bindings/message.h`)
195 2. `struct examples_EmployeeRegistry_GetPerson_Request`. The actual parameters
196 for GetPerson() are represented by a mojom struct.
197
198 Since the request parameters are just a mojom struct, all struct methods are
199 also generated (see above), e.g, ` void
200 examples_EmployeeRegistry_GetPerson_Request_EncodePointersAndHandles()`. Once
201 the request struct has been encoded, the buffer containing the above two structs
202 can be written to a message pipe.
203
204 On the other hand, when reading message (request or response), the message
205 header must first be validated using
206 ```
207 MojomValidationResult MojomMessage_ValidateHeader(const void* in_buf,
208 uint32_t in_buf_size)
209 ```
210 It is now safe to look at the `request_id` in `struct MojomMessage`. If it is a
211 known ordinal (by checking if its any of `example_EmployeeRegistry_*__Ordinal`),
212 you can validate that it has a request or a response. See `bindings/message.h`
213 for more functions that help validate.
214
215 ## Enums and Constants
216
217 Example mojom code:
218 ``` mojom
219 module example;
220
221 enum MyEnum { Zero, One, Four = 4, Five };
222 const uint64 kMyConst = 34;
223 ```
224
225 Generated C code:
226 ``` C
227 typedef uint32_t example_MyEnum;
228 enum example_MyEnum_Enum {
229 examples_MyEnum_Zero = 0,
230 examples_MyEnum_One = 1,
231 examples_MyEnum_Four = 4,
232 examples_MyEnum_Five = 5,
233 };
234
235 #define example_kMyConst ((uint64_t)34)
236 ```
237
238 ## Tagged Unions
239
240 Example mojom code:
241 ``` mojom
242 module example;
243
244 union MyUnion {
245 int8 f0;
246 string f1;
247 MyUnion f2;
248 };
249
250 struct StructWithUnion {
251 MyUnion u;
252 }
253 ```
254 Generated C code:
255 ```C
256 // Generated code for the Tags enum for |MyUnion|.
257 typedef uint32_t example_MyUnion_Tag;
258 enum example_MyUnion_Tag_Enum {
259 example_MyUnion_Tag_f0 = 0,
260 example_MyUnion_Tag_f1 = 1,
261 example_MyUnion_Tag_f2 = 2,
262 example_MyUnion_Tag__UNKNOWN__ = 0xFFFFFFFF,
263 };
264
265 // Generated code for |MyUnion|.
266 union example_MyUnionPtr {
267 struct example_MyUnion* ptr;
268 uint64_t offset;
269 };
270 struct example_MyUnion {
271 uint32_t size;
272 example_MyUnion_Tag tag;
273 union {
274 int8_t f_f0;
275 union MojomStringHeaderPtr f_f1;
276 union example_MyUnionPtr f_f2;
277 uint64_t unknown;
278 } data;
279 };
280
281 // Snippet of generated code for |StructWithUnion|.
282 struct example_StructWithUnion {
283 struct MojomStructHeader header_;
284 struct example_MyUnion u;
285 };
286 ```
287
288 Note that the `MyUnion` inside the `MyUnion` is a pointer object, whereas the
289 `MyUnion` inside `StructWithUnion` is inlined. The only case when unions are
290 pointer objects are when they are inside another union, otherwise they are
291 inlined. Unions are initialized by setting their size and their tag. The size is
292 always 16 bytes if the union is not null (4 for the size field, 4 for the tag,
293 and 8 for the data). The tag must be set to one defined in the generated enum
294 of tags. The unknown tag isn't meant to be encoded over the wire, and exists as
295 an initial value for a union's tag, but the tag should be set to something else
296 before being written to wire. A union whose size is 0 is considered null. There
297 are no functions generated for unions like they are for structs, since unions
298 aren't ever encoded as a top-level data type that the programmer should have to
299 serialize.
300
301 ## Arrays and Strings
302
303 Arrays and strings (which are just arrays of characters) are not top-level data
304 types; they can only be defined within a struct, union or interface method.
305 Arrays inside structs are pointers to an array object. The array object's byte
306 layout is as follow:
307 1. `struct MojomArrayHeader`. This contains:
308 - Number of bytes in the array (this includes the header and the data
309 following the array header; see `2.`)
310 - Number of elements in the array.
311 - (see `bindings/array.h` for more details)
312 2. The contents of the array (the size of this is accounted for in the number
313 of bytes specified in the array header).
314
315 Note that if the array contains pointer objects (structs, arrays, maps), the
316 array contains only the 8-byte pointers (or offsets in its encoded form) -- the objects' data
viettrungluu 2016/08/11 17:15:38 It'd be nice to wrap text (outside of quoted code,
vardhan 2016/08/11 21:48:33 Done.
317 follow the array contents, and their size is not accounted for in the array head er.
318
319 Example of how to allocate and initialize a new array of 5 int32s, and set each one:
320 ```C
321 ...
322 struct MojomArrayHeader* int32_array = MojomArray_New(&buf, 5, sizeof(int32_t));
323 *MOJOM_ARRAY_INDEX(int32_array, int32_t, 0) = 10;
324 *MOJOM_ARRAY_INDEX(int32_array, int32_t, 1) = 20;
325 *MOJOM_ARRAY_INDEX(int32_array, int32_t, 2) = 30;
326 *MOJOM_ARRAY_INDEX(int32_array, int32_t, 3) = 40;
327 *MOJOM_ARRAY_INDEX(int32_array, int32_t, 4) = 50;
328 ```
329
330 Here, `MojomArray_New(..)` allocates space for the buffer and initializes the
331 header, while the `MOJOM_ARRAY_INDEX(.., i)` macro returns the address of the
332 `i`th element.
333
334 Since strings are just arrays of 1-byte characters, you can use
viettrungluu 2016/08/11 17:15:38 Strictly speaking, strings are more than that, sin
vardhan 2016/08/11 21:48:33 Done.
335 `MojomArray_New(&buf, STR_LENGTH, sizeof(uint8_t))` to allocate a string. Note
336 that the mojom strings by convention aren't null terminated (since their length
337 is encoded in the array header).
338
339 ## Maps
340
341 Maps on the wire are mojom structs with two arrays; one for the keys, and one
342 for the values. The `i`th element in the keys array corresponds to the `i`th
343 element in the values array. As such, both arrays must have the same number
344 of elements, and neither arrays can be null.
345
346 # Generated Bindings
347
348 TODO(vardhan)
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698