use std::borrow::Cow;
use std::fmt;
use serde::{de, ser};
use serde_json::value::RawValue;
use super::nests_too_deep_message;
pub(super) fn emit<S: ser::Serializer>(
json: &str,
serializer: S,
depth: usize,
) -> Result<S::Ok, S::Error> {
let mut deserializer = serde_json::Deserializer::from_str(json);
let emitted = de::Deserializer::deserialize_any(&mut deserializer, Emit { serializer, depth })
.map_err(de_to_ser)?;
deserializer.end().map_err(de_to_ser)?;
Ok(emitted)
}
fn nests_too_deep<E: de::Error>() -> E {
de::Error::custom(nests_too_deep_message())
}
fn ser_to_de<S: ser::Error, D: de::Error>(error: S) -> D {
de::Error::custom(error)
}
fn de_to_ser<D: de::Error, S: ser::Error>(error: D) -> S {
ser::Error::custom(error)
}
struct Emit<S> {
serializer: S,
depth: usize,
}
impl<'de, S: ser::Serializer> de::Visitor<'de> for Emit<S> {
type Value = S::Ok;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a JSON value")
}
fn visit_unit<E: de::Error>(self) -> Result<Self::Value, E> {
self.serializer.serialize_unit().map_err(ser_to_de)
}
fn visit_bool<E: de::Error>(self, value: bool) -> Result<Self::Value, E> {
self.serializer.serialize_bool(value).map_err(ser_to_de)
}
fn visit_i64<E: de::Error>(self, value: i64) -> Result<Self::Value, E> {
self.serializer.serialize_i64(value).map_err(ser_to_de)
}
fn visit_u64<E: de::Error>(self, value: u64) -> Result<Self::Value, E> {
self.serializer.serialize_u64(value).map_err(ser_to_de)
}
fn visit_i128<E: de::Error>(self, value: i128) -> Result<Self::Value, E> {
self.serializer.serialize_i128(value).map_err(ser_to_de)
}
fn visit_u128<E: de::Error>(self, value: u128) -> Result<Self::Value, E> {
self.serializer.serialize_u128(value).map_err(ser_to_de)
}
fn visit_f64<E: de::Error>(self, value: f64) -> Result<Self::Value, E> {
self.serializer.serialize_f64(value).map_err(ser_to_de)
}
fn visit_str<E: de::Error>(self, value: &str) -> Result<Self::Value, E> {
self.serializer.serialize_str(value).map_err(ser_to_de)
}
fn visit_seq<A: de::SeqAccess<'de>>(self, mut access: A) -> Result<Self::Value, A::Error> {
let Some(depth) = self.depth.checked_sub(1) else {
return Err(nests_too_deep());
};
let mut sequence = self
.serializer
.serialize_seq(access.size_hint())
.map_err(ser_to_de)?;
while let Some(value) = access.next_element::<&RawValue>()? {
let child = Replay {
json: value.get(),
depth,
};
ser::SerializeSeq::serialize_element(&mut sequence, &child).map_err(ser_to_de)?;
}
ser::SerializeSeq::end(sequence).map_err(ser_to_de)
}
fn visit_map<A: de::MapAccess<'de>>(self, mut access: A) -> Result<Self::Value, A::Error> {
let Some(depth) = self.depth.checked_sub(1) else {
return Err(nests_too_deep());
};
let mut map = self
.serializer
.serialize_map(access.size_hint())
.map_err(ser_to_de)?;
while let Some(key) = access.next_key_seed(Key)? {
ser::SerializeMap::serialize_key(&mut map, key.as_ref()).map_err(ser_to_de)?;
let value = access.next_value::<&RawValue>()?;
let child = Replay {
json: value.get(),
depth,
};
ser::SerializeMap::serialize_value(&mut map, &child).map_err(ser_to_de)?;
}
ser::SerializeMap::end(map).map_err(ser_to_de)
}
}
struct Replay<'a> {
json: &'a str,
depth: usize,
}
impl ser::Serialize for Replay<'_> {
fn serialize<S: ser::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
emit(self.json, serializer, self.depth)
}
}
struct Key;
impl<'de> de::DeserializeSeed<'de> for Key {
type Value = Cow<'de, str>;
fn deserialize<D: de::Deserializer<'de>>(
self,
deserializer: D,
) -> Result<Self::Value, D::Error> {
deserializer.deserialize_str(Key)
}
}
impl<'de> de::Visitor<'de> for Key {
type Value = Cow<'de, str>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a JSON object key")
}
fn visit_str<E: de::Error>(self, value: &str) -> Result<Self::Value, E> {
Ok(Cow::Owned(value.to_owned()))
}
fn visit_borrowed_str<E: de::Error>(self, value: &'de str) -> Result<Self::Value, E> {
Ok(Cow::Borrowed(value))
}
fn visit_string<E: de::Error>(self, value: String) -> Result<Self::Value, E> {
Ok(Cow::Owned(value))
}
}
#[cfg(test)]
mod tests {
#![allow(clippy::unwrap_used)]
use super::emit;
use crate::native::MAX_NATIVE_NESTING_DEPTH;
use serde_json::Value;
fn emit_field<S: serde::ser::Serializer>(json: &str, serializer: S) -> Result<S::Ok, S::Error> {
emit(json, serializer, MAX_NATIVE_NESTING_DEPTH)
}
const TEXT: &str = concat!(
r#"{"id":"pin#0","a":[null,true,false,-1,0,1.5,2.0,1e-7,10000000000.0],"#,
r#""b":{"":[],"c\td":{},"nested":{"a":[[[1]]]}},"#,
r#""é key":"quote\" back\\ tab\t bell\u0007 é","z":18446744073709551615}"#
);
#[test]
fn emits_the_value_a_parse_would_produce() {
let replayed = emit_field(TEXT, serde_json::value::Serializer).unwrap();
assert_eq!(replayed, serde_json::from_str::<Value>(TEXT).unwrap());
}
#[test]
fn compact_emission_reproduces_the_source_text() {
let mut out = Vec::new();
emit_field(TEXT, &mut serde_json::Serializer::new(&mut out)).unwrap();
assert_eq!(String::from_utf8(out).unwrap(), TEXT);
}
#[test]
fn a_borrowed_member_can_be_serialized_more_than_once() {
let member = super::Replay {
json: TEXT,
depth: MAX_NATIVE_NESTING_DEPTH,
};
let expected = serde_json::from_str::<Value>(TEXT).unwrap();
assert_eq!(serde_json::to_value(&member).unwrap(), expected);
assert_eq!(serde_json::to_string(&member).unwrap(), TEXT);
assert_eq!(serde_json::to_value(&member).unwrap(), expected);
}
#[test]
fn one_budget_spans_the_whole_replay() {
let chain =
|containers: usize| format!("{}7{}", "[".repeat(containers), "]".repeat(containers));
let admitted = chain(MAX_NATIVE_NESTING_DEPTH);
let mut out = Vec::new();
emit_field(&admitted, &mut serde_json::Serializer::new(&mut out)).unwrap();
assert_eq!(String::from_utf8(out).unwrap(), admitted);
let error = emit_field(
&chain(MAX_NATIVE_NESTING_DEPTH + 1),
serde_json::value::Serializer,
)
.unwrap_err();
assert!(
error.to_string().contains(&format!(
"native value nests deeper than {MAX_NATIVE_NESTING_DEPTH} containers"
)),
"{error}"
);
}
}