use serde::Deserialize;
use serde::de::{self, Deserializer, MapAccess, SeqAccess, Visitor};
#[derive(Clone, Debug, PartialEq)]
pub(crate) enum OrderedValue {
Null,
Bool(bool),
Number(serde_json::Number),
String(String),
Array(Vec<OrderedValue>),
Object(Vec<(String, OrderedValue)>),
}
impl OrderedValue {
pub(crate) fn type_name(&self) -> &'static str {
match self {
OrderedValue::Null => "null",
OrderedValue::Bool(_) => "boolean",
OrderedValue::Number(_) => "number",
OrderedValue::String(_) => "string",
OrderedValue::Array(_) => "array",
OrderedValue::Object(_) => "object",
}
}
pub(crate) fn as_str(&self) -> Option<&str> {
match self {
OrderedValue::String(text) => Some(text),
_ => None,
}
}
}
pub(crate) fn parse_ordered(bytes: &[u8]) -> Result<OrderedValue, serde_json::Error> {
let mut deserializer = serde_json::Deserializer::from_slice(bytes);
let value = OrderedValue::deserialize(&mut deserializer)?;
deserializer.end()?;
Ok(value)
}
impl<'de> Deserialize<'de> for OrderedValue {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_any(OrderedValueVisitor)
}
}
struct OrderedValueVisitor;
impl<'de> Visitor<'de> for OrderedValueVisitor {
type Value = OrderedValue;
fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
formatter.write_str("any JSON value")
}
fn visit_bool<E: de::Error>(self, value: bool) -> Result<Self::Value, E> {
Ok(OrderedValue::Bool(value))
}
fn visit_i64<E: de::Error>(self, value: i64) -> Result<Self::Value, E> {
Ok(OrderedValue::Number(serde_json::Number::from(value)))
}
fn visit_u64<E: de::Error>(self, value: u64) -> Result<Self::Value, E> {
Ok(OrderedValue::Number(serde_json::Number::from(value)))
}
fn visit_f64<E: de::Error>(self, value: f64) -> Result<Self::Value, E> {
serde_json::Number::from_f64(value)
.map(OrderedValue::Number)
.ok_or_else(|| de::Error::custom("non-finite numbers are not valid JSON"))
}
fn visit_str<E: de::Error>(self, value: &str) -> Result<Self::Value, E> {
Ok(OrderedValue::String(value.to_owned()))
}
fn visit_string<E: de::Error>(self, value: String) -> Result<Self::Value, E> {
Ok(OrderedValue::String(value))
}
fn visit_unit<E: de::Error>(self) -> Result<Self::Value, E> {
Ok(OrderedValue::Null)
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
let mut items = Vec::new();
while let Some(item) = seq.next_element::<OrderedValue>()? {
items.push(item);
}
Ok(OrderedValue::Array(items))
}
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where
A: MapAccess<'de>,
{
let mut entries: Vec<(String, OrderedValue)> = Vec::new();
while let Some((key, value)) = map.next_entry::<String, OrderedValue>()? {
if entries.iter().any(|(existing, _)| *existing == key) {
return Err(de::Error::custom(format!("duplicate object key `{key}`")));
}
entries.push((key, value));
}
Ok(OrderedValue::Object(entries))
}
}
#[cfg(test)]
mod tests {
use super::{OrderedValue, parse_ordered};
type TestResult = Result<(), Box<dyn std::error::Error>>;
#[test]
fn objects_preserve_document_order() -> TestResult {
let parsed = parse_ordered(br#"{"zeta": 1, "alpha": {"nested_z": true, "a": null}}"#)?;
let OrderedValue::Object(entries) = parsed else {
return Err("expected object".into());
};
assert_eq!(entries[0].0, "zeta");
assert_eq!(entries[1].0, "alpha");
let OrderedValue::Object(nested) = &entries[1].1 else {
return Err("expected nested object".into());
};
assert_eq!(nested[0].0, "nested_z");
assert_eq!(nested[1].0, "a");
Ok(())
}
#[test]
fn all_json_value_kinds_parse() -> TestResult {
let parsed = parse_ordered(br#"[null, true, 7, -3, 0.5, "text", [], {}]"#)?;
let OrderedValue::Array(items) = parsed else {
return Err("expected array".into());
};
assert_eq!(items.len(), 8);
assert_eq!(items[0], OrderedValue::Null);
assert_eq!(items[1], OrderedValue::Bool(true));
assert_eq!(items[5].as_str(), Some("text"));
assert_eq!(items[6], OrderedValue::Array(Vec::new()));
assert_eq!(items[7], OrderedValue::Object(Vec::new()));
Ok(())
}
#[test]
fn duplicate_keys_are_rejected() -> TestResult {
let result = parse_ordered(br#"{"a": 1, "a": 2}"#);
let Err(error) = result else {
return Err("duplicate keys must be rejected".into());
};
assert!(error.to_string().contains("duplicate object key `a`"));
Ok(())
}
#[test]
fn trailing_garbage_is_rejected() {
assert!(parse_ordered(b"{} extra").is_err());
}
#[test]
fn type_names_cover_every_kind() -> TestResult {
let parsed = parse_ordered(br#"[null, true, 1, "s", [], {}]"#)?;
let OrderedValue::Array(items) = &parsed else {
return Err("expected array".into());
};
let names: Vec<&str> = items.iter().map(OrderedValue::type_name).collect();
assert_eq!(
names,
vec!["null", "boolean", "number", "string", "array", "object"]
);
assert_eq!(parsed.type_name(), "array");
Ok(())
}
}