blob: d7578e793eb88550360351be2e4c52168c902bf9 [file] [log] [blame]
use crate::any::ErasedValue;
use crate::error::{self, Error};
use crate::seed::ErasedDeserializeSeed;
use alloc::boxed::Box;
use serde::de::{Deserialize, DeserializeSeed, MapAccess};
trait ErasedMapAccess<'de> {
fn erased_next_key_seed(
&mut self,
seed: &mut dyn ErasedDeserializeSeed<'de>,
) -> Result<Option<ErasedValue>, Error>;
fn erased_next_value_seed(
&mut self,
seed: &mut dyn ErasedDeserializeSeed<'de>,
) -> Result<ErasedValue, Error>;
fn erased_size_hint(&self) -> Option<usize>;
}
pub struct Map<'access, 'de> {
erased: Box<dyn ErasedMapAccess<'de> + 'access>,
}
impl<'access, 'de> Map<'access, 'de> {
pub(crate) fn new<A>(map: A) -> Self
where
A: MapAccess<'de> + 'access,
{
Map {
erased: Box::new(map),
}
}
/// Shorthand for `T::deserialize(serde::de::value::MapAccessDeserializer::new(self))`.
pub fn deserialize<T>(self) -> Result<T, Error>
where
T: Deserialize<'de>,
{
T::deserialize(serde::de::value::MapAccessDeserializer::new(self))
}
}
impl<'access, 'de> MapAccess<'de> for Map<'access, 'de> {
type Error = Error;
fn next_key_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
where
T: DeserializeSeed<'de>,
{
self.erased
.erased_next_key_seed(&mut Some(seed))
.map(|erased_value| match erased_value {
Some(value) => Some(unsafe { ErasedValue::take::<T::Value>(value) }),
None => None,
})
}
fn next_value_seed<T>(&mut self, seed: T) -> Result<T::Value, Self::Error>
where
T: DeserializeSeed<'de>,
{
self.erased
.erased_next_value_seed(&mut Some(seed))
.map(|erased_value| unsafe { ErasedValue::take::<T::Value>(erased_value) })
}
fn size_hint(&self) -> Option<usize> {
self.erased.erased_size_hint()
}
}
impl<'de, Access> ErasedMapAccess<'de> for Access
where
Access: MapAccess<'de>,
{
fn erased_next_key_seed(
&mut self,
seed: &mut dyn ErasedDeserializeSeed<'de>,
) -> Result<Option<ErasedValue>, Error> {
self.next_key_seed(seed).map_err(error::erase)
}
fn erased_next_value_seed(
&mut self,
seed: &mut dyn ErasedDeserializeSeed<'de>,
) -> Result<ErasedValue, Error> {
self.next_value_seed(seed).map_err(error::erase)
}
fn erased_size_hint(&self) -> Option<usize> {
self.size_hint()
}
}