use merde_core::{ArrayStart, CowStr, Deserializer, Event, MapStart, MerdeError};
use crate::jiter_lite::{errors::JiterError, jiter::Jiter, parse::Peek};
#[derive(Debug, Clone, PartialEq, Eq)]
enum StackItem<'s> {
ObjectKey(Option<CowStr<'s>>),
ObjectValue,
ObjectEnd,
Array(Option<Peek>),
ArrayEnd,
}
pub struct JsonDeserializer<'s> {
source: &'s str,
jiter: Jiter<'s>,
stack: Vec<StackItem<'s>>,
starter: Option<Event<'s>>,
}
impl std::fmt::Debug for JsonDeserializer<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("JsonDeserializer")
.field("source_len", &self.source)
.field("stack_size", &self.stack.len())
.finish()
}
}
impl<'s> JsonDeserializer<'s> {
pub fn new(source: &'s str) -> Self {
let jiter = Jiter::new(source.as_bytes());
Self {
source,
jiter,
stack: Default::default(),
starter: None,
}
}
}
fn jiter_error(source: &str, err: JiterError) -> MerdeError<'_> {
MerdeError::StringParsingError {
format: "JSON",
index: err.index,
message: err.error_type.to_string(),
source: source.into(),
}
}
impl<'s> Deserializer<'s> for JsonDeserializer<'s> {
async fn next(&mut self) -> Result<Event<'s>, MerdeError<'s>> {
if let Some(ev) = self.starter.take() {
return Ok(ev);
}
let peek: Option<Peek> = match self.stack.pop() {
Some(StackItem::ObjectKey(maybe_key)) => match maybe_key {
Some(key) => {
self.stack.push(StackItem::ObjectValue);
return Ok(Event::Str(key));
}
None => match self
.jiter
.next_key()
.map_err(|e| jiter_error(self.source, e))?
{
Some(key) => {
self.stack.push(StackItem::ObjectValue);
let key = cowify(self.source.as_bytes(), key);
return Ok(Event::Str(key));
}
None => {
return Ok(Event::MapEnd);
}
},
},
Some(StackItem::ObjectValue) => {
self.stack.push(StackItem::ObjectKey(None));
None
}
Some(StackItem::ObjectEnd) => {
return Ok(Event::MapEnd);
}
Some(StackItem::Array(maybe_peek)) => match maybe_peek {
Some(peek) => {
self.stack.push(StackItem::Array(None));
Some(peek)
}
None => {
match self
.jiter
.array_step()
.map_err(|e| jiter_error(self.source, e))?
{
Some(peek) => {
self.stack.push(StackItem::Array(None));
Some(peek)
}
None => {
return Ok(Event::ArrayEnd);
}
}
}
},
Some(StackItem::ArrayEnd) => {
return Ok(Event::ArrayEnd);
}
None => None,
};
let peek = match peek {
Some(ev) => ev,
None => self.jiter.peek().map_err(|e| jiter_error(self.source, e))?,
};
let ev = if peek == Peek::Null {
self.jiter
.known_null()
.map_err(|err| jiter_error(self.source, err))?;
Event::Null
} else if peek == Peek::True || peek == Peek::False {
let bool_value = self
.jiter
.known_bool(peek)
.map_err(|err| jiter_error(self.source, err))?;
Event::Bool(bool_value)
} else if peek.is_num() {
let num = self
.jiter
.known_float(peek)
.map_err(|err| jiter_error(self.source, err))?;
if num.fract() == 0.0 && num >= i64::MIN as f64 && num <= i64::MAX as f64 {
Event::I64(num as i64)
} else {
Event::F64(num)
}
} else if peek == Peek::String {
let s = self
.jiter
.known_str()
.map_err(|err| jiter_error(self.source, err))?;
let s = cowify(self.source.as_bytes(), s);
Event::Str(s)
} else if peek == Peek::Array {
let peek = self
.jiter
.known_array()
.map_err(|err| jiter_error(self.source, err))?;
if let Some(peek) = peek {
self.stack.push(StackItem::Array(Some(peek)));
} else {
self.stack.push(StackItem::ArrayEnd);
}
Event::ArrayStart(ArrayStart { size_hint: None })
} else if peek == Peek::Object {
let key = self
.jiter
.known_object()
.map_err(|err| jiter_error(self.source, err))?;
if let Some(key) = key {
let key = cowify(self.source.as_bytes(), key);
self.stack.push(StackItem::ObjectKey(Some(key)));
} else {
self.stack.push(StackItem::ObjectEnd);
}
Event::MapStart(MapStart { size_hint: None })
} else {
panic!("Unknown peek: {:?}", peek);
};
Ok(ev)
}
fn put_back(&mut self, ev: Event<'s>) -> Result<(), MerdeError<'s>> {
if self.starter.is_some() {
return Err(MerdeError::PutBackCalledTwice);
}
self.starter = Some(ev);
Ok(())
}
}
fn _assert_dyn_deser() {
fn assert_impl<'s, T: merde_core::DynDeserializer<'s>>() {}
assert_impl::<JsonDeserializer>();
}
fn _assert_dyn_deser_ext() {
fn assert_impl<'s, T: merde_core::DynDeserializerExt<'s>>() {}
assert_impl::<JsonDeserializer>();
}
pub(crate) fn cowify<'j>(src: &'j [u8], s: &str) -> CowStr<'j> {
if src.as_ptr_range().contains(&s.as_ptr()) {
CowStr::Borrowed(unsafe {
std::str::from_utf8_unchecked(std::slice::from_raw_parts(s.as_ptr(), s.len()))
})
} else {
CowStr::Owned(s.into())
}
}
#[cfg(test)]
mod tests {
use crate::deserialize::cowify;
use super::JsonDeserializer;
use merde_core::{
Array, CowStr, Deserialize, DynDeserializer, DynDeserializerExt as _, Event, EventType,
Map, MerdeError,
};
use merde_loggingserializer::LoggingDeserializer;
#[derive(Debug, PartialEq)]
pub struct Sample {
pub height: i64,
pub kind: bool,
}
impl<'s> Deserialize<'s> for Sample {
async fn deserialize(de: &mut dyn DynDeserializer<'s>) -> Result<Self, MerdeError<'s>> {
{
let mut height: Option<i64> = None;
let mut kind: Option<bool> = None;
de.next().await?.into_map_start()?;
loop {
match de.next().await? {
Event::Str(k) => match k.as_ref() {
"height" => {
height = Some(i64::deserialize(de).await?);
}
"kind" => {
kind = Some(bool::deserialize(de).await?);
}
_ => {
return Err(MerdeError::UnknownProperty(k));
}
},
Event::MapEnd => {
break;
}
ev => {
return Err(MerdeError::UnexpectedEvent {
got: EventType::from(&ev),
expected: &[EventType::Str],
help: None,
})
}
}
}
Ok(Sample {
height: height.ok_or_else(|| MerdeError::MissingProperty("height".into()))?,
kind: kind.ok_or_else(|| MerdeError::MissingProperty("kind".into()))?,
})
}
}
}
#[test]
fn test_deserialize() {
let input = r#"
[
{
"height": 100,
"kind": true
},
{
"height": 200,
"kind": false
},
{
"height": 150,
"kind": true
}
]
"#;
let deser = JsonDeserializer::new(input);
let mut deser = LoggingDeserializer::new(deser);
let samples = deser.deserialize::<Vec<Sample>>().unwrap();
assert_eq!(
samples,
vec![
Sample {
height: 100,
kind: true
},
Sample {
height: 200,
kind: false
},
Sample {
height: 150,
kind: true
}
]
);
let deser = JsonDeserializer::new(input);
let mut deser = LoggingDeserializer::new(deser);
let value = deser.deserialize::<merde_core::Value>().unwrap();
assert_eq!(
value,
Array::new()
.with(
Map::new()
.with("height", merde_core::Value::I64(100))
.with("kind", merde_core::Value::Bool(true))
)
.with(
Map::new()
.with("height", merde_core::Value::I64(200))
.with("kind", merde_core::Value::Bool(false))
)
.with(
Map::new()
.with("height", merde_core::Value::I64(150))
.with("kind", merde_core::Value::Bool(true))
)
.into()
);
}
#[test]
fn test_cowify() {
let src = "That's a subset!";
let s = &src[4..8];
assert_eq!(cowify(src.as_bytes(), s), CowStr::Borrowed(s));
let src = "Not a subset";
let s = "indeed not";
assert_eq!(cowify(src.as_bytes(), s), CowStr::Owned(s.into()));
}
}