如何在deserialize实现中使用serde_stacker自定义反序列化
我有一个结构体,只有借助serde_stacker才能正常完成反序列化。目前要反序列化Bar结构体时,我需要先将输入转换为用于承载JSON值的serde_json::value::Value类型,再将该类型转换为目标Bar类型,相关测试代码如下:
const SIZE: usize = 30000; #[derive(Clone, Debug, Serialize, Deserialize)] struct Foo { #[serde(with = "BigArray")] vals: [bool; SIZE], } #[derive(Clone, Debug, Serialize, Deserialize)] struct Bar { field0: Foo, } impl Bar { fn custom_deserialization_test(instance: Bar) { let json = serde_json::to_string(&instance).unwrap(); let mut deserializer: serde_json::Deserializer<serde_json::de::StrRead> = serde_json::Deserializer::from_str(&json); let deserializer: serde_stacker::Deserializer< &mut serde_json::Deserializer<serde_json::de::StrRead>, > = serde_stacker::Deserializer::new(&mut deserializer); let value: Value = Value::deserialize(deserializer).unwrap(); let target: Bar = from_value(value).unwrap(); } }
我的疑问是:如何重写Bar的deserialize方法,使其能够像上述示例逻辑一样,直接使用serde_stacker反序列化器,替代常规的serde_json反序列化器完成解析?
我推测可能需要实现某种包装类型,但上述代码最后一行调用的from_value函数,本身依赖Bar派生得到的默认deserialize方法完成JSON对象到Bar类型的转换,不知道该如何调整实现。
你当前实现中通过serde_json::Value做中转的步骤是完全多余的。serde_stacker::Deserializer本身已经实现了serde标准库的Deserializer trait,可以直接传入结构体的反序列化方法,不需要额外中转,也不需要重写整套反序列化逻辑。
最简实现
直接把serde_stacker包装后的反序列化器传给Bar::deserialize即可,不需要走Value中转,测试代码可以直接简化为:
impl Bar { fn custom_deserialization_test(instance: Bar) { let json = serde_json::to_string(&instance).unwrap(); let mut json_de = serde_json::Deserializer::from_str(&json); let stack_safe_de = serde_stacker::Deserializer::new(&mut json_de); // 直接反序列化为目标类型,省略中间Value转换步骤 let target: Bar = Bar::deserialize(stack_safe_de).unwrap(); } }
通用反序列化入口
如果希望调用方不需要手动包装serde_stacker反序列化器,可以单独实现一个反序列化辅助函数,作为Bar的统一反序列化入口,这种方式侵入性最低,也不会和serde_stacker强绑定:
use serde::{Deserialize, Deserializer}; fn deserialize_bar<'de, D: Deserializer<'de>>(d: D) -> Result<Bar, D::Error> { let stack_safe_de = serde_stacker::Deserializer::new(d); Bar::deserialize(stack_safe_de) }
这个函数兼容所有实现了serde Deserializer trait的格式(包括serde_json、serde_yaml等),不需要修改Bar本身的派生逻辑。
自定义Deserialize trait实现
如果需要让Bar的Deserialize实现默认走栈安全逻辑,可以通过remote派生的方式复用自动生成的字段解析代码,不需要手动编写每个字段的反序列化逻辑:
impl<'de> Deserialize<'de> for Bar { fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> { let stack_safe_de = serde_stacker::Deserializer::new(deserializer); // 复用派生的反序列化逻辑,避免手动解析字段 #[derive(Deserialize)] #[serde(remote = "Bar")] struct BarHelper { field0: Foo, } BarHelper::deserialize(stack_safe_de) } }
注意这种方式会让Bar的反序列化逻辑强依赖serde_stacker,如果后续需要支持其他非栈溢出场景的反序列化,灵活性不如独立辅助函数的方案。
补充说明:你之前担心的
from_value依赖默认反序列化实现的问题,本质是多做了一层Value中转导致的。serde的派生反序列化逻辑和具体反序列化器实现无关,只要传入的类型实现了标准Deserializertrait,不管是原生serde_json反序列化器,还是serde_stacker包装后的栈安全版本,都可以正常工作,不需要修改自动生成的字段解析逻辑。
内容的提问来源于stack exchange,提问作者Thorkil Værge

