use std::collections::BTreeSet;
use std::fmt;
use serde::de::{DeserializeSeed, Error as _, MapAccess, SeqAccess, Visitor};
use crate::{Error, Result};
pub fn validate_unique_object_keys(json: &[u8], description: &str) -> Result<()> {
let mut deserializer = serde_json::Deserializer::from_slice(json);
UniqueJson
.deserialize(&mut deserializer)
.and_then(|()| deserializer.end())
.map_err(|error| Error::InvalidInput(format!("{description} is not valid JSON: {error}")))
}
#[derive(Clone, Copy)]
struct UniqueJson;
impl<'de> DeserializeSeed<'de> for UniqueJson {
type Value = ();
fn deserialize<D>(self, deserializer: D) -> std::result::Result<Self::Value, D::Error>
where
D: serde::Deserializer<'de>,
{
deserializer.deserialize_any(self)
}
}
impl<'de> Visitor<'de> for UniqueJson {
type Value = ();
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("a JSON value")
}
fn visit_bool<E>(self, _value: bool) -> std::result::Result<Self::Value, E> {
Ok(())
}
fn visit_i64<E>(self, _value: i64) -> std::result::Result<Self::Value, E> {
Ok(())
}
fn visit_u64<E>(self, _value: u64) -> std::result::Result<Self::Value, E> {
Ok(())
}
fn visit_f64<E>(self, _value: f64) -> std::result::Result<Self::Value, E> {
Ok(())
}
fn visit_str<E>(self, _value: &str) -> std::result::Result<Self::Value, E> {
Ok(())
}
fn visit_none<E>(self) -> std::result::Result<Self::Value, E> {
Ok(())
}
fn visit_unit<E>(self) -> std::result::Result<Self::Value, E> {
Ok(())
}
fn visit_seq<A>(self, mut sequence: A) -> std::result::Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
while sequence.next_element_seed(self)?.is_some() {}
Ok(())
}
fn visit_map<A>(self, mut map: A) -> std::result::Result<Self::Value, A::Error>
where
A: MapAccess<'de>,
{
let mut keys = BTreeSet::new();
while let Some(key) = map.next_key::<String>()? {
if !keys.insert(key.clone()) {
return Err(A::Error::custom(format!("duplicate JSON object key {key}")));
}
map.next_value_seed(self)?;
}
Ok(())
}
}