Last active
September 23, 2024 01:15
-
-
Save RReverser/4bb992ab54e0c6f92b255e60631b789e to your computer and use it in GitHub Desktop.
This file contains hidden or 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 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