Index: docs/intro/mojom_idl.md |
diff --git a/docs/intro/mojom_idl.md b/docs/intro/mojom_idl.md |
index 8b49b675c0268caa95f1e9936f17203314b91e5c..f861e4c26becde232fee0f1edca13753756eb43d 100644 |
--- a/docs/intro/mojom_idl.md |
+++ b/docs/intro/mojom_idl.md |
@@ -1,17 +1,79 @@ |
# Mojom IDL |
The Mojom IDL (interface definition language) is primarily used to describe |
-*interfaces* to be used on [message pipes](message_pipes.md). Below, we describe |
-practical aspects of the Mojom language. Elsewhere, we describe the [Mojom |
-protocol](mojom_protocol.md). (**TODO(vtl)**: Also, serialization format? |
-Versioning?) |
+*interfaces* to be used on [message pipes](message_pipes.md). Below, we give a |
+brief overview of some practical aspects of the Mojom language (for more |
+details, see the [Mojom language](../mojom_lang/mojom_lang.md). Elsewhere, we |
+describe the [Mojom protocol](mojom_protocol.md). (**TODO(vtl)**: Also, |
+serialization format? Versioning?) |
Text files written in Mojom IDL are given the `.mojom` extension by convention |
-(and are usually referred to as Mojom/mojom/`.mojom` files). The Mojom bindings |
-generator (**TODO(vtl)**: link?) may be used to generate code in a variety of |
-languages (including C++, Dart, and Go) from a Mojom file. Such generated code |
-"implements" the things specified in the Mojom file, in a way that's appropriate |
-for the particular target language. |
+(and are usually referred to as Mojom/mojom/`.mojom` files). Mojom IDL permits |
+C++-style comments: single-line comments starting with `//` or multi-line |
+comments enclosed by `/* ... */`. |
+ |
+The Mojom bindings generator (**TODO(vtl)**: link?) may be used to generate code |
+in a variety of languages (including C++, Dart, and Go) from a Mojom file. Such |
+generated code "implements" the things specified in the Mojom file, in a way |
+that's appropriate for the particular target language. |
+ |
+## Modules and imports |
+ |
+A Mojom file begins with an optional *module* declaration, which acts like a C++ |
+namespace declaration (applying to the entire file). It is then followed by zero |
+or more *import* statements, which make the contents of the imported files (and, |
+transitively, their imports) available in the current file. For example: |
+```mojom |
+module my_module.my_submodule; |
+ |
+import "path/to/another.mojom"; |
+import "path/to/yet/a/different.mojom"; |
+``` |
+ |
+### Name resolution |
+ |
+Name resolution is basically C++-like (with `.` instead of `::`): Within |
+`my_module.my_submodule`, an unnested declaration of a name `Foo` declares |
+something with "full" name `my_module.my_submodule.Foo`. A *use* of a name `Foo` |
+could either refer to one of the "full" names: `my_module.my_submodule.Foo`, |
+`my_module.Foo`, or `Foo` (searched in that order). |
+ |
+Nested declarations act in the expected way. E.g., if `Foo` is a struct |
+containing an enum declaration of `Bar`, then `Foo.Bar` (or |
+`my_submodule.Foo.Bar`, or `my_module.my_submodule.Foo.Bar`) can be used to |
+refer to that enum outside of `Foo`. |
+ |
+### Names and ordinals |
+ |
+Generally, at a binary (as opposed to source) level, names in Mojom are not |
+important (except in that they must not collide). Names may be changed without |
+affecting binary compatibility. |
+ |
+Instead, what's important are *ordinals*, which apply to struct fields |
+(including message request/response parameters) and interface messages. Often, |
+these are left implicit, in which case ordinals are assigned consecutively |
+starting from 0. (Obviously, with implicit declaration, the order of declaration |
+of struct fields, etc. is important.) Ordinals may also be assigned explicitly, |
+using the notation `@123` (for example). (This allows struct fields, etc. to be |
+re-ordered in a Mojom file without breaking binary compatibility. |
+ |
+Though ordinals are important for evolving Mojom files in a backwards-compatible |
+way, we will not discuss them in this introduction. |
+ |
+### Naming style |
+ |
+Though names are not important, various code generators expect names in a |
+certain *style*, in order to transform them into a style more appropriate for a |
+given target language: |
+* `StudlyCaps` (a.k.a. `CapitalizedCamelCase`) for: (struct, interface, union, |
+ and enum) type names and message (a.k.a. function or method) names; |
+* `unix_hacker_style` for field names (in structs and unions) and "parameter" |
+ names; |
+* `ALL_CAPS_UNIX_HACKER_STYLE` for enum value names; and |
+* `kStudlyCaps` for const names. |
+ |
+Following this style is highly recommended (and may be required as a practical |
+matter). |
## Interfaces |
@@ -68,234 +130,208 @@ struct MyStruct { |
string b; |
}; |
``` |
-We will discuss in greater detail how structs are declared later. |
+Structs (and interfaces) may also contain enum and const declarations, which |
+we will discuss below. |
+ |
+## Types |
-### Names in Mojom |
+### Non-reference (simple and enum) types |
-Names in Mojom are not important. Except in affecting compatibility at the level |
-of source code (when generating bindings), names in a Mojom file may be changed |
-arbitrarily without any effect on the "meaning" of the Mojom file (subject to |
-basic language requirements, e.g., avoiding collisions with keywords and other |
-names). E.g., the following is completely equivalent to the interface discussed |
-above: |
+We have seen some simple types above, namely `int32`, `uint32`, and `bool`. A |
+complete list of *simple* types is: |
+* `bool`: boolean values; |
+* `int8`, `int16`, `int32`, `int64`: signed 2's-complement integers of the given |
+ size; |
+* `uint8`, `uint16`, `uint32`, `uint64`: unsigned integers of the given size; |
+ and |
+* `float`, `double`: single- and double-precision IEEE floating-point numbers. |
+ |
+Additionally, there are *enum* types, which are user-defined. Internally, enums |
+are signed 2's complement 32-bit integers, so their values are restricted to |
+that range. For example: |
```mojom |
-interface Something { |
- One(int32 an_integer, string a_string); |
- Two() => (bool a_boolean, uint32 an_unsigned); |
- Three() => (); |
+enum MyEnum { |
+ ONE_VALUE = 1, |
+ ANOTHER_VALUE = -5, |
+ THIRD_VALUE, // Implicit value of -5 + 1 = -4. |
+ A_DUPLICATE_VALUE = THIRD_VALUE, |
}; |
``` |
-The `Something` interface is compatible at a binary level with `MyInterface`. A |
-client using the `Something` interface may communicate with a server |
-implementing the `MyInterface` with no issues, and vice versa. |
- |
-The reason for this is that elements (messages, parameters, struct members, |
-etc.) are actually identified by *ordinal* value. They may be specified |
-explicitly (using `@123` notation; see below). If they are not specified |
-explicitly, they are automatically assigned. (The ordinal values for each |
-interface/struct/etc. must assign distinct values for each item, in a |
-consecutive range starting at 0.) |
- |
-Explicitly assigning ordinals allows Mojom files to be rearranged "physically" |
-without changing their meaning. E.g., perhaps one would write: |
+Such an enum type may be used in a struct. For example: |
```mojom |
-interface MyInterface { |
- Bar@1() => (bool x@0, uint32 y@1); |
- Baz@2() => (); |
- |
- // Please don't use this in new code! |
- FooDeprecated@0(int32 a@0, string b@1); |
+struct AStruct { |
+ MyEnum x; |
+ double y; |
}; |
``` |
+(As previously mentioned, an enum declaration may be nested inside a struct or |
+interface declaration.) |
-Ordinals also tie into the versioning scheme (**TODO(vtl)**: link?), which |
-allows Mojom files to be evolved in a backwards-compatible way. We will not |
-discuss this matter further here. |
- |
-**TODO(vtl)**: Maybe mention exceptions to this in attributes (e.g., |
-`ServiceName`). |
+Together, the simple and enum types comprise the *non-reference* types. The |
+remaining types the *reference* types: *pointer* types and *handle* types. |
+Unlike the non-reference types, the reference types all have some notion of |
+"null". |
-## Mojom files |
+### Pointer types |
-A Mojom file consists of, in order: |
-* an optional *module* declaration; |
-* zero or more *import* statements (the order of these is not important); and |
-* zero or more declarations of *struct*s, *interface*s, *union*s, *enum*s, or |
- *const*s (the order of these is not important). |
-(These are all described further below.) |
- |
-Additionally, C/C++-style comments are supported (i.e., single-line comments |
-starting with `//` or multi-line comments of the form `/* ... */`). |
- |
-As stated above, the order of struct/interface/union/enum/const declarations is |
-not important. This is required to allow "cyclic" structures to be defined. |
-Nonetheless, whenever possible, one should declare things before they are |
-"used". For example, the following is valid but not recommended: |
+A struct is itself a pointer type, and can be used as a member of another struct |
+(or as a request/response parameter, for that matter). For example: |
```mojom |
-// NOT recommended. |
- |
-const MyEnum kMyConst = kMyOtherConst; |
-const MyEnum kMyOtherConst = A_VALUE; |
- |
-enum MyEnum { |
- A_VALUE, |
- ANOTHER_VALUE, |
+struct MyStruct { |
+ int32 a; |
+ string b; |
}; |
-``` |
- |
-### Naming style |
- |
-There is a standard style for naming things: |
-* `StudlyCaps` (a.k.a. `CapitalizedCamelCase`) for: (struct, interface, union, |
- and enum) type names and message (a.k.a. function or method) names; |
-* `unix_hacker_style` for field names (in structs and unions) and "parameter" |
- names; |
-* `ALL_CAPS_UNIX_HACKER_STYLE` for enum value names; and |
-* `kStudlyCaps` for const names. |
-Following this style is highly recommended, since code generators for various |
-languages will expect this style, in order to transform the names into a more |
-language-appropriate style. |
- |
-### Module statement |
- |
-The Mojom *module* statement is just a way of logically grouping Mojom |
-declarations. For example: |
-```mojom |
-module my_module; |
-``` |
-Mojom modules are similar to C++ namespaces (and the standard C++ code generator |
-would put generated code into the `my_module` namespace), in that there is no |
-implication that the file contains the entirety of the "module" definiton; |
-multiple files may have the same module statement. (There is also no requirement |
-that the module name have anything to do with the file path containing the Mojom |
-file.) |
- |
-Mojom module names are hierarchical in that they can be composed of multiple |
-parts separated by `.`. For example: |
-```mojom |
-module my_module.my_submodule; |
- |
-struct MyStruct { |
+struct MySecondStruct { |
+ MyStruct x; |
+ MyStruct? y; |
}; |
``` |
-Name look-up is similar to C++: E.g., if the current module is |
-`my_module.my_submodule` then `MyStruct`, `my_submodule.MyStruct`, and |
-`my_module.my_submodule.MyStruct` all refer to the above struct, whereas if the |
-current module is just `my_module` then only the latter two do. |
- |
-### Import declarations |
- |
-An *import* declaration makes the declarations from another Mojom file available |
-in the current Mojom file. Moreover, it operates transitively, in the sense that |
-it also makes the imports of the imported file available, etc. The "argument" to |
-the import statement is a path to a file. Tools that work with Mojom files are |
-typically provided with a search path for importing files (just as a C++ |
-compiler can be provided with an "include path"), for the purposes of resolving |
-these paths. (**TODO(vtl)**: This always includes the current Mojom file's path, |
-right? Is the current path the first path that's searched?) |
- |
-For example: |
-```mojom |
-module my_module; |
+Here, `x` is a *non-nullable* (i.e., required) field of `MySecondStruct`, |
+whereas `y` is *nullable* (i.e., optional). |
+ |
+A complete list of pointer types is: |
+* structs: structs, as discussed above; |
+* `string`/`string?`: Unicode strings; |
+* `array<Type>`/`array<Type>?`: variable-size arrays (a.k.a. vectors or lists) |
+ of type "Type" (which may be any type); |
+* `array<Type, n>`/`array<Type, n>?`: fixed-size arrays of type "Type" and size |
+ "n"; |
+* `map<KeyType, ValueType>`/`map<KeyType, ValueType>?`: maps (a.k.a. |
+ dictionaries) of key type "KeyType" (which may be any non-reference type or |
+ `string`) and value type "ValueType" (which may be any type); and |
+* unions: see below. |
-import "path/to/another.mojom"; |
-import "path/to/yet/a/different.mojom"; |
-``` |
-This makes the contents of the two mentioned Mojom files available, together |
-with whatever they import, transitively. (Note that names are resolved in the |
-way described in the previous section.) |
- |
-Import cycles are not permitted (so, e.g., it would be an error if |
-`path/to/another.mojom` imported the current Mojom file). However, it is |
-entirely valid for Mojom files to be imported (transitively) multiple times |
-(e.g., it is fine for `path/to/another.mojom` to also import |
-`path/to/yet/a/different.mojom`). |
- |
-### Struct declarations |
- |
-A Mojom *struct* declaration consists of a finite sequence of *field |
-declaration*, each of which consists of a *type*, a *name*, and optionally a |
-*default value* (if applicable for the given type). (If no default value is |
-declared, then the default is the default value for the field type, typically 0, |
-null, or similar.) |
- |
-Additionally, a struct may contain enum and const declarations (**TODO(vtl)**: |
-why not struct/union/interface declarations?). While the order of the field |
-declarations (with respect to one another) is important, the ordering of the |
-enum/const declarations (with respect to both the field declarations and other |
-enum/const declarations) is not. (But as before, we recommend declaring things |
-before "use".) |
- |
-Here is an example with these elements: |
+#### Unions |
+ |
+*Unions* are "tagged unions". Union declarations look like struct declarations, |
+but with different meaning. For example: |
```mojom |
-struct Foo { |
- const int8 kSomeConstant = 123; |
- |
- enum MyEnum { |
- A_VALUE, |
- ANOTHER_VALUE |
- }; |
- |
- int8 first_field = kSomeConstant; |
- uint32 second_field = 123; |
- MyEnum etc_etc = A_VALUE; |
- float a; // Default value is 0. |
- string? b; // Default value is null. |
+union MyUnion { |
+ int32 a; |
+ int32 b; |
+ string c; |
}; |
``` |
-(Note that `kSomeConstant` may be referred to as `Foo.kSomeConstant` and, |
-similarly, `MyEnum` as `Foo.MyEnum`. This is required outside of the `Foo` |
-declaration.) |
- |
-### Interface declarations |
- |
-**TODO(vtl)** |
- |
-### Union declarations |
+An element of type `MyUnion` must contain either an `int32` (called `a`), an |
+`int32` (called `b`), *or* a string called `c`. (Like for structs, `MyUnion z` |
+indicates a non-nullable instance, and `MyUnion?` indicates a nullable instance; |
+in the nullable case, `z` may either be null or it must contain one of `a`, `b`, |
+or `c`.) |
-**TODO(vtl)** |
- |
-### Enum declarations |
+### Handle types |
-**TODO(vtl)** |
+#### Raw handle types |
-### Const declarations |
+There are the "raw" *handle* types corresponding to different [Mojo |
+handle](handles.md) types, with mostly self-explanatory names: `handle` (any |
+kind of Mojo handle), `handle<message_pipe>`, `handle<data_pipe_consumer>`, |
+`handle<data_pipe_producer>`, and `handle<shared_buffer>`. These are used to |
+indicate that a given message or struct contains the indicated type of Mojo |
+handle (recall that messages sent on [Mojo message pipes](message_pipes.md) may |
+contain handles in addition to simple data). |
-**TODO(vtl)** |
+Like the pointer types, these may also be nullable (e.g., `handle?`, |
+`handle<message_pipe>?`, etc.), where "null" indicates that no handle is to be |
+sent (and may be realized, e.g., as the invalid Mojo handle). |
-**TODO(vtl)**: Write/(re)organize the sections below. |
+#### Interface types |
-## Data types |
+We have already seen *interface* type declarations. In a message (or struct), it |
+is just a message pipe (endpoint) handle. However, it promises that the *peer* |
+implements the given interface. For example: |
+```mojom |
+interface MyFirstInterface { |
+ Foo() => (); |
+}; |
-### Primitive types |
+interface MySecondInterface { |
+ Bar(MyFirstInterface x); |
+ Baz(MyFirstInterface& y); // Interface request! See below. |
+}; |
+``` |
+Here, a receiver of a `Bar` message is promised a message pipe handle on which |
+it can send (request) messages from `MyFirstInterface` (and then possibly |
+receive responses). I.e., on receiving a `Bar` message, it may then send `Foo` |
+message on `x` (and then receive the response to `Foo`). |
-#### Standard types |
+Like other handle types, instances may be non-nullable or nullable (e.g., |
+`MyFirstInterface?`). |
-#### Enum types |
+#### Interface request types |
-### "Pointer" types |
+*Interface request* types are very much like interface types, and also arise |
+from interface type declarations. They are annotated by a trailing `&`: e.g., |
+`MyFirstInterface&` (or `MyFirstInterface&?` for the nullable version). |
-#### Nullability |
+In a message (or struct), an interface request is also just a message pipe |
+handle. However, it is a promise/"request" that the given message pipe handle |
+implement the given interface (in contrast with the peer implementing it). |
-#### Strings |
+In the above example, the receiver of `Baz` also gets a message pipe handle. |
+However, the receiver is expected to implement `MyFirstInterface` on it (or pass |
+it to someone else who will do so). I.e., `Foo` may be *received* on `y` (and |
+then the response sent on it). |
-#### Maps |
+## Pipelining |
-#### Structs |
+We saw above that Mojom allows both "interfaces" and "interface requests" to be |
+sent in messages. Consider the following interface: |
+```mojom |
+interface Foo { |
+ // ... |
+}; |
-#### Arrays |
+interface FooFactory { |
+ CreateFoo1() => (Foo foo); |
+ CreateFoo2(Foo& foo_request); |
+}; |
+``` |
-#### Unions |
+`CreateFoo1` and `CreateFoo2` are functionally very similar: in both cases, the |
+sender will (eventually) be able to send `Foo` messages on some message pipe |
+handle. However, there are some important differences. |
+ |
+In the case of `CreateFoo1`, the sender is only able to do so upon receiving the |
+response to `CreateFoo1`, since the message pipe handle to which `Foo` messages |
+can be written is contained in the response message to `CreateFoo1`. |
+ |
+For `CreateFoo2`, the operation is somewhat different. Before sending |
+`CreateFoo2`, the sender creates a message pipe. This consists of two message |
+pipe handles (for peer endpoints), which we'll call `foo` and `foo_request` (the |
+latter of which will be sent in the `CreateFoo2` message). Since message pipes |
+are asynchronous and buffered, the sender can start writing `Foo` messages to |
+`foo` at any time, possibly even before `CreateFoo2` is sent! I.e., it can use |
+`foo` without waiting for a response message. This is referred to as |
+*pipelining*. |
+ |
+Pipelining is typically more efficient, since it eliminates eliminating the need |
+to wait for a response, and it is often more natural, since receiving the |
+response often entails returning to the message loop. Thus this is generally the |
+preferred pattern for "factories" as in the above example. |
+ |
+The main caveat is that with pipelining, there is no flow control. The sender of |
+`CreateFoo2` has no indication of when `foo` is actually "ready", though even in |
+the case of `CreateFoo1` there is no real promise that the `foo` in the response |
+is actually "ready". (This is perhaps an indication that flow control should be |
+done on `Foo`, e.g., by having its messages have responses.) |
+ |
+Relatedly, with pipelining, there is limited opportunity to send back |
+information regarding `foo`. (E.g., the preferred method of signalling error is |
+to simply close `foo_request`.) So if additional information is *needed* to make |
+use of `foo`, perhaps the pattern of `CreateFoo1` is preferable, e.g.: |
+```mojom |
+ CreateFoo() => (Foo foo, NeededInfo info); |
+``` |
-### Handle types |
+## Consts |
-#### Raw handle types |
+**TODO(vtl)** |
-#### Interface types |
+## Annotations |
-#### Interface request types |
+**TODO(vtl)** |
-## Annotations |
+## See also |
-## Pipelining |
+**TODO(vtl)** |