3个版本
0.1.2 | 2023年9月25日 |
---|---|
0.1.1 | 2023年5月29日 |
0.1.0 | 2023年3月30日 |
#344 在 进程宏 中
每月下载量37次
63KB
1K SLoC
rkyv-with
为rkyv的{Archive/Serialize/Deserialize}With
特性提供第三方派生宏。
此派生宏的主要用途是能够在不实现自身Archive
、Serialize
和Deserialize
的远程类型上使用rkyv
。这为rusts孤儿规则提供了一个类似的解决方案,类似于serde
的远程支持。
宏
ArchiveWith
派生宏实现了ArchiveWith
和SerializeWith
特性。对于DeserializeWith
特性,请使用DeserializeWith
派生宏。
#[archive_with(...)]
属性有助于微调实现。
archive_with(from(TypeName))
表示原始类型是什么。此属性需要在类型定义的最高级别指定。允许使用多个逗号分隔的类型,即from(Type1, Type2)
。此属性也可以用于字段。archive_with(via(TypeWrapper))
提供了一种将字段类型转换为其他类型的方法,例如,不可存档的类型包含一个PathBuf
字段,而在可存档的对应字段中它是一个String
,通过指定via(rkyv::with::AsString)
archive_with(getter = "path::to::function")
必须在使用包含私有字段的不可存档类型时使用。该函数必须是Fn(&U) -> T
或Fn(&U) -> &T
,其中U
是不可存档的类型,而T
是字段的类型。archive_with(getter_owned)
可以在指定getter = "..."
的同时使用,当函数接受一个所有者实例而不是引用时。
应用宏
// Both trait and macro must be imported
use rkyv::with::ArchiveWith;
use rkyv_with::ArchiveWith;
// This could come from some dependency or otherwise remote module.
// Importantly, this does not implement the rkyv traits
struct UnarchivableInner {
a: u32,
b: Vec<u8>,
unimportant: String,
}
#[derive(rkyv::Archive, ArchiveWith)]
#[archive_with(from(UnarchivableInner))] // must be specified
struct ArchivableInner {
// fields must have the same name
a: u32,
#[with(rkyv::with::CopyOptimize)] // archive wrappers work as usual
b: Vec<u8>,
// not all fields must be included but if fields
// are omitted, `DeserializeWith` can not be derived
}
struct UnarchivableOuter {
archivable_field: i32,
buf: std::path::PathBuf,
inner: UnarchivableInner,
opt: Option<UnarchivableInner>,
vec: Vec<UnarchivableInner>,
}
#[derive(rkyv::Archive, ArchiveWith)]
#[archive_with(from(UnarchivableOuter))]
struct ArchivableOuter {
// If the field's type is archivable, no annotation is required
archivable_field: i32,
// Otherwise one must specify the original type through `from(...)`
// as well as a type to convert between the types through `via(...)`
#[archive_with(from(std::path::PathBuf), via(rkyv::with::AsString))]
buf: String,
// If the archivable type itself serves as converter, `via(...)` can be omitted
#[archive_with(from(UnarchivableInner))]
inner: ArchivableInner,
// As such, e.g. for `Vec` and `Option` it's necessary to specify the full
// original type, as well as the archivable type wrapped in rkyv's Map wrapper
#[archive_with(
from(Option<UnarchivableInner>),
via(rkyv::with::Map<ArchivableInner>),
)]
opt: Option<ArchivableInner>,
// Using the unarchivable type in combination with a with-wrapper is
// of course also always doable
#[with(rkyv::with::Map<ArchivableInner>)]
vec: Vec<UnarchivableInner>,
}
使用生成的实现
use rkyv::with::{ArchiveWith, DeserializeWith, With};
use rkyv::{Archive, Deserialize, Infallible, Serialize};
use rkyv_with::{ArchiveWith, DeserializeWith};
struct Unarchivable {
a: String,
}
// Can be serialized as usual and
// also serves as serialization wrapper
#[derive(Archive, ArchiveWith, Deserialize, DeserializeWith)]
#[archive_with(from(Unarchivable))]
struct ArchivesTheUnarchivable {
a: String,
}
// Can be serialized as usual
#[derive(Archive, Serialize)]
struct Container {
a: i32,
#[with(ArchivesTheUnarchivable)]
b: Unarchivable,
}
let unarchivable = Unarchivable { a: String::new() };
// Serialize the instance
let wrapper = With::<_, ArchivesTheUnarchivable>::cast(&unarchivable);
let bytes = rkyv::to_bytes::<_, 32>(wrapper).unwrap();
let archived = unsafe { rkyv::archived_root::<ArchivesTheUnarchivable>(&bytes) };
// Can go back to the original type
let deserialized_unarchivable: Unarchivable =
ArchivesTheUnarchivable::deserialize_with(archived, &mut Infallible).unwrap();
// Or stick with the wrapper
let deserialized_wrapper: ArchivesTheUnarchivable =
archived.deserialize(&mut Infallible).unwrap();
私有字段
如果字段因为它们是私有的而不能直接访问,那么派生特质需要手动指定获取器函数。
use rkyv::with::ArchiveWith;
use rkyv::Archive;
use rkyv_with::ArchiveWith;
// Imagine again that this is a remote module that you have no way of modifying
mod remote {
#[derive(Clone)]
pub struct Remote {
pub public_field: u32,
private_field: u32,
}
impl Remote {
// By default it will be assumed that the function will take a reference
pub fn to_private_field(&self) -> u32 {
self.private_field
}
// If it takes ownership instead, `getter_owned` will need to be added as seen below
pub fn into_private_field(self) -> u32 {
self.private_field
}
// A publicly available way of creating the type in case you need to deserialize
pub fn new(public_field: u32, private_field: u32) -> Self {
Self { public_field, private_field }
}
}
}
#[derive(Archive, ArchiveWith)]
#[archive_with(from(remote::Remote))]
struct NativeByReference {
public_field: u32,
// Specifying the path to the getter function that takes a reference
#[archive_with(getter = "remote::Remote::to_private_field")]
private_field: u32,
}
#[derive(Archive, ArchiveWith)]
#[archive_with(from(remote::Remote))]
struct NativeByValue {
public_field: u32,
// If the function takes ownership, be sure to also specify `getter_owned`
#[archive_with(getter = "remote::Remote::into_private_field", getter_owned)]
private_field: u32,
}
// Since creating instances of a type that has private fields cannot be done in a general way,
// `DeserializeWith` cannot be derived for such types and instead has to be implemented manually.
// An implementation for the example above could look as follows:
use rkyv::with::DeserializeWith;
use rkyv::{Archived, Fallible};
impl<D: Fallible> DeserializeWith<Archived<NativeByValue>, remote::Remote, D> for NativeByValue {
fn deserialize_with(
archived: &Archived<NativeByValue>,
_deserializer: &mut D,
) -> Result<remote::Remote, <D as Fallible>::Error> {
// Use whichever method is available to create an instance
Ok(remote::Remote::new(archived.public_field, archived.private_field))
}
}
依赖关系
~280–730KB
~18K SLoC