blob: f54750cfe2fefc9310b6d23038e0818ee643ddfd [file] [log] [blame] [view] [edit]
# HLCPP bindings
## Libraries {#libraries}
Given the library declaration:
```fidl
library fuchsia.examples;
```
All code for this library is generated in the `fuchsia::examples` namespace, and
[test scaffolding](#test-scaffolding) is generated in
`fuchsia::examples::testing`.
## Constants {#constants}
All [constants][lang-constants] are generated as a `constexpr`. For example, the
following constants:
```fidl
{%includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/fidl/fuchsia.examples/types.test.fidl" region_tag="consts" %}
```
Are generated in the header file as:
```c++
constexpr uint8_t BOARD_SIZE = 9u;
extern const char[] NAME;
```
The correspondence between FIDL primitive types and C++ types is outlined in
[built-in types](#builtins). Instead of `constexpr`, strings are declared as an
`extern const char[]` in the header file, and defined in a `.cc` file.
## Fields {#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 {#builtins}
The FIDL types are converted to C++ types based on the following table:
|FIDL Type|HLCPP Type|
|--- |--- |
|`bool`|`bool`|
|`int8`|`int8_t`|
|`int16`|`int16_t`|
|`int32`|`int32_t`|
|`int64`|`int64_t`|
|`uint8`|`uint8_t`|
|`uint16`|`uint16_t`|
|`uint32`|`uint32_t`|
|`uint64`|`uint64_t`|
|`float32`|`float`|
|`float64`|`double`|
|`array:N`|`std::array`|
|`vector:N`|`std::vector`|
|`vector:N?`|`fidl::VectorPtr`|
|`string`|`std::string`|
|`string?`|`fidl::StringPtr`|
|`request<P>`, `request<P>?`|`fidl::InterfaceRequest`|
|`P`,`P?`|`fidl::InterfaceHandle`|
|`handle`, `handle?`|`zx::handle`|
|`handle:S`, `handle:S?`|The corresponding zx type is used. For example, `zx::vmo` or `zx::channel`.|
### User defined types {#user-defined-types}
In HLCPP, a user defined type (bits, enum, constant, struct, union, or table) is
referred to in the bindings using the generated class or variable (see [Type
Definitions](#type-definitions)). For a nullable user-defined type `T`,
`unique_ptr` of the equivalent generated type is used.
### Request, response, and event parameters {#request-response-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](#protocols-results)),
it uses the following rules:
* Multiple arguments are generated as an `std::tuple` of the parameter types.
* A single parameter is just referred to using the parameter type itself.
* An empty set of parameters is represented using `void`.
## Type definitions {#type-definitions}
### Bits {#bits}
Given the [bits][lang-bits] definition:
```fidl
{%includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/fidl/fuchsia.examples/types.test.fidl" region_tag="bits" %}
```
The FIDL toolchain generates a C++ `enum class` using the specified underlying
type, or `uint32_t` if none is specified:
```c++
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 are 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`.
Example usage:
```c++
{%includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/fidl/hlcpp/unittests/main.cc" region_tag="bits" adjust_indentation="auto" exclude_regexp="^TEST|^}" %}
```
#### Flexible bits {#flexible-bits}
[Flexible][lang-flexible] bits are implemented as a `class` instead of an `enum
class`, with the following additional methods:
* `constexpr FileMode()`: Default constructor that initializes a value with no
bits set.
* `constexpr FileMode(uint16_t)`: Constructs a value from an underlying
primitive value, preserving any unknown bit members.
* `constexpr cpp17::optional<FileMode> TryFrom(uint16_t value)`: Constructs an
instance of the bits from an underlying primitive value if the value does not
contain any unknown members, and returns `cpp17::nullopt` otherwise.
* `constexpr FileMode TruncatingUnknown(uint16_t value)`: Constructs an instance
of the bits from an underlying primitive value, clearing any unknown members.
* `constexpr FileMode unknown_bits() const`: Returns a bits value that contains
only the unknown members from this bits value.
* `constexpr bool has_unknown_bits() const`: Returns whether this value contains
any unknown bits.
* `explicit constexpr operator uint16_t() const`: Converts the bits value back
to its underlying primitive value.
* `explicit constexpr operator bool() const`: Returns whether any bits are set.
<!-- TODO(fxbug.dev/64760): mask value should be consistent -->
The generated class contains a static number for each bits member as well as
for the bits mask. These correspond exactly with the members of the `enum class`
value, with the addition a `kMask` member that replaces `FileModeMask`.
* `const static FileMode READ`
* `const static FileMode WRITE`
* `const static FileMode EXECUTE`
* `const static FileMode kMask`
Note: When applying bitwise negation to bits values that contain unknown
members, the resulting bits value is only defined for the known bits.
### Enums {#enums}
Given the [enum][lang-enums] definition:
```fidl
{%includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/fidl/fuchsia.examples/types.test.fidl" region_tag="enums" %}
```
The FIDL toolchain generates a C++ `enum class` using the specified underlying
type, or `uint32_t` if none is specified:
```c++
enum class LocationType : uint32_t {
MUSEUM = 1u;
AIRPORT = 2u;
RESTAURANT = 3u;
};
```
Example usage:
```c++
{%includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/fidl/hlcpp/unittests/main.cc" region_tag="enums" adjust_indentation="auto" exclude_regexp="^TEST|^}" %}
```
#### Flexible enums {#flexible-enums}
[Flexible][lang-flexible] enums are implemented as a `class` instead of an `enum
class`, with the following methods:
* `constexpr LocationType()`: Default constructor, which initializes the enum to
an unspecified unknown value.
* `constexpr LocationType(uint32_t value)`: Explicit constructor that takes in a
value of the underlying type of the enum.
* `constexpr bool IsUnknown()`: Returns whether the enum value is unknown.
* `constexpr static LocationType Unknown()`: Returns an enum value that is
guaranteed to be treated as unknown. If the enum has a member annotated with
[`[Unknown]`][unknown-attr], then the value of that member is returned. If
there is no such member, then the underlying value of the returned enum member
is unspecified.
* `explicit constexpr operator int32_t() const`: Converts the enum back to its
underlying value
The generated class contains a static member for each enum member, which are
guaranteed to match the members of the `enum class` in the equivalent
[strict][lang-flexible] enum:
* `const static LocationType MUSEUM`
* `const static LocationType AIRPORT`
* `const static LocationType RESTAURANT`
### Structs {#structs}
Given a [struct][lang-structs] declaration:
```fidl
{%includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/fidl/fuchsia.examples/types.test.fidl" region_tag="structs" %}
```
The FIDL toolchain generates a `Color` type with public members and methods.
* `public` members:
* `uint32_t id{}`: This field is zero-initialized since no default value is
provided.
* `std::string name = "red"`: The corresponding field for `name`.
* Methods:
* `static inline std::unique_ptr<Color> New()`: returns a `unique_ptr` to a
new `Color`.
The 6 special members of `Color` (default, copy and move constructor,
destructor, copy and move assignment) are implicitly defined.
`Color` also has the following associated generated values:
* `ColorPtr`: an alias to `unique_ptr<Color>`.
Structs may have additional members if they represent the response variant of a
[result](#protocols-results).
Example usage:
```c++
{%includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/fidl/hlcpp/unittests/main.cc" region_tag="structs" adjust_indentation="auto" exclude_regexp="^TEST|^}" %}
```
### Unions {#unions}
Given the union definition:
```fidl
{%includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/fidl/fuchsia.examples/types.test.fidl" region_tag="unions" %}
```
FIDL generates a `JsonValue` class. `JsonValue` contains a public tag enum
representing the possible [variants][union-lexicon]:
```c++
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][union-lexicon] 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 used for a
`JsonValue` that has no variant set yet.
`JsonValue` provides the following methods:
* `JsonValue()`: Default constructor. The tag is initially `Tag::Invalid` until
the `JsonValue` is set to a specific variant. Using the `WithFoo` constructors
should be preferred whenever possible.
* `~JsonValue()`: Default destructor
* `static JsonValue WithIntValue(int32&&)` and `static JsonValue
WithStringValue(std::string&&)`: Static constructors that directly construct a
specific variant of the union.
* `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 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(int32_t)` and `JsonValue&
set_string_value(std::string)`: Setter methods for each variant.
* `Tag Which() const`: returns the current [tag][union-lexicon] of the
`JsonValue`.
* `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](#protocols-results).
Example usage:
```c++
{%includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/fidl/hlcpp/unittests/main.cc" region_tag="unions" adjust_indentation="auto" exclude_regexp="^TEST|^}" %}
```
#### Flexible unions and unknown variants
[Flexible][lang-flexible] unions have an extra variant in the generated `Tag`
class:
```c++
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()` returns `JsonValue::Tag::kUnknown`, and
`JsonValue::Ordinal()` returns the unknown ordinal.
A flexible `JsonValue` type will have extra methods for interacting with unknown
data that will depend on whether the type is a
[value or resource type][lang-resource]. Value types will not have
unknown data methods that reference `zx::handle`.
A flexible `JsonValue` that is a [resource][lang-resource] type has the
following extra methods:
* `const vector<uint8_t>* UnknownBytes() const`: Returns the raw bytes of the
union variant if it is unknown, or `nullptr` otherwise.
* `const vector<zx::handle>* UnknownHandles() const`: Returns the handles of the
union variant in [traversal order][traversal] if it is unknown, or
`nullptr` otherwise.
* `JsonValue& SetUnknownData(fidl_xunion_tag_t ordinal, vector<uint8_t> bytes,
vector<zx::handle> handles)`: Similar to the setter methods for the known
members, this sets the union to an unknown variant with the specified ordinal,
bytes, and handles. This method should only be used for testing, e.g. to
ensure that code can handle unknown data correctly.
A flexible `JsonValue` that is a [value][lang-resource] type has the following
extra methods:
* `const vector<uint8_t>* UnknownBytes() const`: Returns the raw bytes of the
union variant if it is unknown, or `nullptr` otherwise.
* `JsonValue& SetUnknownData(fidl_xunion_tag_t ordinal, vector<uint8_t> bytes)`:
Similar to the setter methods for the known members, this sets the union to an
unknown variant with the specified ordinal and bytes. This method should only
be used for testing, e.g. to ensure that code can handle unknown data
correctly.
Encoding a union with an unknown variant writes the unknown data and the
original ordinal back onto the wire.
[Strict][lang-flexible] unions fail when decoding an unknown variant.
[Flexible][lang-flexible] unions that are [value][lang-resource] types fail when
decoding an unknown variant with handles.
### Tables {#tables}
Given the [table][lang-tables] definition:
```table
{%includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/fidl/fuchsia.examples/types.test.fidl" region_tag="tables" %}
```
The FIDL toolchain generates a `User` class with the following methods:
* `User()`: Default constructor, initializes with all fields unset.
* `User(User&&)`: Move constructor.
* `~User()`: Destructor.
* `User& User::operator=(User&&)`: Move assignment.
* `bool IsEmpty() const`: Returns true if no fields are set.
* `bool has_age() const` and `bool has_name() 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_name()`: Mutable field
accessor methods. If the field is not set, a default one will be constructed,
set, and returned.
* `User& set_age(uint8_t)` and `User& set_name(std::string)`: Field setters.
* `void clear_age()` and `void clear_name()`: Clear the value of a field by
calling its destructor
The `User` class will also provide methods for interacting with unknown fields
which will depend on whether the type is a [value or resource type][lang-resource].
Tables that are a value type will not have unknown
data methods that reference `zx::handle`, and will fail to decode data with
unknown fields that contain handles.
If `User` is a [resource][lang-resource] type, it will have the following
methods:
* `const std::map<uint64_t, fidl::UnknownData>>& UnknownData() const`: Returns a
map from ordinal to bytes and handles. The handles are guaranteed to be in
[traversal order][traversal].
* `void SetUnknownDataEntry(uint32_t ordinal, fidl::UnknownData&& data)`: Set
the bytes and handles of an unknown field if it doesn't already exist. This
method should only be used for testing, e.g. to check that tables with unknown
fields are handled correctly.
If `User` is a [value][lang-resource] type, it will have the following methods:
* `const std::map<uint64_t, vector<uint8_t>& UnknownData() const`: Returns a
map from ordinal to bytes.
* `void SetUnknownDataEntry(uint32_t ordinal, vector<uint8_t>&& data)`: Set
the bytes of an unknown field if it doesn't already exist. This method should
only be used for testing, e.g. to check that tables with unknown fields are
handled correctly.
`User` also has the following associated generated values:
* `UserPtr`: an alias to `unique_ptr<User>`.
Example usage:
```c++
{%includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/fidl/hlcpp/unittests/main.cc" region_tag="tables" adjust_indentation="auto" exclude_regexp="^TEST|^}" %}
```
## Protocols {#protocols}
Given the [protocol][lang-protocols]:
```fidl
{%includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/fidl/fuchsia.examples/types.test.fidl" region_tag="protocols" %}
```
Note: The `MakeMove` method above returns a bool representing success, and a
nullable response value. This is considered un-idiomatic, you should use an [error type](#protocols-results)
instead.
FIDL generates a `TicTacToe` class, which acts as an entry point for interacting
with the protocol and defines the interface of the service used by
clients to proxy calls to the server, and for the server for implementing the
protocol. Synchronous clients use a different virtual interface, `TicTacToe_Sync`.
`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)`: 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)`:
Pure virtual method for a two way protocol method. It takes as arguments the
request parameters followed by the response handler callback.
`TicTacToe_Sync` has the following pure virtual methods, corresponding to the
methods in the protocol definition:
* `virtual zx_status_t StartGame(bool start_first)`: Pure virtual method for a
fire and forget protocol method. It takes as arguments the request parameters,
and returns a `zx_status_t` representing whether the request was sent
successfully.
* `virtual zx_status_t MakeMove(uint8_t row, uint8_t col, bool* out_success, std::unique_ptr<GameState>* out_new_state)`: Pure virtual method for a two way
method protocol. It takes as arguments the request parameters, followed by
output pointers for each of the response parameters. It returns a `zx_status_t`
representing whether the method call was made successfully.
Other code may be generated depending on the
[attributes](#protocol-and-method-attributes) applied to the protocol or its
methods.
### Client {#protocols-client}
The FIDL toolchain generates two aliases for the classes used to make calls to a
`TicTacToe` server : `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` and `TicTacToe_Sync`, respectively, which proxies
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][client-tut].
The `fidl::InterfacePtr` type is thread-hostile. All calls to an instance of
this type must be made from the same thread. The `fidl::SynchronousInterfacePtr`
type is thread-compatible. Once an instance of this type is bound it can be used
from multiple threads simultaneously. The `fidl::InterfaceHandle` type can be
used to safely transfer a channel handle between threads. See the class
documentation on these types for more details.
### 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 {#events}
#### Client
For a `TicTacToePtr` `tictactoe`, `tictactoe.events()` returns 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.
Refer to the [top-level generated protocol code](#protocols) for details on the
callback types.
#### Server
For a `Binding<TicTacToe>` `tictactoe`, `tictactoe.events()` returns a stub
class that contains the following public members:
* `void OnOpponentMove(GameState new_state)`: Send an `OnOpponentMove`.
The [tutorial][server-tut] has an example for obtaining a `Binding`.
### Results {#protocols-results}
Given the method with an error type:
```fidl
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` class to represent the response that is
interchangeable with `fit::result<GameState, MoveError>`. Using this feature, an
example implementation of `MakeMove` on the server side could look like:
```c++
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:
```c++
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](#unions). In
addition, `TicTacToe_MakeMove_Result` provides methods that allow interop with
`fit::result`:
* `TicTacToe_MakeMove_Result(fit::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](#protocol-and-method-attributes): 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](#structs), `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 {#protocol-composition}
FIDL does not have a concept of inheritance, and generates full code as
described above for all [composed protocols][lang-protocol-composition]. In
other words, the code generated for
```fidl
protocol A {
Foo();
};
protocol B {
compose A;
Bar();
};
```
Provides the same API as the code generated for:
```fidl
protocol A {
Foo();
};
protocol B {
Foo();
Bar();
};
```
The generated code is identical except for the method ordinals.
### Protocol and method attributes {#protocol-and-method-attributes}
#### Transitional
For protocol methods annotated with the
[`[Transitional]`](/docs/reference/fidl/language/attributes.md#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 {#discoverable}
A protocol annotated with the
[`[Discoverable]`](/docs/reference/fidl/language/attributes.md#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 {#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 classs 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 librarys namespace (e.g. for library
`games.tictactoe`, these classes are generated into
`games::tictactoe::testing`).
For the same `TicTacToe` protocol listed above, the FIDL toolchain generates a
`TicTacToe_TestBase` class that subclasses `TicTacToe` (see
[Protocols](#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.
<!-- xrefs -->
[client-tut]: /docs/development/languages/fidl/tutorials/hlcpp/basics/client.md
[server-tut]: /docs/development/languages/fidl/tutorials/hlcpp/basics/server.md
[lang-constants]: /docs/reference/fidl/language/language.md#constants
[lang-bits]: /docs/reference/fidl/language/language.md#bits
[lang-enums]: /docs/reference/fidl/language/language.md#enums
[lang-flexible]: /docs/reference/fidl/language/language.md#strict-vs-flexible
[lang-structs]: /docs/reference/fidl/language/language.md#structs
[lang-tables]: /docs/reference/fidl/language/language.md#tables
[lang-unions]: /docs/reference/fidl/language/language.md#unions
[lang-protocols]: /docs/reference/fidl/language/language.md#protocols
[lang-protocol-composition]: /docs/reference/fidl/language/language.md#protocol-composition
[lang-resource]: /docs/reference/fidl/language/language.md#value-vs-resource
[union-lexicon]: /docs/reference/fidl/language/lexicon.md#union-terms
[unknown-attr]: /docs/reference/fidl/language/attributes.md#unknown
[traversal]: /docs/reference/fidl/language/wire-format/README.md#traversal-order