FIDL 繫結規格

本文件是 Fuchsia 介面定義語言的規格 (FIDL) 繫結。此資料旨在提供指引與最佳做法 繫結作者,並建議符合人體工學用途的具體方法。

本文件將理解下列關鍵字: RFC2119可能必須不得選用建議必要不應不應不應應該 NOT,

產生的程式碼指標

註解必須置於機器產生的程式碼頂端,表明該註解屬於 由機器產生針對具備如何指出 而非人類撰寫的程式碼),就必須遵循該標準。

Go 為例,產生的來源必須是 依照模式以註解標記

// Code generated by <tool>; DO NOT EDIT.

設定範圍

我們建議使用命名空間機器產生的程式碼,以免與 使用者定義的符號您可以運用 例如 C++ 中的命名空間 Rust 中的模組,或 Go 中的套件 可惡。如果產生的範圍可以命名,則該範圍應使用 FIDL 程式庫名稱的元件,其中包含 產生的程式碼,讓每個 FIDL 程式庫都存在於不重複的範圍內。於 無法設定範圍且共用命名空間時, 產生的名稱 (請參閱「命名」)。

命名

一般來說,產生的程式碼中使用的名稱應與 FIDL 定義以下各節列出可能的例外狀況。

如果是內嵌版面配置,繫結應使用 fidlc 產生的名稱,因為 容器一定不會重複

繫結 MAY 產生的範圍名稱會對應至 FIDL 名稱的命名結構定義 。例如,針對部分 FIDL:

type Outer = struct {
  middle struct {
    inner struct {};
  };
};

產生的程式碼會參照與 範圍最內層的 FIDL 結構體,使用範圍限定為父項命名結構定義的名稱 (例如: 例如 Outer::Middle::Inner)。

套管

產品/服務必須配合該語言的慣用風格 (例如 使用 snake_case 或 CamelCase)。fidlc 會確保 ID 不重複 所強制執行的大小寫版本會納入考量 (請參閱 RFC-0040)。

保留的關鍵字與名稱衝突

產生的程式碼「必須」考量目標中的保留關鍵字 語言,避免在以指定語言使用關鍵字時,出現非預期的字詞 FIDL 定義例如使用「 底線 _ (假設沒有任何關鍵字以底線開頭)。

產生的程式碼「必須」避免產生造成命名衝突的程式碼。適用對象 例如,函式中的參數是根據 FIDL 產生 定義時,本機變數的名稱「必須」不可行 。

序數

方法普通

用於方法的序數是大型 64 位元數字。繫結應發出這些繫結 十六進制的序數,即 0x60e700e002995ef8,而非 6982550709377523448

聯集和資料表序數

用於 uniontable 的序數從 1 開始,且必須形成密集的空間。 因此,這些數字通常很小,繫結應會輸出這些值 以十進位標記法表示的基因體。

原生類型

建議採用最精確且符合人體工學的原生類型 盡可能將內建 FIDL 類型轉換為目標中的原生類型 語言。例如,Dart 繫結會使用 Int32List 來表示 vector<int32>:Narray<int32>:N,而非通用的 List<int>

產生的類型和值

持續支援

產生的程式碼「必須」產生內含每個項目相符值的變數 const 定義。這些變數必須 在支援此功能的語言中,無法變更 (例如在 C++、Rust 和 Go 中的 const; 或 Dart 中的 final)。

位元支援

繫結「必須」提供每個位元成員產生的值。其他可能 會產生值來代表未設定標記的位元以及位元 並設定所有標記 (「位元遮罩」)。這些值應限定為各個組合 分秒必爭

建議您支援下列運算子,而不是產生的值:

  • 位元和,即 &
  • 位元或如 |
  • 位元專屬或位元組合,即 ^
  • 位元不是位元,即 ~
  • 位元差異,也就是指單一運算元中的所有位元,但位元除外 相同。通常由 - 運算子表示。

FIDL 位元運算的不變之處在於,它們不會 除非來源運算元發生相對應的未知位元,否則就不會產生不明位元。 所有建議的運算子都有這個屬性,但 bitwise not 除外。 實作 bitwise not 作業「必須」進一步遮蓋產生的結果 值為所有值的遮罩。在虛擬程式碼中:

~value1   means   mask & ~bits_of(value1)

為了方便起見,系統會在 JSON IR 中提供這個遮罩值。

在支援運算子超載的語言 (例如 C++) 中,bitwise not 「必須」在 此方法一律會取消取消位元欄位的不明成員。支援語言 不支援運算子超載 (例如 Go) 的值應該提供 InvertBits() 方法 (以最適合該語言的方式使用) 執行遮蓋作業

比起位元不要,更優先採用位元差異運算子 運算子,因為前者會保留未知的位元:

// Unknown bits in value1 are preserved.
value1 = value1 - value2

// Unknown bits in value1 are cleared, even if the user may only intend to
// clear just the bits in value2.
value1 = value1 & ~value2

繫結「不得」支援其他可能導致無效運算子的運算子 位元值 (或讓他人無法清楚知道其意義的翻譯),例如:

  • 位元位移,例如 <<>>
  • 位元無正負號移位,例如 >>>

若是產生的程式碼包含包裝基礎程式碼的類型 位元數值,則必須可以在原始值與 包裝函式類型。建議您讓此轉換明確。

繫結 MAY 可提供函式,用於轉換 和 bits 型別本身bits的基本型別。這類轉換者可能是 變種版本

  • 如果輸入值包含任何不明值,則可能失敗 (或傳回空值) 位元。
  • 截斷輸入值中的任何未知位元。
  • 僅適用於彈性位元:保留從 輸入值

不明資料

對於彈性位元:

  • 繫結「必須」提供檢查值是否包含任何未知的方法 也可以提供擷取這些未知位元的方法。
  • 位元不運算子會取消設定所有未知的成員 與已知成員的價值相同 (但對已知成員來說並無用處)。 其他位元運算子也會為未知位元成員保留相同的語意,如 吸引已知成員的對話

嚴格位元可以一併提供上述 API,以簡化轉換 以便靈活調整

在某些語言中,很難或無法 從原始物件手動建立 bits 類型的執行個體 防止繫結設計人員將嚴格的位元值限制為 並受到妥善限制的網域在此情況下,繫結作者「必須」提供 與未知資料相關的 API。

在含有已編譯檢查淘汰警告的語言 (例如 Rust) 中, 資料相關 API 應提供嚴格位元但標示為已淘汰。

列舉支援

繫結「必須」為每個列舉成員提供產生的值。這些值 範圍限定於每個列舉

若是產生的程式碼包含包裝基礎程式碼的類型 整數列舉值,則應可在原始值與 包裝函式類型。建議您讓此轉換明確。

不明資料

針對彈性列舉:

  • 繫結「必須」能讓使用者判斷列舉是否為不明 包括能夠與列舉比對 (針對 支援 switchmatch 或類似結構的語言)。
  • 繫結 「可能」會公開列舉的基礎原始值 (可能為未知)。
  • 繫結「必須」提供取得有效未知列舉的方法,如果沒有 需要提供明確的未知原始原始值。如果 列舉成員會以 @unknown 屬性加註 那麼這個未知的列舉建構函式「必須」使用註記的值 成員。否則,未指定不明建構函式使用的值。
  • 必須將 @unknown 成員在任何情況下都視為不明 函式,用來判定值是否不明。

結構支援

繫結「必須」為每個支援下列項目的結構體提供類型 作業:

  • 以每個成員有明確值的建構。
  • 讀取及寫入成員。

聯合支援

繫結「必須」為每個聯集提供類型,並支援下列項目 作業:

  • 使用明確變數集建構。不建議繫結 無需加入子類即可建構這個屬性僅適用於 或是因為指定語言限制,而導致您的成效不佳。
  • 讀取/寫入聯集的變化版本及其相關資料 變數。

如果是沒有聯集類型或聯集值常值的語言,建議採用 支援 Factory 方法來建構新聯集,為其中一個 可能的變化版本例如,在 C 語言中,這能夠 程式碼,例如:

my_union_t foo;
foo.set_variant(bar);
do_stuff(foo);

連結包括:

do_stuff(my_union_with_variant(bar));

這些工廠方法必須命名為 [Type]-with-[Variant],且大小寫正確 目標語言

舉例來說, HLCPPGo 繫結。

不明資料

針對彈性聯集

  • 序數不明時,解碼「必須」成功,但重新編碼則「必須」失敗。
  • 繫結「必須」提供一種方式,協助判斷聯集是否有未知的變化版本。
  • 繫結「可」提供存取不明變數序數的方法。
  • 繫結 MAY 可提供建構函式,以便建立含有不明變數的聯集。
    • 該建構函式的名稱「必須」不鼓勵在實際執行程式碼中使用,例如: unknown_variant_for_testing()
    • 建構函式「不得」允許使用者選擇序數。
    • 建立建構函式可以防止最終開發人員使用以下工具建立聯集: 未知的變體,例如手動解碼原始位元組。

資料表支援

繫結「必須」為每個資料表提供支援以下類型的類型 作業:

  • 此架構可選擇是否要指定每個成員的值。
  • 讀取及寫入每個成員,包括檢查特定成員 設定。這些元件必須遵循以下命名配置:get_[member]set_[member]、 和 has_[member] (正確大小寫)。

繫結 MAY 可為只需要指定值的資料表提供建構函式 適用於含有值的欄位舉例來說,在 Rust 中,這可以完成 使用 ::EMPTY 常數和結構體更新語法。提供支援 可讓使用者以負責任的方式編寫程式碼 。

不明資料

所有資料表都彈性

如果有不明欄位,則「必須」成功解碼及重新編碼。 重新編碼時「必須」省略未知的欄位。

繫結 MAY 可讓您判斷表格是否包含任何未知資訊 各個欄位的資料他們「可能」提供存取標準的方法。

繫結「不得」提供建立含有不明欄位或 現有資料表的不明欄位。

嚴格且可彈性的類型

遇到任何未知資料時,嚴格類型「必須」無法解碼。 將含有未知資料的值解碼時,彈性型別「必須」成功。

彈性 FIDL 類型及其在不明事物的行為範例:

FIDL 類型 存取不明資料 重新編碼保真度
彈性位元 原始整數 無失真
彈性列舉 原始整數 無失真
彈性的聯集 布林值或序數 失敗
桌子 布林值或序數 有損

一般來說,解碼期間可捨棄基本的未知資料 或儲存在解碼的類型中無論是哪一種情況,類型 都「必須」指出 無論在解碼時是否會遇到不明資料詳情請參閱 列舉 支援位元支援union 支援資料表支援章節 具體指導方針。

繫結作者應有利於最佳化 strict 類型,但可能會增加費用 共 flexible 類。舉例來說,如果這兩者在設計之間有利弊 繫結作者應偏好最佳化 strict 類型。

必須可轉換類型,將類型從嚴格變更為彈性。

值類型和資源類型

值類型不得包含帳號代碼,且資源類型可能包含控制代碼。

在值類型和彈性類型之間的互動中,彈性類型 Google 會優先處理需求具體來說,解碼函式的彈性值類型 包含不明帳號代碼「必須」成功。

通訊協定支援

活動

繫結「必須」支援處理或忽略通訊協定中的事件。 繫結 MAY 可讓使用者指定部分事件的處理邏輯,並省略 通訊協定中某些其他事件的邏輯。

如果使用者未指定事件的處理邏輯,繫結 收到活動後,請務必照常通訊。也就是 如果不是傳送使用者未指定的事件,也並非錯誤。 用戶端的對應處理邏輯

繫結應盡量避免指定事件之間的兒童不宜行為 會傳入端點

收到不明內容時,繫結「必須」關閉連線 嚴格事件

網域錯誤類型

繫結可為通訊協定提供某種形式的特殊支援 (選用) 方法包含符合慣用方式的錯誤類型 目標語言。

例如,提供某種「結果」格式的語言。類型 (例如聯集) 包含「成功」的類型變數和「錯誤」變數),例如 Rust 的 C++ 中的 result::Resultfpromise::result 可能提供自動轉換 接收或傳送含有錯誤的方法回應 類型。

例外狀況的語言可以視需要由系統產生的通訊協定方法程式碼 提出與該錯誤類型對應的例外狀況。

如果無法這樣做,產生的程式碼「可能」可以提供便利性 能直接回應成功回應或錯誤值的函式。 接收錯誤類型回應,以便避免使用樣板的使用者程式碼 初始化結果聯集。

處理錯誤

通訊協定「可能會」傳回傳輸錯誤。傳輸錯誤可能是 可歸類為從原生類型與 線路資料或基礎傳輸機制的錯誤 (例如 例如呼叫 zx_channel_write_etc 時取得的錯誤)。這些錯誤 可能包括錯誤狀態和其他診斷資訊。

將這些傳輸錯誤定義為終端。文件的其他部分 請指定其他情況做為終端機錯誤,例如不正確地 或交易 ID

  • 編碼期間出現驗證錯誤 (如果執行驗證的話)。
  • 解碼錯誤。
  • 基礎傳輸機制的錯誤。

相較之下,網域錯誤 (在以 error 語法宣告的方法中) 和 架構錯誤 (在 flexible 雙向方法中) 並非終端機。

終端機錯誤處理

繫結「必須」提供非同步用戶端和伺服器 API 基礎端點連線發生終端機錯誤時,用戶端 和伺服器 API 必須關閉基礎端點 來卸除連線

FIDL 的 IPC 傳輸模型不含暫時性錯誤,因此 ,例如再次傳送相同的回覆觸發卸除時間為 錯誤有助於採用這種繫結方式,並可以簡化錯誤處理程序。

繫結 MAY 可提供同步用戶端和伺服器 API。在同步 API 中 如果終端機發生錯誤,則關閉端點通常需要鎖定。如果這樣 因效能因素而不適合,這些 API 可能會保持連線保持開啟 遇到終端機錯誤時,應予以明確記錄。 非同步變種版本應是推薦的 API 變種版本

繫結「可能」可提供不具有基礎設施的用戶端和伺服器 API 適用於低階用途這些 API 無法關閉端點 遇到終端機錯誤時,應予以明確記錄。父層 變種版本應是建議的 API 變種版本。

同業的特殊處理

基礎傳輸機制回報對等互連端點 在傳送訊息時關閉 (例如,使用者收到 ZX_ERR_PEER_CLOSED 錯誤時 寫入管道時,用戶端/伺服器「必須」先讀取和處理 否則會先顯示傳輸錯誤,最後才向使用者顯示傳輸錯誤 連線狀態

基礎傳輸機制通知對等互連端點 在等待訊息期間關閉 (例如觀察 ZX_CHANNEL_PEER_CLOSED 信號) 等待管道中的信號時,用戶端/伺服器「必須」先讀取 先處理任何剩餘訊息,再向使用者顯示傳輸錯誤 然後關閉連線

這是為了配合管道的讀取語意: 端點 A <-> B,假設有多個訊息寫入 B,然後 B已結束營業。使用者可以繼續從「A」讀取內容,無須觀察同類應用程式已關閉 才能排除所有使用中的訊息。也就是「同業關閉」 則在無法從端點讀取訊息前,才算是嚴重錯誤。

處理類型和權利檢查

繫結「必須」對傳入和傳入要求強制執行帳號代碼類型和權利檢查 撥出的電話。這表示 zx_channel_write_etc、 必須使用 zx_channel_read_etczx_channel_call_etc,而不是 和非對等的對等項目

在傳出方向中,必須根據 FIDL 定義確切來說,這類中繼資料應置於 zx_handle_disposition_t,以便叫用 zx_channel_write_etczx_channel_call_etc。這些系統呼叫會執行類型和權限檢查 。

在傳入方向中,zx_channel_read_etczx_channel_call_etczx_handle_info_t 物件的形式提供類型和權利資訊。 繫結本身必須執行適當的檢查,如下所示:

假設帳號代碼 h 已讀取,且其在 FIDL 檔案中的權限為 R

  • 帳號代碼 h 缺少權利所包含的權利,因此不符合這項錯誤 的近似值。發生這項條件時,「必須」關閉管道。
  • 如果帳號代碼 h 擁有的權利超過權利 R,則其權利必須降低為 Rzx_handle_replace

此外,如果 h 的類型有誤,就會發生錯誤。頻道 如果發生這個條件,就必須關閉。

如需詳細範例,請參閱「帳號代碼生命週期」。

Iovec 支援

繫結可以選擇使用向量化 zx_channel_write_etczx_channel_call_etc 個系統呼叫。使用這些符號時,請「務必」使用第一個 iovec 項目 且大小足以容納 FIDL 交易郵件標頭 (16 個位元組)。

屬性

繫結「必須」支援下列屬性

  • @transitional

最佳做法

替代輸出內容

如為繫結,為 FIDL 提供替代輸出方法,此為選用性質 線格式。

針對產生的圖片,其中一種輸出內容是容易使用的偵錯列印 。例如,您可以輸出位元的值:

type Mode = strict bits {
    READ = 1;
    WRITE = 2;
};

可能會顯示 "Mode.Read | Mode.Write" 字串,而非原始值 "0b11"

您可以為產生的每個 FIDL 實作類似的易用列印。 。

訊息記憶體配置

繫結 可以提供使用者自行提供記憶體的選項 這能讓使用者控制系統傳送或接收訊息的時間 分配速度。

傳輸格式記憶體配置

繫結「可能」含有所產生 FIDL 類型的記憶體佈局 傳輸類型。理論上這麼做可以避免多餘副本, 做為交易訊息直接使用,反之亦然。於 執行傳送 FIDL 訊息可能涉及複製步驟 訊息的元件會組合成連續的記憶體區塊 (稱為 「線性化」)。此方法的缺點是會使 更嚴謹:變更 FIDL 電匯格式的變更變得更加複雜。

C++ 電線繫結是這個方法的唯一繫結。

相等比較

針對結構體、資料表和聯集等匯總類型,繫結可提供 能對兩個相同 類型。「請勿」為資源類型提供這些運算子 (詳情請參閱 RFC-0057深度等式) 分別是 帳號代碼。避免為資源類型公開等式運算子 可防止因相等運算「消失」而造成來源中斷CANNOT TRANSLATE 處理常式會新增至類型。

複製中

針對結構體、資料表和聯集等匯總類型,繫結可提供 功能,以便複製類型的執行個體不應複製 用於建立帳號代碼副本 (請參閱 RFC-0057) 並不保證會成功避免公開資源的副本運算子 類型可防止因複製作業「消失」而造成來源中斷或 將控制點新增至型別後,簽名會隨之變更。

測試公用程式

如果繫結產生專門用於的其他程式碼,此為選用參數 測試期間。舉例來說,繫結可以產生 因此使用者只須使用 我們要在測試中練習

Epitaphs

繫結「必須」針對 Epitaph 提供支援 (也就是產生的程式碼),讓 以便接收及處理八分音符的用戶端資料。

setter 和 getter

繫結 MAY 會為匯總型別 (結構體、結構體、 聯集和資料表)。即使是 getter/setter 方法使用的語言 使用這些方法將允許重新命名內部欄位名稱 而不會破壞該欄位的用法

要求「回應者」

以譯文語言使用 FIDL 繫結實作 FIDL 通訊協定時, 繫結提供了 API 來讀取要求參數,以及將訊息寫入 回應參數 (如果有的話)。舉例來說,請求參數可以是 做為函式的引數,而回應參數可能會 做為函式的傳回類型

FIDL 通訊協定:

protocol Hasher {
    Hash(struct {
        value string;
    }) -> (struct {
        result array<uint8, 10>;
    });
};

繫結可能會產生:

// Users would implement this interface to provide an implementation of the
// Hasher FIDL protocol
interface Hasher {
  // Respond to the request by returning the desired response
  hash: (value: string): Uint8Array;
};

繫結 MAY 可提供用於寫入資料的回應者物件 回應。在上述範例中,這指的是傳送額外的 函式引數中的回應者物件,同時讓函式傳回虛線:

interface Hasher {
  hash: (value: string, responder: HashResponder): void;
};

interface HashResponder {
  sendResponse(value: Uint8Array);
};

使用回應者物件有以下好處:

  • 提升人體工學:作答者可用於提供 與客戶互動。舉例來說,作答者可採用 使用憑證關閉管道,或提供用於傳送事件的 API。適用對象 雙向的方法,回應者可以提供傳送回應的機制。
  • 提高靈活度:將這些行為全部封裝為單一型別 可讓您在繫結中新增或移除行為,而不需要 只變更回應者,對繫結使用者進行破壞性變更 而非通訊協定物件

提供作答者物件時,繫結應謹慎處理回應者 與處理要求所使用的執行緒不同。 回應程式也可能比處理要求早很多, 範例。實務上 ,將作答者的擁有權從 或要求處理常式類別,例如傳遞至非同步函式的回呼。

物件「不一定」稱為回應者。舉例來說 視方法觸發和遺漏或兩種方法而定,使用不同的名稱:

interface Hasher {
  // the Hash method is a two-way method, so the object is called a responder
  hash: (value: string, responder: HashResponder): void;
  // the SetSeed method is a fire and forget method, so it gets a different name
  setSeed: (seed: number, control: HasherControlHandle): void;
}

測試

GIDL 合規性測試

GIDL 是一種測試定義語言和工具, FIDL 定義一致性測試。這些測試會針對各個繫結進行標準化 並確保編碼器、解碼器和涵蓋範圍 極端案例

已解碼物件的深度品質

比較物件等性可能並不容易,在下列情況中更是如此 經解碼的 FIDL 物件在解碼期間,可能會呼叫 zx_handle_replace 帳號代碼。發生這種情況時 初始輸入控點將會關閉,並建立新的帳號代碼 更換為更少的權利

因此,您無法直接比較處理常式值。 就能比較控點,方法是查看其 koid (核心 ID)、類型和 以確保他們的權利維持不變。