程式庫
根據程式庫宣告:
library fuchsia.examples;
這個程式庫的所有程式碼都會在 fuchsia::examples
命名空間中產生,而測試鷹架則是在 fuchsia::examples::testing
中產生。
常數
所有constants都會產生為 constexpr
。例如,下列常數:
const BOARD_SIZE uint8 = 9;
const NAME string = "Tic-Tac-Toe";
在標頭檔案中產生的值如下:
constexpr uint8_t BOARD_SIZE = 9u;
extern const char[] NAME;
FIDL 原始類型和 C++ 類型之間的對應列於內建類型中。系統會在標頭檔案中宣告字串為 extern const char[]
,並在 .cc
檔案內定義字串,而非 constexpr
。
欄位
本節說明 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 中,使用產生的類別或變數會在繫結中參照使用者定義類型 (位元、列舉、常數、結構、聯集或資料表 (請參閱類型定義)。針對可為空值的使用者定義類型 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
值的成員,並加上取代 FileModeMask
的 kMask
成員。
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
成員相符:
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: reserved;
2: int_value int32;
3: 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
成員都有一個與 union
定義中指定的 ordinal 相符的值。此外,還有 Invalid
欄位,這是用於尚未設定變化版本的 JsonValue
的初始值。
JsonValue
提供以下方法:
JsonValue()
:預設建構函式。直到JsonValue
設為特定變數為止,否則標記一開始會處於Tag::Invalid
。請盡可能使用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
。在設定變化版本之前,使用者不應存取聯集,因此應視為未定義的行為。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
:傳回聯集變體的原始位元組;如果不是,則傳回nullptr
。const vector<zx::handle>* UnknownHandles() const
:在遍歷順序中傳回聯集變數的控制代碼,否則傳回nullptr
。JsonValue& SetUnknownData(fidl_xunion_tag_t ordinal, vector<uint8_t> bytes, vector<zx::handle> handles)
:與已知成員的 setter 方法類似,這會將聯集設為有指定序數、位元組和控點的不明變數。這個方法只應用於測試,例如確保程式碼可正確處理不明資料。
屬於「值」類型的彈性 JsonValue
包含下列額外方法:
const vector<uint8_t>* UnknownBytes() const
:傳回聯集變體的原始位元組;如果不是,則傳回nullptr
。JsonValue& SetUnknownData(fidl_xunion_tag_t ordinal, vector<uint8_t> bytes)
:與已知成員的 setter 方法類似,這會將聯集設為具有指定序數和位元組的不明變數。這個方法只應用於測試,例如確保程式碼可正確處理未知資料。
為含有不明變體的聯集編碼會將未知的資料,將原始序數寫回線路。
解碼不明變化版本時,Strict 聯集會失敗。使用帳號代碼解碼不明變數時,值類型的彈性聯集會失敗。
桌子
根據資料表定義:
type User = table {
1: reserved;
2: age uint8;
3: 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)
:欄位設定器。void clear_age()
和void clear_name()
:呼叫刪除器來清除欄位的值
User
類別也會提供與不明欄位互動的方法,視類型為值或資源類型而定。屬於值類型的資料表不會有參照 zx::handle
的不明資料方法,且無法使用包含控制代碼的不明欄位解碼資料。
const std::map<uint64_t, fidl::UnknownData>>& UnknownData() const
:傳回位元組對位元組的對應,並會處理。帳號代碼保證符合遍歷順序。void SetUnknownDataEntry(uint32_t ordinal, fidl::UnknownData&& data)
:設定未知欄位的位元組和控點 (如果不存在)。此方法僅應用於測試,例如檢查有不明欄位的資料表是否正確處理。
如果 User
是 value 類型,就會採用下列方法:
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
保留的名稱做為內嵌版面配置。
通訊協定
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
類別,該類別可做為與通訊協定互動的進入點,並定義用戶端用於 Proxy 呼叫伺服器的服務介面,以及用於實作通訊協定的伺服器。同步用戶端會使用不同的虛擬介面: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)
:適用於火災與 forget 通訊協定方法的純虛擬方法。並將要求參數視為引數。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
的 Proxy 類別,該類別會分別透過 Proxy 將要求傳送至伺服器。在本例中,如果有名為 async_tictactoe
的 TicTacToePtr
,呼叫 async_tictactoe->StartGame(start_first)
或 async_tictactoe->MakeMove(row,
col, callback)
即可發出要求。
HLCPP 教學課程中會介紹如何設定 InterfacePtr
或 SynchronousInterfacePtr
並繫結至管道的範例。
fidl::InterfacePtr
類型為執行緒主機。凡是呼叫此類型例項的呼叫,都必須從相同的執行緒進行。fidl::SynchronousInterfacePtr
類型與執行緒相容。繫結這個類型的例項後,便可從多個執行緒同時使用。fidl::InterfaceHandle
類型可用於在執行緒之間安全地轉移管道帳號代碼。詳情請參閱這些類型的類別說明文件。
伺服器
為 FIDL 通訊協定實作伺服器時,需要提供 TicTacToe
的具體實作。
如要瞭解如何設定及繫結伺服器實作,請參閱 HLCPP 教學課程。
事件
用戶端
如果是 TicTacToePtr
tictactoe
,tictactoe.events()
會傳回 Proxy 類別,其中包含下列公開成員:
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
是錯誤類型,即MakeMove
和DryRunMove
的範例中的MoveError
。- 只有在該方法使用錯誤語法時,才會出現這個變數。
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 結構,其中包含成功回應的每個參數對應的欄位。除了一般結構可用的方法和成員之外,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
和 flexible
單向方法和事件,傳送單向方法及接收事件的 API 相同。
如果是 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 類型的公用程式。您可以在教學課程中找到使用資訊。