serde 源码解析 | Deserialization篇 第二部分
上篇,已经把反序列化的总体过程描述了一遍,也留下了几个问题,DeserializeSeed和PhantomData是什么,EnumAccess中的variant方法被visit_enum调用后,为什么能产生一个__Field实例呢?
 | pub trait DeserializeSeed<'de>: Sized {     type Value;     fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>     where         D: Deserializer<'de>; }
  pub trait Deserialize<'de>: Sized {     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>     where         D: Deserializer<'de>; }
 
  | 
 
和Deserialize的区别,就在于用DeserializeSeed自定义了输出的类型,不必和实现类型一致。
也就是说,对一个DeserializeSeed-thing调用它的deserialize去消费一个deserializer提供的数据,可以返回的是自定义的Value类型。
回忆通常情况下,对Deserialize的使用,是利用泛型参数,由Result<T>推断出具体的T类型,再调用对应的deserialze方法,返回一个T类型的实例,这个过程只有类型参与,属于无状态的反序列化,比如下面的T::deserialize()
 | pub fn from_str<'a, T>(s: &'a str) -> Result<T> where     T: Deserialize<'a>, {     let mut deserializer = Deserializer::from_str(s);     let t = T::deserialize(&mut deserializer)?;    	Ok(t) }
 
  | 
 
但是对于实现了DeserializeSeed的类型,使用上有所不同,通常是初始化成为一个实例,可以拥有自己的数据,常被当作参数seed传入一个形如fn *_seed()的方法,由它调用seed上的反序列化方法,比如下面的seed.deserialize(),这个deserialize过程则允许seed`自身数据参与,所以是个有状态的反序列化过程。
 | fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant)> where 	V: DeserializeSeed<'de>, {     let val = seed.deserialize(&mut *self.de)?;     if self.de.next_char()? == ':' {         Ok((val, self))     } else {         Err(Error::ExpectedMapColon)     } }
 
  | 
 
不妨再来看看,哪些地方存在这样的fn *_seed():
SeqAccess中的next_element_seed
 
MapAccess中的next_key_seed、next_value_seed、next_entry_seed
 
EnumAccess中的variant_seed
 
VariantAcess中的newtype_variant_seed
 
这些方法出现在deserializer为visitor提供的集合数据类型中。一个visitor,只有在实现了visit_seq、visit_map、visit_enum这类方法的前提下,才有机会使用有状态的反序列化。
但在实际工作中,大多数情况的反序列化,都是无状态的,所以给这些fn *_seed()方法传递的DeserializeSeed-thing,也就是参数seed,自然可以没有自己的数据,仅仅把某种类型信息给传递进去。像这种有类型、却没有实际数据的东西,标准库里专门有个类型叫PhantomData,幽灵数据来表示,编译器不会给他分配内存空间,只用来做类型的推断和方法的关联。
Serde已经为PhantomData实现DeserializeSeed,使其成为DeserializeSeed-thing,直接把PhantomData传入fn *_seed()里,就等效于无状态Deserialize的过程,只有类型参与。
 | impl<'de, T> DeserializeSeed<'de> for PhantomData<T> where     T: Deserialize<'de>, {     type Value = T;
      #[inline]     fn deserialize<D>(self, deserializer: D) -> Result<T, D::Error>     where         D: Deserializer<'de>,     {                  T::deserialize(deserializer)     } }
 
  | 
 
甚至,因为无状态反序列化太普遍,Serde提供了一种快捷方式,比如next_element_seed的无状态化版本是next_element,就直接帮你传入了PhantomData,使用next_element时,T就通过表达式左值的类型来推断就OK了。
 | fn next_element<T>(&mut self) -> Result<Option<T>, Self::Error> where 	T: Deserialize<'de>, {     self.next_element_seed(PhantomData) }
 
  | 
 
有了这样的基础,再看visit_enum就清楚了,中间调用match _serde::de::EnumAccess::variant(__data)时,推断出T的类型是__Field,也就是使用的variant版本如下:
 | fn variant<__Field>(self) -> Result<(__Field, Self::Variant), Self::Error> where 	__Field: Deserialize<'de>, {     self.variant_seed(PhantomData) }
 
  | 
 
因此PhantomData是PhantomData<__Field>的一个“实例”,实现了DeserializeSeed,传到variant_seed中叫做seed,根据PhantomData默认的DeserializeSeed的实现,variant_seed中语句seed.deserialize(deserializer)的本质就是__Field::deserialize(deserializer),于是产生了具体的__Field值。
嵌套之路
清楚了__Field的来历之后,不妨再关注一下tuple中的第二项,VariantAccess-thing,它包含着四个必须实现的方法,概括了可能出现的枚举形态
unit_variant,比如对应Command::Quit 
newtype_variant,比如对应Command::Rm 
tuple_variant,比如对应Command::SomeCmd(a, b, c)这种 
struct_variant,比如对应Command::{Get, Set} 
一个VariantAccess可以看做特定领域的deserializer,这个四个方法和通用的deserialize_*方法的作用类似,由上层调用,提示接下来的数据应该可以按照什么样的规则去解析。所以这里的Visitor和VariantAccess功能上如同一对Deserialize和Deserializer,这不就是一层嵌套吗?
举两个例子,这两个简单的match分支,Command::Quit和Command::Rm ,就分别提示接下来按照unit_variat和newtype_variant的规则解析数据。
 |  (__Field::__field2, __variant) => {     _serde::export::Result::map(_serde::de::VariantAccess::newtype_variant::<String>(__variant), Command::Rm) } (__Field::__field3, __variant) => {     match _serde::de::VariantAccess::unit_variant(__variant) {         _serde::export::Ok(__val) => __val,         _serde::export::Err(__err) => {             return _serde::export::Err(__err);         }     };     _serde::export::Ok(Command::Quit) }
 
  | 
 
但是复杂一点的Command::Set,它调用的是struct_variant,表明接下来期待的是结构性的枚举。到这里,更明显的嵌套出现了,又新建一个__Field类型,用来保存Command::Get中的Key和Value的标识符信息。然后派出一个visitor,可以从SeqAccess或者MapAccess类型的数据来构建Command::Get的实例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
   | 
  #[allow(non_camel_case_types)] enum __Field { __field0, __field1, __ignore, } struct __FieldVisitor; impl<'de> _serde::de::Visitor<'de> for __FieldVisitor {     type Value = __Field;     fn expecting(&self, __formatter: &mut _serde::export::Formatter)     fn visit_u64<__E>(self, __value: u64)      fn visit_str<__E>(self, __value: &str)      fn visit_bytes<__E>(self, __value: &[u8]) } impl<'de> _serde::Deserialize<'de> for __Field { ... }
 
  struct __Visitor<'de> {     marker: _serde::export::PhantomData<Command>,     lifetime: _serde::export::PhantomData<&'de ()>, } impl<'de> _serde::de::Visitor<'de> for __Visitor<'de> {     type Value = Command;     fn expecting(&self, __formatter: &mut _serde::export::Formatter) -> _serde::export::fmt::Result {         _serde::export::Formatter::write_str(__formatter, "struct variant Command::Set")     }          #[inline]     fn visit_seq<__A>(self, mut __seq: __A) -> _serde::export::Result<Self::Value, __A::Error>     where     __A: _serde::de::SeqAccess<'de>,     {                  let __field0 = match match _serde::de::SeqAccess::next_element::<String>(&mut __seq) {             _serde::export::Ok(__val) => __val,             _serde::export::Err(__err) => {                 return _serde::export::Err(__err);             }         } {             _serde::export::Some(__value) => __value,             _serde::export::None => {                 return _serde::export::Err(_serde::de::Error::invalid_length(                     0usize,                     &"struct variant Command::Set with 2 elements",                 ));             }         };         let __field1 = match match _serde::de::SeqAccess::next_element::<String>(&mut __seq) {             _serde::export::Ok(__val) => __val,             _serde::export::Err(__err) => {                 return _serde::export::Err(__err);             }         } {             _serde::export::Some(__value) => __value,             _serde::export::None => {                 return _serde::export::Err(_serde::de::Error::invalid_length(                     1usize,                     &"struct variant Command::Set with 2 elements",                 ));             }         };                  _serde::export::Ok(Command::Set {             key: __field0,             value: __field1,         })     }          #[inline]     fn visit_map<__A>(self, mut __map: __A) }
  const FIELDS: &'static [&'static str] = &["key", "value"]; _serde::de::VariantAccess::struct_variant(     __variant,     FIELDS,     __Visitor {         marker: _serde::export::PhantomData::<Command>,         lifetime: _serde::export::PhantomData,     }, )
 
  | 
 
因为json中struct和字典表达形式相同,并且key值都包含在序列化数据中,所以不必使用提供的_fields参数,直接交给deserialize_map就足够。
 |  fn struct_variant<V>(self, _fields: &'static [&'static str], visitor: V) -> Result<V::Value> where 	V: Visitor<'de>, {     de::Deserializer::deserialize_map(self.de, visitor) }
 
  | 
 
deserialize_map自然检查map的开闭标识,然后给予一个实现了MapAccess的结构。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
   | fn deserialize_map<V>(mut self, visitor: V) -> Result<V::Value> where 	V: Visitor<'de>, {          if self.next_char()? == '{' {                  let value = visitor.visit_map(CommaSeparated::new(&mut self))?;                  if self.next_char()? == '}' {             Ok(value)         } else {             Err(Error::ExpectedMapEnd)         }     } else {         Err(Error::ExpectedMap)     } }
 
  | 
 
后面的事情,就是CommaSeparated和visit_map相互配合产生Command::Get了,过程类似Enum和visit_enum的交互,这里就不再详细一步步跟踪了。
尾声
我们用两章的篇幅介绍了反序列化过程。
第一个关键点,明确角色
Deserialize观察目标类型,制作Visitor,调用Deserializer,交付Visitor 
Deserialzier和被序列化数据打交道,根据Deserialize的提示,把序列化数据解析成恰当的基础数据结构,交给Visitor 
Visitor根据Deserializer给的基础数据类型,按既定规则生成目标类型 
第二个关键点,集合类型的反序列化
当Deserializer被提示接下来的数据可能是由集合类型序列化而来时,所谓的恰当的基础数据结构,就是实现了*Access系列 trait 的结构,代表着某一种特定结构的Deserializer。其实也就只有四个。
| Trait | 
Description | 
| EnumAccess | 
重要方法是variant,一次性调用,返回(T, VariantAccess),判断数据属于哪种枚举 | 
| VariantAccess | 
四个必须方法,一次性调用,解析具体的某种枚举 | 
| MapAccess | 
按照map的风格访问处理已序列化数据,next_key,next_value等 | 
| SeqAccess | 
按照seq的风格访问处理已序列化数据,next_element | 
他们统一的风格就是都使用了fn *_seed()的模式,通过DeserializerSeed,提供有状态反序列化的能力。普通的反序列化场景,往往不需要有状态,因此传入PhantomData,直接使用无状态反序列化。
Ok,反序列化也介绍到这里吧。如果想要进一步巩固serde,自己写一个data format的Deserializer和Serializer吧。下一篇,我们为redis协议写一个基础的序列化工具。