Skip to content

Instantly share code, notes, and snippets.

@Lucretiel
Created April 6, 2022 20:42
Show Gist options
  • Save Lucretiel/3da82296a75a5c6fca677109c000b049 to your computer and use it in GitHub Desktop.
Save Lucretiel/3da82296a75a5c6fca677109c000b049 to your computer and use it in GitHub Desktop.
Adapters for `SeqAccess` and `MapAccess` that operate with move semantics
use std::{convert::Infallible, marker::PhantomData, mem};
use serde::de;
pub trait SeqAccess<'de>: Sized {
type Error: de::Error;
fn next_value_seed<S>(self, seed: S) -> Result<Option<(S::Value, Self)>, Self::Error>
where
S: de::DeserializeSeed<'de>;
fn next_value<T>(self) -> Result<Option<(T, Self)>, Self::Error>
where
T: de::Deserialize<'de>,
{
self.next_value_seed(PhantomData)
}
}
pub trait MapKeyAccess<'de>: Sized {
type Error: de::Error;
type Value: MapValueAccess<'de>;
#[allow(clippy::type_complexity)]
fn next_key_seed<S>(self, seed: S) -> Result<Option<(S::Value, Self::Value)>, Self::Error>
where
S: de::DeserializeSeed<'de>;
fn next_key<T>(self) -> Result<Option<(T, Self::Value)>, Self::Error>
where
T: de::Deserialize<'de>,
{
self.next_key_seed(PhantomData)
}
#[allow(clippy::type_complexity)]
fn next_entry_seed<K, V>(
self,
key: K,
value: V,
) -> Result<
Option<(
(K::Value, V::Value),
<Self::Value as MapValueAccess<'de>>::Key,
)>,
Self::Error,
>
where
K: de::DeserializeSeed<'de>,
V: de::DeserializeSeed<'de>,
Self::Value: MapValueAccess<'de, Error = Self::Error>,
{
self.next_key_seed(key)?
.map(|(key, value_access)| {
value_access
.next_value_seed(value)
.map(|(value, key_access)| ((key, value), key_access))
})
.transpose()
}
#[allow(clippy::type_complexity)]
fn next_entry<K, V>(
self,
) -> Result<Option<((K, V), <Self::Value as MapValueAccess<'de>>::Key)>, Self::Error>
where
K: de::Deserialize<'de>,
V: de::Deserialize<'de>,
Self::Value: MapValueAccess<'de, Error = Self::Error>,
{
self.next_entry_seed(PhantomData, PhantomData)
}
}
pub trait MapValueAccess<'de>: Sized {
type Error: de::Error;
type Key: MapKeyAccess<'de>;
fn next_value_seed<S>(self, seed: S) -> Result<(S::Value, Self::Key), Self::Error>
where
S: de::DeserializeSeed<'de>;
fn next_value<T>(self) -> Result<(T, Self::Key), Self::Error>
where
T: de::Deserialize<'de>,
{
self.next_value_seed(PhantomData)
}
}
pub struct AccessAdapter<'de, K, V> {
lifetime: PhantomData<&'de ()>,
state: AccessAdapterState<K, V>,
}
enum AccessAdapterState<K, V> {
Ready(K),
Value(V),
Dead,
}
impl<K, V> AccessAdapterState<K, V> {
fn take(&mut self) -> Self {
mem::replace(self, AccessAdapterState::Dead)
}
}
impl<'de, S> AccessAdapter<'de, S, Infallible>
where
S: SeqAccess<'de>,
{
pub fn new_seq(seq: S) -> Self {
Self {
lifetime: PhantomData,
state: AccessAdapterState::Ready(seq),
}
}
}
impl<'de, K> AccessAdapter<'de, K, K::Value>
where
K: MapKeyAccess<'de>,
K::Value: MapValueAccess<'de, Error = K::Error, Key = K>,
{
pub fn new_map(map: K) -> Self {
Self {
lifetime: PhantomData,
state: AccessAdapterState::Ready(map),
}
}
}
impl<'de, S> de::SeqAccess<'de> for AccessAdapter<'de, S, Infallible>
where
S: SeqAccess<'de>,
{
type Error = S::Error;
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
where
T: de::DeserializeSeed<'de>,
{
match self.state.take() {
AccessAdapterState::Ready(seq) => seq.next_value_seed(seed).map(|opt| {
opt.map(|(value, seq)| {
self.state = AccessAdapterState::Ready(seq);
value
})
}),
AccessAdapterState::Value(inf) => match inf {},
AccessAdapterState::Dead => Ok(None),
}
}
}
impl<'de, K> de::MapAccess<'de> for AccessAdapter<'de, K, K::Value>
where
K: MapKeyAccess<'de>,
K::Value: MapValueAccess<'de, Error = K::Error, Key = K>,
{
type Error = K::Error;
#[inline]
fn next_key_seed<S>(&mut self, seed: S) -> Result<Option<S::Value>, Self::Error>
where
S: de::DeserializeSeed<'de>,
{
match self.state.take() {
AccessAdapterState::Ready(access) => access.next_key_seed(seed).map(|opt| {
opt.map(|(key, value_access)| {
self.state = AccessAdapterState::Value(value_access);
key
})
}),
AccessAdapterState::Value(_access) => panic!("called next_key_seed out of order"),
AccessAdapterState::Dead => Ok(None),
}
}
#[inline]
fn next_value_seed<S>(&mut self, seed: S) -> Result<S::Value, Self::Error>
where
S: de::DeserializeSeed<'de>,
{
match self.state.take() {
AccessAdapterState::Ready(_access) => panic!("called next_value_seet out of order"),
AccessAdapterState::Value(access) => {
access.next_value_seed(seed).map(|(value, key_access)| {
self.state = AccessAdapterState::Ready(key_access);
value
})
}
AccessAdapterState::Dead => panic!("called next_value_seet out of order"),
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment