HLCPP bindings

Libraries

All generated code for a given fidl library is placed in a corresponding C++ namespace. For example, given the library declaration:

library games.tictactoe;

All declarations in the file reside in the games::tictactoe namespace, and test scaffolding will be generated in games::tictactoe::testing.

Constants

All primitives are generated as a constexpr. For example, the following constants:

const uint8 BOARD_SIZE = 9;
const string NAME = "Tic-Tac-Toe";

Are generated in the header file as:

constexpr uint8_t BOARD_SIZE = 42u;
extern const char[] NAME;

The correspondence between FIDL primitive types and C++ types is outlined in built-in types. Instead of constexpr, strings are declared as an extern const char[] in the header file, and defined in a .cc file.

Fields

This section describes how the FIDL toolchain converts FIDL types to native types in HLCPP. These types can appear as members in an aggregate type or as parameters to a protocol method.

Built-in types

The FIDL types are converted to C++ types based on the following table:

FIDL TypeHLCPP Type
boolbool
int8int8_t
int16int16_t
int32int32_t
int64int64_t
uint8uint8_t
uint16uint16_t
uint32uint32_t
uint64uint64_t
float32float
float64double
array:Nstd::array
vector:Nstd::vector
vector:N?fidl::VectorPtr
stringstd::string
string?fidl::StringPtr
request and request?fidl::InterfaceRequest
Pand P?fidl::InterfaceHandle
handle and handle?zx::handle
handle and handle?The corresponding zx type is used. For example, zx::vmo or zx::channel.

User defined types

In HLCPP, a user defined type (bits, enum, constant, struct, union, or table) is referred to using the generated class or variable (see Type Definitions). For a nullable user-defined type T, a unique_ptr<T> is used.

Request, response, and event parameters

Whenever FIDL needs to generate a single type representing parameters for a request, response, or event (e.g. when generating fit::result compatible result types), it uses the following rules:

  • Multiple arguments are generated as an std::tuple of the parameter types.
  • A single parameter is generated following the usual rules described above.
  • An empty set of parameters is represented using void.

Type definitions

Bits

Given a bits definition like:

bits FileMode : uint16 {
    READ = 0b001;
    WRITE = 0b010;
    EXECUTE = 0b100;
};

The FIDL toolchain generates an C++ enum class using the specified underlying type, or uint32_t if none is specified:

enum class FileMode : uint16_t {
    READ = 1u;
    WRITE = 2u;
    EXECUTE = 4u;
};

In addition, FIDL generates the following methods for FileMode:

  • Bitwise operators: implementations for the |, |=, &, &=, ^, ^=, and ~ operators will be generated, allowing bitwise operations on the bits like: mode |= FileMode::EXECUTE.

FIDL also generates a const static FileMode FileModeMask variable. This is a bitmask containing all of the bits in the enum class, which can be used to get rid of any unused bit values from a raw underlying uint16_t (or whichever type the bits are based on). In the above example, FileModeMask has a value of 0b111.

Enums

Given an enum definition like:

enum Color {
    RED = 1;
    GREEN = 2;
    BLUE = 3;
};

The FIDL toolchain generates an equivalent C++ enum class using the specified underlying type, or uint32_t if none is specified:

enum class Color : uint32_t {
    RED = 1u;
    GREEN = 2u;
    BLUE = 3u;
};

Structs

Given a struct declaration:

struct Color {
    uint32 id;
    string name = "red";
};

The FIDL toolchain generates a final WebPage with public members and methods.

  • public members:

    • uint32_t id{};: since id has no default value, it is zero-initialized.
    • std::string url = "www.example.com": the corresponding field for url.
  • Methods:

    • static inline std::unique_ptr<WebPage> New(): returns a unique_ptr to a new WebPage.

The 6 special members of WebPage (default, copy and move constructor, destructor, copy and move assignment) are implicitly defined.

WebPage also has the following associated generated values:

  • WebPagePtr: an alias to unique_ptr<WebPage>.

Structs may have additional members if they represent the response variant of a result.

Unions

The following terminology is used when discussing unions:

  • Variant: the selected member of a union.
  • Tag: the target language variant discriminator. In HLCPP, these are represented using enums.
  • Ordinal: the on the wire variant discriminator.

Given the following union definition:

union JsonValue {
    1: reserved;
    2: int32 int_value;
    3: string string_value;
};

FIDL will generate a final JsonValue class. JsonValue contains a public tag enum representing the possible variants:

enum Tag : fidl_xunion_tag_t {
  kIntValue = 2,
  kStringValue = 3,
  Invalid = std::numeric_limits<fidl_xunion_tag_t>::max(),
};

Each member of Tag has a value matching its ordinal specified in the union definition. Reserved fields do not have any generated code. In addition, there is an Invalid field which is the initial value of the tag of an instance of the JsonValue class that has no variant set yet.

The FIDL toolchain generates the following methods on JsonValue:

  • JsonValue(): Default constructor. The tag is initially Tag::Invalid until the JsonValue is set to a specific variant
  • ~JsonValue(): Default destructor
  • static JsonValue WithIntValue(int32&&) and static JsonValue WithStringValue(std::string&&): These static methods are used to construct a Foo directly from one of the variants.
  • static inline std::unique_ptr<JsonValue> New(): Returns a unique_ptr to a new JsonValue
  • bool has_invalid_tag(): Returns true if the instance of JsonValue does not yet have a variant set. Users should not access a union until a variant is set - doing so should be considered undefined behavior.
  • bool is_int_value() const and bool is_string_value() const: Each variant has an associated method to check whether an instance of JsonValue is of that variant
  • const int32_t& int_value() const and const std::string string_value() const: Read-only accessor methods for each variant. These methods will fail if JsonValue does not have the specified variant set
  • int32_t& int_value() and std::string string_value(): Mutable accessor methods for each variant. If the JsonValue has a different variant than the called accessor method, it will destroy its current data and re-initialize it as the specified variant.
  • JsonValue& set_int_value(class int32_t value) and Foo& set_string_value(class std::string value): Setter methods for each variant.
  • Tag Which() const: returns the current tag of the Foo.
  • fidl_xunion_tag_t Ordinal() const: returns the raw fidl_xunion_tag_t tag. Prefer to use Which() unless the raw ordinal is required

JsonValue also has the following associated generated values:

  • JsonValuePtr: an alias to unique_ptr<Foo>.

Unions may have additional methods if they represent the response variant of a result.

Flexible unions and unknown variants

Flexible unions (that is, unions that are prefixed with the flexible keyword in their FIDL definition) will have an extra variant in the generated Tag:

enum Tag : fidl_xunion_tag_t {
    kUnknown = 0,
    ... // other fields omitted
};

When a FIDL message containing a union with an unknown variant is decoded into JsonValue, JsonValue::Which() will return JsonValue::Tag::kUnknown, and JsonValue::Ordinal() will return the unknown ordinal.

JsonValue will also have the following extra methods:

  • const vector<uint8_t>* UnknownData() const: returns the raw bytes of the union variant

HLCPP does not support encoding a JsonValue if it has an unknown ordinal. Re-encoding a union with an unknown variant does not write the unknown bytes back onto the wire, instead encoding an absent union. Therefore, encoding a message with an uninitialized union will only succeed if this union is allowed to be absent (i.e. if it is specified as JsonValue? instead of JsonValue).

Non-flexible (i.e. strict) unions fail when decoding a data containing an unknown variant.

Tables

Given the following table definition:

table User {
    1: reserved;
    2: uint8 age;
    3: string name;
};

The FIDL toolchain will generate a final User class that defines the following methods:

  • User(): Default constructor, initializes with all fields unset.
  • User(User&& other): Move constructor.
  • ~User(): Destructor.
  • User& User::operator=(User&& other): Move assignment.
  • bool IsEmpty() const: Returns whether no fields are set.
  • bool has_x() const and bool has_y() const: Returns whether a field is set.
  • const uint8_t& age() const and const std::string& name() const: Read-only field accessor methods. These fail if the field is not set.
  • uint8_t* mutable_age() and std::string* mutable_age(): Mutable field accessor methods. If the field is not set, a default one will be constructed, set, and returned.
  • User& set_age(uint8_t _value) and User& set_name(std::string _value): Field setters.
  • void clear_age() and void clear_name(): Clear the value of a field by calling its destructor

User also has the following associated generated values:

  • UserPtr: an alias to unique_ptr<User>.

Protocols

Given a protocol:

protocol TicTacToe {
    StartGame(bool start_first);
    MakeMove(uint8 row, uint8 col) -> (bool success, GameState? new_state);
    -> OnOpponentMove(GameState new_state);
};

FIDL will generate a TicTacToe class, which acts as an entry point for interacting with the protocol and defines the interface of the service which is used by clients to proxy calls to the server, and for the server for implementing the protocol.

TicTacToe contains the following member types:

  • MakeMoveCallback and OnOpponentMoveCallback: Each response and event has a member type generated that represents the type of the callback for handling that response or event. In the above example, MakeMoveCallback aliases fit::function<void(bool, std::unique_ptr<GameState>)> and OnOpponentMoveCallback aliases fit::function<void(GameState)>.

TicTacToe additionally has the following pure virtual methods, corresponding to the methods in the protocol definition:

  • virtual void StartGame(bool start_first) = 0: Pure virtual method for a fire and forget protocol method. It takes as arguments the request parameters.
  • virtual void MakeMove(uint8_t row, uint8_t col, MakeMoveCallback callback) = 0: Pure virtual method for a two way protocol method. It takes as arguments the request parameters followed by the response handler callback.

Other code may be generated depending on the attributes applied to the protocol or its methods.

Client

Clients do not use the TicTacToe class directly. Instead, the FIDL toolchain generates two aliases for the classes used to make calls to a server implementing the TicTacToe protocol: TicTacToePtr, which aliases fidl::InterfacePtr<TicTacToe> representing an async client, and TicTacToeSyncPtr, which aliases fidl::SynchronousInterfacePtr<TicTacToe> representing a synchronous client.

When dereferenced, TicTacToePtr and TicTacToeSyncPtr return a proxy class that implements TicTacToe, which is how the client makes requests to the server. In this example, given a TicTacToePtr called async_tictactoe, requests could be made by calling async_tictactoe->StartGame(start_first) or async_tictactoe->MakeMove(row, col, callback).

Examples on how to set up and bind an InterfacePtr or a SynchronousInterfacePtr to a channel are covered in the HLCPP tutorial.

Server

Implementing a server for a FIDL protocol involves providing a concrete implementation of TicTacToe.

Examples on how to set up and bind a server implementation are covered in the HLCPP tutorial.

Events

Client

For a TicTacToePtr tictactoe, tictactoe.events() will return a proxy class that contains the following public members:

  • OnOpponentMoveCallback OnOpponentMove: The callback handler for the OnOpponentMove event.

Clients can handle events by setting the members of this class to the desired event handlers.

Server

For a Binding<TicTacToe> tictactoe, tictactoe.events() will return a stub class that contains the following public members:

  • void OnOpponentMove(GameState new_state): Send an OnOpponentMove.

Results

Given a method:

protocol TicTacToe {
    MakeMove(uint8 row, uint8 col) -> (GameState new_state) error MoveError;
};

FIDL generates code so that clients and servers can use fit::result in place of the generated MakeMove response type. This is done by generating a TicTacToe_MakeMove_Result (following the naming scheme [protocol]_[method]_Result) class to represent the response, which is interchangeable with fit::result<GameState, MoveError>. Using this feature, an example implementation of MakeMove on the server side could look like:

void  MakeMove(MakeMoveCallback callback) override {
    callback(fit::ok(game_state_.state()));
    // or, in the error case: callback(fit::error(Error::kInvalid);
}

An example of using this on the client side, in the async case would be:

async_game->MakeMove([&](fit::result<GameState, MoveError>> response) { ... });

When generating code, the FIDL toolchain treats TicTacToe_MakeMove_Result as a union with two variants: response, which is a generated type described below, and err, which is the error type (in this case uint32), which means that it provides all the methods available to a regular union. In addition, TicTacToe_MakeMove_Result provides methods that allow interop with fit::result:

  • TicTacToe_MakeMove_Resultfit::result<GameState, MoveError>&& result): Move constructor from a fit::result.
  • TicTacToe_MakeMove_Result(fit::ok_result<GameState>&& result): Move constructor from a fit::ok_result.
  • TicTacToe_MakeMove_Result(fit::error_result<MoveError>&& result): Move constructor from a fit::error_result.
  • operator fit::result<GameState, MoveError>() &&: Conversion to a fit::result.

Note that the successful result type parameter of the fit::result follows the parameter type conversion rules: if MakeMove returned multiple values on success, the result type would be a tuple of the response parameters fit::result<std::tuple<...>, ...>, and if MakeMove returned an empty response, the result type would be fit::result<void, ...>.

The FIDL toolchain also generates a TicTacToe_MakeMove_Response class, which is the type of the response variant of TicTacToe_MakeMove_Result. This class is treated as a FIDL struct with fields corresponding to each parameter of the successful response. In addition to the methods and members available to a regular struct, TicTacToe_MakeMove_Response provides additional methods that allow interop with std::tuple:

  • explicit TicTacToe_MakeMove_Response(std::tuple<GameState> _value_tuple): Constructor from a tuple.
  • operator std::tuple<GameState>() &&: Conversion operator for a tuple.

Protocol composition

FIDL does not have a concept of inheritance, and generates full code as described above for all composed protocols. In other words, the code generated for

protocol A {
    Foo();
};

protocol B {
    compose A;
    Bar();
};

Provides the same API as the code generated for:

protocol A {
    Foo();
};

protocol B {
    Foo();
    Bar();
};

The generated code is identical except for the method ordinals.

Protocol and method attributes

Transitional

For protocols annotated with the [Transitional] attribute, the virtual methods on the protocol class are not pure. This allows implementations of the protocol class with missing method overrides to compile successfully.

Discoverable

A protocol annotated with the [Discoverable] attribute causes the FIDL toolchain to generate an additional static const char Name_[] field on the protocol class, containing the full protocol name. For a protocol Baz in the library foo.bar, the generated name is "foo.bar.Baz".

Test scaffolding

The FIDL toolchain also generates a file suffixed with _test_base.h that contains convenience code for testing FIDL server implementations. This file contains a class for each protocol that provides stub implementations for each of the class’s methods, making it possible to implement only the methods that are used during testing. These classes are generated into a testing namespace that is inside of the generated library’s namespace (e.g. for library games.tictactoe, these classes are generated into games::tictactoe::testing).

Given a protocol:

protocol TicTacToe {
    StartGame(bool start_first);
    MakeMove(uint8 row, uint8 col) -> (bool success, GameState? new_state);
    -> OnOpponentMove(GameState new_state);
};

The FIDL toolchain generates a TicTacToe_TestBase class that subclasses TicTacToe (see Protocols), offering the following methods:

  • virtual ~TicTacToe_TestBase() {}: Destructor.
  • virtual void NotImplemented_(const std::string& name) = 0: Pure virtual method that is overridden to define behavior for unimplemented methods.

TicTacToe_TestBase provides an implementation for the virtual protocol methods StartGame and MakeMove, which are implemented to just call NotImplemented_("StartGame") and NotImplemented_("MakeMove"), respectively.