HLCPP 绑定

鉴于库声明:

library fuchsia.examples;

此库的所有代码都在 fuchsia::examples 命名空间中生成,并且 系统会在 Google Cloud 中生成测试基架 fuchsia::examples::testing

常量

所有常量都会以 constexpr 的形式生成。例如, 以下常量:

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

在头文件中生成为:

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

有关 FIDL 基元类型与 C++ 类型之间的对应关系,请参见 内置类型。字符串被声明为constexpr extern const char[],并在 .cc 文件中定义。

字段

本部分介绍 FIDL 工具链如何将 FIDL 类型转换为原生 即 HLCPP 中的类型。这些类型可以在汇总类型中显示为成员,也可以显示为 传递给协议方法。

内置类型

系统会根据下表将 FIDL 类型转换为 C++ 类型:

FIDL 类型 HLCPP 类型
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<T, N> std::array
vector<T>:N std::vector
vector<T>:<N, optional> fidl::VectorPtr
string std::string
string:optional fidl::StringPtr
server_end:Pserver_end:<P, optional> fidl::InterfaceRequest
client_end:Pclient_end:<P, optional> fidl::InterfaceHandle
zx.Handlezx.Handle:optional zx::handle
zx.Handle:Szx.Handle:<S, optional> 会使用对应的 zx 类型。例如,zx::vmozx::channel

用户定义的类型

在 HLCPP 中,用户定义的类型(位、枚举、常量、结构体、联合或表) (请参阅类型 定义)。对于可为 null 的用户定义类型 T, 系统将使用生成的等效类型的 unique_ptr

请求、响应和事件参数

每当 FIDL 需要为 请求、响应或事件(例如,生成 fpromise::result 兼容的结果类型时); 它使用以下规则:

  • 系统会生成多个参数,作为参数类型的 std::tuple
  • 单个形参是指使用形参类型本身。
  • 一组空参数使用 void 表示。

类型定义

块数

根据 bits 的定义:

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

FIDL 工具链使用指定的底层代码生成 C++ enum class, 类型,如果未指定任何类型,则为 uint32_t

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

此外,FIDL 还会为 FileMode 生成以下方法:

  • 按位运算符:||=&&=^^=、 和 ~ 运算符生成,允许对 mode |= FileMode::EXECUTE

FIDL 还会生成 const static FileMode FileModeMask 变量。这是一个 包含枚举类中所有位的位掩码,可用于获取 移除原始底层 uint16_t(或任何类型)中未使用的位值 bits所依据的)。在上述示例中,FileModeMask 的值为 0b111

用法示例:

auto flags = fuchsia::examples::FileMode::READ | fuchsia::examples::FileMode::WRITE;
ASSERT_EQ(static_cast<uint16_t>(flags), 0b11);
flags |= fuchsia::examples::FileMode::EXECUTE;
ASSERT_EQ(flags, fuchsia::examples::FileModeMask);

灵活位

灵活位以 class(而非 enum class)的形式实现,并包含以下额外的方法:

  • constexpr FileMode():默认构造函数,用于在不使用 位设置。
  • constexpr FileMode(uint16_t):根据底层计算公式 原始值,保留所有未知位成员。
  • constexpr cpp17::optional<FileMode> TryFrom(uint16_t value):构造一个 来自底层基元值的位实例(如果值不是该基元值的) 包含任何未知成员,否则返回 cpp17::nullopt
  • constexpr FileMode TruncatingUnknown(uint16_t value):构建实例 从底层基元值中提取位,从而清除所有未知成员。
  • constexpr FileMode unknown_bits() const:返回包含以下内容的位值 只有该位值中的未知成员。
  • constexpr bool has_unknown_bits() const:返回此值是否包含 任何未知位。
  • explicit constexpr operator uint16_t() const:转换回位值 基础原始值。
  • explicit constexpr operator bool() const:返回是否设置了任何位。

生成的类包含每个位成员的静态数字,以及 位掩码。这些代码与enum class的成员完全一致 值,并添加了一个 kMask 成员来替换 FileModeMask

  • const static FileMode READ
  • const static FileMode WRITE
  • const static FileMode EXECUTE
  • const static FileMode kMask

枚举

根据 enum 定义:

type LocationType = strict enum {
    MUSEUM = 1;
    AIRPORT = 2;
    RESTAURANT = 3;
};

FIDL 工具链使用指定的底层代码生成 C++ enum class, 类型,如果未指定任何类型,则为 uint32_t

enum class LocationType : uint32_t {
    MUSEUM = 1u;
    AIRPORT = 2u;
    RESTAURANT = 3u;
};

用法示例:

ASSERT_EQ(static_cast<uint32_t>(fuchsia::examples::LocationType::MUSEUM), 1u);

灵活的枚举

柔性枚举以 class(而非 enum class)的形式实现,具体方法如下:

  • constexpr LocationType():默认构造函数,用于将枚举初始化为 未指定的未知值。
  • constexpr LocationType(uint32_t value):接受 枚举的基本类型的值。
  • constexpr bool IsUnknown():返回枚举值是否未知的指示值。
  • constexpr static LocationType Unknown():返回一个枚举值,该值为 将被视为未知如果枚举具有使用 [Unknown],则返回该成员的值。如果 不存在此类成员,则返回的枚举成员的基础值 未指定参数。
  • explicit constexpr operator int32_t() const:将枚举转换回 基础价值

生成的类包含每个枚举成员的静态成员, 保证与等效组件中 enum class 的成员相匹配 strict 枚举:

  • const static LocationType MUSEUM
  • const static LocationType AIRPORT
  • const static LocationType RESTAURANT

结构体

假设有一个 struct 声明:

type Color = struct {
    id uint32;
    @allow_deprecated_struct_defaults
    name string:MAX_STRING_LENGTH = "red";
};

FIDL 工具链会生成一个具有公共成员和方法的 Color 类型。

  • public 个成员:

    • uint32_t id{}:此字段是零初始化的,因为没有默认值 。
    • std::string name = "red"name 的对应字段。
  • 方法:

    • static inline std::unique_ptr<Color> New():将 unique_ptr 返回到 新的Color

Color 的 6 个特殊成员(默认、复制和移动构造函数、 析构函数、复制和移动赋值)。

Color 还包含以下生成的值:

  • ColorPtrunique_ptr<Color> 的别名。

如果结构体代表 result

用法示例:

fuchsia::examples::Color default_color;
ASSERT_EQ(default_color.id, 0u);
ASSERT_EQ(default_color.name, "red");

fuchsia::examples::Color blue = {1, "blue"};
ASSERT_EQ(blue.id, 1u);

联合体

根据并集的定义:

type JsonValue = strict union {
    1: int_value int32;
    2: string_value string:MAX_STRING_LENGTH;
};

FIDL 会生成一个 JsonValue 类。JsonValue 包含一个公共标记枚举 表示可能的变体

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

Tag 的每个成员都有一个与其指定的 ordinal 值相匹配的值。 (在 union 定义中)。此外,还有一个 Invalid 字段, 用于尚未设置变体的 JsonValue 的初始值。

JsonValue 提供以下方法:

  • JsonValue():默认构造函数。代码最初处于 Tag::Invalid 状态, JsonValue 设置为特定变体。使用 WithFoo 构造函数 应优先使用
  • ~JsonValue():默认析构函数
  • static JsonValue WithIntValue(int32&&)static JsonValue WithStringValue(std::string&&):直接构造 具体变体。
  • static inline std::unique_ptr<JsonValue> New():将 unique_ptr 返回至 新JsonValue
  • bool has_invalid_tag():如果 JsonValue 的实例返回 true,则返回 true 还没有变体集。在出现变体之前,用户不应访问联合体 设置 - 这样做应被视为未定义的行为。
  • bool is_int_value() constbool is_string_value() const:每个变体 具有一个关联方法,用于检查 JsonValue 的实例是否属于 该变体
  • const int32_t& int_value() constconst std::string& string_value() const:每个变体的只读访问器方法。如果存在以下情况,这些方法将会失败: JsonValue 没有指定的变体集
  • int32_t& int_value()std::string& string_value():可变的访问器 方法。如果 JsonValue 的变体与 调用了访问器方法,它会销毁其当前数据并重新初始化它 作为指定的变体。
  • JsonValue& set_int_value(int32_t)JsonValue& set_string_value(std::string):每个变体的 setter 方法。
  • Tag Which() const:返回当前所设的 JsonValue
  • fidl_xunion_tag_t Ordinal() const:返回原始 fidl_xunion_tag_t 标记。 除非需要原始序数,否则优先使用 Which()

JsonValue 还包含以下生成的值:

  • JsonValuePtrunique_ptr<Foo> 的别名。

如果联合体表示 result

用法示例:

auto int_val = fuchsia::examples::JsonValue::WithIntValue(1);
ASSERT_EQ(int_val.Which(), fuchsia::examples::JsonValue::Tag::kIntValue);
ASSERT_TRUE(int_val.is_int_value());

auto str_val = fuchsia::examples::JsonValue::WithStringValue("1");
ASSERT_EQ(str_val.Which(), fuchsia::examples::JsonValue::Tag::kStringValue);
ASSERT_TRUE(str_val.is_string_value());

fuchsia::examples::JsonValuePtr other_int_val = std::make_unique<fuchsia::examples::JsonValue>();
other_int_val->set_int_value(5);
ASSERT_EQ(other_int_val->int_value(), 5);

灵活并集和未知变体

灵活联合在生成的 Tag 中有一个额外的变体 类:

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

当包含未知变体的并集的 FIDL 消息被解码为 JsonValueJsonValue::Which() 返回 JsonValue::Tag::kUnknownJsonValue::Ordinal() 返回未知序数。

灵活的 JsonValue 类型将提供用于与未知类型进行交互的额外方法 取决于类型是否是 值或资源类型。值类型 引用了“zx::handle”的未知数据方法。

一种资源类型的灵活 JsonValue 具有 以下额外方法:

  • const vector<uint8_t>* UnknownBytes() const:返回 如果未知,则设为 union 变体;否则,返回 nullptr
  • const vector<zx::handle>* UnknownHandles() const:返回 遍历顺序的并集变体(如果未知);或者 否则为 nullptr
  • JsonValue& SetUnknownData(fidl_xunion_tag_t ordinal, vector<uint8_t> bytes, vector<zx::handle> handles):类似于已知 成员,这会将联合体设置为具有指定序数的未知变体, 字节和句柄。此方法应仅用于测试,例如更改为 确保代码可以正确处理未知数据。

类型的灵活 JsonValue 具有以下特征 extra 方法:

  • const vector<uint8_t>* UnknownBytes() const:返回 如果未知,则设为 union 变体;否则,返回 nullptr
  • JsonValue& SetUnknownData(fidl_xunion_tag_t ordinal, vector<uint8_t> bytes): 与已知成员的 setter 方法类似,此方法将联合设置为 具有指定序数和字节的未知变体。此方法只能 用于测试,例如以确保代码可以处理未知数据 正确。

对包含未知变体的并集进行编码会写入未知数据和 重新连接到电线上。

在解码未知变体时,严格联合会失败。 在以下情况下,属于类型的灵活联合会失败 使用句柄对未知变体进行解码。

表格

根据 table 定义:

type User = table {
    1: age uint8;
    2: name string:MAX_STRING_LENGTH;
};

FIDL 工具链会通过以下方法生成 User 类:

  • User():默认构造函数,初始化时未设置所有字段。
  • User(User&&):移动构造函数。
  • ~User():析构函数。
  • User& User::operator=(User&&):移动作业。
  • bool IsEmpty() const:如果未设置任何字段,则返回 true。
  • bool has_age() constbool has_name() const:返回字段是否 。
  • const uint8_t& age() constconst std::string& name() const:只读 字段访问器方法。如果未设置此字段,则会失败。
  • uint8_t* mutable_age()std::string* mutable_name():可变字段 访问器方法。如果未设置此字段,则将构建默认字段。 并将其返回。
  • User& set_age(uint8_t)User& set_name(std::string):字段 setter。
  • void clear_age()void clear_name():按 调用其析构函数

User 类还会提供与未知字段交互的方法 具体取决于类型是值还是资源类型。 属于值类型的表不会包含未知 引用 zx::handle 的数据方法,使用 包含标识名的未知字段。

如果 User资源类型,则将具有以下特征 方法:

  • const std::map<uint64_t, fidl::UnknownData>>& UnknownData() const:返回 从序数映射到字节和句柄。标识名在 遍历顺序
  • void SetUnknownDataEntry(uint32_t ordinal, fidl::UnknownData&& data):已设置 未知字段的字节和句柄(如果尚不存在)。这个 方法只能用于测试,例如以检查包含未知 字段的正确处理。

如果 User类型,它将具有以下方法:

  • const std::map<uint64_t, vector<uint8_t>& UnknownData() const:返回 从序数映射到字节。
  • void SetUnknownDataEntry(uint32_t ordinal, vector<uint8_t>&& data):已设置 未知字段的字节(如果尚不存在)。此方法应 仅用于测试,例如检查包含未知字段的表是否 正确处理。

User 还包含以下生成的值:

  • UserPtrunique_ptr<User> 的别名。

用法示例:

fuchsia::examples::User user;
ASSERT_FALSE(user.has_age());
user.set_age(100);
*user.mutable_age() += 100;
ASSERT_EQ(user.age(), 200);
user.clear_age();
ASSERT_TRUE(user.IsEmpty());

内嵌布局

生成的 C++ 代码使用 fidlc 预留的名称 内嵌布局

协议

给定 protocol

closed protocol TicTacToe {
    strict StartGame(struct {
        start_first bool;
    });
    strict MakeMove(struct {
        row uint8;
        col uint8;
    }) -> (struct {
        success bool;
        new_state box<GameState>;
    });
    strict -> OnOpponentMove(struct {
        new_state GameState;
    });
};

FIDL 生成一个 TicTacToe 类,用作与 API 交互的入口点 协议,并定义了由代理使用的服务的接口, 客户端来代理对服务器的调用,而服务器则负责实现 协议。同步客户端使用不同的虚拟接口 TicTacToe_Sync

TicTacToe 包含以下成员类型:

  • MakeMoveCallbackOnOpponentMoveCallback:每个响应和事件都有一个 生成的成员类型,表示用于处理的回调类型 响应或事件。在上面的示例中,MakeMoveCallback 别名 fit::function<void(bool, std::unique_ptr<GameState>)>OnOpponentMoveCallback 别名 fit::function<void(GameState)>

TicTacToe 还包含以下纯虚拟方法,分别对应于 与协议定义中的方法相同:

  • virtual void StartGame(bool start_first):用于火灾和 忘记协议方法。它接受请求参数作为参数。
  • virtual void MakeMove(uint8_t row, uint8_t col, MakeMoveCallback callback): 用于双向协议方法的纯虚拟方法。它将作为 请求参数,后跟响应处理程序回调。

TicTacToe_Sync 提供以下纯虚拟方法,对应于 方法:

  • virtual zx_status_t StartGame(bool start_first):用于 触发并忘记协议方法。它将请求形参作为实参, 并返回表示请求是否已发送的 zx_status_t 成功。
  • virtual zx_status_t MakeMove(uint8_t row, uint8_t col, bool* out_success, std::unique_ptr<GameState>* out_new_state):适用于双向的纯虚拟方法 方法协议。它接受请求参数作为参数,后跟 每个响应参数的输出指针。它会返回一个 zx_status_t 表示方法调用是否成功。

系统可能会生成其他代码, 属性。 方法。

客户端

FIDL 工具链会为用于调用 TicTacToe 服务器:TicTacToePtr,其别名为 fidl::InterfacePtr<TicTacToe> 表示异步客户端,以及 TicTacToeSyncPtr,别名“fidl::SynchronousInterfacePtr<TicTacToe>” 代表同步客户端

解引用后,TicTacToePtrTicTacToeSyncPtr 会返回一个代理类 分别实现 TicTacToeTicTacToe_Sync, 向服务器发出请求在此示例中,假设存在一个名为 TicTacToePtr async_tictactoe,可通过调用 async_tictactoe->StartGame(start_first)async_tictactoe->MakeMove(row, col, callback)

有关如何设置和绑定 InterfacePtr 或 频道获得的SynchronousInterfacePtr HLCPP 教程

fidl::InterfacePtr 类型是线程恶意的。对 必须来自同一线程。fidl::SynchronousInterfacePtr 类型是线程兼容的。绑定此类型的实例后,即可使用 同时从多个线程中提取数据fidl::InterfaceHandle 类型可以是 用于在线程之间安全地传输通道句柄。查看课程 请参阅关于这些类型的文档。

服务器

实现针对 FIDL 协议的服务器涉及提供一个具体的 TicTacToe 的实现。

有关如何设置和绑定服务器实现的示例,请参阅 HLCPP 教程。

事件

客户端

对于 TicTacToePtr tictactoetictactoe.events() 会返回一个代理类 包含以下公开成员:

  • OnOpponentMoveCallback OnOpponentMoveOnOpponentMove 事件。

客户端可以将该类的成员设置为所需的 事件处理脚本

请参阅生成的顶级协议代码,详细了解 回调类型。

服务器

对于 Binding<TicTacToe> tictactoetictactoe.events() 会返回一个桩 类,其中包含以下公开成员:

  • void OnOpponentMove(GameState new_state):发送 OnOpponentMove

教程提供了一个获取 Binding 的示例。

结果

给定的具有错误类型的方法、灵活方法或具有 错误类型:

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

    flexible GetState() -> (struct {
      current_state GameState;
    });

    flexible DryRunMove(struct {
      row uint8;
      col uint8;
    }) -> (struct {
      new_state GameState;
    }) error MoveError;
};

FIDL 生成代码,以便客户端和服务器可以使用 fpromise::result 替换所生成的响应类型这是通过生成结果类来实现的 用于表示可与 fpromise::result 互换的响应。

  • MakeMove
    • 生成类 TicTacToe_MakeMove_Result
    • 可与fpromise::result<GameState, MoveError>互换
  • GetState
    • 生成类 TicTacToe_GetState_Result
    • 可与fpromise::result<GameState, fidl::FrameworkErr>互换
  • DryRunMove

    • 生成类 TicTacToe_DryRunMove_Result
    • 可互换 fpromise::result<GameState, std::variant<MoveError, fidl::FrameworkErr>>

    使用此功能,这些方法在服务器端的示例实现 可能如下所示:

void MakeMove(uint8_t row, uint8_t col, MakeMoveCallback callback) override {
  std::optional<MoveError> error = ApplyMove(row, col);
  if (!error.has_value()) {
    callback(fpromise::ok(game_state_.state()));
  }
  callback(fpromise::error(error.value()));
}

void GetState(MakeMoveCallback callback) override {
  callback(fpromise::ok(game_state_.state()));
  // The server application code *must not* attempt to send a
  // fidl::FrameworkErr. If it does, the server binding will panic.
  }

void DryRynMove(uint8_t row, uint8_t col, MakeMoveCallback callback) override {
  std::optional<MoveError> error = TestMove(row, col);
  if (!error.has_value()) {
    callback(fpromise::ok(game_state_.state()));
  }
  // The server application code *must not* attempt to send a
  // fidl::FrameworkErr. If it does, the server binding will panic.
  callback(fpromise::error(error.value()));
}

以异步方式在客户端使用此项的示例:

async_game->MakeMove([&](fpromise::result<GameState, MoveError> response) { ... });
async_game->GetState(
    [&](fpromise::result<GameState, fidl::FrameworkErr> response) { ... });
async_game->DryRunMove(
    [&](fpromise::result<GameState, std::variant<MoveError, fidl::FrameworkErr>> response) { ... });

在客户端,fidl::FrameworkErr 表示灵活的双向 并不知道其交互方式。

生成代码时,FIDL 工具链会将 TicTacToe_*_Result 视为 union,最多包含三个变体:

  • response 是生成的类型,遵循 参数类型转化规则
    • 如果 MakeMove 在其结构体返回值类型中返回单个参数,或者 返回类型是元组或并集,返回类型是 fpromise::result<T, ...>,其中 T 是 结构体、元组或联合返回值类型。
    • 如果 MakeMove 在成功时返回了多个值,则结果类型将为 响应参数 fpromise::result<std::tuple<...>, ...> 的元组
    • 如果 MakeMove 返回空响应,则结果类型将为 fpromise::result<void, ...>
  • err 是错误类型,在两者的示例中均为 MoveError MakeMoveDryRunMove
    • 仅当该方法使用错误语法时,此变体才存在。
  • framework_err 的类型始终为 fidl::FrameworkErr
    • 仅当该方法为 flexible 时,此变体才会存在。

TicTacToe_*_Result 类型提供了常规 并集。此外,TicTacToe_*_Result 类型还提供 允许与 fpromise::result 互操作,例如 TicTacToe_MakeMove_Result:

  • TicTacToe_MakeMove_Result(fpromise::result<GameState, MoveError>&& result):移动 fpromise::result 构造函数。
  • TicTacToe_MakeMove_Result(fpromise::ok_result<GameState>&& result):移动 fpromise::ok_result 构造函数。
  • TicTacToe_MakeMove_Result(fpromise::error_result<MoveError>&& result):移动 fpromise::error_result 构造函数。
  • operator fpromise::result<GameState, MoveError>() &&:转换为 fpromise::result

其他TicTacToe_*_Result类型将针对其 相应的 fpromise::result 类型。

FIDL 工具链还会生成一个 TicTacToe_MakeMove_Response 类,该类用于 是 TicTacToe_MakeMove_Resultresponse 变体的类型。此课程 被视为 FIDL 结构,其字段与 成功响应。除了向 Kubernetes 提供的方法和成员 regular structTicTacToe_MakeMove_Response 提供额外的 允许与 std::tuple 互操作的方法:

  • explicit TicTacToe_MakeMove_Response(std::tuple<GameState> _value_tuple): 元组的构造函数。
  • operator std::tuple<GameState>() &&:元组的转换运算符。

未知互动处理

服务器端

当协议声明为 openajar 时,生成的接口类 例如TicTacToe 将包含一个额外的虚拟方法,称为 handle_unknown_method,带有以下签名:

// If the protocol is open:
virtual void handle_unknown_method(uint64_t ordinal, bool method_has_response) = 0;
// If the protocol is ajar:
virtual void handle_unknown_method(uint64_t ordinal) = 0;

实现 openajar 服务器时,您还必须实现此 方法。ordinal 参数是调用该方法的 FIDL 方法序号, 调用了该方法。如果协议为 open,则使用 method_has_response 参数 指示方法是单向还是双向;单向方法, method_has_response 为 false;对于双向方法,则为 true。在 ajar 中 协议,只能处理未知的单向方法。

无论何时,服务器都会调用 handle_unknown_method 方法 可以处理的未知灵活方法。

客户端

客户端无法判断 flexible 单向方法是否已知 与服务器通信。对于 flexible 双向方法,结果 并集可用于判断某个方法是否被已知 服务器如果 TicTacToe_<Method>_Resultframework_err 变体 类已设置,或者转换后的 fpromise::result 具有 fidl::FrameworkErr 错误集,表示服务器无法识别该方法。

对于 strict,用于发送单向方法和接收事件的 API 是相同的 以及 flexible 单向方法和事件。

对于 openajar 协议,生成的 TicTacToe_Proxy 类将具有一个名为 handle_unknown_event 的额外公共字段,其类型如下:

fit::function<void(uint64_t)> handle_unknown_event;

就像协议中声明的事件的事件处理脚本一样,例如 OnOpponentMove 时,您可以在此处分配一个函数回调,以便在调用 收到未知的 flexible 事件。单个 uint64_t 参数 回调是事件的 FIDL 方法序号。

协议组合

FIDL 没有继承的概念,它会生成完整的代码, (针对所有组合协议)执行上述操作。在 也就是

protocol A {
    Foo();
};

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

提供与针对以下各项生成的代码相同的 API:

protocol A {
    Foo();
};

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

除了方法序数之外,生成的代码完全相同。

协议和方法属性

过渡风格

对于带有 @transitional 属性,因此协议类中的 virtual 方法并非纯粹的方法。这样, 缺少要编译的方法替换协议类的实现 成功。

可检测到

使用 @discoverable 属性会导致 FIDL 工具链在协议类上生成额外的 static const char Name_[] 字段,其中包含完整的协议名称。对于 库 foo.bar 中的协议 Baz,生成的名称为 "foo.bar.Baz"

测试基架

FIDL 工具链还会生成一个带有 _test_base.h 后缀的文件, 包含用于测试 FIDL 服务器实现的便捷代码。此文件 包含每个协议的类,为每个协议提供存根实现 类的方法,从而可以仅实现 都会用到这些类会生成到 testing 命名空间中, 位于生成的库的命名空间内(例如 games.tictactoe,这些类会生成到 games::tictactoe::testing)。

对于上面列出的同一 TicTacToe 协议,FIDL 工具链会生成 作为 TicTacToe 的子类的 TicTacToe_TestBase 类(请参阅 协议),提供以下方法:

  • virtual ~TicTacToe_TestBase() {}:析构函数。
  • virtual void NotImplemented_(const std::string& name) = 0:纯虚拟 方法。

TicTacToe_TestBase 提供虚拟协议方法的实现 StartGameMakeMove,实现为仅调用 NotImplemented_("StartGame")NotImplemented_("MakeMove")

扩展程序

fostr 是一个单独的库,提供用于设置格式的实用程序 (美观输出)HLCPP 中的 FIDL 类型。您可以在以下位置找到使用情况信息: 教程