库
鉴于库声明:
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:P 、server_end:<P, optional> |
fidl::InterfaceRequest |
client_end:P ,client_end:<P, optional> |
fidl::InterfaceHandle |
zx.Handle ,zx.Handle:optional |
zx::handle |
zx.Handle:S 、zx.Handle:<S, optional> |
会使用对应的 zx 类型。例如,zx::vmo 或 zx::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
还包含以下生成的值:
ColorPtr
:unique_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() const
和bool is_string_value() const
:每个变体 具有一个关联方法,用于检查JsonValue
的实例是否属于 该变体const int32_t& int_value() const
和const 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
还包含以下生成的值:
JsonValuePtr
:unique_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 消息被解码为
JsonValue
,JsonValue::Which()
返回 JsonValue::Tag::kUnknown
,
JsonValue::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() const
和bool has_name() const
:返回字段是否 。const uint8_t& age() const
和const 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
还包含以下生成的值:
UserPtr
:unique_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
包含以下成员类型:
MakeMoveCallback
和OnOpponentMoveCallback
:每个响应和事件都有一个 生成的成员类型,表示用于处理的回调类型 响应或事件。在上面的示例中,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>
”
代表同步客户端
解引用后,TicTacToePtr
和 TicTacToeSyncPtr
会返回一个代理类
分别实现 TicTacToe
和 TicTacToe_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
tictactoe
,tictactoe.events()
会返回一个代理类
包含以下公开成员:
OnOpponentMoveCallback OnOpponentMove
:OnOpponentMove
事件。
客户端可以将该类的成员设置为所需的 事件处理脚本
请参阅生成的顶级协议代码,详细了解 回调类型。
服务器
对于 Binding<TicTacToe>
tictactoe
,tictactoe.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
MakeMove
和DryRunMove
。- 仅当该方法使用错误语法时,此变体才存在。
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_Result
的 response
变体的类型。此课程
被视为 FIDL 结构,其字段与
成功响应。除了向 Kubernetes 提供的方法和成员
regular struct,TicTacToe_MakeMove_Response
提供额外的
允许与 std::tuple
互操作的方法:
explicit TicTacToe_MakeMove_Response(std::tuple<GameState> _value_tuple)
: 元组的构造函数。operator std::tuple<GameState>() &&
:元组的转换运算符。
未知互动处理
服务器端
当协议声明为 open
或 ajar
时,生成的接口类
例如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;
实现 open
或 ajar
服务器时,您还必须实现此
方法。ordinal
参数是调用该方法的 FIDL 方法序号,
调用了该方法。如果协议为 open
,则使用 method_has_response
参数
指示方法是单向还是双向;单向方法,
method_has_response
为 false;对于双向方法,则为 true。在 ajar
中
协议,只能处理未知的单向方法。
无论何时,服务器都会调用 handle_unknown_method
方法
可以处理的未知灵活方法。
客户端
客户端无法判断 flexible
单向方法是否已知
与服务器通信。对于 flexible
双向方法,结果
并集可用于判断某个方法是否被已知
服务器如果 TicTacToe_<Method>_Result
的 framework_err
变体
类已设置,或者转换后的 fpromise::result
具有 fidl::FrameworkErr
错误集,表示服务器无法识别该方法。
对于 strict
,用于发送单向方法和接收事件的 API 是相同的
以及 flexible
单向方法和事件。
对于 open
和 ajar
协议,生成的 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
提供虚拟协议方法的实现
StartGame
和 MakeMove
,实现为仅调用
NotImplemented_("StartGame")
和 NotImplemented_("MakeMove")
。
扩展程序
fostr
是一个单独的库,提供用于设置格式的实用程序
(美观输出)HLCPP 中的 FIDL 类型。您可以在以下位置找到使用情况信息:
教程。