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 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
//! Deserialization of externally tagged values.
//!
//! See [`ser::external`](::ser::external) for a description of this tagging
//! format.
use de::seed::SeedFactory;
use std::fmt;
use std::marker::PhantomData;
use serde;
/// Deserialize an externally tagged value.
///
/// The deserializer controls the underlying data format while the seed-factory
/// specifies the instructions (depending on the tag) on how the value should be
/// deserialized.
///
/// See [`de`](::de) for more information on
/// [`SeedFactory`](::de::SeedFactory) and implementations thereof.
///
/// See [`deserialize_seed`](deserialize_seed) for a version that allows you to
/// pass a `DeserializeSeed` to deserialize the tag. This version is equivalent
/// to `deserialize_seed(deserializer, seed_factory, PhantomData<T>)`
pub fn deserialize<'de, T, D, F>(deserializer: D, seed_factory: F) -> Result<F::Value, D::Error>
where
T: serde::Deserialize<'de>,
D: serde::Deserializer<'de>,
F: SeedFactory<'de, T>,
{
deserialize_seed(deserializer, seed_factory, PhantomData::<T>)
}
/// Deserialize an externally tagged value with the given tag-seed.
///
/// The deserializer controls the underlying data format while the seed-factory
/// specifies the instructions (depending on the tag) on how the value should be
/// deserialized.
///
/// See [`de`](::de) for more information on
/// [`SeedFactory`](::de::SeedFactory) and implementations thereof.
pub fn deserialize_seed<'de, D, F, S>(
deserializer: D,
seed_factory: F,
tag_seed: S,
) -> Result<F::Value, D::Error>
where
D: serde::Deserializer<'de>,
F: SeedFactory<'de, S::Value>,
S: serde::de::DeserializeSeed<'de>,
{
deserializer.deserialize_map(Visitor::new(seed_factory, tag_seed))
}
/// A visitor that can be used to deserialize an externally tagged value.
///
/// This visitor handles an externally tagged value, which is represented by a
/// map containing a single entry, where the key is the tag and the value is the
/// value that should be deserialized. Thus it will return an error if the
/// visited type is not a map.
///
/// The [`SeedFactory`](::de::SeedFactory) provided to this visitor
/// provides a `serde::de::DeserializeSeed` implementation depending on the tag,
/// which then determines how the value is going to be deserialized.
///
/// See [`de`](::de) for more information on
/// [`SeedFactory`](::de::SeedFactory) and implementations thereof.
pub struct Visitor<F, S> {
seed_factory: F,
tag_seed: S,
}
impl<F, S> Visitor<F, S> {
/// Creates a new visitor with the given
/// [`SeedFactory`](::de::SeedFactory).
pub fn new(seed_factory: F, tag_seed: S) -> Self {
Visitor {
seed_factory,
tag_seed,
}
}
}
impl<'de, F, S> serde::de::Visitor<'de> for Visitor<F, S>
where
F: SeedFactory<'de, S::Value>,
S: serde::de::DeserializeSeed<'de>,
{
type Value = F::Value;
fn expecting(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
write!(fmtr, "a map with exactly one entry")
}
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where
A: serde::de::MapAccess<'de>,
{
use serde::de::Error;
// try to validate the length
match map.size_hint() {
Some(n) if n != 1 => Err(serde::de::Error::invalid_length(n, &self))?,
_ => {},
}
let tag = map.next_key_seed(self.tag_seed)?
.ok_or_else(|| Error::invalid_length(0, &"a map with exactly one entry"))?;
map.next_value_seed(self.seed_factory.seed(tag)?)
}
}