新的 C++ 繫結提供「natural」和「wire」變體。自然 連接線為安全與人體工學,且電線連接 且能提供最佳效能大部分的程式碼都應使用自然繫結。 只在效能需求或需要時,才轉向電線繫結。 您需要精確地控制記憶體配置
程式庫
加入程式庫宣告:
library fuchsia.examples;
通訊協定類型會在 fuchsia_examples
命名空間中產生。
這個程式庫的網域物件會在
fuchsia_examples::wire
命名空間和 Sscaffolding
會在 fidl::testing
命名空間中產生
系統會轉換產生的類型名稱,以遵循 Google C++ 樣式指南。
常數
常數會以 constexpr
的形式產生。舉例來說,
下列常數:
const BOARD_SIZE uint8 = 9;
const NAME string = "Tic-Tac-Toe";
在標頭檔案中產生如下:
constexpr uint8_t kBoardSize = 9u;
extern const char[] kName;
FIDL 原始類型和 C++ 類型之間的對應關係列於
內建類型。字串會宣告為constexpr
extern const char[]
(由標頭檔案定義),並由 .cc
檔案定義。
欄位
本節說明 FIDL 工具鍊如何將 FIDL 類型轉換為 C++ 線 。這些類型可以以成員形式顯示在匯總類型中,或是以參數的形式顯示 是一種通訊協定方法
內建類型
根據下表,FIDL 類型會轉換為 C++ 類型:
FIDL 類型 | C++ 線路類型 |
---|---|
bool |
bool , (requires sizeof(bool) == 1) |
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> |
fidl::Array<T, N> |
vector<T>:N |
fidl::VectorView<T> |
string |
fidl::StringView |
client_end:P |
fidl::ClientEnd<P> |
server_end:P |
fidl::ServerEnd<P> |
zx.Handle |
zx::handle |
zx.Handle:S |
會盡可能使用對應的 zx 類型。例如 zx::vmo 或 zx::channel |
選用的向量、字串、用戶端/伺服器結束和控制處理的 C++ 相同 線路,當做不選擇性的對應方式。
使用者定義的類型
C++ 線繫結會為每個使用者定義的位元、列舉、結構體定義類別
資料表和聯集。針對嚴格列舉,這類項目會定義 enum class
,而非
聯集可以使用相同的類別來代表選用
非選用值。如果是裝箱結構體,則使用 fidl::ObjectView
。請參閱「記憶體
通訊社網域物件的擁有權,進一步瞭解 fidl::ObjectView
。
類型定義
點數
如果是 bits 定義:
type FileMode = strict bits : uint16 {
READ = 0b001;
WRITE = 0b010;
EXECUTE = 0b100;
};
FIDL 工具鍊會產生 FileMode
類別,其中每個類別都有靜態成員
旗標,以及包含所有位元成員遮罩的 kMask
成員 (在
以下為範例 0b111
):
const static FileMode kRead
const static FileMode kWrite
const static FileMode kExecute
const static FileMode kMask
FileMode
提供以下方法:
explicit constexpr FileMode(uint16_t)
:從基礎建構值 原始值,保留所有未知位元成員。constexpr static cpp17::optional<FileMode> TryFrom(uint16_t value)
:結構 是基礎原始值的位元例項 (如果值這麼做) 不包含任何未知的成員,否則會傳回cpp17::nullopt
。constexpr static FileMode TruncatingUnknown(uint16_t value)
:建構 從基礎原始值中擷取位元的例項,清除任何未知資訊 成員。- 位元運算子:
|
、|=
、&
、&=
、^
、^=
的實作項目。 和~
運算子,以便允許在位元上進行位元運算,例如mode |= FileMode::kExecute
。 - 比較運算子
==
和!=
。 uint16_t
和bool
的明確轉換函式。
如果 FileMode
為「彈性」,則內容如下:
其他方法:
constexpr FileMode unknown_bits() const
:傳回包含下列內容的位元值: 接收此位元值中的未知成員。constexpr bool has_unknown_bits() const
:傳回此值是否包含 找出所有未知位元。
使用範例:
static_assert(std::is_same<fuchsia_examples::FileMode, fuchsia_examples::wire::FileMode>::value,
"natural bits should be equivalent to wire bits");
static_assert(fuchsia_examples::FileMode::kMask == fuchsia_examples::wire::FileMode::kMask,
"natural bits should be equivalent to wire bits");
using fuchsia_examples::wire::FileMode;
auto flags = FileMode::kRead | FileMode::kWrite | FileMode::kExecute;
ASSERT_EQ(flags, FileMode::kMask);
列舉
採用 enum 定義:
type LocationType = strict enum {
MUSEUM = 1;
AIRPORT = 2;
RESTAURANT = 3;
};
FIDL 工具鍊會使用指定的基礎程式碼產生 C++ enum class
類型,如果未指定,則使用 uint32_t
:
enum class LocationType : uint32_t {
kMuseum = 1u;
kAirport = 2u;
kRestaurant = 3u;
};
使用範例:
static_assert(
std::is_same<fuchsia_examples::LocationType, fuchsia_examples::wire::LocationType>::value,
"natural enums should be equivalent to wire enums");
ASSERT_EQ(static_cast<uint32_t>(fuchsia_examples::wire::LocationType::kMuseum), 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 kMuseum
const static LocationType kAirport
const static LocationType kRestaurant
Structs
假設有 struct 宣告:
type Color = struct {
id uint32;
@allow_deprecated_struct_defaults
name string:MAX_STRING_LENGTH = "red";
};
FIDL 工具鍊會產生對等的 struct
:
struct Color {
uint32_t id = {};
fidl::StringView name = {};
}
C++ 繫結不支援預設值,因此會改為零初始化 所有結構體的欄位
使用範例:
// Wire structs are simple C++ structs with all their member fields declared
// public. One may invoke aggregate initialization:
fuchsia_examples::wire::Color blue = {1, "blue"};
ASSERT_EQ(blue.id, 1u);
ASSERT_EQ(blue.name.get(), "blue");
// ..or designated initialization.
fuchsia_examples::wire::Color blue_designated = {.id = 1, .name = "blue"};
ASSERT_EQ(blue_designated.id, 1u);
ASSERT_EQ(blue_designated.name.get(), "blue");
// A wire struct may be default constructed, but user-defined default values
// are not supported.
// Default-initializing a struct means all fields are zero-initialized.
fuchsia_examples::wire::Color default_color;
ASSERT_EQ(default_color.id, 0u);
ASSERT_TRUE(default_color.name.is_null());
ASSERT_TRUE(default_color.name.empty());
// There are no getters/setters. One simply reads or mutates the member field.
blue.id = 2;
ASSERT_EQ(blue.id, 2u);
// Here we demonstrate that wire structs do not own their out-of-line children.
// Copying a struct will not copy their out-of-line children. Pointers are
// simply aliased.
{
fuchsia_examples::wire::Color blue2 = blue;
ASSERT_EQ(blue2.name.data(), blue.name.data());
}
// Similarly, destroying a wire struct object does not destroy out-of-line
// children. Destroying |blue2| does not invalidate the string contents in |name|.
ASSERT_EQ(blue.name.get(), "blue");
聯合工會
以聯集定義為例:
type JsonValue = strict union {
1: int_value int32;
2: string_value string:MAX_STRING_LENGTH;
};
FIDL 會產生 JsonValue
類別。JsonValue
包含公開標記列舉
代表可能的「變化版本」:
enum class Tag : fidl_xunion_tag_t {
kIntValue = 2,
kStringValue = 3,
};
Tag
中的每個成員都有一個與 union
中指定的序數值相符的值
定義
JsonValue
提供以下方法:
JsonValue()
:預設建構函式。建構的聯集一開始位於 「不存在」否則就要等到變數設定完成為止WithFoo
建構函式應該 優先使用。~JsonValue()
:用來清除基礎聯集資料的解構函式。JsonValue(JsonValue&&)
:預設移動建構函式。JsonValue& operator=(JsonValue&&)
:預設移動作業static JsonValue WithIntValue(fidl::ObjectView<int32>)
和static JsonValue WithStringValue(fidl::ObjectView<fidl::StringView>)
:靜態 建構函式,直接建構聯集特定變數。bool has_invalid_tag()
:如果JsonValue
的執行個體出現,則傳回true
則尚未設定變化版本組合呼叫這個方法而不先設定 變化版本會導致斷言錯誤。bool is_int_value() const
和bool is_string_value() const
:每個變化版本 擁有相關聯的方法,可檢查JsonValue
的例項是否 該變化版本const int32_t& int_value() const
和const fidl::StringView& string_value() const
:每個變化版本的唯讀存取子方法。呼叫這些方法 如未先設定變化版本,就會導致斷言錯誤。int32_t& int_value()
和fidl::StringView& string_value()
:可變動 各個變數的存取子方法。如果JsonValue
執行作業,這些方法就會失敗 未指定指定的變化版本組合Tag Which() const
:傳回目前 標記JsonValue
。在不先設定變化版本的情況下呼叫此方法, 斷言錯誤。
使用範例:
// When the active member is larger than 4 bytes, it is stored out-of-line,
// and the union will borrow the out-of-line content. The lifetimes can be
// tricky to reason about, hence the FIDL runtime provides a |fidl::AnyArena|
// interface for arena-based allocation of members. The built-in
// implementation is |fidl::Arena|.
//
// Pass the arena as the first argument to |With...| factory functions, to
// construct the member content on the arena, and have the union reference it.
fidl::Arena arena;
fuchsia_examples::wire::JsonValue str_union =
fuchsia_examples::wire::JsonValue::WithStringValue(arena, "1");
// |Which| obtains an enum corresponding to the active member, which may be
// used in switch cases.
ASSERT_EQ(str_union.Which(), fuchsia_examples::wire::JsonValue::Tag::kStringValue);
// Before accessing the |string_value| member, one should check if the union
// indeed currently holds this member, by querying |is_string_value|.
// Accessing the wrong member will cause a panic.
ASSERT_TRUE(str_union.is_string_value());
ASSERT_EQ("1", str_union.string_value().get());
// When the active member is smaller or equal to 4 bytes, such as an
// |int32_t| here, the entire member is inlined into the union object.
// In these cases, arena allocation is not necessary, and the union
// object wholly owns the member.
fuchsia_examples::wire::JsonValue int_union = fuchsia_examples::wire::JsonValue::WithIntValue(1);
ASSERT_TRUE(int_union.is_int_value());
ASSERT_EQ(1, int_union.int_value());
// A default constructed wire union is invalid.
// It must be initialized with a valid member before use.
// One is not allowed to send invalid unions through FIDL client/server APIs.
fuchsia_examples::wire::JsonValue default_union;
ASSERT_TRUE(default_union.has_invalid_tag());
default_union = fuchsia_examples::wire::JsonValue::WithStringValue(arena, "hello");
ASSERT_FALSE(default_union.has_invalid_tag());
ASSERT_TRUE(default_union.is_string_value());
ASSERT_EQ(default_union.string_value().get(), "hello");
// Optional unions are represented with |fidl::WireOptional|.
fidl::WireOptional<fuchsia_examples::wire::JsonValue> optional_json;
ASSERT_FALSE(optional_json.has_value());
optional_json = fuchsia_examples::wire::JsonValue::WithIntValue(42);
ASSERT_TRUE(optional_json.has_value());
// |fidl::WireOptional| has a |std::optional|-like API.
fuchsia_examples::wire::JsonValue& value = optional_json.value();
ASSERT_TRUE(value.is_int_value());
// When switching over the tag from a flexible union, one must add a `default:`
// case, to handle members not understood by the FIDL schema or to handle
// newly added members in a source compatible way.
fuchsia_examples::wire::FlexibleJsonValue flexible_value =
fuchsia_examples::wire::FlexibleJsonValue::WithIntValue(1);
switch (flexible_value.Which()) {
case fuchsia_examples::wire::FlexibleJsonValue::Tag::kIntValue:
ASSERT_EQ(flexible_value.int_value(), 1);
break;
case fuchsia_examples::wire::FlexibleJsonValue::Tag::kStringValue:
FAIL() << "Unexpected tag. |flexible_value| was set to int";
break;
default: // Removing this branch will fail to compile.
break;
}
彈性聯集和未知的變體
彈性聯集在產生的 Tag
中有額外變化版本
類別:
enum class Tag : fidl_xunion_tag_t {
... // other fields omitted
kUnknown = ::std::numeric_limits<::fidl_union_tag_t>::max(),
};
當 FIDL 訊息含有不明變體的聯集時,解碼成
JsonValue
、JsonValue::Which()
會傳回 JsonValue::Tag::kUnknown
。
C++ 繫結繫結不會儲存原始位元組和未知的控制 子類
系統不支援對有未知變體的聯集編碼,因此會造成 編碼失敗。
表格
採用 table 定義:
type User = table {
1: age uint8;
2: name string:MAX_STRING_LENGTH;
};
FIDL 工具鍊會使用下列方法產生 User
類別:
User()
:預設建構函式,會初始化未設定任何欄位的空白資料表。User::Builder(fidl::AnyArena& arena)
:建構工具 Factory。 傳回分配影格和成員的fidl::WireTableBuilder<User>
隨機應變User::ExternalBuilder(fidl::ObjectView<fidl::WireTableFrame<User>> frame)
: 外部建構工具工廠。傳回fidl::WireTableExternalBuilder<User>
提供的圖像。這個建構工具需要謹慎的記憶體管理 偶爾會有幫助Caveat Emptor。User(User&&)
:預設移動建構函式。~User()
:預設解構函式。User& operator=(User&&)
:預設移動指派作業。bool IsEmpty() const
:如果未設定任何欄位,則傳回 true。bool has_age() const
和bool has_name() const
:傳回欄位是否為 設定。const uint8_t& age() const
和const fidl::StringView& name() const
: 唯讀欄位存取子方法。在不先設定的情況下呼叫這些方法 欄位會導致斷言錯誤。
為了建構資料表,系統會額外產生三個類別:
fidl::WireTableBuilder<User>
、fidl::WireTableExternalBuilder<User>
和
fidl::WireTableFrame<User>
。
fidl::WireTableFrame<User>
是資料表內部儲存空間的容器。
而且會與建構工具分開配置,以維持
基準線格式僅供建構工具在內部使用。
fidl::WireTableFrame<User>
具有以下方法:
WireTableFrame()
:預設建構函式。
fidl::WireTableExternalBuilder<User>
具有以下方法:
fidl::WireTableExternalBuilder<User> age(uint8_t)
: 設定年齡的方式fidl::WireTableExternalBuilder<User> name(fidl::ObjectView<fidl::StringView>)
: 使用已分配的值設定名稱。User Build()
:建構並傳回資料表物件。呼叫Build()
後 必須捨棄建構工具
fidl::WireTableBuilder<User>
具有
fidl::WireTableExternalBuilder<User>
(但針對來自
setter) 並新增:
fidl::WireTableBuilder<User> name(std::string_view)
:透過分配方式設定名稱 從建構工具的運動場開始新的fidl::StringView
,並複製提供的 字串插入該字串。
使用範例:
fidl::Arena arena;
// To construct a wire table, you need to first create a corresponding
// |Builder| object, which borrows an arena. The |arena| will be used to
// allocate the table frame, a bookkeeping structure for field presence.
auto builder = fuchsia_examples::wire::User::Builder(arena);
// To set a table field, call the member function with the same name on the
// builder. The arguments will be forwarded to the field constructor, and the
// field is allocated on the initial |arena|.
builder.age(10);
// Note that only the inline portion of the field is automatically placed in
// the arena. The field itself may reference its own out-of-line content,
// such as in the case of |name| whose type is |fidl::StringView|. |name|
// will reference the "jdoe" literal, which lives in static program storage.
builder.name("jdoe");
// Call |Build| to finalize the table builder into a |User| table.
// The builder is no longer needed after this point. |user| will continue to
// reference objects allocated in the |arena|.
fuchsia_examples::wire::User user = builder.Build();
ASSERT_FALSE(user.IsEmpty());
// Before accessing a field, one should check if it is present, by querying
// |has_...|. Accessing an absent field will panic.
ASSERT_TRUE(user.has_name());
ASSERT_EQ(user.name().get(), "jdoe");
// Setters may be chained, leading to a fluent syntax.
user = fuchsia_examples::wire::User::Builder(arena).age(30).name("bob").Build();
ASSERT_FALSE(user.IsEmpty());
ASSERT_TRUE(user.has_age());
ASSERT_EQ(user.age(), 30);
ASSERT_TRUE(user.has_name());
ASSERT_EQ(user.name().get(), "bob");
// A default constructed wire table is empty.
// This is mostly useful to make requests or replies with empty tables.
fuchsia_examples::wire::User defaulted_user;
ASSERT_TRUE(defaulted_user.IsEmpty());
// In some situations it could be difficult to provide an arena when
// constructing tables. For example, here it is hard to provide constructor
// arguments to 10 tables at once. Because a default constructed wire table is
// empty, a new table instance should be built and assigned in its place.
fidl::Array<fuchsia_examples::wire::User, 10> users;
for (auto& user : users) {
ASSERT_TRUE(user.IsEmpty());
user = fuchsia_examples::wire::User::Builder(arena).age(30).Build();
ASSERT_FALSE(user.IsEmpty());
ASSERT_EQ(user.age(), 30);
}
ASSERT_EQ(users[0].age(), 30);
// Finally, tables support checking if it was received with unknown fields.
// A table created by ourselves will never have unknown fields.
ASSERT_FALSE(user.HasUnknownData());
除了使用 fidl::ObjectView
指派欄位之外,您也可以使用
請參閱通訊網域物件的記憶體擁有權一文中的配置策略。
內嵌版面配置
產生的 C++ 程式碼會使用 fidlc
選擇的名稱,供
內嵌版面配置。
C++ 繫結也會產生範圍名稱來參照內嵌版面配置。適用對象 以 FIDL 為例:
type Outer = struct {
inner struct {};
};
內部結構體可使用其全域不重複名稱 Inner
,如下所示:
範圍名稱 Outer::Inner
這在頂層節點非常實用
名稱遭到 @generated_name
屬性覆寫。
例如:
type Outer = struct {
inner
@generated_name("SomeCustomName") struct {};
};
內部結構體稱為 SomeCustomName
或 Outer::Inner
。
另一個例子是通訊協定結果類型:
型別成功和錯誤變化版本 (例如 TicTacToe_MakeMove_Result
) 可
參照為 TicTacToe_MakeMove_Result::Response
TicTacToe_MakeMove_Result::Err
。
通訊協定
指定通訊協定之後:
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
類別,做為類型的進入點
用戶端和伺服器
課程中也會快速介紹 Memorystore
這是 Google Cloud 的全代管 Redis 服務本課程的成員會在
本節其他部分
輸入的管道端點
C++ 繫結會透過 Zircon 傳送及接收 FIDL 通訊協定訊息
管道傳輸,其中存放任何位元組的 blob 和
控制代碼而不是公開原始端點,例如 zx::channel
、API
能夠公開三個範本式端點類別
fidl::ClientEnd<TicTacToe>
:TicTacToe
通訊協定的用戶端端點。 且擁有zx::channel
。需要專屬擁有權的用戶端繫結 管道就會取用這個類型舉例來說fidl::WireClient<TicTacToe>
的建構方式可能是fidl::ClientEnd<TicTacToe>
,也稱為「將管道繫結至 訊息調度工具」錯誤訊息。fidl::UnownedClientEnd<TicTacToe>
:借用某些用戶端的無從值 都位於TicTacToe
通訊協定的端點不需要的用戶端 API 專屬擁有權則視為管道專屬擁有權。UnownedClientEnd
衍生自ClientEnd
相同通訊協定類型的borrow()
。借用的端點可以std::move
包圍在相同的 但無法在處理程序之外捨棄或轉移 擁有一根無人用的借款fidl::ServerEnd<TicTacToe>
:TicTacToe
通訊協定的伺服器端點; 且擁有zx::channel
。需要專屬擁有權的伺服器繫結 管道就會取用這個類型舉例來說 「fidl::ServerEnd<TicTacToe>
」可能會提供給「fidl::BindServer<TicTacToe>
」 來建立伺服器繫結
沒有 UnownedServerEnd
,因為還不需要安全實作
以及目前的功能組合
您可以使用
::fidl::CreateEndpoints<TicTacToe>
程式庫呼叫。在通訊協定要求中
直線情境,這時就能立即在
用戶端端點,std::move()
- 對遠端伺服器端點發出連向
伺服器
詳情請參閱這些類型的課程說明文件。
要求與回應類型
FIDL 方法或事件的要求類型可透過一對存取
別名、fidl::WireRequest
和 fidl::WireEvent
:
fidl::WireRequest<TicTacToe::StartGame>
fidl::WireRequest<TicTacToe::MakeMove>
fidl::WireEvent<TicTacToe::OnOpponentMove>
如果要求或事件使用的類型屬於已命名類型,別名會指向
並套用到該類型如果要求類型為匿名類型,別名會指向
並為該匿名類型產生的類型名稱適用於方法要求
事件,產生的要求類型會是 [Method]Request
。
與要求不同,對雙向方法的回應會產生新型別
fidl::WireResult
:
fidl::WireResult<TicTacToe::MakeMove>
fidl::WireResult
類型繼承自 fidl::Status
,而其狀態會指出
是否在 FIDL 層呼叫成功如果方法包含非空白
回應或使用 FIDL 錯誤語法,產生的 WireResult
類型也會
設有一組存取子,用來存取傳回值或應用程式層
錯誤。內含結果的可用存取子如下:
WireResultUnwrapType<FidlMethod>* Unwrap()
const WireResultUnwrapType<FidlMethod>* Unwrap() const
WireResultUnwrapType<FidlMethod>& value()
const WireResultUnwrapType<FidlMethod>& value() const
WireResultUnwrapType<FidlMethod>* operator->()
const WireResultUnwrapType<FidlMethod>* operator->() const
WireResultUnwrapType<FidlMethod>& operator*()
const WireResultUnwrapType<FidlMethod>& operator*() const
WireResultUnwrapType
是另一種類型別名,取決於
方法使用錯誤語法。根據這個範例程式庫
library response.examples;
protocol Test {
Foo() -> (struct { x int32; });
Bar() -> () error int32;
Baz() -> (struct { x int32; }) error int32;
};
以下是 Test
中每個方法的 fidl::WireResultUnwrapType
。
通訊協定:
fidl::WireResultUnwrapType<response_examples::Test::Foo> = response_examples::wire::TestFooResponse
fidl::WireResultUnwrapType<response_examples::Test::Bar> = fit::result<int32_t>
fidl::WireResultUnwrapType<response_examples::Test::Baz> = fit::result<int32_t, ::response_examples::wire::TestBazResponse*>
用戶端
C++ 線繫結繫結提供多種與 FIDL 互動的方式 視為用戶端
fidl::WireClient<TicTacToe>
:這個類別會公開 傳出的非同步與同步呼叫,以及非同步事件 處理和處理資料擁有管道的用戶端。async_dispatcher_t*
是 必須支援非同步 API,以及事件和錯誤處理。 且必須與單一執行緒調度器搭配使用。這個類別的物件必須 繫結至用戶端端點,然後在 執行調度器對於多數用途,這是我們建議的變化版本。 但無法使用async_dispatcher_t
或 用戶端必須在執行緒之間移動。fidl::WireSharedClient<TicTacToe>
:這堂課程對討論串發表的意見較少 相較於WireClient
,必須採用兩階段的關閉模式 避免使用釋放後記憶體此類別的物件可在 任意執行緒並支援與多執行緒調度器搭配使用。適用對象 詳情請參閱新的 C++ 繫結執行緒指南。fidl::WireSyncClient<TicTacToe>
:這個類別公開純同步 API 以及處理事件。擁有用戶端末端 頻道。fidl::WireCall<TicTacToe>
:這個類別與WireSyncClient
相同 但不具備管道用戶端的擁有權 當實作的 C API 符合下列條件時,WireCall
可能更偏好WireSyncClient
取用原始zx_handle_t
。
WireClient
fidl::WireClient
符合執行緒安全規定,且支援同步和非同步
呼叫和非同步事件處理等功能。
創作
系統會建立用戶端,並透過用戶端 fidl::ClientEnd<P>
建立至通訊協定 P
。
async_dispatcher_t*
和選用指標
WireAsyncEventHandler
,用來定義
會在收到 FIDL 事件或用戶端解除繫結時呼叫。如果
不會覆寫特定事件的虛擬方法,該事件將被忽略。
class EventHandler : public fidl::WireAsyncEventHandler<TicTacToe> {
public:
EventHandler() = default;
void OnOpponentMove(fidl::WireEvent<OnOpponentMove>* event) override {
/* ... */
}
void on_fidl_error(fidl::UnbindInfo unbind_info) override { /* ... */ }
};
fidl::ClientEnd<TicTacToe> client_end = /* logic to connect to the protocol */;
EventHandler event_handler;
fidl::WireClient<TicTacToe> client;
client.Bind(std::move(client_end), dispatcher, &event_handler);
發生在伺服器端 遭到伺服器關閉或從伺服器收到無效郵件。您可能也會發現 刪除用戶端物件,即可主動拆散繫結。
傳出 FIDL 方法
您可以透過 fidl::WireClient
執行個體叫用傳出的 FIDL API。
取消參照 fidl::WireClient
可讓您存取下列方法:
StartGame
(火災和忘記):fidl::Status StartGame(bool start_first)
:火災的代管變化版本 清除方法
MakeMove
(雙向):[...] MakeMove(uint8_t row, uint8_t col)
:相關元件的代管變化版本 非同步雙重驗證方式它會傳回必須使用的內部類型 註冊非同步接續的接收結果,以接收結果,例如 做為回呼。請參閱指定非同步瀏覽器 接續。後續攻擊 除非調度器關閉,否則在調度工具執行緒上執行。
fidl::WireClient::buffer
提供下列方法的存取權:
fidl::Status StartGame(bool start_first)
:呼叫端配置的火災變化版本 以及清除方法[...] MakeMove(uint8_t row, uint8_t col)
:非同步、呼叫端配置 則為雙向方法的變化版本這會傳回與 受管理的變化版本
fidl::WireClient::sync
提供下列方法的存取權:
fidl::WireResult<MakeMove> MakeMove(uint8_t row, uint8_t col)
:同步、 採用兩種方法的代管變化版本而且WireSyncClient
。
指定非同步接續
請參閱對應的 C++ 說明文件註解。
系統會透過結果物件 (代表 成功解碼的回應,或發生錯誤。如果使用者需要 將每個 FIDL 呼叫的錯誤傳播至其來源器。例如 處理現有的 FIDL 呼叫時,可能必須另外發出 FIDL 呼叫;且 發生錯誤時,必須無法通過原始呼叫。
下列是傳回物件上幾個方法的方法:
Then
:接受回呼,並最多叫用回呼一次,直到 用戶端停止服務。ThenExactlyOnce
:傳遞回呼時,系統會完全執行回呼 不論呼叫成功或失敗都一樣不過,由於回呼 以非同步方式叫用,刪除 用戶端:回呼擷取到的物件 可能不是有效名稱ThenExactlyOnce
做出控制時,也可能會使用回應內容 分配負載TicTacToe
只有一個回應內容。fidl::WireResponseContext<TicTacToe::MakeMove>
,具備純粹的 應該覆寫以處理呼叫結果的方法:
virtual void OnResult(fidl::WireUnownedResult<MakeMove>& result) = 0;
呼叫 OnResult
時,結果物件代表成功
發生解碼或錯誤您有責任確保
背景物件會超過整個非同步呼叫的持續時間,因為
fidl::WireClient
會依地址借用結構定義物件,以避免隱含
分配速度。
集中式錯誤處理常式
繫結因發生錯誤而遭到撤銷時,
fidl::WireAsyncEventHandler<TicTacToe>::on_fidl_error
就會從
包含詳細原因的調度器執行緒。錯誤是調度工具時
關閉,則系統會從呼叫的執行緒叫用 on_fidl_error
調度工具關閉。建議為記錄或
在該處理常式中釋出資源
WireSyncClient
fidl::WireSyncClient<TicTacToe>
是同步用戶端,能夠提供
方法如下:
explicit WireSyncClient(fidl::ClientEnd<TicTacToe>)
:建構函式。~WireSyncClient()
:預設解構函式。WireSyncClient(&&)
:預設移動建構函式。WireSyncClient& operator=(WireSyncClient&&)
:預設移動指派作業。const fidl::ClientEnd<TicTacToe>& client_end() const
:傳回基礎 「用戶端端點」。fidl::Status StartGame(bool start_first)
:火災的代管變化版本 找不到方法呼叫。要求的緩衝區分配完全是在 這個函式fidl::WireResult<TicTacToe::MakeMove> MakeMove(uint8_t row, uint8_t col)
: 兩種方法呼叫的代管變化版本,使用的參數做為 並傳回WireResult
物件。要求的緩衝區分配 並在這個函式中完成所有回應。繫結 會根據以下內容,在編譯期間計算此呼叫專屬的安全緩衝區大小 FIDL 電匯格式和長度上限限制。緩衝區會分配至 例如不超過 512 個位元組 或者其他堆積上的問題詳情請見 WireResult,進一步瞭解緩衝區管理。fidl::Status HandleOneEvent(SyncEventHandler& event_handler)
:封鎖 收看的是管道中的一個事件如果伺服器傳送了惡意程式碼 序號包含的狀態會傳回。請參閱事件一節。
fidl::WireSyncClient<TicTacToe>::buffer
提供以下方法:
fidl::WireUnownedResult<TicTacToe::StartGame> StartGame(bool start_first)
: 呼叫者分配的火災和遺忘呼叫變體 做為引數傳遞至buffer
的要求緩衝區儲存空間,以及 要求參數,然後傳回fidl::WireUnownedResult
。fidl::WireUnownedResult<TicTacToe::MakeMove> MakeMove(uint8_t row, uint8_t col)
:兩種方法的呼叫端配置變體,以要求 用來編碼要求的空間以及接收回應 傳遞給buffer
方法的相同記憶體資源。
請注意,每個方法都具有自有和呼叫端分配的變化版本。簡單來說 每個方法擁有的變化版本都會處理要求的記憶體配置 而呼叫端分配的變化版本則可讓使用者提供 緩衝區上自有變化版本更容易使用,但可能會產生 分配速度。
WireCall
fidl::WireCall<TicTacToe>
提供的方法與在
WireSyncClient
,唯一的差別在於 WireCall
可以是
構建為 fidl::UnownedClientEnd<TicTacToe>
,也就是藉用
用戶端端點:
fidl::WireResult<StartGame> StartGame(bool start_first)
:擁有的變化版本StartGame
。fidl::WireResult<MakeMove> MakeMove(uint8_t row, uint8_t col)
:擁有的變化版本 (共MakeMove
個)。
fidl::WireCall<TicTacToe>(client_end).buffer
提供以下方法:
fidl::WireUnownedResult<StartGame> StartGame(bool start_first)
:StartGame
的呼叫端配置變化版本。fidl::WireUnownedResult<MakeMove> MakeMove(uint8_t row, uint8_t col);
:MakeMove
的呼叫端配置變化版本。
Result、WireredResult 和 WireUnownedResult
WireSyncClient
和 WireCall
每個方法的代管變化版本
會傳回 fidl::WireResult<Method>
類型,而呼叫端分配的變化版本則會傳回
全都會傳回 fidl::WireUnownedResult<Method>
啟動及忘記方法
fidl::WireClient
會傳回 fidl::Status
。這些類型定義了一組
方法:
zx_status status() const
會傳回傳輸狀態。解碼器就會傳回 於線性化、編碼、產生 對基礎管道的呼叫並解碼結果如果狀態為ZX_OK
,呼叫成功,反之亦然。fidl::Reason reason() const
會傳回失敗作業的詳細資料。 當status()
不是ZX_OK
時。舉例來說,如果編碼失敗,reason()
會傳回fidl::Reason::kEncodeError
。不應呼叫reason()
當狀態為ZX_OK
時。const char* error_message() const
出現錯誤訊息 狀態不是ZX_OK
。否則,則會傳回nullptr
。- (僅適用於雙向呼叫的 WireResult 和 WireUnownedResult)
T* Unwrap()
會傳回回應結構的指標。適用對象WireResult
,指標會指向結果物件擁有的記憶體。適用對象WireUnownedResult
,指標會指向呼叫端提供的緩衝區。 只有在狀態為ZX_OK
時才能呼叫Unwrap()
。
此外,進行雙向呼叫的 WireResult
和 WireUnownedResult
將會
實作傳回回應結構本身本身的解碼運算子。
這允許程式碼,例如:
fidl::WireResult result = client.sync()->MakeMove(0, 0);
auto* response = result.Unwrap();
bool success = response->success;
簡單來說:
fidl::WireResult result = client.sync()->MakeMove(0, 0);
bool success = result->success;
WireResult<Method>
會管理所有緩衝區和控制代碼的擁有權,而::Unwrap()
會傳回檢視區塊。因此,這個物件的使用期限 就會參照未包裝回應。
分配策略和移動語意
WireResult
會將回應緩衝區內嵌至內嵌,如果訊息保證
不超過 512 個位元組由於結果物件通常會在 上建立
呼叫端的堆疊,這實際上意味著回應是經過堆疊分配
模型的規模很小如果回應大小上限超過 512 個位元組,
WireResult
而是包含堆積分配的緩衝區。
因此,系統不支援 WireResult
上的 std::move()
。內容必須是
如果緩衝區為內嵌,就會複製,而指向外部物件的指標必須
但只要更新到目標物件中的位置,
通常認為是低成本的移動作業負擔
如果需要在多個函式呼叫周圍傳遞結果物件,請考慮 預先分配最外層函式中的緩衝區,並使用呼叫端配置 變種版本
伺服器
實作 FIDL 通訊協定的伺服器需要提供具體
實作 TicTacToe
。
產生的 fidl::WireServer<TicTacToe>
類別具有純虛擬方法
對應 FIDL 通訊協定中定義的方法呼叫。使用者導入
TicTacToe
伺服器,方法是提供
fidl::WireServer<TicTacToe>
,具有以下純虛擬方法:
virtual void StartGame(StartGameRequestView request, StartGameCompleter::Sync& completer)
virtual void MakeMove(MakeMoveRequestView request, MakeMoveCompleter::Sync& completer)
請參閱 C++ 伺服器範例,瞭解如何繫結 設置伺服器實作
C++ 線繫結也提供手動分派訊息的函式
fidl::WireDispatch<TicTacToe>
:
void fidl::WireDispatch<TicTacToe>(fidl::WireServer<TicTacToe>* impl, fidl::IncomingMessage&& msg, ::fidl::Transaction* txn)
:調度 。如果沒有相符的處理常式,系統會關閉 訊息,並通知txn
發生錯誤。
要求
每個產生的 FIDL 方法都會提供要求做為第一個引數 處理常式。這個畫面會顯示要求的檢視畫面 (指標)。所有要求引數都是 透過方向鍵運算子和引數名稱存取
例如:
request->start_first
request->row
如需要求生命週期的附註,請參閱通訊網域物件的記憶體擁有權。
完成者
每個產生的 FIDL 方法最後一個引數都會提供完整引數
處理常式中,位於該方法的所有 FIDL 要求參數之後。完整程序
類別會擷取完成 FIDL 交易的多種方式,例如:依
回覆留言、用證詞關閉管道等,
同步版本和非同步版本 (但 ::Sync
類別是以
引數)。這個範例中的完成者如下:
fidl::WireServer<TicTacToe>::StartGameCompleter::Sync
fidl::WireServer<TicTacToe>::StartGameCompleter::Async
fidl::WireServer<TicTacToe>::MakeMoveCompleter::Sync
fidl::WireServer<TicTacToe>::MakeMoveCompleter::Async
所有完整類別都提供以下方法:
void Close(zx_status_t status)
:關閉管道,並以status
的身分傳送 先生所說。
此外,兩種方法會為以下項目提供兩個版本的 Reply
方法:
回覆回覆:受管理的變化版本和呼叫端分配的變化版本。這些
對應 client API 中的變化版本。例如:
MakeMoveCompleter::Sync
和 MakeMoveCompleter::Async
都提供了
下列 Reply
方法:
::fidl::Status Reply(bool success, fidl::ObjectView<GameState> new_state)
::fidl::Status Reply(fidl::BufferSpan _buffer, bool success, fidl::ObjectView<GameState> new_state)
由於 Reply 傳回的狀態與未繫結狀態相同, 可以放心忽略
最後,同步完成者的兩種方法可以轉換為非同步
透過 ToAsync()
方法建立完整的程式碼非同步完成工具可以在範圍外留存
處理常式的特殊 IP 位址,例如將其移到 lambda 擷取中,讓伺服器可以
以非同步方式回應要求非同步完成工具與
以同步完成的方式回應用戶端請參閱回應要求
非同步管理
平行訊息處理
根據預設,系統會依序處理來自單一繫結的訊息,即
會視需要喚醒連接到調度工具的單一執行緒 (執行迴圈),
讀取訊息、執行處理常式,然後傳回調度工具。
::Sync
完成者提供額外的 API EnableNextDispatch()
,可能會
來選擇性地解除這項限制具體來說,就是呼叫這個 API
讓另一個執行緒等待調度器處理下一則訊息
而第一個執行緒仍位於處理常式時。請注意,
重複呼叫相同 Completer
中的 EnableNextDispatch()
為等冪。
void DirectedScan(int16_t heading, ScanForPlanetsCompleter::Sync& completer) override {
// Suppose directed scans can be done in parallel. It would be suboptimal to block one scan until
// another has completed.
completer.EnableNextDispatch();
fidl::VectorView<Planet> discovered_planets = /* perform a directed planet scan */;
completer.Reply(std::move(discovered_planets));
}
呼叫端分配的方法
上述幾個 API 會提供自有和呼叫端分配的變化版本 產生的方法
呼叫端分配的變化版本會將所有記憶體配置負責
呼叫函式。fidl::BufferSpan
類型會參照緩衝區位址和大小。這項服務
繫結程式庫會使用這些 URI 來建構 FIDL 要求,因此
必須夠大方法參數 (例如 heading
) 為
在緩衝區中「線性化」為適當位置。建立機器學習模型時
建立緩衝區的方法:
// 1. On the stack
using StartGame = TicTacToe::StartGame;
fidl::SyncClientBuffer<StartGame> buffer;
auto result = client.buffer(buffer.view())->StartGame(true);
// 2. On the heap
auto buffer = std::make_unique<fidl::SyncClientBuffer<StartGame>>();
auto result = client.buffer(buffer->view())->StartGame(true);
// 3. Some other means, e.g. thread-local storage
constexpr uint32_t buffer_size = fidl::SyncClientMethodBufferSizeInChannel<StartGame>();
uint8_t* buffer = allocate_buffer_of_size(buffer_size);
fidl::BufferSpan buffer_span(/* data = */buffer, /* capacity = */request_size);
auto result = client.buffer(buffer_span)->StartGame(true);
// Check the transport status (encoding error, channel writing error, etc.)
if (result.status() != ZX_OK) {
// Handle error...
}
// Don't forget to free the buffer at the end if approach #3 was used...
,瞭解如何調查及移除這項存取權。使用呼叫端配置的變種版本時,
result
物件會借用 要求和回應緩衝區 (因此其類型位於WireUnownedResult
下方)。 請確保緩衝區時間超過result
物件。 請參閱 WireUnownedResult。
活動
在 C++ 繫結中,事件可以非同步或同步處理。 視所用的用戶端類型而定。
非同步用戶端
使用 fidl::WireClient
時,可藉由傳遞
fidl::WireAsyncEventHandler<TicTacToe>*
類別。
WireAsyncEventHandler
類別具備以下成員:
virtual void OnOpponentMove(fidl::WireEvent<OnOpponentMove>* event) {}
: OnOpponentMove 事件的處理常式 (每個事件一個方法)。virtual on_fidl_error(::fidl::UnbindInfo info) {}
:方法呼叫 用戶端遇到終端機錯誤。
要處理事件和錯誤,類別繼承自
必須定義 fidl::WireAsyncEventHandler<TicTacToe>
。
同步處理用戶端
在 WireSyncClient
中,系統會呼叫
HandleOneEvent
函式,並將
fidl::WireSyncEventHandler<TicTacToe>
。
WireSyncEventHandler
是一種類別,其中包含每個項目的純虛擬方法
活動。這個範例包含下列成員:
virtual void OnOpponentMove(fidl::WireEvent<TicTacToe::OnOpponentMove>* event) = 0
:OnOpponentMove 事件的控制代碼。
為處理事件,這個類別沿用自 WireSyncEventHandler
。這個類別必須定義所有事件的虛擬方法
。然後必須建立此類別的例項。
處理單一事件的方法有兩種。每個執行個體都會使用 定義的事件處理常式類別:
::fidl::Status fidl::WireSyncClient<TicTacToe>::HandleOneEvent( SyncEventHandler& event_handler)
:同步處理用戶端的繫結版本。::fidl::Status fidl::WireSyncEventHandler<TicTacToe>::HandleOneEvent( fidl::UnownedClientEnd<TicTacToe> client_end)
:未繫結版本, 使用fidl::UnownedClientEnd<TicTacToe>
處理特定事件的一次 處理常式。
每次呼叫 HandleOneEvent
時,此方法都會在管道上等候確切時間
1 則收到的訊息。接著系統會解碼訊息。如果結果是
fidl::Status::Ok()
,然後只呼叫一種虛擬方法。否則
未呼叫任何虛擬方法,且狀態代表錯誤。
如果處理常式始終相同 (從一次呼叫 HandleOneEvent
到
WireSyncEventHandler
物件必須建構一次
。HandleOneEvent
。
如果事件標示為轉換,預設的導入方式為
這會導致 HandleOneEvent
在收到
未經使用者處理的轉換事件。
伺服器
fidl::WireSendEvent
的用途是從伺服器端傳送事件。這裡共有兩個
超載:
fidl::WireSendEvent(const fidl::ServerBindingRef<Protocol>& binding_ref)
透過伺服器繫結參照傳送事件。fidl::WireSendEvent(const fidl::ServerEnd<Protocol>& endpoint)
透過端點傳送事件
使用伺服器繫結物件傳送事件
將伺服器實作項目繫結至管道時,fidl::BindServer
會傳回
fidl::ServerBindingRef<Protocol>
,也就是您
以安全的方式執行伺服器繫結作業
使用繫結參照呼叫 fidl::WireSendEvent
會傳回以下介面:
傳送事件。
事件寄件者介麵包含傳送每個事件的方法。身為
具體範例,TicTacToe
的事件傳送者介面會提供
方法如下:
fidl::Status OnOpponentMove(GameState new_state)
:代管的變種版本。
呼叫 .buffer(...)
會傳回類似介面配置呼叫端
變種版本,從傳入的記憶體資源分配編碼緩衝區
.buffer
,類似於用戶端 API,以及伺服器
完成者。
使用 ServerEnd 物件傳送事件
伺服器端點本身則以 fidl::ServerEnd<Protocol>
表示。
使用伺服器繫結物件傳送事件:
伺服器端點會繫結至
。但是有時候可能會需要傳送事件
直接對 fidl::ServerEnd<TicTacToe>
物件執行動作,不必設定伺服器
繫結。
fidl::WireSendEvent
會使用 fidl::ServerEnd<Protocol>
的常數參照。
但不支援 zx::unowned_channel
,減少使用
端點。
結果
依據方法:
protocol TicTacToe {
MakeMove(struct {
row uint8;
col uint8;
}) -> (struct {
new_state GameState;
}) error MoveError;
};
FIDL 會在完成工具中產生便利的方法
分別對應至含有錯誤類型的方法根據回覆「變化版本」
完成者將使用 ReplySuccess
和/或 ReplyError
方法來回應
直接與成功或錯誤資料互動,無須建立聯集。
就代管口味而言,以下兩種方法皆可供使用:
void ReplySuccess(GameState new_state)
void ReplyError(MoveError error)
由於 ReplyError
不需要堆積分配,因此只有 ReplySuccess
存在
呼叫端配置的變種版本:
void ReplySuccess(fidl::BufferSpan _buffer, GameState new_state)
請注意,傳入的緩衝區是用來保存「整個」回應,而不只是保存回應 與成功變化版本對應的資料
您也可以使用定期產生的 Reply
方法:
void Reply(TicTacToe_MakeMove_Result result)
:自有的變化版本。void Reply(fidl::BufferSpan _buffer, TicTacToe_MakeMove_Result result)
: 呼叫端分配的變化版本。
自有和呼叫端分配的變化版本會使用
TicTacToe_MakeMove_Result
:此為具有兩個欄位的「聯集」
變化版本:Response
,即 TicTacToe_MakeMove_Response
和 Err
,且
是 MoveError
。系統產生的 TicTacToe_MakeMove_Response
是
將回應參數做為欄位的 struct。在本例中
new_state
設有單一欄位,即 GameState
。
不明互動處理
伺服器端
通訊協定宣告為 open
或 ajar
時,系統會產生
fidl::WireServer<Protocol>
類型也會沿用
fidl::UnknownMethodHandler<Protocol>
。UnknownMethodHandler
會定義
伺服器必須實作的單一抽象方法,呼叫
handle_unknown_method
,包含以下簽名:
virtual void handle_unknown_method(UnknownMethodMetadata<Protocol> metadata,
UnknownMethodCompleter::Sync& completer) = 0;
提供的 UnknownMethodMetadata
是包含一或兩個欄位的結構
取決於通訊協定是 ajar
或 open
。中繼資料如下
結構體類似,為求簡單,省略範本引數:
struct UnknownMethodMetadata {
// Ordinal of the method that was called.
uint64_t method_ordinal;
// Whether the method that was called was a one-way method or a two-way
// method. This field is only defined if the protocol is open, since ajar
// protocols only handle one-way methods.
UnknownMethodType unknown_method_type;
};
UnknownMethodType
是包含 kOneWay
和 kTwoWay
兩個變數的列舉,分別用於
指出呼叫的方法種類
UnknownMethodCompleter
與單向用於單向的完整類型相同
方法。
用戶端
用戶端無法判斷 flexible
單向方法是否已知
檢查與否針對 flexible
雙向方法,如果已知該方法不明
fidl::WireResult
的 fidl::Status
皆為
ZX_ERR_NOT_SUPPORTED
,原因為 fidl::Reason::kUnknownMethod
。
kUnknownMethod
原因只適用於彈性的雙向方法。
除了可能會收到 Reason
的
kUnknownMethod
,strict
和 flexible
沒有 API 差異
方法。
如果是 open
和 ajar
通訊協定,系統會產生
fidl::WireAsyncEventHandler<Protocol>
和
fidl::WireSyncEventHandler<Protocol>
將沿用自
fidl::UnknownEventHandler<Protocol>
。UnknownEventHandler
定義了
事件處理常式必須實作 (稱為 handle_unknown_event
) 的方法,
這項簽章:
virtual void handle_unknown_event(UnknownEventMetadata<Protocol> metadata) = 0;
UnknownEventMetadata
有這個版面配置,其中省略了以下範本的範本引數:
簡單易用:
struct UnknownEventMetadata {
// Ordinal of the event that was received.
uint64_t event_ordinal;
};
通訊協定組合
FIDL 沒有繼承的概念,而會產生完整的程式碼做為 以上說明適用於所有編寫的通訊協定。於 也就是程式碼產生的
protocol A {
Foo();
};
protocol B {
compose A;
Bar();
};
提供的 API 與為以下項目產生的程式碼相同:
protocol A {
Foo();
};
protocol B {
Foo();
Bar();
};
產生的程式碼會相同,但方法序數除外。
通訊協定和方法屬性
不透明
適用於附有
@transitional
敬上
通訊協定類別上的 virtual
方法隨附預設值
Close(ZX_NOT_SUPPORTED)
實作。這樣一來,您就能將
缺少方法覆寫的通訊協定類別,以成功編譯。
可供偵測
通訊協定加上
@discoverable
敬上
屬性會使 FIDL 工具鍊在通訊協定類別上產生額外的 static const char
Name[]
欄位,其中包含完整的通訊協定名稱。
持續且獨立使用 FIDL 線段
單獨使用 FIDL 線格式,例如編碼和解碼個人 目前尚不支援 FIDL 網域物件 (https://fxbug.dev/42163274)。
測試施工架
FIDL 工具鍊也會產生名為 wire_test_base.h
的檔案,其中包含
用於測試 FIDL 用戶端和伺服器實作的便利程式碼。使用條件
這些標頭,取決於繫結目標標籤加上 _testing
後置字串
(my_library_cpp_testing
,而非 my_library_cpp
)。
伺服器測試基礎
測試基礎標頭為每個提供虛設常式的通訊協定,包含一個類別
每個類別的方法實作,因此能
僅適用於測試期間使用的方法。這些類別屬於範本
fidl::testing::WireTestBase<Protocol>
或
fidl::testing::TestBase<Protocol>
,其中 Protocol
是
為虛構值 (例如,通訊協定 games.tictactoe/TicTacToe
的測試鹼基為
fidl::testing::WireTestBase<games_tictactoe::TicTacToe>
或
fidl::testing::TestBase<games_tictactoe::TicTacToe>
)。
針對上述相同的 TicTacToe
通訊協定,產生測試基礎子類別
fidl::WireServer<TicTacToe>
和 fidl::Server<TicTacToe>
(請參閱
通訊協定),並且提供下列方法:
virtual ~WireTestBase() = default
或virtual ~TestBase() = default
: 破壞者。virtual void NotImplemented_(const std::string& name, ::fidl::CompleterBase& completer) = 0
:已覆寫為定義應用程式行為的純虛擬方法
測試基礎會提供虛擬通訊協定方法的實作內容
StartGame
和 MakeMove
,為了僅呼叫
NotImplemented_("StartGame", completer)
和 NotImplemented_("MakeMove",
completer)
。
同步事件處理常式測試基礎
測試基礎標頭為每個提供虛設常式的通訊協定,包含一個類別
每個類別事件的實作方式,讓您能在實作時
僅用於測試期間使用的事件。這與伺服器測試基礎類似
這些類別分別是
fidl::testing::WireSyncEventHandlerTestBase<Protocol>
,其中Protocol
是
虛設常式的 FIDL 通訊協定。
針對上述相同的 TicTacToe
通訊協定,產生測試基礎子類別
fidl::WireSyncEventHandler<TicTacToe>
(請參閱「通訊協定」一節),產品
下列事件:
virtual ~WireSyncEventHandlerTestBase() = default
:解構。virtual void NotImplemented_(const std::string& name) = 0
:純虛擬 方法。
測試基礎會提供虛擬通訊協定事件的實作內容
OnOpponentMove
,為了只呼叫
NotImplemented_("OnOpponentMove")
。