Index: mojo/public/c/docs/bindings/TUTORIAL.md |
diff --git a/mojo/public/c/docs/bindings/TUTORIAL.md b/mojo/public/c/docs/bindings/TUTORIAL.md |
deleted file mode 100644 |
index 629f185e9771079df30e3b1b84f70f41a47438e6..0000000000000000000000000000000000000000 |
--- a/mojo/public/c/docs/bindings/TUTORIAL.md |
+++ /dev/null |
@@ -1,372 +0,0 @@ |
-# C bindings guide |
- |
-The Mojo C bindings are a way to talk the Mojom protocol, the canonical protocol |
-for communication between Mojo programs. The library under `bindings/` provides |
-functionality for encoding, decoding and other computation, so it needs to be |
-linked together with C code generated from .mojom files. These C bindings are |
-lower-level than the C++ bindings (or any other language, for that matter), |
-are more error-prone, and require some knowledge of the C Mojo API and the |
-mojom encoding format. This document assumes the reader knows about (or knows |
-how to look up) this relevant information. Consequently, C bindings can also |
-be faster; generated bindings are smaller than the C++ equivalent, while |
-encoding and decoding is faster. The intention is to use them only when you |
-require speed and flexibility. |
- |
-## Structs |
- |
-Let's look at what the generated code looks like for the following struct: |
- |
-``` mojom |
-module example; |
- |
-enum Gender { MALE, FEMALE }; |
-struct Person { |
- uint32 age; |
- string name; |
- Gender gender; |
-}; |
-``` |
- |
-A small snippet of the generated C code for the struct and enum: |
- |
-```C |
-// Generated code for mojom enum 'example.Gender'. |
-typedef uint32_t example_Gender; |
-enum example_Gender_Enum { |
- examples_Gender_MALE = 0, |
- examples_Gender_MALE = 1, |
-}; |
- |
-// Generated code for mojom struct 'example.Person'. |
-union example_PersonPtr { |
- struct example_Person* ptr; |
- uint64_t offset; |
-}; |
-struct example_Person { |
- struct MojomStructHeader header_; |
- uint32_t age; |
- example_Gender gender; |
- union MojomStringHeaderPtr name; |
-}; |
-``` |
- |
-The mojom wire format of a struct is comparable to the C memory model of a |
-struct, with some restrictions; in the example above, we see that the order of |
-the fields is different between the mojom and C structs, since the generated C |
-structs are in packing order, not ordinal order. Although not applicable in this |
-example, there may be additional fields inserted in the generated C struct for |
-padding purposes -- since 4-byte data types need to be 4-byte aligned, the |
-generated C bindings may include some fields not explicitly present in the |
-mojom. Since it's not immediately obvious where padding fields could be |
-inserted, it helps to examine the generated C struct to make sure what the |
-fields are, and if possible, set them using field initializers. The |
-`example_PersonPtr` union is used to represent an offset in the encoded form, or |
-a pointer in the unencoded form. |
- |
-Since mojom objects appear in depth-first order relative to their parent object, |
-we can use a `struct MojomBuffer` and calls to `MojomBuffer_Allocate(..)` to |
-linearly allocate space. The struct needs to be constructed and provided by the |
-user, and it contains 3 fields: A pointer to the buffer, size of the buffer in |
-bytes, and the byte-position of the next allocation, typically set to 0. |
- |
-For instance, to allocate space for the `name` parameter of an `example_Person`, |
-we can do so this way: |
-```C |
-char byte_buffer[512] = {0}; |
-struct MojomBuffer buf = {byte_buffer, sizeof(byte_buffer), 0}; |
- |
-// First allocate space for the example_Person struct: |
-struct example_Person* person = |
- (struct example_Person*)MojomBuffer_Allocate(&buf, sizeof(struct example_Person)); |
- |
-// Allocate enough space for a 10 character string. |
-person->name.ptr = (struct MojomStringHeader*)MojomBuffer_Allocate( |
- &buf, |
- sizeof(struct MojomStringHeader) + 10); |
-``` |
- |
-We can extract how much buffer space was used by reading `buf.num_byes_used`. |
- |
-Along with the C struct, there are some functions generated that help encode and |
-decode mojom structs, amongst other things. For the `example.Person` mojom |
-struct, the following functions are generated: |
- |
-```c |
-struct example_Person* example_Person_DeepCopy( |
- struct MojomBuffer* in_buffer, |
- struct example_Person* in_data); |
- |
-void example_Person_EncodePointersAndHandles( |
- struct example_Person* inout_struct, uint32_t in_struct_size, |
- struct MojomHandleBuffer* inout_handle_buffer); |
- |
-void example_Person_DecodePointersAndHandles( |
- struct example_Person* inout_struct, uint32_t in_struct_size, |
- MojomHandle inout_handles[], uin32_t in_num_handles); |
- |
-MojomValidationResult example_Person_Validate( |
- const struct example_Person* in_struct, uint32_t in_struct_size, |
- uint32_t in_num_handles); |
-``` |
- |
-The generated `example_Person_DeepCopy(..)` function is used to copy over the |
-`in_data` into another buffer, specified by `MojomBuffer`. The primary purpose |
-of this function is "linearize" a given `struct example_Person` and its |
-referenced objects into the new buffer. This essentially recursively copies all |
-objects in encoding order. The returned copy can then be encoded. |
- |
-Example usage copying a struct example_Person `person`: |
-```c |
-... |
-char byte_buffer[512] = {0}; |
-struct MojomBuffer buf = {byte_buffer, sizeof(byte_buffer), 0}; |
-struct example_Person* new_person = example_Person_DeepCopy(&buf, person); |
-assert(new_person != NULL); |
-... |
-``` |
- |
-The generated `example_Person_EncodePointersAndHandles(..)` is used to encode |
-a given C struct so that it's in wire-format, ready to send over a message pipe. |
-This encoding process involves translating pointers into relative offsets, and |
-extracting handles out of the struct into a separate handle array (and replacing |
-the handle values in the struct with references into the handle array). The |
-supplied `struct MojomHandleBuffer` needs to be constructed and provided by the |
-user and contains 3 fields: pointer to a handles array, the size of the array |
-(number of elements), and the starting offset into the array where handles can |
-be moved into (typically set to 0). |
- |
-The generated `example_Person_DecodePointersAndHandles(..)` does the inverse -- |
-it translates relative offsets into pointers, and moves handles out of the |
-handle array and into the struct (based on the encoded offset into the array). |
-In practice, before decoding a mojom struct into a usable C struct, it should be |
-first validated; this function may crash on invalid encoded data. |
- |
-The generated `example_Person_Validate(..)` validates an encoded `struct |
-example_Person`. The function returns `MOJOM_VALIDATION_ERROR_NONE` if the |
-struct is valid, in which case the struct can be decoded. See |
-`bindings/validation.h` for more error codes. |
- |
-## Interfaces |
- |
-It isn't enough to talk to other mojo applications by encoding structs and |
-referenced objects alone; communication happens via interface message calls |
-(i.e., sending mojom messages), so we need to frame our structs this way. The |
-following example describes what's generated for interfaces. Consider an |
-interface `Population` with a message `GetPerson()` that returns a `Person` |
-object given their name: |
- |
-```mojom |
-module example; |
- |
-[ServiceName="example.EmployeeRegistry"] |
-interface EmployeeRegistry { |
- GetPerson(string name) => (Person person); |
-}; |
-``` |
- |
-The generated code: |
-```C |
-#define example_EmployeeRegistry__ServiceName \ |
- ((const char*)"example::EmployeeRegistry") |
-#define example_EmployeeRegistry__CurrentVersion ((uint32_t)0) |
- |
-// For message GetPerson: |
-#define example_EmployeeRegistry_GetPerson__Ordinal ((uint32_t)0) |
-#define example_EmployeeRegistry_GetPerson__MinVersion ((uint32_t)0) |
- |
-// Request struct for GetPerson(): |
-struct example_EmployeeRegistry_GetPerson_Request { |
- struct MojomStructHeader header_; |
- struct MojomStringHeaderPtr name; |
-}; |
- |
-// Response struct for GetPerson(): |
-struct example_EmployeeRegistry_GetPerson_Response { |
- struct MojomStructHeader header_; |
- struct example_PersonPtr person; |
-}; |
-``` |
- |
-We see that the parameters (and return value) of the `GetPerson(..)` message are |
-contained within mojom structs. To send a `GetPerson(..)` request, an interface |
-request message must be constructed. An interface request message for |
-`GetPerson(..)` consists of the following data in the following order: |
- |
- 1. `struct MojomMessageWithRequestId`. This contains: |
- - the message ordinal (generated above) which represents which message it is. |
- - flags that say if it's a request or response. |
- - a request ID, since this message is expecting a response. |
- - (see `bindings/message.h`) |
- 2. `struct examples_EmployeeRegistry_GetPerson_Request`. This contains the |
- actual parameters for GetPerson(). |
- |
-Since the request parameters are just a mojom struct, all relevant functions for |
-structs are also generated (see above), e.g, ` void |
-examples_EmployeeRegistry_GetPerson_Request_EncodePointersAndHandles()`. Once |
-the request struct has been encoded, the buffer containing the above two structs |
-can be written to a message pipe. |
- |
-On the other hand, when reading an incoming message, the message header must |
-first be validated using |
-``` |
-MojomValidationResult MojomMessage_ValidateHeader(const void* in_buf, |
- uint32_t in_buf_size); |
-``` |
-- If the message arrives on the client side: |
- 1. It must be validated as a response message. |
- 2. You must check that the message ordinal is known and expects a response |
- message. |
-- If the message arrives on the server side: |
- 1. It must be validated as a request message, and that it's a known ordinal. |
- 2. If the message's ordinal is known to expect a response, the request message |
- must be validated as expecting a response. |
- |
-If valid, it is safe to look at the `request_id` in `struct MojomMessage`, and |
-the `ordinal` describing the message. By checking if it's any of |
-`example_EmployeeRegistry_*__Ordinal`, you can further validate that it is a |
-request or expects a response. See `bindings/message.h` for more functions that |
-help validate message headers. Once the message header is fully validated, you |
-must also validate the request or response mojom struct following the message |
-header using the generated `*_Validate(..)` function. |
- |
-Note that validation is run on encoded messages and structs on the wire -- |
-decoding a struct without validating it first is dangerous. |
- |
-## Enums and Constants |
- |
-Example mojom code: |
-``` mojom |
-module example; |
- |
-enum MyEnum { Zero, One, Four = 4, Five }; |
-const uint64 kMyConst = 34; |
-``` |
- |
-Generated C code: |
-``` C |
-typedef uint32_t example_MyEnum; |
-enum example_MyEnum_Enum { |
- examples_MyEnum_Zero = 0, |
- examples_MyEnum_One = 1, |
- examples_MyEnum_Four = 4, |
- examples_MyEnum_Five = 5, |
-}; |
- |
-#define example_kMyConst ((uint64_t)34) |
-``` |
- |
-## Tagged Unions |
- |
-Example mojom code: |
-``` mojom |
-module example; |
- |
-union MyUnion { |
- int8 f0; |
- string f1; |
- MyUnion f2; |
-}; |
- |
-struct StructWithUnion { |
- MyUnion u; |
-} |
-``` |
-Generated C code: |
-```C |
-// Generated code for the Tags enum for |MyUnion|. |
-typedef uint32_t example_MyUnion_Tag; |
-enum example_MyUnion_Tag_Enum { |
- example_MyUnion_Tag_f0 = 0, |
- example_MyUnion_Tag_f1 = 1, |
- example_MyUnion_Tag_f2 = 2, |
- example_MyUnion_Tag__UNKNOWN__ = 0xFFFFFFFF, |
-}; |
- |
-// Generated code for |MyUnion|. |
-union example_MyUnionPtr { |
- struct example_MyUnion* ptr; |
- uint64_t offset; |
-}; |
-struct example_MyUnion { |
- uint32_t size; |
- example_MyUnion_Tag tag; |
- union { |
- int8_t f_f0; |
- union MojomStringHeaderPtr f_f1; |
- union example_MyUnionPtr f_f2; |
- uint64_t unknown; |
- } data; |
-}; |
- |
-// Snippet of generated code for |StructWithUnion|. |
-struct example_StructWithUnion { |
- struct MojomStructHeader header_; |
- struct example_MyUnion u; |
-}; |
-``` |
- |
-Note that the `MyUnion` inside the `MyUnion` is a pointer object, whereas the |
-`MyUnion` inside `StructWithUnion` is inlined. The only case when unions are |
-pointer objects are when they are inside another union, otherwise they are |
-inlined. Unions are initialized by setting their size and their tag. The size is |
-always 16 bytes if the union is not null (4 for the size field, 4 for the tag, |
-and 8 for the data). The tag must be set to one defined in the generated enum of |
-tags. The unknown tag isn't meant to be encoded over the wire, and exists as an |
-initial value for a union's tag, but the tag should be set to a valid tag |
-before being written to wire. A union whose size is 0 is considered null. Unlike |
-for structs, there are no functions generated for unions, since unions are never |
-encoded as a top-level object type on the wire. |
- |
-## Arrays and Strings |
- |
-Arrays and strings (which are just arrays of characters) are not top-level data |
-types; they can only be defined within a struct, union or interface message. |
-Arrays inside structs are pointers to an array object. The array object's byte |
-layout is as follow: |
- 1. `struct MojomArrayHeader`. This contains: |
- - Number of bytes in the array (this includes the header and the data |
- following the array header; see `2.`) |
- - Number of elements in the array. |
- - (see `bindings/array.h` for more details) |
- 2. The contents of the array (the size of this is accounted for in the number |
- of bytes specified in the array header). |
- |
-Note that if the array contains pointer objects (structs, arrays, maps), the |
-array contains only the 8-byte pointers (or offsets in its encoded form) -- the |
-objects' data follow the array contents, and their size is not accounted for in |
-the array header. |
- |
-Example of how to allocate and initialize a new array of 5 int32s, and set each |
-one: |
-```C |
-... |
-struct MojomArrayHeader* int32_array = MojomArray_New(&buf, 5, sizeof(int32_t)); |
-*MOJOM_ARRAY_INDEX(int32_array, int32_t, 0) = 10; |
-*MOJOM_ARRAY_INDEX(int32_array, int32_t, 1) = 20; |
-*MOJOM_ARRAY_INDEX(int32_array, int32_t, 2) = 30; |
-*MOJOM_ARRAY_INDEX(int32_array, int32_t, 3) = 40; |
-*MOJOM_ARRAY_INDEX(int32_array, int32_t, 4) = 50; |
-``` |
- |
-Here, `MojomArray_New(..)` allocates space for the buffer and initializes the |
-header, while the `MOJOM_ARRAY_INDEX(.., i)` macro returns the address of the |
-`i`th element. |
- |
-TODO(vardhan): Explain how to make an array of bools. |
- |
-Since a mojom string is an array of UTF-8 encoded characters, you can use |
-`MojomArray_New(&buf, NUM_CHARACTERS, sizeof(uint8_t))` if they are ASCII |
-characters. Otherwise, since UTF-8 characters may be variable-sized, you must be |
-careful to set the number of characters appropriately, as it may not be the same |
-as the number of bytes (minus the header). By convention, mojom strings are not |
-null-terminated. |
- |
-## Maps |
- |
-Maps on the wire are mojom structs with two arrays; one for the keys, and one |
-for the values. The `i`th element in the keys array corresponds to the `i`th |
-element in the values array. As such, both arrays must have the same number |
-of elements, and neither may be null. |
- |
-# Additional Readings |
-* [Internals of the generated bindings](INTERNALS.md) |