新增 C++ 繫結

新的 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::vmozx::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_tbool 的明確轉換函式。

如果 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() constbool is_string_value() const:每個變化版本 擁有相關聯的方法,可檢查 JsonValue 的例項是否 該變化版本
  • const int32_t& int_value() constconst 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 訊息含有不明變體的聯集時,解碼成 JsonValueJsonValue::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() constbool has_name() const:傳回欄位是否為 設定。
  • const uint8_t& age() constconst 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 {};
};

內部結構體稱為 SomeCustomNameOuter::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::WireRequestfidl::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> 建立至通訊協定 Pasync_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

WireSyncClientWireCall 每個方法的代管變化版本 會傳回 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()

此外,進行雙向呼叫的 WireResultWireUnownedResult 將會 實作傳回回應結構本身本身的解碼運算子。 這允許程式碼,例如:

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::SyncMakeMoveCompleter::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(),然後只呼叫一種虛擬方法。否則 未呼叫任何虛擬方法,且狀態代表錯誤。

如果處理常式始終相同 (從一次呼叫 HandleOneEventWireSyncEventHandler 物件必須建構一次 。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_ResponseErr,且 是 MoveError。系統產生的 TicTacToe_MakeMove_Response 是 將回應參數做為欄位的 struct。在本例中 new_state 設有單一欄位,即 GameState

不明互動處理

伺服器端

通訊協定宣告為 openajar 時,系統會產生 fidl::WireServer<Protocol> 類型也會沿用 fidl::UnknownMethodHandler<Protocol>UnknownMethodHandler 會定義 伺服器必須實作的單一抽象方法,呼叫 handle_unknown_method,包含以下簽名:

virtual void handle_unknown_method(UnknownMethodMetadata<Protocol> metadata,
                                   UnknownMethodCompleter::Sync& completer) = 0;

提供的 UnknownMethodMetadata 是包含一或兩個欄位的結構 取決於通訊協定是 ajaropen。中繼資料如下 結構體類似,為求簡單,省略範本引數:

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 是包含 kOneWaykTwoWay 兩個變數的列舉,分別用於 指出呼叫的方法種類

UnknownMethodCompleter 與單向用於單向的完整類型相同 方法。

用戶端

用戶端無法判斷 flexible 單向方法是否已知 檢查與否針對 flexible 雙向方法,如果已知該方法不明 fidl::WireResultfidl::Status 皆為 ZX_ERR_NOT_SUPPORTED,原因為 fidl::Reason::kUnknownMethodkUnknownMethod 原因只適用於彈性的雙向方法。

除了可能會收到 ReasonkUnknownMethodstrictflexible 沒有 API 差異 方法。

如果是 openajar 通訊協定,系統會產生 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() = defaultvirtual ~TestBase() = default: 破壞者。
  • virtual void NotImplemented_(const std::string& name, ::fidl::CompleterBase& completer) = 0:已覆寫為定義應用程式行為的純虛擬方法

測試基礎會提供虛擬通訊協定方法的實作內容 StartGameMakeMove,為了僅呼叫 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")