本文件說明如何更新或擴充元件檢查檔案格式。
擴充格式時,請務必不要破壞任何現有功能,特別是「檢查讀取器和驗證測試」。不過,把所有變更封裝成單一變更,可能會讓人不知所措。一般來說,鏈結中應有 5 到 9 個變更或步驟,才能修改 VMO 格式:
- (可能不適用) 更新 VMO 格式說明文件來選擇類型編號。
- 更新 Rust 讀取器。
- 更新 C++ 讀取器。
- 更新 Rust 寫入者。
- 更新 C++ 寫入器。
- (視情況) 更新驗證工具。
- 更新說明文件。
- (非變更)(選用) 傳送功能公告。
選擇類型號碼
在「檢查檔案格式」中查看類型資料表,並選擇可用的類型編號。目前的規格共有 256 種可能類型。
實作
如果沒有讀取者或寫入者,測試讀者或寫入者相當麻煩,而且在沒有讀取器和寫入者的情況下,難以取得適當的區塊層級 API。
如何測試閱讀器和寫入者:
選擇語言、設計並完全以該語言實作功能,並透過單元測試模擬 API 的實際使用情形。
將變更分割成個別的讀取者和寫入者變更,將寫入者堆疊在讀取器之上。
此時,仰賴 writer API 的讀取器中的測試可能已在讀取器變更中故障。
反覆執行該變更,並使用較低層級功能重新編寫測試 (保留原始版本的測試)。
一般而言,您可以在讀取器變更項目中設置區塊程式碼的所有變更,雖然可以做到可能,但對於讀取器 API 感到混亂。
測試會是很醜。重新執行寫入器變更並移除修改後的測試,並以高階 API 所編寫的原始測試取代。
將兩個變更做參考,然後在第二種語言中複製這些內容。
(選用) 視變更的內容而定,您可能必須適時更新validator測試,因為現有區塊的現有格式變更可能會導致這些測試中斷。
以下各節概述瞭如何整合各項變更,但實務來說,在按照上述方式分割設計前,請將下列幾點做為提示,以一致的方式設計整個系統。
更新 Rust 實作
本節中的範例會建立名為 MyFoo
的新類型。
設定
- 包含測試:
fx set core.x64 --with //src/lib/diagnostics:tests
執行測試:
fx test inspect-format-tests fuchsia-inspect-tests
讀取者變更
Bitfield 最新消息
如果定義新的區塊類型,請更新
BlockType
列舉。更新為
BlockType
定義的方法和函式。如果變更現有區塊中的欄位或建立新的
BlockType
,請更新位元欄位版面配置。執行
inspect-format-tests
以驗證變更編譯:
fx test inspect-format-tests
更新區塊定義,加入用來讀取及寫入新欄位的方法。目前建議您在區塊程式庫中加入寫入功能;如果沒有這個程式庫,就無法撰寫讀者測試。
編寫可以執行新功能的區塊測試。
撰寫測試,在區塊的前 8 到 16 個位元組上做出斷言。
一般而言,這意味著將預期內容寫入為包含十六進位值的
&[u8]
,並斷言該區塊作為容器使用的緩衝區。
更新讀取器
您可以在 mod.rs 中找到閱讀器程式碼。由於目前沒有高階 API 寫入者,因此這項變動的測試可能會很困難。
寫入者變更
狀態
這裡的主要變更是 State
功能。您可以在這裡將區塊分配並轉換為新的類型。如果您只修改現有區塊,那麼這可能就是您唯一需要變更的地方。
建立新的值類型
您可以在類型目錄中為類型新增檔案。
在建立的檔案中建立新類型。使用現有類型做為範例。類型一律可以存取內部
State
。請使用此方法為新類型建立必要的方法,並呼叫在State
中建立的方法。將方法新增至
Node
以建立新類型。確保您的類型在 VMO 中具有 RAII 語意。如果類型是值,系統可能會透過步驟 1 中現有類型複製的樣板來自動執行此操作。
最後,返回並更新讀取器變更內容中的測試以使用新的 API!
更新 C++ 實作
本節中的範例會建立名為 MyFoo
的新類型。
如上所述,本節應該在 Gerrit 中進行兩項變更。
設定
- 包含測試:
fx set core.x64 --with //zircon/system/ulib/inspect:tests
- 執行測試。
fx test inspect-cpp-unittest
讀取者變更
Bitfield 最新消息
本節說明如何為新類型定義位元欄位。
更新區塊定義。
變更
BlockType
以加入新的類型。例如:kMyFoo = #;
如果類型需要新標頭 (通常並非
VALUE
),請使用結構為類型定義標頭位元欄位。例如:struct MyFooBlockFields final : public BlockFields
。如果您的類型需要新的酬載 (需要使用區塊的第二個 8 個位元組),請使用結構定義類型適用的酬載位元欄位。例如:
struct MyFooBlockPayload final
。如果類型包含列舉 (例如格式),請在 block.h 頂端定義新列舉,例如:
enum class MyFooBlockFormat : uint8_t
。
實作類型讀取器
本節說明如何讓新類型更容易讀取。
值 (Node
的子項)
為您的類型更新
PropertyFormat
列舉。這必須是在這個特定列舉中依序排列,且不需要與您選擇的格式類型序數相符。建立新的值類型。例如:
using MyFooValue = internal::Value<T, static_cast<size_t>(PropertyFormat::kMyFoo)>;
使用新的值更新
PropertyValue
變體。注意:fit::internal::variant
中的索引必須與PropertyFormat
的值相符。
不是值
- 您必須在階層檔案中自行製作記憶體內表示法物件。
更新實際閱讀器。
更新
InnerScanBlocks
來調度類型。如要建立新的Property
,可能只需要新增BlockType
。如果您需要自訂剖析器,請實作
InnerParseMyFoo
,這會視需要採用父項,以及指向已掃描區塊的指標。
寫入者變更
類型包裝函式宣告
本節說明如何為新類型宣告 C++ RAII 樣式包裝函式。
類型包裝函式包含類型所擁有的區塊索引。您必須在狀態動作更新中實作這些區塊的作業,包括建立及刪除作業。
更新寫入者類型定義。
判斷您是否可以重複使用現有的包裝函式,或是否需要自訂類型:
重複使用
如果您需要支援 Add、Subtract 和 Set:
using MyFoo = internal::NumericProperty<T>
,其中T
是這些作業的引數類型。如需支援 Set:
using MyFoo = internal::Property<T>
,其中T
是要設定的引數類型。如果您需要支援陣列中的數字運算:
using MyFood = internal::ArrayProperty<T>
,其中T
是陣列中運算單元的引數類型。如果您需要支援插入直方圖:
using MyFoo = internal::{Linear,Exponential}Histogram<T>
,其中T
是插入的引數。
訂製
建立新的類型包裝函式。例如
class MyFoo final
。確保您的課程具有
internal::State
這個好友課程。注意:如需可複製的起點,請參閱class Link
。
狀態動作最新資訊
State
類別是所有類型作業的實際實作。本節說明如何實作完成包裝函式實作所需的作業。
更新
State
標頭:新增「建立」和「免費」方法。例如:
MyFoo CreateMyFoo(<args>); void FreeMyFoo(MyFoo* property);
,其中args
通常包含名稱、父項和某些初始值。為您需要支援類型的每項作業新增方法。舉例來說,如果您的類型可以設定,就要設定
void SetMyFoo(MyFoo* property, T)
,其中T
與從更新到 types.h 的類型相同。
更新
State
:實作新型別的方法。實作方式因類型而異。本節概略說明每個方法必須執行的操作:
MyFoo CreateMyFoo(Args...)
負責配置多個區塊、設定其值,然後傳回這些區塊納入MyFoo
中。您可以使用私人建構函式,從其包裝的BlockIndex
物件建立MyFoo
。許多內部輔助程式 可簡化這項作業如需範例,請參閱CreateIntProperty
。void FreeMyFoo(MyFoo* property)
負責釋放MyFoo
納入的所有區塊。釋放區塊有時必須遵循特定的排序要求或更新。如需如何釋出值的範例,請參閱InnerFreeValue
。例如
void SetMyFoo(MyFoo* property, T value)
等作業,會變更分配給MyFoo
的區塊值以實作作業。如需範例,請參閱SetIntProperty
。
實作類型包裝函式
本節說明如何實作先前宣告的包裝函式方法。
更新寫入者類型定義:
如果您使用現有的範本類型,則必須為新的基礎類型
T
覆寫每個方法。例如,輸入using MyFoo = internal::Property<T>
,您就會寫入:template<> void internal::Property<T>::OPERATION(...) { ... }
如果您是自行建立類型,則只需為宣告的方法建立定義即可。您必須採取下列行動:
讓建構函式呼叫
state_->CreateMyFoo(...);
呼叫
state_->FreeMyFoo(...);
做為解構器讓您的其他方法在 State 上呼叫對應的實作。
呼叫前,先檢查所有的建構函式和方法,確認
state_
並非空值。