#struct #serialization #serde #extract #framework #deserializer #deserialize

serde_extract

通过Serde框架实现两个结构体的重映射

1 个不稳定版本

0.1.0 2022年12月22日

#1804 in 编码

LGPL-3.0-only

27KB
588

serde_extract

Crates.io License

使具有 Serialize 的值转换为 Deserializer

实际上,这允许从一个实现了 Serialize 的结构体中提取一个实现了 Deserialize 的结构体。

使用方法

TL;DR

#[derive(serde_derive::Serialize)]
struct Source<'a> {
	a: &'a str,
	b: u32,
}
#[derive(Debug, PartialEq, serde_derive::Deserialize)]
struct Extract {
	b: u32,
}
assert_eq!(
	Extract { b: 3 },
	serde_extract::extract(&Source { a: "hello", b: 3 }).unwrap(),
);

更实际的例子

假设我们处于一个需要实现分页的SDK的场景中,我们只需要发送一次原始查询,但如果原始查询中提供了 page_size,则需要重新发送它。由于管理分页的代码不了解底层结构,并且由于将 page_size 参数添加到我们的 make_paginated_request 函数将非常不灵活(假设)并且更倾向于将其与查询参数的其他部分一起指定,因此这是一个适合此crate的使用场景。

// This will be our original query
#[derive(serde_derive::Serialize)]
struct SomeSpecificRequest {
	field_a: &'static str,
	page_size: usize,
}

// Let's say make_request is our generic function that makes a call to the server
make_paginated_request(&SomeSpecificRequest {
	field_a: "hello!",
	page_size: 2,
})
.expect("Failed to make request");

fn make_paginated_request<S: serde::Serialize>(
	serializable: &S,
) -> Result<(), Box<dyn std::error::Error>> {
	#[derive(serde_derive::Deserialize)]
	struct MaybePageSize {
		page_size: Option<usize>,
	}
	// We will reuse the page size for the subsequent paginated requests if it was
	// provided in the original query, so we need to extract it
	let page_size_for_this_request =
		serde_extract::extract::<MaybePageSize, _>(serializable)?.page_size;
	// this works:
	assert_eq!(page_size_for_this_request, Some(2));
	// Make request...
	Ok(())
}

限制

  • 目前不支持序列(尽管理论上可以添加支持,生成代码的算法复杂度为O(n²),其中n是序列中元素的数量,因为我们需要通过 MapAccess 通过 Visitor 重新驱动每个元素调用 Serializer
  • 出于同样的原因,目前不支持将数据反序列化为 map。具体来说,目前我们只能提取具有通过 deserialize_struct 指示的名称的字段。(这允许驱动 Serializer 的次数与要提取的字段数相同。在实际中,如果双方都是常规结构体,优化器可能将其转换为零成本提取。在理论上,支持将数据反序列化为maps可以添加,其算法复杂度为O(n²),其中n是输入字段的数量。)

依赖项

~120–360KB