Rust 繫結

正在產生 FIDL Rust Crate

您可以透過下列兩種方式從 FIDL 程式庫產生 FIDL Rust Crate:

  1. 手動使用標準 FIDL 工具鍊
  2. 自動使用 Fuchsia 建構系統 (在後端使用標準 FIDL 工具鍊)。這個選項僅適用於 Fuchsia 來源樹狀結構。

程式庫

FIDL library 會對應至名為 fidl_ 的 Rust 程式庫 Crate,後面接著包含底線 (而非半形句號) 的完整程式庫路徑。

例如,假設 library 宣告:

library fuchsia.examples;

對應的 FIDL Crate 已命名為 fidl_fuchsia_examples

use fidl_fuchsia_examples as fex;

性狀

FIDL Rust Crate 中的部分方法和常數是由實作 FIDL 執行階段 Crate 提供的特徵提供。如要存取這些特徵,您必須匯入對應的特徵。最簡單的做法是從 Prelude 模組一次匯入所有資源:

use fidl::prelude::*;

上述功能會使用 as _ 語法重新匯出特徵,因此 glob 匯入只會將特徵納入解析方法和常數的範圍。不會匯入特徵名稱。

常數

假設常數

const BOARD_SIZE uint8 = 9;
const NAME string = "Tic-Tac-Toe";

FIDL 工具鍊會產生下列常數:

  • pub const BOARD_SIZE: u8
  • pub const NAME: &str

FIDL 原始類型和 Rust 類型之間的對應請參閱內建類型

欄位

本節說明 FIDL 工具鍊如何將 Rust 中的 FIDL 類型轉換為原生類型。這些類型可以顯示為匯總類型的成員,或顯示為通訊協定方法的參數。

內建類型

在下表中,如果您同時指定「擁有」和「借用」變體,則「擁有」類型是指出現在匯總類型中的類型 (例如結構欄位或向量元素的類型),而「借用」類型則是指從用戶端的角度來看,將其做為通訊協定方法參數或元組參數使用的類型。為了利用 Rust 擁有權模型,擁有和借用的區別存在。發出包含 T 類型參數的要求時,經 Proxy 的函式呼叫不需要取得 T 的擁有權,因此 FIDL 工具鍊需要產生 T 的借用版本。借用的版本通常使用 &mut,因為類型 T 可能包含控點,在這種情況下,FIDL 在編碼時會將控制代碼歸零,以修改輸入內容。如果使用 &mut 取代擁有權,呼叫端在不含控制代碼的情況下,可允許呼叫端重複使用輸入值。

FIDL 類型 鐵鏽類型
bool bool
int8 i8
int16 i16
int32 i32
int64 i64
uint8 u8
uint16 u16
uint32 u32
uint64 u64
float32 f32
float64 f64
array<T, N> &mut [T; N] (借用)
[T, N] (已擁有)
vector<T>:N &[T] (借用,如果 T 是原始數值)
&mut dyn ExactSizeIterator (借用)
Vec (擁有)
string &str (借用)
String (已擁有)
server_end:P fidl::endpoints::ServerEnd<PMarker>,其中 PMarker 是此通訊協定的標記類型
client_end:P fidl::endpoints::ClientEnd<PMarker> 其中 PMarker 是此通訊協定的標記類型
zx.Handle fidl::Handle
zx.Handle:S 使用對應的帳號代碼類型。例如 fidl::Channelfidl::Vmo

使用者定義的類型

位元、列舉和資料表一律會使用其產生的類型 T。struct 和 unions 可分為必要或選用,可在自有的結構定義或借用情境中使用,這代表有四種可能的 Rust 類型。特定 struct Tunion T 的類型如下:

已擁有 借用
必要 T &mut T
選用 Option<T> Option<&mut T>

要求、回應和事件參數

當 FIDL 需要產生單一 Rust 類型來代表要求、回應或事件的參數時 (例如針對結果類型),系統會使用下列規則:

  • 多個參數會以參數類型的元組表示。
  • 單一參數只會以參數的類型表示。
  • 一組空參數會以 () 單位類型表示。

類型

比特

採用 bits 定義:

type FileMode = strict bits : uint16 {
    READ = 0b001;
    WRITE = 0b010;
    EXECUTE = 0b100;
};

FIDL 工具鍊會產生一組名為 FileModebitflags,其中包含 FileMode::READFileMode::WRITEFileMode::EXECUTE 標記。

bitflags 結構還包含下列方法:

  • get_unknown_bits(&self) -> u16:傳回原始值,其中僅包含此位元值中的未知成員。如果是 strict 位元,則會標示為 #[deprecated] 且一律傳回 0。
  • has_unknown_bits(&self) -> bool:傳回這個值是否包含任何不明位元。如果是 strict 位元,會標示 #[deprecated] 並一律傳回 false

產生的 FileMode 結構一律具備完整的 #[derive] 規則組合。

使用範例:

let flags = fex::FileMode::READ | fex::FileMode::WRITE;
println!("{:?}", flags);

列舉

採用 enum 定義:

type LocationType = strict enum {
    MUSEUM = 1;
    AIRPORT = 2;
    RESTAURANT = 3;
};

FIDL 工具鍊會使用指定的基礎類型產生 Rust enum;如未指定,則產生 u32

#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[repr(u32)]
pub enum LocationType {
    Museum = 1,
    Airport = 2,
    Restaurant = 3,
}

使用下列方法:

  • from_primitive(prim: u32) -> Option<Self>:傳回與鑑別值 (如有) 對應的列舉變化版本 Some,否則傳回 None
  • into_primitive(&self) -> u32:傳回底層差別值。
  • is_unknown(&self) -> bool:傳回此列舉是否不明。如果是嚴格類型,則會標示為 #[deprecated],且一律傳回 false

如果 LocationType 是「彈性」,則具有下列其他方法:

  • from_primitive_allow_unknown(prim: u32) -> Self:從原始值建立列舉的執行個體。
  • unknown() -> Self:傳回未知的預留位置列舉值。如果列舉包含標示為 [Unknown] 的成員,此方法傳回的值會包含指定未知成員的值。

產生的 LocationType enum 一律具備完整的 #[derive] 規則組合。

使用範例:

let from_raw = fex::LocationType::from_primitive(1).expect("Could not create LocationType");
assert_eq!(from_raw, fex::LocationType::Museum);
assert_eq!(fex::LocationType::Restaurant.into_primitive(), 3);

為提供來源相容性,「彈性」列舉具有不明巨集,應用於比對不明成員 (而非 _ 模式)。例如,請參閱 LocationTypeUnknown!() 巨集的用法:

match location_type {
    fex::LocationType::Museum => println!("museum"),
    fex::LocationType::Airport => println!("airport"),
    fex::LocationType::Restaurant => println!("restaurant"),
    fex::LocationTypeUnknown!() => {
        println!("unknown value: {}", location_type.into_primitive())
    }
}

不明巨集的運作方式與 _ 模式相同,但可以設為展開廣泛比對。如要找出遺漏的案件,這項資訊就能派上用場。

結構

使用 struct 宣告:

type Color = struct {
    id uint32;
    @allow_deprecated_struct_defaults
    name string:MAX_STRING_LENGTH = "red";
};

FIDL 工具鍊會產生 Rust struct

#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Color {
    pub id: u32,
    pub name: String,
}

產生的 Color struct 符合 #[derive] 規則

使用範例:

let red = fex::Color { id: 0u32, name: "red".to_string() };
println!("{:?}", red);

工會

假設使用 union 定義:

type JsonValue = strict union {
    1: reserved;
    2: int_value int32;
    3: string_value string:MAX_STRING_LENGTH;
};

FIDL 工具鍊會產生 Rust enum

#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum JsonValue {
    IntValue(i32),
    StringValue(String),
}

使用下列方法:

  • ordinal(&self) -> u64:傳回 FIDL 類型中指定的有效變數序數。
  • is_unknown(&self) -> bool:傳回此聯集是否為未知。對於非彈性的聯集類型,一律會傳回 false。如果是嚴格類型,則會標示為 #[deprecated],且一律傳回 false

如果 JsonValue 是「彈性」,則具有下列其他方法:

  • unknown_variant_for_testing() -> Self:建立未知的聯集值。這只能在測試中使用。

產生的 JsonValue enum 符合 #[derive] 規則

使用範例:

let int_val = fex::JsonValue::IntValue(1);
let str_val = fex::JsonValue::StringValue("1".to_string());
println!("{:?}", int_val);
assert_ne!(int_val, str_val);

彈性聯集和未知變體

彈性聯集會產生額外變數,以代表未知情況。系統會將這個變化版本視為私人變數,因此不應直接參照,

為提供來源相容性,「彈性」聯集具有不明巨集,應用於比對未知成員,而非 _ 模式。例如,請參閱 JsonValueUnknown!() 巨集的用法:

match json_value {
    fex::JsonValue::IntValue(val) => println!("int: {}", val),
    fex::JsonValue::StringValue(val) => println!("string: {}", val),
    fex::JsonValueUnknown!() => println!("unknown ordinal: {}", json_value.ordinal()),
}

不明巨集的運作方式與 _ 模式相同,但可以設為展開廣泛比對。如要找出遺漏的案件,這項資訊就能派上用場。

如果 FIDL 訊息包含具有未知變數的聯集,並解碼為 JsonValueJsonValue::is_unknown() 就會傳回 true。

彈性聯集具有自訂 PartialEq,可使未知變化版本的行為與 NaN 相同:這些變數不會與任何項目 (包括本身) 進行比較,如要瞭解這項決策的背景資訊,請參閱「RFC-0137:捨棄 FIDL 中的不明資料」。

Strict 聯集在解碼未知的變數時失敗。彈性聯集在解碼未知的變數時成功,但重新編碼時會失敗。

桌子

使用 table 定義:

type User = table {
    1: reserved;
    2: age uint8;
    3: name string:MAX_STRING_LENGTH;
};

FIDL 工具鍊會產生 struct User,並包含選用成員:

#[derive(Debug, PartialEq)]
pub struct User {
  pub age: Option<u8>,
  pub name: Option<String>,
  #[doc(hidden)]
  pub __source_breaking: fidl::marker::SourceBreaking,
}

如果在解碼時發現任何不明欄位,就會捨棄這些欄位。您無法加以存取,也無法判斷這些它們是否存在。

__source_breaking 成員信號表示初始化資料表時,如果新增欄位,就會造成 API 故障。您應該改用結構更新語法,在未指定的欄位中填入 Default::default()。例如:

let user = fex::User { age: Some(20), ..Default::default() };
println!("{:?}", user);
assert!(user.age.is_some());

同樣地,表格也不允許完整比對。您必須改用 .. 語法忽略未指定的欄位。例如:

let fex::User { age, name, .. } = user;

產生的 User struct 符合 #[derive] 規則

內嵌版面配置

產生的 Rust 程式碼會使用 fidlc 為內嵌版面配置保留的名稱

衍生作品

FIDL 工具鍊為 FIDL 類型產生新的 structenum 時,會從預先定義的實用特徵清單中盡可能嘗試 derive,包括 DebugCopyClone 等。您可以在附錄 A 中找到完整的特徵清單。

如果是結構體、聯集和資料表等匯總類型,決定工具組合的決定方式是從所有可能的衍生清單開始,然後根據類型中連帶顯示的欄位移除部分。舉例來說,傳遞含有 vector 的匯總類型不會衍生 Copy,而且我包含 handle 的類型 (即未標示為 resource 的類型) 不會衍生 CopyClone。如有疑問,請參考產生的程式碼,檢查特定類型衍生的特徵。如需實作詳情,請參閱附錄 B

通訊協定

通訊協定為依據:

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;
    });
};

TicTacToe 互動的主要進入點是 TicTacToeMarker 結構,其中包含兩個相關聯的類型:

  • Proxy:與非同步用戶端搭配使用的相關 Proxy 類型。在此範例中,這是產生的 TicTacToeProxy 類型。同步用戶端應直接使用 TicTacToeSynchronousProxy (請參閱同步),這不會儲存在 TicTacToeMarker 上的相關類型中。
  • RequestStream:實作這個通訊協定的伺服器必須處理相關聯的要求串流。在這個範例中,這是由 FIDL 產生的 TicTacToeRequestStream

此外,TicTacToeMarker 透過實作 fidl::endpoints::ProtocolMarker 具備下列相關常數:

  • DEBUG_NAME: &’static str:適用於偵錯的服務名稱。

視通訊協定或其方法所套用的通訊協定和方法屬性而定,可能會產生其他程式碼。

用戶端

非同步

如果是非同步用戶端,FIDL 工具鍊會產生包含以下項目的 TicTacToeProxy 結構:

相關聯的類型:

  • TicTacToeProxy::MakeMoveResponseFutFuture 類型,用於雙向方法的回應。這個類型會實作 std::future::Future<Output = Result<(bool, Option<Box<GameState>>), fidl::Error>> + Send

方法:

  • new(channel: fidl::AsyncChannel) -> TicTacToeProxy:為 TicTacToe 建立新的 Proxy。
  • take_event_stream(&self) -> TicTacToeEventStream:從伺服器端取得事件 Stream (請參閱事件)。

實作 fidl::endpoints::Proxy 的方法:

  • from_channel(channel: fidl::AsyncChannel) -> TicTacToeProxy:與 TicTacToeProxy::new 相同。
  • into_channel(self) -> Result<fidl::AsyncChannel>:嘗試將 Proxy 轉換回管道。
  • as_channel(&self) -> &fidl::AsyncChannel:取得 Proxy 基礎管道的參照
  • is_closed(&self) -> bool:檢查 Proxy 是否已收到 PEER_CLOSED 信號。
  • on_closed<'a>(&'a self) -> fuchsia_async::OnSignals<'a>:在 Proxy 收到 PEER_CLOSED 信號時完成的 Future。

實作 TicTacToeProxyInterface 的方法:

  • start_game(&self, mut start_first: bool) -> Result<(), fidl::Error>:啟動和忘記通訊協定方法的 Proxy 方法。它會將要求參數做為引數,並傳回空白結果。
  • make_move(&self, mut row: u8, mut col: u8) -> Self::MakeMoveResponseFut:雙向的 Proxy 方法。它會將要求參數做為引數,並傳回回應的 Future

Rust 教學課程中會提供設定非同步 Proxy 的範例。

TicTacToeProxyInterface 特徵在測試用戶端程式碼時非常實用。舉例來說,如果您編寫的函式會採用 &T 做為 T: TicTacToeProxyInterface 的參數,則可以使用假 Proxy 類型對該函式進行單元測試:

use futures::future::{ready, Ready};

struct FakeTicTacToeProxy {
    move_response: (bool, Option<Box<GameState>>),
}

impl TicTacToeProxyInterface for FakeTicTacToeProxy {
    fn start_game(&self, mut start_first: bool) -> Result<(), fidl::Error> {
      Ok(())
    }

    type MakeMoveResponseFut = Ready<fidl::Result<(bool, Option<Box<GameState>>)>>;
    fn make_move(&self, mut row: u8, mut col: u8) -> Self::MakeMoveResponseFut {
        ready(self.move_response.clone())
    }
}

同步

對於 TicTacToe 通訊協定的同步用戶端,FIDL 工具鍊會使用下列方法產生 TicTacToeSynchronousProxy 結構:

  • new(channel: fidl::Channel) -> TicTacToeSynchronousProxy:透過管道的用戶端傳回新的同步 Proxy。系統會假設伺服器端實作 TicTacToe 通訊協定。
  • into_channel(self) -> fidl::Channel:將 Proxy 轉換回管道。
  • start_game(&self, mut a: i64) -> Result<(), fidl::Error>:啟動和忘記方法的 Proxy 方法:將要求參數做為引數,並傳回空白結果。
  • make_move(&self, mut row: u8, mut col: u8, __deadline: zx::Time) -> Result<(bool, Option<Box<GameState>>), fidl::Error>:雙向方法的 Proxy 方法。它會將要求參數做為引數,後面接有期限參數,此參數用於指定方法呼叫等待回應的時間長度 (或 zx::Time::INFINITE 無限期封鎖)。這個方法會傳回回應參數Result
  • wait_for_event(&self, deadline: zx::Time) -> Result<TicTacToeEvent, fidl::Error>:在收到事件或期限到期前進行封鎖 (使用 zx::Time::INFINITE 無限期封鎖)。它會傳回 TicTacToeEvent 列舉Result

Rust 教學課程中提供了設定同步 Proxy 的範例。

伺服器

通訊協定要求串流

為了表示對伺服器的傳入要求串流,FIDL 工具鍊會產生實作 futures::Stream<Item = Result<TicTacToeRequest, fidl::Error>>fidl::endpoints::RequestStreamTicTacToeRequestStream 類型。每個通訊協定都有對應的要求串流類型。

要求列舉

TicTacToeRequest 是一個列舉,代表 TicTacToe 通訊協定的可能要求。其中包含以下變化版本:

  • StartGame { start_first: bool, control_handle: TicTacToeControlHandle }:觸發和忘記要求,其中包含要求參數和控制控點
  • MakeMove { row: u8, col: u8, responder: TicTacToeMakeMoveResponder }:雙向方法要求,包含要求參數和回應者

每個通訊協定都會產生一個列舉。

要求作答者

這兩種方法都有對應的產生的回應者類型,伺服器會使用該類型回應要求。在這個範例中,只有一種方法,FIDL 工具鍊會產生 TicTacToeMakeMoveResponder,以提供下列方法:

  • send(self, mut success: bool, mut new_state: Option<&mut GameState>) -> Result<(), fidl::Error>:傳送回應。
  • send_no_shutdown_on_err(self, mut success: bool, mut new_state: Option<&mut GameState>) -> Result<(), fidl::Error>:與 send 類似,但不在發生錯誤時關閉管道。
  • control_handle(&self) -> &TicTacToeControlHandle:取得基礎的控制控制代碼
  • drop_without_shutdown(mut self):在不關閉管道情況下捨棄回應者。

通訊協定控制控點

FIDL 工具鍊會產生 TicTacToeControlHandle,以封裝伺服器端的 TicTacToe 通訊協定的用戶端端點。其中包含以下方法:

  • shutdown(&self):關閉管道。
  • shutdown_with_epitaph(&self, status: zx_status::Status):傳送劇集,然後關閉管道。
  • send_on_opponent_move(&self, mut new_state: &mut GameState) -> Result<(), fidl::Error>:事件的 Proxy 方法,這個方法會將事件參數做為引數,並傳回空白結果 (請參閱「事件」)。

活動

用戶端

針對在非同步用戶端上接收事件,FIDL 工具鍊會產生 TicTacToeEventStream,您可以使用 TicTacToeProxy 中的 take_event_stream() 方法取得此資訊。TicTacToeEventStream 實作 futures::Stream<Item = Result<TicTacToeEvent, fidl::Error>>

針對在同步用戶端接收事件,FIDL 工具鍊會在傳回 TicTacToeEventTicTacToeSynchronousProxy 上產生 wait_for_event 方法。

TicTacToeEvent 是代表可能事件的列舉。它具有以下變化版本:

  • OnOpponentMove { new_state: GameState }TicTacToeEvent 事件。

並提供以下方法:

  • into_on_opponent_move(self) -> Option<GameState>:傳回事件參數Some;如果變化版本與方法呼叫不符,則傳回 None

伺服器

伺服器可以使用與通訊協定對應的「控制控制代碼」傳送事件。控制項控點可透過從用戶端收到的 TicTacToeRequest 取得。如果是觸發和忘記方法,可透過 control_handle 欄位取得控制控點;如果是兩種方法,可透過回應器的 control_handle() 方法取得控制控點。通訊協定的控制控制代碼也可以透過對應的要求串流 (在此範例中為 TicTacToeRequestStream) 取得,因為其實作了 fidl::endpoints::RequestStream

成果

如果方法為錯誤類型:

protocol TicTacToe {
    MakeMove(struct {
      row uint8;
      col uint8;
    }) -> (struct {
      new_state GameState;
    }) error MoveError;
};

FIDL 工具鍊會為 std::result::Result<GameState, MoveError> 產生公開 TicTacToeMakeMoveResult 類型別名。系統會產生這個方法的其餘繫結程式碼,就像其含有 TicTacToeMakeMoveResult 類型的單一回應參數 result。用於取得成功結果的類型會遵循參數類型轉換規則

不明互動處理

伺服器端

宣告通訊協定為 openajar 時,產生的要求列舉會有一個名為 _UnknownMethod 的額外變數,其中包含以下欄位:

#[non_exhausitve]
_UnknownMethod {
    /// Ordinal of the method that was called.
    ordinal: u64,
    /// Control handle for the protocol.
    control_handle: TicTacToeControlHandle,
    /// Enum indicating whether the method is a one-way method or a two way
    /// method. This field only exists if the protocol is open.
    method_type: fidl::MethodType,
}

MethodType 是包含 OneWayTwoWay 兩個單位變數的列舉,用於指出呼叫的方法類型。

每當伺服器收到彈性的不明事件時,要求串流就會發出要求列舉的這個變化版本。

用戶端

用戶端無法判斷伺服器是否已得知 flexible 單向方法。如果是 flexible 雙向方法,如果伺服器不知道該方法,用戶端會收到值為 fidl::Error::UnsupportedMethodErr 結果。UnsupportedMethod 錯誤僅適用於彈性雙向方法。

除了可能收到 UnsupportedMethod 錯誤以外,用戶端上的 strictflexible 方法沒有 API 差異。

如果是 openajar 通訊協定,產生的事件列舉會有一個名為 _UnknownEvent 的額外變數,其中包含以下欄位:

#[non_exhaustive]
_UnknownEvent {
    /// Ordinal of the event that was sent.
    ordinal: u64,
}

每當用戶端收到不明事件時,用戶端事件串流就會發出這個事件列舉變化版本。

通訊協定組成

FIDL 沒有繼承的概念,並會針對所有組合的通訊協定產生上述的完整程式碼。換句話說,為下列項目產生的程式碼:

protocol A {
    Foo();
};

protocol B {
    compose A;
    Bar();
};

與下列程式碼相同:

protocol A {
    Foo();
};

protocol B {
    Foo();
    Bar();
};

通訊協定和方法屬性

過渡

@transitional 屬性只會影響 ProxyInterface 特徵,後者有時用於測試程式碼。針對非測試程式碼,只要讓要求處理常式在 Request 處理常式中暫時使用全部接收的比對臂,即可在伺服器端轉換通訊協定。用戶端程式碼不需要軟轉換,因為產生的 Proxy 一律會實作所有方法。

針對加上 @transitional 屬性註解的方法,非同步用戶端ProxyInterface 特徵會提供呼叫 unimplemented!() 的預設實作。如前文所述,這不會影響 Proxy 類型,因為其一律會實作所有 trait 的方法。不過,如果在用戶端單元測試中使用 ProxyInterface 特徵,則有助於進行軟轉換。

可供偵測

針對加上 @discoverable 屬性註解的通訊協定,「標記」類型會額外實作 fidl::endpoints::DiscoverableProtocolMarker 特徵。這會提供與 PROTOCOL_NAME 相關聯的常數。

明確的編碼和解碼

系統會在收到 FIDL 訊息時自動編碼並解碼。您也可以明確編碼及解碼,例如將 FIDL 資料保存到檔案。遵循 RFC-0120:單獨使用 FIDL 傳輸格式的規定,繫結會提供永久 API獨立 API

保留

如要明確編碼及解碼,建議您使用 persistunpersist。這適用於「非資源」結構、資料表和聯集。

例如,您可以保留 Color 結構

let original_value = fex::Color { id: 0, name: "red".to_string() };
let bytes = fidl::persist(&original_value)?;

然後將其拆除:

let decoded_value = fidl::unpersist(&bytes)?;
assert_eq!(original_value, decoded_value);

一般版 UI

如果是永久性 API 不足的進階用途,您可以使用獨立編碼和解碼 API。這適用於所有結構體、資料表和聯集。函式可分為兩組,一組用於類型,另一種用於資源類型。

舉例來說,由於 JsonValue 聯集是值類型,因此我們使用 standalone_encode_value 對其進行編碼:

let original_value = fex::JsonValue::StringValue("hello".to_string());
let (bytes, wire_metadata) = fidl::standalone_encode_value(&original_value)?;

這樣做會回傳位元組向量與儲存線格式中繼資料的不透明物件。如要解碼,請將兩個值傳遞至 standalone_decode_value

let decoded_value = fidl::standalone_decode_value(&bytes, &wire_metadata)?;
assert_eq!(original_value, decoded_value);

再舉一個例子,請考慮結構 EventStruct

type EventStruct = resource struct {
    event zx.Handle:<EVENT, optional>;
};

由於這是資源類型,因此我們使用 standalone_encode_resource 進行編碼:

let original_value = fex::EventStruct { event: Some(fidl::Event::create()) };
let (bytes, handle_dispositions, wire_metadata) =
    fidl::standalone_encode_resource(original_value)?;

除了位元組和傳輸格式中繼資料外,這也會傳回 HandleDisposition 向量。如要解碼,請將控制代碼轉換為 HandleInfo,然後將這三個值全部傳遞至 standalone_decode_resource

let mut handle_infos = fidl::convert_handle_dispositions_to_infos(handle_dispositions)?;
let decoded_value: fex::EventStruct =
    fidl::standalone_decode_resource(&bytes, &mut handle_infos, &wire_metadata)?;
assert!(decoded_value.event.is_some());

附錄 A:衍生特徵

"Debug",
"Copy",
"Clone",
"Default",
"Eq",
"PartialEq",
"Ord",
"PartialOrd",
"Hash",

附錄 B:填滿衍生工具

特徵衍生規則的計算會顯示在 fidlgen_rust 中:

// Calculates what traits should be derived for each output type,
// filling in all `*derives` in the IR.
func (c *compiler) fillDerives(ir *Root) {