| # [FTP](../README.md)-025: Bit Flags |
| |
| _Just a Little Bit_ |
| |
| Field | Value |
| ----------|-------------------------- |
| Status | Accepted |
| Authors | kulakowski@google.com |
| Submitted | 2019-01-09 |
| Reviewed | 2019-01-24 |
| |
| # Summary |
| |
| Extend the FIDL language with bit flag declarations. |
| |
| # Motivation |
| |
| There are several use cases for describing a set of flags over an integer in |
| FIDL. |
| Currently, users of FIDL are advised to make a set of constants of the same |
| underlying type. |
| Because these are all independent, creation of invalid values cannot be |
| detected by the bindings at runtime. |
| |
| # Design |
| |
| ## Source language Changes |
| |
| This proposal adds the `bits` keyword to FIDL. |
| |
| `bits` introduce a top-level declaration, similar to `enum`s. |
| Formally, the productions in the grammar are as follows: |
| |
| ``` |
| bits-declaration = ( attribute-list ) , "bits" , IDENTIFIER , ( ":" , type-constructor ) , |
| "{" , ( bits-or-enum-member , ";" )+ , "}" ; [NOTE 1] |
| |
| bits-or-enum-member = ( attribute-list ) , IDENTIFIER , ( "=" , bits-or-enum-member-value ) ; |
| |
| bits-or-enum-member-value = IDENTIFIER | literal ; [NOTE 2] |
| ``` |
| |
| Notes: |
| |
| 1. The `bits-declaration` allows the more liberal `type-constructor` in the grammar, but |
| the compiler limits this to unsigned integer types, see [primitives]. |
| |
| 2. The `bits-or-enum-member-value` allows the more liberal `literal` in the grammar, but the compiler limits this to: |
| * A `NUMERIC-LITERAL` in the context of an `enum`; |
| * A `NUMERIC-LITERAL` which must be a power of two, in the context of a `bits`. |
| |
| Each member in a `bits` declaration is a power of two. |
| This proposal suggests not allowing more complicated expressions in the `bits` |
| declaration itself, nor allowing them to be ORed together in `bits` constant |
| expressions, for the sake of simplicity. |
| They could be added to `bits` declarations in the future. |
| |
| An example of a `bits` declaration, taken from constants currently in the |
| fuchsia.io library: |
| |
| ```fidl |
| bits OpenRights : uint32 { |
| READABLE = 0x00000001; |
| WRITABLE = 0x00000002; |
| ADMIN = 0x00000004; |
| }; |
| ``` |
| |
| Furthermore, this proposal adds a binary literal syntax like so: |
| |
| ```fidl |
| bits OpenRights : uint32 { |
| READABLE = 0b0001; |
| WRITABLE = 0b0010; |
| ADMIN = 0b0100; |
| }; |
| ``` |
| |
| ## Semantics |
| |
| Overflowing the underlying integer type is a compilation error. |
| |
| Each `bits` member value must be distinct. |
| |
| Serializing or deserializing a `bits` value which has a bit set that is not a |
| member of the `bits` declaration is a validation error. |
| |
| The semantics of `bits` are distinct from `enum`. |
| An `enum` value must be exactly one of the values declared in FIDL, while |
| `bits` may not. |
| For instance, if `OpenRights` were an `enum`, the only valid values to send |
| would be `1`, `2`, and `4`. |
| As a `bits` type, though, `0`, `3`, `5`, `6`, and `7` are all also valid. |
| |
| ## Bindings |
| |
| Each language binding will be extended to handle these values idiomatically. |
| At worst, this simply generates a constant for each `bits` member as though it |
| were an integral constant of the underlying type. |
| |
| The wire format for a `bits` value is the same as the underlying integral value. |
| |
| Serializing and deserializing code should ensure that the value is a subset of |
| the described bits. |
| For instance, attempting to use 8 as an `OpenRights` value should fail validation. |
| |
| ## Signal and Rights Constants |
| |
| I also propose adding signal and handle right values to the `zx` library. |
| This includes a `bits` declaration of all the signal value and rights, and |
| possibly a set of constants with default rights for each handle type. |
| |
| # Implementation strategy |
| |
| ## Phase 1 |
| |
| Add all of the source changes to the FIDL compiler, including parser tests. |
| |
| ## Phase 2 |
| |
| Add support to all language bindings, and to the compatibility test suite. |
| |
| ## Phase 3 |
| |
| Migrate existing pile-of-int-constants to `bits`. |
| |
| # Ergonomics |
| |
| This change makes FIDL more ergonomic, by letting users explicitly express |
| their intention, and readers see the explicit grouping. |
| |
| # Documentation and examples |
| |
| This proposal describes changes to the FIDL grammar above. |
| |
| I would tweak the FIDL tutorial to include an example of this pattern. |
| |
| # Backwards compatibility |
| |
| This is a backwards compatible change to FIDL source. |
| |
| The wire format is backwards compatible, in the sense that the value of `(2 | |
| 4)`, or `6`, is the same on the wire whether sent as a `uint32` or a `bits Bits : |
| uint32`. |
| |
| # Performance |
| |
| Changing a type in FIDL from a `uint32` to a `bits` value adds some |
| minor overhead in the bindings of checking that the serialized or deserialized |
| value is valid. |
| |
| This is a bitmask and a branch, and unlikely to be noticable. |
| |
| # Security |
| |
| I do not see a security downside. |
| The better type safety is perhaps a minor upside. |
| |
| # Testing |
| `fidlc` host unit tests will exercise the FIDL parser. |
| |
| The compatibility test suite will be extended with `bits` types of various sizes |
| and values to exercise the sending and receiving paths of all supported |
| bindings. |
| |
| # Drawbacks, alternatives, and unknowns |
| |
| This proposal suggests only allowing bits for unsigned integer types. |
| I believe it would be possible to allow it for signed underlying types, but |
| with more care than desirable necessary in all of the language bindings. |
| I'd rather not have us accidentally shifting bits too far in C/C++ in |
| particular. |
| |
| More general bitfield patterns seem more complicated than worthwhile for this |
| proposal. |
| By this I mean carving an integer type up into ranges of several bits, and |
| giving each range of bits a name as a field. |
| |
| `&` and `~` expressions feel unnecessary, at least at first. |
| Target languages could optionally support such arithmetic expressions on bit |
| flag values, but I do not yet see a need for them in FIDL constants directly. |
| |
| # Prior art and references |
| |
| The hesitancy to do anything too complicated with member values, and to avoid |
| signed types, is based on eternal confusion with those concepts in C and C++, |
| whose bindings must support this concept. |
| |
| <!-- xrefs --> |
| [primitives]: /docs/reference/fidl/language/language.md#primitives |