47 个稳定版本 (3 个主要版本)

4.2.0 2024年7月19日
4.1.1 2024年5月20日
4.0.2 2024年2月25日
3.15.2 2024年2月25日
1.0.2 2019年12月30日

#143 in 编码

Download history 155454/week @ 2024-05-03 155681/week @ 2024-05-10 164805/week @ 2024-05-17 159504/week @ 2024-05-24 172499/week @ 2024-05-31 156901/week @ 2024-06-07 162153/week @ 2024-06-14 176424/week @ 2024-06-21 172627/week @ 2024-06-28 157524/week @ 2024-07-05 170925/week @ 2024-07-12 169709/week @ 2024-07-19 172130/week @ 2024-07-26 165985/week @ 2024-08-02 168468/week @ 2024-08-09 131104/week @ 2024-08-16

667,985 每月下载量
用于 454 个crate (40 个直接使用)

MIT 许可证

445KB
11K SLoC

zvariant

此crate提供了数据编码/解码的API,用于从/到D-Bus线格式。这种二进制线格式简单且非常高效,因此在D-Bus上下文之外也很有用。这种格式的修改版,GVariant,被广泛用于高效存储任意数据,并由本crate支持(如果您启用了gvariant cargo功能)。

自2.0版本以来,API基于serde,因此如果您已经熟悉serde,您会发现它非常直观。如果您不熟悉serde,在学习此crate之前,您可能想先阅读它的教程

状态:稳定。

示例代码

序列化和反序列化是通过顶级函数实现的

use std::collections::HashMap;
use zvariant::{serialized::Context, to_bytes, Type, LE};
use serde::{Deserialize, Serialize};

// All serialization and deserialization API, needs a context.
let ctxt = Context::new_dbus(LE, 0);
// You can also use the more efficient GVariant format:
// let ctxt = Context::new_gvariant(LE, 0);

// i16
let encoded = to_bytes(ctxt, &42i16).unwrap();
let decoded: i16 = encoded.deserialize().unwrap().0;
assert_eq!(decoded, 42);

// strings
let encoded = to_bytes(ctxt, &"hello").unwrap();
let decoded: &str = encoded.deserialize().unwrap().0;
assert_eq!(decoded, "hello");

// tuples
let t = ("hello", 42i32, true);
let encoded = to_bytes(ctxt, &t).unwrap();
let decoded: (&str, i32, bool) = encoded.deserialize().unwrap().0;
assert_eq!(decoded, t);

// Vec
let v = vec!["hello", "world!"];
let encoded = to_bytes(ctxt, &v).unwrap();
let decoded: Vec<&str> = encoded.deserialize().unwrap().0;
assert_eq!(decoded, v);

// Dictionary
let mut map: HashMap<i64, &str> = HashMap::new();
map.insert(1, "123");
map.insert(2, "456");
let encoded = to_bytes(ctxt, &map).unwrap();
let decoded: HashMap<i64, &str> = encoded.deserialize().unwrap().0;
assert_eq!(decoded[&1], "123");
assert_eq!(decoded[&2], "456");

// derive macros to handle custom types.
#[derive(Deserialize, Serialize, Type, PartialEq, Debug)]
struct Struct<'s> {
    field1: u16,
    field2: i64,
    field3: &'s str,
}

assert_eq!(Struct::signature(), "(qxs)");
let s = Struct {
    field1: 42,
    field2: i64::max_value(),
    field3: "hello",
};
let ctxt = Context::new_dbus(LE, 0);
let encoded = to_bytes(ctxt, &s).unwrap();
let decoded: Struct = encoded.deserialize().unwrap().0;
assert_eq!(decoded, s);

// It can handle enums too, just that all variants must have the same number and types of fields.
// Names of fields don't matter though. You can make use of `Value` or `OwnedValue` if you want to
// encode different data in different fields.
#[derive(Deserialize, Serialize, Type, PartialEq, Debug)]
enum Enum<'s> {
    Variant1 { field1: u16, field2: i64, field3: &'s str },
    Variant2(u16, i64, &'s str),
    Variant3 { f1: u16, f2: i64, f3: &'s str },
}

// Enum encoding uses a `u32` to denote the variant index. For unit-type enums that's all that's
// needed so the signature is just `u` but complex enums are encoded as a structure whose first
// field is the variant index and the second one is the field(s).
assert_eq!(Enum::signature(), "(u(qxs))");
let e = Enum::Variant3 {
    f1: 42,
    f2: i64::max_value(),
    f3: "hello",
};
let encoded = to_bytes(ctxt, &e).unwrap();
let decoded: Enum = encoded.deserialize().unwrap().0;
assert_eq!(decoded, e);

// Enum encoding can be adjusted by using the `serde_repr` crate
// and by annotating the representation of the enum with `repr`.
use serde_repr::{Serialize_repr, Deserialize_repr};

#[derive(Deserialize_repr, Serialize_repr, Type, PartialEq, Debug)]
#[repr(u8)]
enum UnitEnum {
    Variant1,
    Variant2,
    Variant3,
}

assert_eq!(UnitEnum::signature(), "y");
let encoded = to_bytes(ctxt, &UnitEnum::Variant2).unwrap();
let e: UnitEnum = encoded.deserialize().unwrap().0;
assert_eq!(e, UnitEnum::Variant2);

// Unit enums can also be (de)serialized as strings.
#[derive(Deserialize, Serialize, Type, PartialEq, Debug)]
#[zvariant(signature = "s")]
enum StrEnum {
    Variant1,
    Variant2,
    Variant3,
}

assert_eq!(StrEnum::signature(), "s");

除了主序列化和反序列化API需要显式调用serialized::Context实例之外,被序列化或反序列化的类型还必须实现Type trait,以及分别实现SerializeDeserialize。有关更多详细信息,请参阅Type模块文档

大多数D-Bus的基本类型与所有原始Rust类型一一对应。唯一的两个例外是,SignatureObjectPath,它们实际上只是字符串。这些类型由Basic trait处理。

同样,大多数的容器类型也很好地映射到常见的Rust类型和集合(如上述示例代码所示)。唯一值得注意的例外是ARRAY类型。由于Rust中的数组是固定大小的,serde将其视为元组,因此本库也是如此。这意味着它们被编码为D-Bus的STRUCT类型。如果您需要将数据序列化到D-Bus数组或从D-Bus数组反序列化,则需要使用切片(数组可以轻松转换为切片)、Vecarrayvec::ArrayVec

D-Bus字符串类型,包括SignatureObjectPath,有一个额外的限制,即Rust中的字符串没有。它们不能包含任何内部空字节('\0')。包含此字符的字符串的编码/解码将返回错误。

通用的D-Bus类型VARIANTValue表示,这是一个枚举,它恰好包含其他类型的任意一个值。请参阅Value模块文档以获取示例。

no-std

虽然std目前是硬性要求,但计划在未来提供可选的no-std支持。另一方面,noalloc支持目前没有计划,因为这将非常困难。然而,社区贡献可以改变这一点。😊

可选功能

功能 描述
gvariant 启用GVariant格式支持
arrayvec arrayvec::ArrayVecarrayvec::ArrayString实现Type
enumflags2 enumflags2::BitFlags<F>实现Type
option-as-array 启用使用数组编码对Option<T>(反)序列化

gvariant功能与option-as-array冲突,因此不应同时启用。

依赖关系

~1.5–3MB
~65K SLoC