use std::{
collections::HashMap,
fmt,
marker::PhantomData,
};
use serde::{
Deserialize,
Deserializer,
de::{
self,
MapAccess,
Visitor,
},
};
pub(in crate::wire) struct StrictStringMap<V>(HashMap<String, V>);
impl<V> StrictStringMap<V> {
pub(in crate::wire) fn into_inner(self) -> HashMap<String, V> {
self.0
}
}
impl<'de, V> Deserialize<'de> for StrictStringMap<V>
where
V: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct StrictStringMapVisitor<V>(PhantomData<V>);
impl<'de, V> Visitor<'de> for StrictStringMapVisitor<V>
where
V: Deserialize<'de>,
{
type Value = StrictStringMap<V>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a map with unique string keys")
}
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where
A: MapAccess<'de>,
{
let mut values = HashMap::new();
while let Some((key, value)) = map.next_entry::<String, V>()? {
if values.insert(key.clone(), value).is_some() {
return Err(de::Error::custom(format!(
"duplicate map key '{key}'"
)));
}
}
Ok(StrictStringMap(values))
}
}
deserializer.deserialize_map(StrictStringMapVisitor(PhantomData))
}
}