RFC-0061:可延伸聯集 | |
---|---|
狀態 | 已接受 |
領域 |
|
說明 | 為了提供更多方式來表示形狀可能需要隨著時間而改變的聯集,我們建議將現存的聯集替換為可延伸的聯集。 |
作者 | |
提交日期 (年-月-日) | 2018-09-26 |
審查日期 (年-月-日) | 2018-10-11 |
「提供給夏威夷和阿拉斯加」
摘要
為了提供更多方式來表示形狀可能需要改變的酬載 隨著時間的推移,我們建議取代現有的工會, 可延伸聯集。
提振精神
如今,工會無法隨時間演進,甚至可以警告 "一般而言,變更聯集的定義會破壞二進位 相容性。」
如今有許多聯集 (具擴展性) 例如 fuchsia.modular/TriggerCondition, 欄位被淘汰而不會移除;或 fuchsia.modular/Interaction.
如稍後所述,
以及許多現行表示法
。不過
保持 static unions
和 extensible 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」設為 0, num_handles 設為 0,資料點為 FIDL_ALLOC_ABSENT, 即0。 基本上,空值的可延伸聯集是 0 的 24 個位元組。
語言繫結
可延伸的聯集與聯集類似,差別在於您也需要 處理「未知」會定義在聯集讀取時的狀況 在理想情況下
union Name { Type1 field1; ...; TypeN fieldN; };
正好是可延伸聯集 所以程式碼可以輕鬆切換 未知情況的模數支援,也就是 唯有在可延伸聯集案例中才有意義
一開始,我們建議不要對保留的成員顯示任何語言繫結: 為求完整,我們不會預期這些錯誤 在語言繫結中執行公開 API 會很有幫助。
執行策略
導入作業包含兩個步驟。
首先,我們會為可延伸聯集提供支援:
- 使用不同的其他語言導入功能 (
fidlc
) 關鍵字 (xunion
) 以區分靜態聯集和可延伸 聯集。 - 實作各種核心語言繫結 (C、C++、Rust、Go、Dart)。 擴充相容性測試,並據此執行其他測試。
第二,我們會將所有靜態聯集移轉到可延伸的聯集:
產生靜態聯集的序數,然後放在 JSON IR 中。 後端一開始應會忽略這些項目。
在讀取路徑上,有兩種讀取聯集模式,就像是 以及像可延伸的工會一樣 (需要一般支線) )。 根據交易的標幟選擇其中一種方式 郵件標頭。
更新寫入路徑,將聯集編碼為可延伸聯集,並表示 只要在交易訊息標頭中設定 旗標即可。
更新、部署及傳播所有寫入器後,請將 靜態聯集處理和軟體轉換的鷹架程式碼。
說明文件和範例
這至少需要在以下位置提供文件:
回溯相容性
可延伸聯集明確不與「靜態」回溯相容 聯集。
成效
不使用時不會影響效能。 建構期間對效能的影響微乎其微。
安全性
不會影響安全性。
測試
在編譯器中進行單元測試,以及各種版本的編碼/解碼作業 語言繫結和相容性測試,可檢查各種語言 相互繫結
缺點、替代方案和未知
可擴充的工會比不可延伸的工會效率較低。 此外,不可延伸的聯集無法透過其他方式表達 如何以不同語言 有鑑於此,我們提議兩種功能並排運作。
然而,我們可以決定只有可延伸的聯集存在,
與目前定義的聯集一起傳送
這剛好碰到福希西亞的多個地方,而工會代表這些地點。
對成效至關重要的訊息,而且缺少
期望,例如fuchsia.io/NodeInfo
,fuchsia.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 並非可擴充。