Created
April 6, 2022 20:42
-
-
Save Lucretiel/3da82296a75a5c6fca677109c000b049 to your computer and use it in GitHub Desktop.
Adapters for `SeqAccess` and `MapAccess` that operate with move semantics
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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