Skip to content

Instantly share code, notes, and snippets.

@RReverser
Last active September 23, 2024 01:15
Show Gist options
  • Save RReverser/4bb992ab54e0c6f92b255e60631b789e to your computer and use it in GitHub Desktop.
Save RReverser/4bb992ab54e0c6f92b255e60631b789e to your computer and use it in GitHub Desktop.
use serde::de::{DeserializeSeed, MapAccess, Visitor};
use serde::{forward_to_deserialize_any, Deserializer};
use std::fmt::Formatter;
struct CaseInsensitiveStructWrapper<T> {
fields: &'static [&'static str],
inner: T,
}
impl<T> CaseInsensitiveStructWrapper<T> {
fn wrap<T2, R>(
self,
inner2: T2,
handle_wrapper: impl Fn(T, CaseInsensitiveStructWrapper<T2>) -> R,
) -> R {
handle_wrapper(
self.inner,
CaseInsensitiveStructWrapper {
fields: self.fields,
inner: inner2,
},
)
}
}
impl<'de, V: Visitor<'de>> Visitor<'de> for CaseInsensitiveStructWrapper<V> {
type Value = V::Value;
fn expecting(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
self.inner.expecting(formatter)
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
self.inner.visit_str(
self.fields
.iter()
.copied()
.find(|field| field.eq_ignore_ascii_case(value))
.unwrap_or(value),
)
}
fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error>
where
A: MapAccess<'de>,
{
self.wrap(map, Visitor::visit_map)
}
}
impl<'de, D: Deserializer<'de>> Deserializer<'de> for CaseInsensitiveStructWrapper<D> {
type Error = D::Error;
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.wrap(visitor, Deserializer::deserialize_identifier)
}
forward_to_deserialize_any! {
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
bytes byte_buf option unit unit_struct newtype_struct seq tuple
tuple_struct map enum ignored_any struct identifier
}
}
impl<'de, K: DeserializeSeed<'de>> DeserializeSeed<'de> for CaseInsensitiveStructWrapper<K> {
type Value = K::Value;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
self.wrap(deserializer, DeserializeSeed::deserialize)
}
}
impl<'de, A: MapAccess<'de>> MapAccess<'de> for CaseInsensitiveStructWrapper<A> {
type Error = A::Error;
fn next_key_seed<K: DeserializeSeed<'de>>(
&mut self,
seed: K,
) -> Result<Option<K::Value>, A::Error> {
self.inner.next_key_seed(CaseInsensitiveStructWrapper {
fields: self.fields,
inner: seed,
})
}
fn next_value_seed<V: DeserializeSeed<'de>>(&mut self, seed: V) -> Result<V::Value, A::Error> {
self.inner.next_value_seed(seed)
}
}
struct CaseInsensitiveStructDeserializer<D> {
inner: D,
}
impl<'de, D: Deserializer<'de>> Deserializer<'de> for CaseInsensitiveStructDeserializer<D> {
type Error = D::Error;
fn deserialize_struct<V: Visitor<'de>>(
self,
name: &'static str,
fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error> {
self.inner.deserialize_struct(
name,
fields,
CaseInsensitiveStructWrapper {
fields,
inner: visitor,
},
)
}
fn deserialize_any<V: Visitor<'de>>(self, _visitor: V) -> Result<V::Value, Self::Error> {
Err(serde::de::Error::custom(
"CaseInsensitiveStructDeserializer can only be used with structs",
))
}
forward_to_deserialize_any! {
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
bytes byte_buf option unit unit_struct newtype_struct seq tuple
tuple_struct map enum identifier ignored_any
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment