生成 FIDL Rust crate
您可以通过以下两种方式从 FIDL 库生成 FIDL Rust crate:
- 使用标准 FIDL 工具链手动构建。
 - 自动使用 Fuchsia build 系统(该系统在后台使用标准 FIDL 工具链)。此选项仅在 Fuchsia 源代码树中提供。
 
库
FIDL library 会映射到名为 fidl_ 的 Rust 库 crate,后跟使用下划线(而非点)的完整库路径。
例如,给定 library 声明:
library fuchsia.examples;
相应的 FIDL crate 名为 fidl_fuchsia_examples:
use fidl_fuchsia_examples as fex;
trait
FIDL Rust crate 中的某些方法和常量是通过实现 FIDL 运行时 crate 中的 trait 提供的。如需访问它们,您必须导入相应的 trait。最简单的方法是从 prelude 模块中一次性导入它们:
use fidl::prelude::*;
序言使用 as _ 语法重新导出 trait,因此全局导入只会将 trait 引入到作用域中以解析方法和常量。它不会导入 trait 名称本身。
常量
假设有以下常量:
const BOARD_SIZE uint8 = 9;
const NAME string = "Tic-Tac-Toe";
FIDL 工具链会生成以下常量:
pub const BOARD_SIZE: u8pub const NAME: &str
内置类型中概述了 FIDL 基元类型与 Rust 类型之间的对应关系。
字段
本部分介绍了 FIDL 工具链如何在 Rust 中将 FIDL 类型转换为原生类型。这些类型可以作为汇总类型中的成员或作为协议方法的参数出现。
内置类型
在下表中,如果同时指定了“自有”和“借用”变体,“自有”类型是指将出现在汇总类型中的类型(例如,作为结构体字段或矢量元素的类型),而“借用”类型是指如果将其用作协议方法参数(从客户端的角度)或响应元组值(从服务器的角度)时,将出现的类型。之所以区分“拥有”和“借用”,是为了充分利用 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::Channel 或 fidl::Vmo | 
用户定义的类型
位、枚举和表始终使用其生成的类型 T 进行引用。结构体和联合体可以是必需的,也可以是可选的,并且可以在拥有的上下文或借用的上下文中使用,这意味着有四种可能的等效 Rust 类型。对于给定的 struct T 或 union T,类型如下所示:
| 自有 | 借用 | |
|---|---|---|
| 必需 | T | 
&mut T | 
| 可选 | Option<T> | 
Option<&mut T> | 
请求、响应和事件参数
当 FIDL 需要生成一个 Rust 类型来表示请求、响应或事件的参数(例如结果类型)时,它会使用以下规则:
- 多个参数表示为参数类型的元组。
 - 单个参数仅使用参数的类型表示。
 - 空参数集使用单位类型 
()表示。 
类型
位
给定位定义:
type FileMode = strict bits : uint16 {
    READ = 0b001;
    WRITE = 0b010;
    EXECUTE = 0b100;
};
FIDL 工具链会生成一组名为 FileMode 的 bitflags,其中包含标志 FileMode::READ、FileMode::WRITE 和 FileMode::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);
枚举
给定以下枚举定义:
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())
    }
}
未知宏的行为与 _ 模式相同,但可以配置为展开为完全匹配。这对于发现缺失的支持请求非常有用。
结构体
假设有以下结构体声明:
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);
联合体
给定联合定义:
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 一样:它们与任何内容(包括自身)的比较结果均不等于 0。如需了解此决定的背景信息,请参阅 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 类型生成新的 struct 或 enum 时,它会尝试尽可能从预定义的实用 trait 列表中 derive 尽可能多的 trait,包括 Debug、Copy、Clone 等。完整的 trait 列表可参阅附录 A。
对于结构体、联合体和表等汇总类型,派生集的确定方法是:从所有可能的派生列表开始,然后根据类型中存在的传递字段移除一些派生。例如,传递包含 vector 的汇总类型不会派生 Copy,并且可能包含 handle 的类型(即未标记为 resource 的类型)不会派生 Copy 和 Clone。如有疑问,请参阅生成的代码,检查特定类型派生了哪些 trait。如需了解实现详情,请参阅附录 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:要与异步客户端搭配使用的关联代理类型。在此示例中,这是生成的TicTacToeProxy类型。同步客户端应直接使用TicTacToeSynchronousProxy(请参阅同步),而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创建新的代理。take_event_stream(&self) -> TicTacToeEventStream:从服务器端获取事件的Stream(请参阅事件)。
实现 fidl::endpoints::Proxy 的方法:
from_channel(channel: fidl::AsyncChannel) -> TicTacToeProxy:与TicTacToeProxy::new相同。into_channel(self) -> Result<fidl::AsyncChannel>:尝试将代理转换回渠道。as_channel(&self) -> &fidl::AsyncChannel:获取对代理底层渠道的引用is_closed(&self) -> bool:检查代理是否已收到PEER_CLOSED信号。on_closed<'a>(&'a self) -> fuchsia_async::OnSignals<'a>:获取一个 Future,该 Future 会在代理收到PEER_CLOSED信号时完成。
实现 TicTacToeProxyInterface 的方法:
start_game(&self, mut start_first: bool) -> Result<(), fidl::Error>:火花协议方法的代理方法。它接受请求参数作为参数,并返回一个空结果。make_move(&self, mut row: u8, mut col: u8) -> Self::MakeMoveResponseFut:双向方法的代理方法。它接受请求参数作为参数,并返回响应的Future。
如需查看设置异步代理的示例,请参阅 Rust 教程。
TicTacToeProxyInterface trait 对测试客户端代码很有用。例如,如果您编写了一个函数,它接受 &T 作为参数,其中 T:
TicTacToeProxyInterface,则可以使用虚构的代理类型对其进行单元测试:
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:通过通道的客户端返回新的同步代理。假定服务器端实现了TicTacToe协议。into_channel(self) -> fidl::Channel:将代理转换回渠道。start_game(&self, mut a: i64) -> Result<(), fidl::Error>:火花式方法的代理方法:它将请求参数作为参数,并返回一个空结果。make_move(&self, mut row: u8, mut col: u8, __deadline: zx::MonotonicInstant) -> Result<(bool, Option<Box<GameState>>), fidl::Error>:双向方法的代理方法。它将请求参数作为参数,后跟一个截止期限参数,该参数决定了方法调用将等待响应的时间(或zx::MonotonicInstant::INFINITE无限期阻塞)。它会返回响应参数的Result。wait_for_event(&self, deadline: zx::MonotonicInstant) -> Result<TicTacToeEvent, fidl::Error>:阻塞,直到收到事件或截止期限到期(使用zx::MonotonicInstant::INFINITE可无限期阻塞)。它会返回TicTacToeEvent枚举的Result。
如需了解如何设置同步代理,请参阅 Rust 教程。
处理转化
此流程图展示了 Rust FIDL 生态系统中同步客户端的句柄封装容器类型之间的各种转换。
服务器
协议请求流
为了表示传入服务器的请求流,FIDL 工具链会生成一个实现 futures::Stream<Item
= Result<TicTacToeRequest, fidl::Error>> 和 fidl::endpoints::RequestStream 的 TicTacToeRequestStream 类型。每种协议都有对应的请求流类型。
处理转化
此流程图展示了 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>:事件的代理方法,将事件的参数作为参数,并返回一个空结果(请参阅事件)。
事件
客户端
如需在异步客户端上接收事件,FIDL 工具链会生成 TicTacToeEventStream,您可以使用 TicTacToeProxy 上的 take_event_stream() 方法获取该事件。TicTacToeEventStream 实现了 futures::Stream<Item = Result<TicTacToeEvent,
fidl::Error>>。
如需在同步客户端上接收事件,FIDL 工具链会在 TicTacToeSynchronousProxy 上生成一个返回 TicTacToeEvent 的 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。用于成功结果的类型遵循参数类型转换规则。
未知互动处理
服务器端
将协议声明为 open 或 ajar 后,生成的请求枚举将有一个名为 _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 是一个枚举,包含两个单元变体 OneWay 和 TwoWay,用于指明调用了哪种类型的方法。
每当服务器收到灵活的未知事件时,请求流都会发出请求枚举的此变体。
客户端
客户端无法确定服务器是否知道 flexible 单向方法。对于 flexible 双向方法,如果服务器不认识该方法,客户端将收到值为 fidl::Error::UnsupportedMethod 的 Err 结果。只有在使用灵活的双向方法时,才会出现 UnsupportedMethod 错误。
除了可能会收到 UnsupportedMethod 错误之外,客户端上的 strict 和 flexible 方法之间没有 API 差异。
对于 open 和 ajar 协议,生成的事件枚举将有一个名为 _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 trait,后者有时会在测试代码中使用。对于非测试代码,可以通过让请求处理程序在 Request 处理程序中暂时使用万能匹配分支,在服务器端转换协议。客户端代码无需进行软过渡,因为生成的代理始终会实现所有方法。
对于带有 @transitional 属性注解的方法,异步客户端的 ProxyInterface trait 会提供调用 unimplemented!() 的默认实现。如前所述,这对 Proxy 类型没有影响,该类型始终会实现 trait 的所有方法。不过,当在客户端单元测试中将 ProxyInterface trait 用于虚构代理时,它有助于实现平滑过渡。
可检测到
对于带有 @discoverable 属性注解的协议,Marker 类型还会实现 fidl::endpoints::DiscoverableProtocolMarker trait。这提供了 PROTOCOL_NAME 关联常量。
显式编码和解码
FIDL 消息在发送时会自动编码,在接收时会自动解码。您还可以显式编码和解码,例如将 FIDL 数据持久保存到文件中。根据 RFC-0120:独立使用 FIDL 线格格式,这些绑定提供了一个持久性 API 和一个独立 API。
持久性
如需显式编码和解码,建议使用 persist 和 unpersist。这适用于非资源结构体、表和联合体。
例如,您可以保留 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);
一般界面
对于 Persistence 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:派生 trait
"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) {