Skip to content

Commit

Permalink
Fix empty objects / empty arrays
Browse files Browse the repository at this point in the history
Closes #85
  • Loading branch information
fasterthanlime committed Oct 4, 2024
1 parent b0ef446 commit 67b4f4c
Show file tree
Hide file tree
Showing 2 changed files with 179 additions and 39 deletions.
132 changes: 132 additions & 0 deletions merde/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -872,6 +872,8 @@ pub fn none_of<I, T>(_f: impl FnOnce(I) -> T) -> Option<T> {
#[cfg(test)]
#[cfg(feature = "json")]
mod json_tests {
use std::collections::HashMap;

use super::*;
use crate::json::{from_str, JsonSerialize};

Expand Down Expand Up @@ -961,6 +963,136 @@ mod json_tests {

assert_eq!(original, deserialized);
}

#[test]
fn test_u8_zero() {
let original: u8 = 0;
let serialized = original.to_json_string();
let deserialized: u8 = from_str(&serialized).unwrap();
assert_eq!(original, deserialized);
}

#[test]
fn test_u8_max() {
let original: u8 = u8::MAX;
let serialized = original.to_json_string();
let deserialized: u8 = from_str(&serialized).unwrap();
assert_eq!(original, deserialized);
}

#[test]
fn test_i8_min() {
let original: i8 = i8::MIN;
let serialized = original.to_json_string();
let deserialized: i8 = from_str(&serialized).unwrap();
assert_eq!(original, deserialized);
}

#[test]
fn test_i8_max() {
let original: i8 = i8::MAX;
let serialized = original.to_json_string();
let deserialized: i8 = from_str(&serialized).unwrap();
assert_eq!(original, deserialized);
}

#[test]
fn test_i64_min() {
let original: i64 = i64::MIN;
let serialized = original.to_json_string();
let deserialized: i64 = from_str(&serialized).unwrap();
assert_eq!(original, deserialized);
}

#[test]
fn test_i64_max() {
let original: i64 = i64::MAX;
let serialized = original.to_json_string();
let deserialized: i64 = from_str(&serialized).unwrap();
assert_eq!(original, deserialized);
}

#[test]
fn test_string_owned() {
let original = String::from("Hello, World!");
let serialized = original.to_json_string();
let deserialized: String = from_str(&serialized).unwrap();
assert_eq!(original, deserialized);
}

#[test]
fn test_string_borrowed() {
let original: &str = "Hello, World!";
let serialized = original.to_json_string();
let deserialized: String = from_str(&serialized).unwrap();
assert_eq!(original, deserialized);
}

#[test]
fn test_vec_empty() {
let original: Vec<i32> = Vec::new();
let serialized = original.to_json_string();
let deserialized: Vec<i32> = from_str(&serialized).unwrap();
assert_eq!(original, deserialized);
}

#[test]
fn test_vec_non_empty() {
let original = vec![1, 2, 3, 4, 5];
let serialized = original.to_json_string();
let deserialized: Vec<i32> = from_str(&serialized).unwrap();
assert_eq!(original, deserialized);
}

#[test]
fn test_hashmap_empty() {
let original: HashMap<String, i32> = HashMap::new();
let serialized = original.to_json_string();
let deserialized: HashMap<String, i32> = from_str(&serialized).unwrap();
assert_eq!(original, deserialized);
}

#[test]
fn test_hashmap_non_empty() {
let mut original = HashMap::new();
original.insert("key1".to_string(), 42);
original.insert("key2".to_string(), -10);
let serialized = original.to_json_string();
let deserialized: HashMap<String, i32> = from_str(&serialized).unwrap();
assert_eq!(original, deserialized);
}

#[test]
fn test_option_some() {
let original: Option<i32> = Some(42);
let serialized = original.to_json_string();
let deserialized: Option<i32> = from_str(&serialized).unwrap();
assert_eq!(original, deserialized);
}

#[test]
fn test_option_none() {
let original: Option<i32> = None;
let serialized = original.to_json_string();
let deserialized: Option<i32> = from_str(&serialized).unwrap();
assert_eq!(original, deserialized);
}

#[test]
fn test_bool_true() {
let original = true;
let serialized = original.to_json_string();
let deserialized: bool = from_str(&serialized).unwrap();
assert_eq!(original, deserialized);
}

#[test]
fn test_bool_false() {
let original = false;
let serialized = original.to_json_string();
let deserialized: bool = from_str(&serialized).unwrap();
assert_eq!(original, deserialized);
}
}

// used to test out doc-tests
Expand Down
86 changes: 47 additions & 39 deletions merde_json/src/deserialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ use crate::{

#[derive(Debug, Clone, PartialEq, Eq)]
enum StackItem<'s> {
ObjectFirstKey(CowStr<'s>),
ObjectKey,
ObjectKey(Option<CowStr<'s>>),
ObjectValue,
ArrayFirstValue(Peek),
Array,
ObjectEnd,
Array(Option<Peek>),
ArrayEnd,
}

/// A JSON deserializer
Expand Down Expand Up @@ -64,47 +64,56 @@ impl<'s> Deserializer<'s> for JsonDeserializer<'s> {
}

let peek: Option<Peek> = match self.stack.pop() {
Some(StackItem::ObjectFirstKey(key)) => {
self.stack.push(StackItem::ObjectValue);
return Ok(Event::Str(key));
}
Some(StackItem::ObjectKey) => match self
.jiter
.next_key()
.map_err(|e| jiter_error(self.source, e))?
{
Some(StackItem::ObjectKey(maybe_key)) => match maybe_key {
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
}
Some(StackItem::ArrayFirstValue(peek)) => {
self.stack.push(StackItem::Array);
Some(peek)
}
Some(StackItem::Array) => {
match self
None => match self
.jiter
.array_step()
.next_key()
.map_err(|e| jiter_error(self.source, e))?
{
Some(peek) => {
self.stack.push(StackItem::Array);
Some(peek)
Some(key) => {
self.stack.push(StackItem::ObjectValue);
let key = cowify(self.source.as_bytes(), key);
return Ok(Event::Str(key));
}
None => {
// end of the array!
return Ok(Event::ArrayEnd);
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,
};
Expand Down Expand Up @@ -148,9 +157,9 @@ impl<'s> Deserializer<'s> for JsonDeserializer<'s> {
.known_array()
.map_err(|err| jiter_error(self.source, err))?;
if let Some(peek) = peek {
self.stack.push(StackItem::ArrayFirstValue(peek));
self.stack.push(StackItem::Array(Some(peek)));
} else {
self.stack.push(StackItem::Array);
self.stack.push(StackItem::ArrayEnd);
}
Event::ArrayStart(ArrayStart { size_hint: None })
} else if peek == Peek::Object {
Expand All @@ -160,10 +169,9 @@ impl<'s> Deserializer<'s> for JsonDeserializer<'s> {
.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::ObjectFirstKey(key));
self.stack.push(StackItem::ObjectKey(Some(key)));
} else {
// well it's empty, but we'll find that soon enough
self.stack.push(StackItem::ObjectKey);
self.stack.push(StackItem::ObjectEnd);
}
Event::MapStart
} else {
Expand Down

0 comments on commit 67b4f4c

Please sign in to comment.