RFC-0061:可擴充聯集

RFC-0061:可延伸聯集
狀態已接受
領域
  • FIDL
說明

為了提供更多方式來表示形狀可能需要隨著時間而改變的聯集,我們建議將現存的聯集替換為可延伸的聯集。

作者
提交日期 (年-月-日)2018-09-26
審查日期 (年-月-日)2018-10-11

「提供給夏威夷和阿拉斯加」

摘要

為了提供更多方式來表示形狀可能需要改變的酬載 隨著時間的推移,我們建議取代現有的工會, 可延伸聯集

提振精神

如今,工會無法隨時間演進,甚至可以警告 "一般而言,變更聯集的定義會破壞二進位 相容性。」

如今有許多聯集 (具擴展性) 例如 fuchsia.modular/TriggerCondition, 欄位被淘汰而不會移除;或 fuchsia.modular/Interaction.

稍後所述, 以及許多現行表示法 。不過 保持 static unionsextensible unions 都會出現 請參閱 優點和缺點

設計

為了引入可延伸聯集,我們必須修改 FIDL 的多個部分: 語言和 fidlc、JSON IR、有線格式和所有語言 繫結。 因此,我們也必須在多個地區記錄這項新功能。 我們會逐一討論各項變更。

語言

語法上,可延伸的聯集看起來與靜態聯集完全相同:

union MyExtensibleUnion {
    Type1 field1;
    Type2 field2;
     ...
    TypeN fieldN;
}

在背景,每個欄位都會獲派一個序數,也就是可以類似 資料表 看看各欄位的優缺點 方法一般 就會自動指派

具體違規事項如下:

  • 序數是使用與方法序相相同的演算法進行計算 (詳細資料)、 將程式庫名稱串連起來 「.」、「可延伸聯集名稱」、「/」以及成員名稱 然後取用 SHA256,並使用 0x7fffffff 遮蓋。
  • 序數為 uint32沒有任何兩個欄位可聲明相同序數、 且禁止使用 0。 如果是序數衝突,[Selector] 屬性 應用於提供別名 (或成員重新命名)。
  • 有形可以稀疏,跟資料表的運作方式不同, 稠密語料
  • 可延伸的聯集不允許有空值的欄位
  • 可延伸聯集必須至少有一名成員

可延伸聯集可以在任何目前可以使用工會的位置使用 。 尤其是:

  • 結構體、表格和可延伸聯集可以包含可延伸聯集;
  • 可延伸的聯集可以包含結構體、資料表和可延伸聯集;
  • 介面引數或傳回可以是可延伸聯集;
  • 可延伸聯集可為空值。

JSON IR

在下列表格中,我們會在每個聯集欄位宣告中新增一個鍵 「一般」。

傳輸格式

線路上會用可延伸聯集 區別選項 (填充 8 個位元組),後面接著 製作人已知的各種成員信封。 具體來說,就是:

  • uint32 標記,包含要編碼的成員序數。
  • 用於對齊 8 個位元組的 uint32 邊框間距
  • 儲存信封中位元組數的 uint32 num_bytes。 一律為 8 的倍數,如果信封為空值,則必須為 0;
  • 儲存在信封中的 uint32 num_handles。 如果信封為空值,則必須為 0;
  • uint64 資料指標,用於表示 離線資料:
    • 0 表示信封為空值;
    • FIDL_ALLOC_PRESENT (或 UINTPTR_MAX) 時, 以及下一個離線物件
  • 如果使用解碼函式,這個 data 指標會是 nullptr (如果信封為空值,則為信封的有效指標)。
  • 收到後,信封就會保留 內容。

可為空值的可延伸聯集具有「標記」、「num_bytes」設為 0num_handles 設為 0資料點為 FIDL_ALLOC_ABSENT, 即0。 基本上,空值的可延伸聯集是 0 的 24 個位元組。

語言繫結

可延伸的聯集與聯集類似,差別在於您也需要 處理「未知」會定義在聯集讀取時的狀況 在理想情況下

union Name { Type1 field1; ...; TypeN fieldN; };

正好是可延伸聯集 所以程式碼可以輕鬆切換 未知情況的模數支援,也就是 唯有在可延伸聯集案例中才有意義

一開始,我們建議不要對保留的成員顯示任何語言繫結: 為求完整,我們不會預期這些錯誤 在語言繫結中執行公開 API 會很有幫助。

執行策略

導入作業包含兩個步驟。

首先,我們會為可延伸聯集提供支援:

  1. 使用不同的其他語言導入功能 (fidlc) 關鍵字 (xunion) 以區分靜態聯集和可延伸 聯集。
  2. 實作各種核心語言繫結 (C、C++、Rust、Go、Dart)。 擴充相容性測試,並據此執行其他測試。

第二,我們會將所有靜態聯集移轉到可延伸的聯集:

  1. 產生靜態聯集的序數,然後放在 JSON IR 中。 後端一開始應會忽略這些項目。

  2. 在讀取路徑上,有兩種讀取聯集模式,就像是 以及像可延伸的工會一樣 (需要一般支線) )。 根據交易的標幟選擇其中一種方式 郵件標頭。

  3. 更新寫入路徑,將聯集編碼為可延伸聯集,並表示 只要在交易訊息標頭中設定 旗標即可。

  4. 更新、部署及傳播所有寫入器後,請將 靜態聯集處理和軟體轉換的鷹架程式碼。

說明文件和範例

這至少需要在以下位置提供文件:

回溯相容性

可延伸聯集明確與「靜態」回溯相容 聯集。

成效

不使用時不會影響效能。 建構期間對效能的影響微乎其微。

安全性

不會影響安全性。

測試

在編譯器中進行單元測試,以及各種版本的編碼/解碼作業 語言繫結和相容性測試,可檢查各種語言 相互繫結

缺點、替代方案和未知

可擴充的工會比不可延伸的工會效率較低。 此外,不可延伸的聯集無法透過其他方式表達 如何以不同語言 有鑑於此,我們提議兩種功能並排運作。

然而,我們可以決定只有可延伸的聯集存在, 與目前定義的聯集一起傳送 這剛好碰到福希西亞的多個地方,而工會代表這些地點。 對成效至關重要的訊息,而且缺少 期望,例如fuchsia.io/NodeInfofuchsia.net/IpAddress

維持靜態聯合國的優缺點

優點

  • 與聯集相比,可延伸聯集會產生 8 個位元組的費用 ( 信封大小和控制代碼數量)。 此外,可擴充的工會一律將資料儲存在非雲端中 (即資料點額外 8 個位元組),而 nullable unions'儲存於離線資料
  • 聯集的編碼方式,系統無法以 其他 FIDL 中的基元。 因此,如果這類內容已從語言中移除,應移除部分類別的訊息 變得既精簡又有效率
  • 在某些情況下,以及視用途而定,聯集可以表示 但情況不同;但這並非正常值 不使用聯集而重新編寫的其中一個例子是 fuchsia.net.stack/InterfaceAddressChangeEvent 僅適用於 fuchsia.net.stack/InterfaceAddressChange 其中 InterfaceAddress 可以直接寫入,並使用 enum 指出已經新增或移除。

缺點

  • 同時保留靜態聯集和可延伸聯集會迫使複雜性, 包括編譯器、JSON IR、所有後端,以及編碼/解碼功能。 增減幅度極低,在 FIDL 的世界中,大小差異為邊際 進行編碼時,編碼效率不高。 此外,您可以視需要在可擴展聯集進行解碼。
  • 舉例來說,以下是讓收益降到最低的分析範例,以下是 fuchsia.io/NodeInfo:
    • 目前 NodeInfo 提供 6 個選項:服務 (大小 1)、檔案 (大小 4)、 目錄 (大小 1)、直立線 (大小 4)、vmofile (大小 24)、裝置 (大小為 4)。
    • 因此,NodeInfo 的總大小一律為 32 個位元組,意即 代碼 + max(選項大小) = 8 + 24 = 32。
    • 採用可延伸聯集時,NodeInfo 大小會依選項而異 編碼方式。 一律採用 16 位元組的「tax」值(第 8 個),因此相應的大小 be: service = 24, file = 24, directory = 24, pipe = 24, vmofile = 40, 型式的裝置 = 24。
    • 因此,無論在哪種情況下,我們都會以 8 個位元組表示 附加 8 個位元組的 vmofile。
  • 靜態聯集和可延伸 我也擔心 我們希望圖書館作者在使用單類閱讀時,會跳轉使用文字 選擇可擴充的工會是一個比較安全的長期選擇,而且成本極低。

總而言之,我們決定以可延伸的聯集取代靜態聯集。

標記與序數

我們使用普通來表示指派給欄位的內部數值。 亦即透過雜湊算出的值。 我們使用標記來表示繫結中的變化版本表示法: 在 Go 中,這可能是 alias 類型的常數,在 Dart 中這可以是 enum

fidlc 編譯器只會處理序數。 開發人員最有可能只處理代碼。 繫結則提供從高階標記轉譯至低層級標記 內部序數。

沒有任何空的可擴充聯集

在設計階段,我們考慮將可延伸聯集保持空白。 然而,我們選擇拒絕結束這件事,也就是選擇可為空值 使用單一變體 (例如空白結構體) 的可延伸聯集 可建立意圖的模型 這也可以避免有兩個「單位」可延伸聯盟的值,例如: 空值和空白值。

既有藝術品和參考資料

  • 通訊協定緩衝區具有「oneof」
  • 除非是特殊情況,否則 FlatBuffers 的 union 並非可擴充。