use std::collections::BTreeMap;
use std::fmt::{self, Formatter};
use std::marker::PhantomData;
use serde::de::{Error, MapAccess, SeqAccess, Visitor};
use serde::{Deserialize, Deserializer};
use serde_json::{Map, Number, Value};
use uuid::Uuid;
use crate::safelong::{SafeLong, SafeUnsignedLong};
pub trait DeserializeStrict<'de>: Sized {
fn deserialize_strict<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error>;
}
#[derive(Debug)]
pub struct Strict<T>(pub T);
impl<T: Default> Default for Strict<T> {
fn default() -> Self {
Self(T::default())
}
}
impl<'de, T: DeserializeStrict<'de>> Deserialize<'de> for Strict<T> {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
T::deserialize_strict(deserializer).map(Self)
}
}
macro_rules! primitive {
($($ty:ty),* $(,)?) => {
$(impl<'de> DeserializeStrict<'de> for $ty {
fn deserialize_strict<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
Self::deserialize(deserializer)
}
})*
};
}
primitive!(String, bool, i32, u32, Uuid, SafeLong, SafeUnsignedLong);
impl<'de> DeserializeStrict<'de> for Value {
fn deserialize_strict<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
UniqueValue::deserialize(deserializer).map(|value| value.0)
}
}
impl<'de> DeserializeStrict<'de> for f64 {
fn deserialize_strict<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let value = Self::deserialize(deserializer)?;
if value.is_finite() {
Ok(value)
} else {
Err(D::Error::custom("expected a finite float64"))
}
}
}
impl<'de, T: DeserializeStrict<'de>> DeserializeStrict<'de> for Option<T> {
fn deserialize_strict<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
Option::<Strict<T>>::deserialize(deserializer).map(|value| value.map(|value| value.0))
}
}
impl<'de, T: DeserializeStrict<'de>> DeserializeStrict<'de> for Vec<T> {
fn deserialize_strict<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
Vec::<Strict<T>>::deserialize(deserializer)
.map(|values| values.into_iter().map(|value| value.0).collect())
}
}
impl<'de, T: DeserializeStrict<'de>> DeserializeStrict<'de> for BTreeMap<String, T> {
fn deserialize_strict<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
struct MapVisitor<T>(PhantomData<T>);
impl<'de, T: DeserializeStrict<'de>> Visitor<'de> for MapVisitor<T> {
type Value = BTreeMap<String, T>;
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str("a map with unique string keys")
}
fn visit_map<A: MapAccess<'de>>(self, mut access: A) -> Result<Self::Value, A::Error> {
let mut values = BTreeMap::new();
while let Some(key) = access.next_key::<String>()? {
if values.contains_key(&key) {
return Err(A::Error::custom(format!("duplicate key {key:?}")));
}
values.insert(key, access.next_value::<Strict<T>>()?.0);
}
Ok(values)
}
}
deserializer.deserialize_map(MapVisitor(PhantomData))
}
}
pub fn from_slice<T: for<'de> DeserializeStrict<'de>>(
bytes: &[u8],
) -> Result<T, serde_json::Error> {
let value = serde_json::from_slice::<UniqueValue>(bytes)?;
serde_json::from_value::<Strict<T>>(value.0).map(|value| value.0)
}
struct UniqueValue(Value);
impl<'de> Deserialize<'de> for UniqueValue {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
struct ValueVisitor;
impl<'de> Visitor<'de> for ValueVisitor {
type Value = UniqueValue;
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str("a JSON value without duplicate object keys")
}
fn visit_unit<E: Error>(self) -> Result<Self::Value, E> {
Ok(UniqueValue(Value::Null))
}
fn visit_bool<E: Error>(self, value: bool) -> Result<Self::Value, E> {
Ok(UniqueValue(Value::Bool(value)))
}
fn visit_i64<E: Error>(self, value: i64) -> Result<Self::Value, E> {
Ok(UniqueValue(Value::Number(value.into())))
}
fn visit_u64<E: Error>(self, value: u64) -> Result<Self::Value, E> {
Ok(UniqueValue(Value::Number(value.into())))
}
fn visit_f64<E: Error>(self, value: f64) -> Result<Self::Value, E> {
Number::from_f64(value)
.map(|value| UniqueValue(Value::Number(value)))
.ok_or_else(|| E::custom("expected a finite JSON number"))
}
fn visit_str<E: Error>(self, value: &str) -> Result<Self::Value, E> {
Ok(UniqueValue(Value::String(value.to_owned())))
}
fn visit_string<E: Error>(self, value: String) -> Result<Self::Value, E> {
Ok(UniqueValue(Value::String(value)))
}
fn visit_seq<A: SeqAccess<'de>>(self, mut access: A) -> Result<Self::Value, A::Error> {
let mut values = Vec::new();
while let Some(value) = access.next_element::<UniqueValue>()? {
values.push(value.0);
}
Ok(UniqueValue(Value::Array(values)))
}
fn visit_map<A: MapAccess<'de>>(self, mut access: A) -> Result<Self::Value, A::Error> {
let mut values = Map::new();
while let Some(key) = access.next_key::<String>()? {
if values.contains_key(&key) {
return Err(A::Error::custom(format!("duplicate key {key:?}")));
}
values.insert(key, access.next_value::<UniqueValue>()?.0);
}
Ok(UniqueValue(Value::Object(values)))
}
}
deserializer.deserialize_any(ValueVisitor)
}
}
#[cfg(test)]
mod tests {
use serde::{Deserialize, Deserializer};
use serde_json::Value;
use super::{DeserializeStrict, from_slice};
#[derive(Deserialize)]
struct Union(Value);
impl<'de> DeserializeStrict<'de> for Union {
fn deserialize_strict<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
Self::deserialize(deserializer)
}
}
#[test]
fn duplicate_keys_are_rejected_before_union_or_map_decoding() {
for input in [
r#"{"type":"table","type":"location"}"#,
r#"{"type":"table","table":{"labels":{"team":"first","team":"second"}}}"#,
r#"[{"nested":{"key":1,"key":2}}]"#,
r#"{"key":1,"\u006bey":2}"#,
] {
let error = from_slice::<Union>(input.as_bytes()).err().unwrap();
assert!(error.to_string().contains("duplicate key"));
assert!(from_slice::<Value>(input.as_bytes()).is_err());
}
let decoded =
from_slice::<Union>(br#"{"type":"table","table":{"labels":{"team":"first"}}}"#)
.unwrap();
assert_eq!(decoded.0["table"]["labels"]["team"], "first");
assert!(from_slice::<Union>(b"{} {}").is_err());
assert_eq!(from_slice::<Value>(b"null").unwrap(), Value::Null);
assert_eq!(from_slice::<Value>(b"[null, 1.5, true]").unwrap()[1], 1.5);
assert!(from_slice::<Value>(b"NaN").is_err());
}
}