Rust 繫結

產生 FIDL Rust 箱

您可以透過兩種方式從 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 執行階段 Crate 中的特徵,即可提供 FIDL Rust Crate 中的部分方法和常數。如要存取這些資源,您必須匯入相應特徵。最簡單的方法是從前奏模組一次匯入所有模組:

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 工具鍊如何將 FIDL 類型轉換為 Rust 中的原生類型。這些類型可做為集合類型的成員,或做為通訊協定方法的參數。

內建類型

在下表中,如果同時指定「owned」和「borrowed」變體,則「owned」類型是指在匯總類型中顯示的類型 (例如結構體欄位或向量元素的類型),而「borrowed」類型則是指如果用於做為通訊協定方法參數 (從用戶端的角度) 或回應元組值 (從伺服器的角度) 時,會顯示的類型。之所以區分擁有和借用,是為了充分利用 Rust 的擁有權模式。當您使用 T 類型的參數提出要求時,代理函式呼叫不需要取得 T 的擁有權,因此 FIDL 工具鍊需要產生 T 的借用版本。借用版本通常會使用 &mut,因為 T 類型可能包含句柄,在這種情況下,FIDL 繫結會在編碼時將句柄設為零,進而修改輸入內容。使用 &mut 而非取得擁有權,可讓呼叫端在輸入值不含句柄時重複使用輸入值。

FIDL 類型 Rust 類型
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 進行參照。結構體和聯集可以是必要或選用,並用於擁有的上下文或借用上下文,這表示有四種可能的等同 Rust 類型。對於特定 struct Tunion T,類型如下:

自有 borrowed
必要 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:傳回原始值,其中只包含此位元值中的不明成員。對於「嚴格」位元,則會標示為 #[deprecated],並一律傳回 0。
  • has_unknown_bits(&self) -> bool:會傳回這個值是否包含任何不明位元。對於「嚴格」位元,會標示為 #[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())
    }
}

不明巨集的運作方式與 _ 模式相同,但可設定為擴展至完整比對。這對發現遺漏的個案相當實用。

Structs

假設已宣告 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: int_value int32;
    2: 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 訊息解碼為 JsonValue 時,JsonValue::is_unknown() 會傳回 true。

彈性聯集有自訂 PartialEq,可讓未知的變數的行為類似於 NaN:不會與任何值 (包括自身) 相等。如需這項決定的背景資訊,請參閱 RFC-0137:在 FIDL 中捨棄不明資料

在解碼不明變數時,嚴格的聯集會失敗。彈性聯集在解碼不明變種時會成功,但在重新編碼時會失敗。

表格

給定資料表定義:

type User = table {
    1: age uint8;
    2: 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:實作此通訊協定的伺服器需要處理的相關要求串流。在這個範例中,這個值是 TicTacToeRequestStream,由 FIDL 產生。

此外,TicTacToeMarker 還具有實作 fidl::endpoints::ProtocolMarker 的下列相關常數:

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

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

用戶端

非同步

針對非同步用戶端,FIDL 工具鍊會產生 TicTacToeProxy 結構體,其中包含以下項目:

相關類型:

  • TicTacToeProxy::MakeMoveResponseFut:雙向方法回應的 Future 類型。這個類型會實作 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:取得對等端的基礎管道參照
  • 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>:用於 fire and forget 通訊協定方法的 Proxy 方法。它會將要求參數做為引數,並傳回空白結果。
  • make_move(&self, mut row: u8, mut col: u8) -> Self::MakeMoveResponseFut:雙向方法的 Proxy 方法。它會將要求參數做為引數,並傳回回應的 Future

如需設定非同步 Proxy 的範例,請參閱 Rust 教學課程

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())
    }
}
處理轉換

這張流程圖說明在 Rust FIDL 生態系統中,用於非同步用戶端的句柄包裝函式類型之間可用的各種轉換。請注意,虛線表示可能失敗的方法或函式。

同步

針對 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::MonotonicInstant) -> Result<(bool, Option<Box<GameState>>), fidl::Error>:雙向方法的 Proxy 方法。該方法會將要求參數做為引數,後面接著是截止期限參數,該參數會決定方法呼叫會等待多久時間等待回應 (或 zx::MonotonicInstant::INFINITE 無限期阻斷)。它會傳回回應參數Result
  • wait_for_event(&self, deadline: zx::MonotonicInstant) -> Result<TicTacToeEvent, fidl::Error>:阻斷,直到收到事件或截止時間到期為止 (使用 zx::MonotonicInstant::INFINITE 可無限期阻斷)。此方法會傳回 TicTacToeEvent enumResult

如需設定同步 Proxy 的範例,請參閱 Rust 教學課程

處理轉換

此流程圖說明在 Rust FIDL 生態系統中,同步用戶端的句柄包裝函式類型之間可使用的各種轉換。

伺服器

通訊協定要求串流

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

處理轉換

此流程圖說明 Rust FIDL 生態系統中,用於非同步伺服器的句柄包裝函式類型之間可用的各種轉換。

要求列舉

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 時,系統產生的 request enum 將會包含額外的變化版本 _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 雙向方法,如果伺服器不認識該方法,用戶端會收到 Err 結果,其值為 fidl::Error::UnsupportedMethodUnsupportedMethod 錯誤只會發生在彈性雙向方法中。

除了可能會發生 UnsupportedMethod 錯誤之外,在用戶端上,strictflexible 方法之間沒有任何 API 差異。

針對 openajar 通訊協定,系統會產生額外的 _UnknownEvent 變化版本,其中包含以下欄位:event enum

#[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 類型,因為該類型一律會實作所有特徵的方法。不過,如果在用戶端單元測試中使用 ProxyInterface 特徵來模擬 Proxy,這項功能就會有所助益。

可供偵測

如果是標記為 @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) {