use std::{cell::Cell, fmt};
use serde::de::{self, DeserializeSeed, Deserializer, MapAccess, SeqAccess, Visitor};
use serde_json::{Map, Number, Value};
use crate::ParseOutcome;
const DUPLICATE_KEY: &str = "lognorm duplicate object key";
const NUMBER_TOKEN: &str = "$serde_json::private::Number";
struct Literals<'a> {
input: &'a str,
position: Cell<usize>,
}
impl<'a> Literals<'a> {
fn new(input: &'a str) -> Self {
Self {
input,
position: Cell::new(0),
}
}
fn next(&self) -> Option<&'a str> {
let bytes = self.input.as_bytes();
let mut index = self.position.get();
while let Some(&byte) = bytes.get(index) {
match byte {
b'"' => {
index += 1;
while let Some(offset) = bytes
.get(index..)
.and_then(|rest| memchr::memchr2(b'"', b'\\', rest))
{
index += offset;
if bytes.get(index) == Some(&b'"') {
break;
}
index += 2;
}
index += 1;
}
b'-' | b'0'..=b'9' => {
let start = index;
while bytes.get(index).is_some_and(|byte| {
matches!(byte, b'0'..=b'9' | b'-' | b'+' | b'.' | b'e' | b'E')
}) {
index += 1;
}
self.position.set(index);
return self.input.get(start..index);
}
_ => index += 1,
}
}
self.position.set(index);
None
}
}
fn number(literal: &str) -> Result<Value, &'static str> {
let float = literal.parse::<f64>().map_err(|_| "invalid JSON number")?;
if !float.is_finite() {
return Err("number out of range");
}
if !literal.contains(['.', 'e', 'E']) {
match (literal.parse::<u64>(), literal.parse::<i64>()) {
(Ok(integer), _) => return Ok(Value::Number(integer.into())),
(_, Ok(integer)) if integer != 0 => return Ok(Value::Number(integer.into())),
(_, Ok(_)) => {}
_ => return Ok(Value::String(literal.to_owned())),
}
}
let number = Number::from_f64(float).ok_or("number out of range")?;
if same_decimal(literal, &number.to_string()) {
Ok(Value::Number(number))
} else {
Ok(Value::String(literal.to_owned()))
}
}
fn same_decimal(left: &str, right: &str) -> bool {
decimal_parts(left).is_some_and(|parts| decimal_parts(right) == Some(parts))
}
fn decimal_parts(text: &str) -> Option<(bool, String, i64)> {
let negative = text.starts_with('-');
let unsigned = text.strip_prefix('-').unwrap_or(text);
let (mantissa, exponent) = unsigned.split_once(['e', 'E']).unwrap_or((unsigned, "0"));
let fraction_len = mantissa
.split_once('.')
.map_or(0, |(_, fraction)| fraction.len());
let mut digits: String = mantissa
.chars()
.filter(|ch| *ch != '.')
.skip_while(|ch| *ch == '0')
.collect();
if digits.is_empty() {
return Some((negative, digits, 0));
}
let significant_len = digits.trim_end_matches('0').len();
let trailing_zeros = digits.len() - significant_len;
digits.truncate(significant_len);
let exponent = exponent
.parse::<i64>()
.ok()?
.checked_sub(i64::try_from(fraction_len).ok()?)?
.checked_add(i64::try_from(trailing_zeros).ok()?)?;
Some((negative, digits, exponent))
}
fn close(exact: f64, decoded: f64) -> bool {
let difference = (exact - decoded).abs();
exact == decoded || difference <= exact.abs() * 1e-12 || difference <= 1e-300
}
struct Pass<'a> {
literals: Literals<'a>,
keep_literal_strings: bool,
saw_literal_string: Cell<bool>,
}
impl<'a> Pass<'a> {
fn new(input: &'a str, keep_literal_strings: bool) -> Self {
Self {
literals: Literals::new(input),
keep_literal_strings,
saw_literal_string: Cell::new(false),
}
}
}
#[derive(Clone, Copy)]
struct Preserve<'p, 'a>(&'p Pass<'a>);
impl Preserve<'_, '_> {
fn number<E: de::Error>(self, decoded: impl FnOnce(&str) -> bool) -> Result<Value, E> {
let value = match self.0.literals.next() {
Some(literal) if decoded(literal) => number(literal).map_err(E::custom)?,
_ => return Err(E::custom("number literal out of order")),
};
if value.is_string() {
self.0.saw_literal_string.set(true);
if !self.0.keep_literal_strings {
return Ok(Value::Null);
}
}
Ok(value)
}
}
impl<'de> DeserializeSeed<'de> for Preserve<'_, '_> {
type Value = Value;
fn deserialize<D: Deserializer<'de>>(self, deserializer: D) -> Result<Value, D::Error> {
deserializer.deserialize_any(self)
}
}
impl<'de> Visitor<'de> for Preserve<'_, '_> {
type Value = Value;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("a JSON value without duplicate object keys")
}
fn visit_bool<E: de::Error>(self, value: bool) -> Result<Value, E> {
Ok(Value::Bool(value))
}
fn visit_i64<E: de::Error>(self, value: i64) -> Result<Value, E> {
self.number(|literal| literal.parse::<i64>() == Ok(value))
}
fn visit_u64<E: de::Error>(self, value: u64) -> Result<Value, E> {
self.number(|literal| literal.parse::<u64>() == Ok(value))
}
fn visit_f64<E: de::Error>(self, value: f64) -> Result<Value, E> {
self.number(|literal| {
literal
.parse::<f64>()
.is_ok_and(|exact| close(exact, value))
})
}
fn visit_str<E: de::Error>(self, value: &str) -> Result<Value, E> {
Ok(Value::String(value.to_owned()))
}
fn visit_string<E: de::Error>(self, value: String) -> Result<Value, E> {
Ok(Value::String(value))
}
fn visit_unit<E: de::Error>(self) -> Result<Value, E> {
Ok(Value::Null)
}
fn visit_seq<A: SeqAccess<'de>>(self, mut sequence: A) -> Result<Value, A::Error> {
let mut values = Vec::new();
while let Some(value) = sequence.next_element_seed(self)? {
values.push(value);
}
Ok(Value::Array(values))
}
fn visit_map<A: MapAccess<'de>>(self, mut object: A) -> Result<Value, A::Error> {
let mut values = Map::new();
while let Some(key) = object.next_key::<String>()? {
if key == NUMBER_TOKEN {
let text = object.next_value::<String>()?;
return self.number(|literal| same_decimal(literal, &text));
}
if values.contains_key(&key) {
return Err(de::Error::custom(DUPLICATE_KEY));
}
let value = object.next_value_seed(self)?;
values.insert(key, value);
}
Ok(Value::Object(values))
}
}
pub(crate) struct Decoded {
pub(crate) fields: Map<String, Value>,
pub(crate) recognition: Option<Map<String, Value>>,
}
pub(crate) fn object(input: &str) -> Result<Decoded, ParseOutcome> {
if reserved_key(input) {
return Err(ParseOutcome::InvalidJson);
}
let pass = Pass::new(input, true);
let fields = decode(input, &pass)?;
let recognition = if pass.saw_literal_string.get() {
Some(decode(input, &Pass::new(input, false))?)
} else {
None
};
Ok(Decoded {
fields,
recognition,
})
}
fn decode(input: &str, pass: &Pass<'_>) -> Result<Map<String, Value>, ParseOutcome> {
let mut deserializer = serde_json::Deserializer::from_str(input);
let value = Preserve(pass)
.deserialize(&mut deserializer)
.map_err(|error| {
if error.to_string().starts_with(DUPLICATE_KEY) {
ParseOutcome::DuplicateKeys
} else {
ParseOutcome::InvalidJson
}
})?;
deserializer.end().map_err(|_| ParseOutcome::InvalidJson)?;
match value {
Value::Object(fields) => Ok(fields),
_ => Err(ParseOutcome::Text),
}
}
fn reserved_key(input: &str) -> bool {
if !input.contains("private") && !input.contains("\\u") {
return false;
}
let mut strings = input.char_indices();
while let Some((start, ch)) = strings.next() {
if ch != '"' {
continue;
}
let mut escaped = false;
for (end, ch) in strings.by_ref() {
if escaped {
escaped = false;
continue;
}
if ch == '\\' {
escaped = true;
continue;
}
if ch == '"' {
if input[end + 1..].trim_start().starts_with(':') {
let raw = &input[start..=end];
if serde_json::from_str::<String>(raw).ok().as_deref() == Some(NUMBER_TOKEN) {
return true;
}
}
break;
}
}
}
false
}