mod de;
mod se;
mod value;
pub use self::se::*;
pub use self::value::*;
use crate::{stry, Buffers, Deserializer, Error, ErrorType, Node, Result};
use crate::{BorrowedValue, OwnedValue};
use serde::de::DeserializeOwned;
use serde_ext::Deserialize;
use std::fmt;
use std::io;
use value_trait::prelude::*;
type ConvertResult<T> = std::result::Result<T, SerdeConversionError>;
#[derive(Debug)]
pub enum SerdeConversionError {
NanOrInfinity,
NumberOutOfBounds,
Oops,
}
impl std::fmt::Display for SerdeConversionError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use SerdeConversionError::{NanOrInfinity, NumberOutOfBounds, Oops};
match self {
NanOrInfinity => write!(f, "JSON can not represent NAN or Infinity values"),
NumberOutOfBounds => write!(f, "Serde can not represent 128 bit values"),
Oops => write!(
f,
"Unreachable code is reachable, oops - please open a bug with simd-json"
),
}
}
}
impl std::error::Error for SerdeConversionError {}
#[cfg_attr(not(feature = "no-inline"), inline)]
pub fn from_slice<'a, T>(s: &'a mut [u8]) -> Result<T>
where
T: Deserialize<'a>,
{
let mut deserializer = stry!(Deserializer::from_slice(s));
T::deserialize(&mut deserializer)
}
#[cfg_attr(not(feature = "no-inline"), inline)]
pub fn from_slice_with_buffers<'a, T>(s: &'a mut [u8], buffers: &mut Buffers) -> Result<T>
where
T: Deserialize<'a>,
{
let mut deserializer = stry!(Deserializer::from_slice_with_buffers(s, buffers));
T::deserialize(&mut deserializer)
}
#[cfg_attr(not(feature = "no-inline"), inline)]
pub unsafe fn from_str<'a, T>(s: &'a mut str) -> Result<T>
where
T: Deserialize<'a>,
{
let mut deserializer = stry!(Deserializer::from_slice(unsafe { s.as_bytes_mut() }));
T::deserialize(&mut deserializer)
}
#[cfg_attr(not(feature = "no-inline"), inline)]
pub unsafe fn from_str_with_buffers<'a, T>(s: &'a mut str, buffers: &mut Buffers) -> Result<T>
where
T: Deserialize<'a>,
{
let mut deserializer = stry!(Deserializer::from_slice_with_buffers(
unsafe { s.as_bytes_mut() },
buffers
));
T::deserialize(&mut deserializer)
}
#[cfg_attr(not(feature = "no-inline"), inline)]
pub fn from_reader<R, T>(mut rdr: R) -> Result<T>
where
R: io::Read,
T: DeserializeOwned,
{
let mut data = Vec::new();
if let Err(e) = rdr.read_to_end(&mut data) {
return Err(Error::generic(ErrorType::Io(e)));
};
let mut deserializer = stry!(Deserializer::from_slice(&mut data));
T::deserialize(&mut deserializer)
}
#[cfg_attr(not(feature = "no-inline"), inline)]
pub fn from_reader_with_buffers<R, T>(mut rdr: R, buffers: &mut Buffers) -> Result<T>
where
R: io::Read,
T: DeserializeOwned,
{
let mut data = Vec::new();
if let Err(e) = rdr.read_to_end(&mut data) {
return Err(Error::generic(ErrorType::Io(e)));
};
let mut deserializer = stry!(Deserializer::from_slice_with_buffers(&mut data, buffers));
T::deserialize(&mut deserializer)
}
impl serde::de::Error for Error {
fn custom<T: fmt::Display>(msg: T) -> Self {
Self::generic(ErrorType::Serde(msg.to_string()))
}
}
impl serde_ext::ser::Error for Error {
fn custom<T: fmt::Display>(msg: T) -> Self {
Self::generic(ErrorType::Serde(msg.to_string()))
}
}
impl<'de> Deserializer<'de> {
#[cfg_attr(not(feature = "no-inline"), inline)]
fn next(&mut self) -> Result<Node<'de>> {
let r = self
.tape
.get(self.idx)
.copied()
.ok_or_else(|| Self::error(ErrorType::Syntax));
self.idx += 1;
r
}
#[cfg_attr(not(feature = "no-inline"), inline)]
fn peek(&self) -> Result<Node> {
self.tape
.get(self.idx)
.copied()
.ok_or_else(|| Self::error(ErrorType::Eof))
}
#[cfg_attr(not(feature = "no-inline"), inline)]
#[allow(clippy::cast_sign_loss)]
fn parse_u8(&mut self) -> Result<u8> {
match unsafe { self.next_() } {
Node::Static(s) => s
.as_u8()
.ok_or_else(|| Self::error(ErrorType::ExpectedUnsigned)),
_ => Err(Self::error(ErrorType::ExpectedUnsigned)),
}
}
#[cfg_attr(not(feature = "no-inline"), inline)]
#[allow(clippy::cast_sign_loss)]
fn parse_u16(&mut self) -> Result<u16> {
let next = unsafe { self.next_() };
match next {
Node::Static(s) => s
.as_u16()
.ok_or_else(|| Self::error(ErrorType::ExpectedUnsigned)),
_ => Err(Self::error(ErrorType::ExpectedUnsigned)),
}
}
#[cfg_attr(not(feature = "no-inline"), inline)]
#[allow(clippy::cast_sign_loss)]
fn parse_u32(&mut self) -> Result<u32> {
match unsafe { self.next_() } {
Node::Static(s) => s
.as_u32()
.ok_or_else(|| Self::error(ErrorType::ExpectedUnsigned)),
_ => Err(Self::error(ErrorType::ExpectedUnsigned)),
}
}
#[cfg_attr(not(feature = "no-inline"), inline)]
#[allow(clippy::cast_sign_loss)]
fn parse_u64(&mut self) -> Result<u64> {
match unsafe { self.next_() } {
Node::Static(s) => s
.as_u64()
.ok_or_else(|| Self::error(ErrorType::ExpectedUnsigned)),
_ => Err(Self::error(ErrorType::ExpectedUnsigned)),
}
}
#[cfg_attr(not(feature = "no-inline"), inline)]
#[allow(clippy::cast_sign_loss)]
fn parse_u128(&mut self) -> Result<u128> {
match unsafe { self.next_() } {
Node::Static(s) => s
.as_u128()
.ok_or_else(|| Self::error(ErrorType::ExpectedUnsigned)),
_ => Err(Self::error(ErrorType::ExpectedUnsigned)),
}
}
#[cfg_attr(not(feature = "no-inline"), inline)]
#[allow(clippy::cast_sign_loss)]
fn parse_i8(&mut self) -> Result<i8> {
match unsafe { self.next_() } {
Node::Static(s) => s
.as_i8()
.ok_or_else(|| Self::error(ErrorType::ExpectedSigned)),
_ => Err(Self::error(ErrorType::ExpectedSigned)),
}
}
#[cfg_attr(not(feature = "no-inline"), inline)]
#[allow(clippy::cast_sign_loss)]
fn parse_i16(&mut self) -> Result<i16> {
match unsafe { self.next_() } {
Node::Static(s) => s
.as_i16()
.ok_or_else(|| Self::error(ErrorType::ExpectedSigned)),
_ => Err(Self::error(ErrorType::ExpectedSigned)),
}
}
#[cfg_attr(not(feature = "no-inline"), inline)]
#[allow(clippy::cast_sign_loss)]
fn parse_i32(&mut self) -> Result<i32> {
match unsafe { self.next_() } {
Node::Static(s) => s
.as_i32()
.ok_or_else(|| Self::error(ErrorType::ExpectedSigned)),
_ => Err(Self::error(ErrorType::ExpectedSigned)),
}
}
#[cfg_attr(not(feature = "no-inline"), inline)]
#[allow(clippy::cast_sign_loss)]
fn parse_i64(&mut self) -> Result<i64> {
match unsafe { self.next_() } {
Node::Static(s) => s
.as_i64()
.ok_or_else(|| Self::error(ErrorType::ExpectedSigned)),
_ => Err(Self::error(ErrorType::ExpectedSigned)),
}
}
#[cfg_attr(not(feature = "no-inline"), inline)]
#[allow(clippy::cast_sign_loss)]
fn parse_i128(&mut self) -> Result<i128> {
match unsafe { self.next_() } {
Node::Static(s) => s
.as_i128()
.ok_or_else(|| Self::error(ErrorType::ExpectedSigned)),
_ => Err(Self::error(ErrorType::ExpectedSigned)),
}
}
#[cfg_attr(not(feature = "no-inline"), inline)]
#[allow(clippy::cast_possible_wrap, clippy::cast_precision_loss)]
fn parse_double(&mut self) -> Result<f64> {
match unsafe { self.next_() } {
#[allow(clippy::useless_conversion)] Node::Static(StaticNode::F64(n)) => Ok(n.into()),
Node::Static(StaticNode::I64(n)) => Ok(n as f64),
Node::Static(StaticNode::U64(n)) => Ok(n as f64),
_ => Err(Self::error(ErrorType::ExpectedFloat)),
}
}
}
impl TryFrom<serde_json::Value> for OwnedValue {
type Error = SerdeConversionError;
fn try_from(item: serde_json::Value) -> ConvertResult<Self> {
use serde_json::Value;
Ok(match item {
Value::Null => Self::Static(StaticNode::Null),
Value::Bool(b) => Self::Static(StaticNode::Bool(b)),
Value::Number(b) => {
if let Some(n) = b.as_i64() {
Self::Static(StaticNode::I64(n))
} else if let Some(n) = b.as_u64() {
Self::Static(StaticNode::U64(n))
} else if let Some(n) = b.as_f64() {
Self::Static(StaticNode::from(n))
} else {
return Err(SerdeConversionError::Oops);
}
}
Value::String(b) => Self::String(b),
Value::Array(a) => a
.into_iter()
.map(Self::try_from)
.collect::<ConvertResult<Self>>()?,
Value::Object(o) => o
.into_iter()
.map(|(k, v)| Ok((k, Self::try_from(v)?)))
.collect::<ConvertResult<Self>>()?,
})
}
}
impl TryInto<serde_json::Value> for OwnedValue {
type Error = SerdeConversionError;
fn try_into(self) -> ConvertResult<serde_json::Value> {
use serde_json::Value;
Ok(match self {
Self::Static(StaticNode::Null) => Value::Null,
Self::Static(StaticNode::Bool(b)) => Value::Bool(b),
Self::Static(StaticNode::I64(n)) => Value::Number(n.into()),
#[cfg(feature = "128bit")] Self::Static(StaticNode::I128(n)) => Value::Number(
i64::try_from(n)
.map_err(|_| SerdeConversionError::NumberOutOfBounds)?
.into(),
),
Self::Static(StaticNode::U64(n)) => Value::Number(n.into()),
#[cfg(feature = "128bit")] Self::Static(StaticNode::U128(n)) => Value::Number(
u64::try_from(n)
.map_err(|_| SerdeConversionError::NumberOutOfBounds)?
.into(),
),
Self::Static(StaticNode::F64(n)) => {
#[allow(clippy::useless_conversion)] if let Some(n) = serde_json::Number::from_f64(n.into()) {
Value::Number(n)
} else {
return Err(SerdeConversionError::NanOrInfinity);
}
}
Self::String(b) => Value::String(b),
Self::Array(a) => Value::Array(
a.into_iter()
.map(TryInto::try_into)
.collect::<ConvertResult<Vec<Value>>>()?,
),
Self::Object(o) => Value::Object(
o.into_iter()
.map(|(k, v)| Ok((k, v.try_into()?)))
.collect::<ConvertResult<serde_json::map::Map<String, Value>>>()?,
),
})
}
}
impl<'value> TryFrom<serde_json::Value> for BorrowedValue<'value> {
type Error = SerdeConversionError;
fn try_from(item: serde_json::Value) -> ConvertResult<Self> {
use serde_json::Value;
match item {
Value::Null => Ok(BorrowedValue::from(())),
Value::Bool(b) => Ok(BorrowedValue::from(b)),
Value::Number(b) => match (b.as_i64(), b.as_u64(), b.as_f64()) {
(Some(n), _, _) => Ok(Self::from(n)),
(_, Some(n), _) => Ok(Self::from(n)),
(_, _, Some(n)) => Ok(Self::from(n)),
_ => Err(SerdeConversionError::Oops),
},
Value::String(b) => Ok(Self::String(b.into())),
Value::Array(a) => a.into_iter().map(Self::try_from).collect(),
Value::Object(o) => o
.into_iter()
.map(|(k, v)| Ok((k, Self::try_from(v)?)))
.collect(),
}
}
}
impl<'value> TryInto<serde_json::Value> for BorrowedValue<'value> {
type Error = SerdeConversionError;
fn try_into(self) -> ConvertResult<serde_json::Value> {
use serde_json::Value;
Ok(match self {
BorrowedValue::Static(StaticNode::Null) => Value::Null,
BorrowedValue::Static(StaticNode::Bool(b)) => Value::Bool(b),
BorrowedValue::Static(StaticNode::I64(n)) => Value::Number(n.into()),
#[cfg(feature = "128bit")] BorrowedValue::Static(StaticNode::I128(n)) => Value::Number(
i64::try_from(n)
.map_err(|_| SerdeConversionError::NumberOutOfBounds)?
.into(),
),
BorrowedValue::Static(StaticNode::U64(n)) => Value::Number(n.into()),
#[cfg(feature = "128bit")] BorrowedValue::Static(StaticNode::U128(n)) => Value::Number(
u64::try_from(n)
.map_err(|_| SerdeConversionError::NumberOutOfBounds)?
.into(),
),
BorrowedValue::Static(StaticNode::F64(n)) => {
#[allow(clippy::useless_conversion)] if let Some(n) = serde_json::Number::from_f64(n.into()) {
Value::Number(n)
} else {
return Err(SerdeConversionError::NanOrInfinity);
}
}
BorrowedValue::String(b) => Value::String(b.to_string()),
BorrowedValue::Array(a) => Value::Array(
a.into_iter()
.map(TryInto::try_into)
.collect::<ConvertResult<Vec<Value>>>()?,
),
BorrowedValue::Object(o) => Value::Object(
o.into_iter()
.map(|(k, v)| Ok((k.to_string(), v.try_into()?)))
.collect::<ConvertResult<serde_json::map::Map<String, Value>>>()?,
),
})
}
}
#[cfg(test)]
mod test {
#![allow(clippy::unwrap_used)]
use crate::{
error::Error, json, BorrowedValue, Deserializer as SimdDeserializer, ErrorType, OwnedValue,
};
use float_cmp::assert_approx_eq;
use halfbrown::{hashmap, HashMap};
use serde::{Deserialize, Serialize};
use serde_json::{json as sjson, to_string as sto_string, Value as SerdeValue};
use std::collections::BTreeMap;
#[derive(Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
struct UnitStruct;
#[derive(Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
struct NewTypeStruct(u8);
#[derive(Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
struct TupleStruct(u8, u8);
#[derive(Debug, Serialize, Deserialize)]
struct TestStruct {
value: String,
}
#[derive(Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
struct TestStruct2 {
value: u8,
}
#[derive(Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
enum E {
NewTypeVariant(u8),
UnitVariant,
StructVariant { r: u8, g: u8, b: u8 },
StructVariant2 { r: u8, g: u8, b: u8 },
TupleVariant(u8, u8, u8),
}
#[derive(Debug, Serialize, Deserialize)]
struct TestPoint(f64, f64);
#[test]
fn convert_owned_value() {
let v: OwnedValue = json!({
"int": 42,
"int2": i64::MAX as u64 + 1,
"float": 7.2,
"neg-int": -23,
"string": "string",
"bytes": b"bytes",
"bool": true,
"null": null,
"array": [42, 7, -23, false, null, {"key": "value"}],
"object": {
"array": [42, 7, -23, false, null, {"key": "value"}],
},
"tuple": (122, -14, true, 13_i8, -14_i16, 'c', 22_u8, 23_u16, 24_u32, 25_u64, (), None as Option<i32>, Some(3.25_f32), b"bytes"),
"struct": TestStruct{value: "value".to_string()},
"test_struct": TestStruct2{value: 3},
"point": TestPoint(3., 4.),
"unit_variant": E::UnitVariant,
"new_type_variant": E::NewTypeVariant(3),
"struct_variant": E::StructVariant{r:0, g:0, b:0},
"tuple_variant": E::TupleVariant(3, 4, 5),
});
let s: SerdeValue = sjson!({
"int": 42,
"int2": i64::MAX as u64 + 1,
"float": 7.2,
"neg-int": -23,
"string": "string",
"bytes": b"bytes",
"bool": true,
"null": null,
"array": [42, 7, -23, false, null, {"key": "value"}],
"object": {
"array": [42, 7, -23, false, null, {"key": "value"}],
},
"tuple": (122, -14, true, 13_i8, -14_i16, 'c', 22_u8, 23_u16, 24_u32, 25_u64, (), None as Option<i32>, Some(3.25_f32), b"bytes"),
"struct": TestStruct{value: "value".to_string()},
"test_struct": TestStruct2{value: 3},
"point": TestPoint(3., 4.),
"unit_variant": E::UnitVariant,
"new_type_variant": E::NewTypeVariant(3),
"struct_variant": E::StructVariant{r:0, g:0, b:0},
"tuple_variant": E::TupleVariant(3, 4, 5),
});
let s_c: SerdeValue = v.clone().try_into().unwrap();
assert_eq!(s, s_c);
let v_c: OwnedValue = s.try_into().unwrap();
assert_eq!(v, v_c);
let mut v_ser = crate::serde::to_string(&v).unwrap();
let s_ser = serde_json::to_string(&v).unwrap();
assert_eq!(s_ser, v_ser);
let s_deser: OwnedValue = serde_json::from_str(&v_ser).unwrap();
assert_eq!(v, s_deser);
let v_deser: OwnedValue = unsafe { crate::serde::from_str(&mut v_ser).unwrap() };
assert_eq!(v, v_deser);
}
#[test]
fn convert_borrowed_value() {
let v: BorrowedValue = json!({
"int": 42,
"int2": i64::MAX as u64 + 1,
"float": 7.2,
"neg-int": -23,
"string": "string",
"bool": true,
"null": null,
"object": {
"array": [42, 7, -23, false, null, {"key": "value"}],
},
"tuple": (122, -14, true, 13_i8, -14_i16, 'c', 22_u8, 23_u16, 24_u32, 25_u64, (), None as Option<i32>, Some(3.25_f32), b"bytes"),
"unit_struct": UnitStruct,
"new_type_struct": NewTypeStruct(3),
"tuple_struct": TupleStruct(3, 4),
"struct": TestStruct{value: "value".to_string()},
"test_struct": TestStruct2{value: 3},
"point": TestPoint(3., 4.),
"unit_variant": E::UnitVariant,
"new_type_variant": E::NewTypeVariant(3),
"struct_variant": E::StructVariant{r:0, g:0, b:0},
"tuple_variant": E::TupleVariant(3, 4, 5),
})
.into();
let s: SerdeValue = sjson!({
"int": 42,
"int2": i64::MAX as u64 + 1,
"float": 7.2,
"neg-int": -23,
"string": "string",
"bool": true,
"null": null,
"object": {
"array": [42, 7, -23, false, null, {"key": "value"}],
},
"tuple": (122, -14, true, 13_i8, -14_i16, 'c', 22_u8, 23_u16, 24_u32, 25_u64, (), None as Option<i32>, Some(3.25_f32), b"bytes"),
"unit_struct": UnitStruct,
"new_type_struct": NewTypeStruct(3),
"tuple_struct": TupleStruct(3, 4),
"struct": TestStruct{value: "value".to_string()},
"test_struct": TestStruct2{value: 3},
"point": TestPoint(3., 4.),
"unit_variant": E::UnitVariant,
"new_type_variant": E::NewTypeVariant(3),
"struct_variant": E::StructVariant{r:0, g:0, b:0},
"tuple_variant": E::TupleVariant(3, 4, 5),
});
let s_c: SerdeValue = v.clone().try_into().unwrap();
assert_eq!(s, s_c);
let v_c: BorrowedValue = s.try_into().unwrap();
assert_eq!(v, v_c);
}
#[test]
fn option_field_absent() {
#[derive(serde::Deserialize, Debug, PartialEq, Eq)]
pub struct Person {
pub name: String,
pub middle_name: Option<String>,
pub friends: Vec<String>,
}
let mut raw_json = r#"{"name":"bob","friends":[]}"#.to_string();
let result: Result<Person, _> = super::from_slice(unsafe { raw_json.as_bytes_mut() });
assert_eq!(
result,
Ok(Person {
name: "bob".to_string(),
middle_name: None,
friends: vec![],
})
);
}
#[test]
fn option_field_present() {
#[derive(serde::Deserialize, Debug, PartialEq, Eq)]
pub struct Person {
pub name: String,
pub middle_name: Option<String>,
pub friends: Vec<String>,
}
let mut raw_json = r#"{"name":"bob","middle_name": "frank", "friends":[]}"#.to_string();
let result: Result<Person, _> = super::from_slice(unsafe { raw_json.as_bytes_mut() });
assert_eq!(
result,
Ok(Person {
name: "bob".to_string(),
middle_name: Some("frank".to_string()),
friends: vec![],
})
);
}
#[test]
fn convert_enum() {
#[allow(dead_code)]
#[derive(serde::Deserialize, Debug, PartialEq, Eq)]
#[serde(tag = "type")]
enum Message {
Request { id: usize, method: String },
Response { id: String, result: String },
}
#[derive(serde::Deserialize, Debug, PartialEq, Eq)]
#[serde(tag = "type", content = "v")]
pub enum Color {
Red(String), Green { v: bool },
Blue,
}
#[derive(serde::Deserialize, Debug, PartialEq, Eq)]
#[serde(tag = "type")]
pub enum Color1 {
Red(String),
Green { v: bool }, Blue,
}
let mut raw_json = r#"{"type": "Request", "id": 1, "method": "..."}"#.to_string();
let result: Result<Message, _> = super::from_slice(unsafe { raw_json.as_bytes_mut() });
assert_eq!(
result,
Ok(Message::Request {
id: 1,
method: "...".to_string()
})
);
let mut raw_json = r#"{"type": "Response", "id": "1", "result": "..."}"#.to_string();
let result: Result<Message, _> = super::from_slice(unsafe { raw_json.as_bytes_mut() });
assert_eq!(
result,
Ok(Message::Response {
id: "1".to_string(),
result: "...".to_string()
})
);
let mut raw_json = r#"{"type": "Red", "v": "1"}"#.to_string();
let result: Result<Color, _> = super::from_slice(unsafe { raw_json.as_bytes_mut() });
assert_eq!(result, Ok(Color::Red("1".to_string())));
let mut raw_json = r#"{"type": "Blue"}"#.to_string();
let result: Result<Color, _> = super::from_slice(unsafe { raw_json.as_bytes_mut() });
assert_eq!(result, Ok(Color::Blue));
let mut raw_json = r#"{"type": "Green", "v": false}"#.to_string();
let result: Result<Color1, _> = super::from_slice(unsafe { raw_json.as_bytes_mut() });
assert_eq!(result, Ok(Color1::Green { v: false }));
let mut raw_json = r#"{"type": "Blue"}"#.to_string();
let result: Result<Color1, _> = super::from_slice(unsafe { raw_json.as_bytes_mut() });
assert_eq!(result, Ok(Color1::Blue));
}
#[derive(serde_ext::Deserialize)]
pub struct Foo {
#[allow(unused)]
bar: Bar,
}
#[derive(serde_ext::Deserialize)]
pub enum Bar {
A,
}
#[test]
fn object_simd_json() {
let mut json = br#"{"bar":"A"}"#.to_vec();
crate::from_slice::<Foo>(&mut json).unwrap();
}
#[test]
fn simple_simd_json() {
let mut json = br#""A""#.to_vec();
assert!(crate::from_slice::<Bar>(&mut json).is_ok());
}
#[test]
fn array_as_struct() {
#[derive(serde_ext::Deserialize)]
struct Point {
x: u64,
y: u64,
}
let mut json = b"[1,2]".to_vec();
let p: Point = serde_json::from_slice(&json).unwrap();
assert_eq!(p.x, 1);
assert_eq!(p.y, 2);
let p: Point = crate::from_slice(&mut json).unwrap();
assert_eq!(p.x, 1);
assert_eq!(p.y, 2);
}
#[test]
#[allow(clippy::cast_precision_loss)]
fn floats() {
#[derive(serde_ext::Deserialize)]
struct Point {
x: f64,
y: f64,
}
let mut json = br#"{"x":1.0,"y":2.0}"#.to_vec();
let p: Point = crate::from_slice(&mut json).unwrap();
assert_approx_eq!(f64, p.x, 1_f64);
assert_approx_eq!(f64, p.y, 2_f64);
let json = json!({"x":-1,"y":i64::MAX as u64 + 1});
let p: Point = unsafe { crate::from_str(&mut crate::to_string(&json).unwrap()).unwrap() };
assert_approx_eq!(f64, p.x, -1_f64);
assert_approx_eq!(f64, p.y, i64::MAX as f64 + 1.0);
}
#[test]
fn vectors() {
let input: Vec<UnitStruct> = vec![UnitStruct];
let mut v_str = crate::to_string(&input).unwrap();
assert_eq!(input, unsafe {
crate::from_str::<Vec<UnitStruct>>(&mut v_str).unwrap()
});
let input: Vec<()> = Vec::new();
let mut v_str = crate::to_string(&input).unwrap();
assert_eq!(input, unsafe {
crate::from_str::<Vec<()>>(&mut v_str).unwrap()
});
let input: Vec<Option<u8>> = vec![None, Some(3_u8)];
let mut v_str = crate::to_string(&input).unwrap();
dbg!(&v_str);
assert_eq!(input, unsafe {
crate::from_str::<Vec<Option<u8>>>(&mut v_str).unwrap()
});
let input: Vec<(i32, f32)> = vec![(3, 3.)];
let mut v_str = crate::to_string(&input).unwrap();
assert_eq!(input, unsafe {
crate::from_str::<Vec<(i32, f32)>>(&mut v_str).unwrap()
});
let input = vec![vec![3_u8]];
let mut v_str = crate::to_string(&input).unwrap();
assert_eq!(input, unsafe {
crate::from_str::<Vec<Vec<u8>>>(&mut v_str).unwrap()
});
let input: Vec<NewTypeStruct> = vec![NewTypeStruct(3_u8)];
let mut v_str = crate::to_string(&input).unwrap();
assert_eq!(input, unsafe {
crate::from_str::<Vec<NewTypeStruct>>(&mut v_str).unwrap()
});
let input: Vec<TupleStruct> = Vec::new();
let mut v_str = crate::to_string(&input).unwrap();
assert_eq!(input, unsafe {
crate::from_str::<Vec<TupleStruct>>(&mut v_str).unwrap()
});
let input = vec![TupleStruct(3, 3)];
let mut v_str = crate::to_string(&input).unwrap();
assert_eq!(input, unsafe {
crate::from_str::<Vec<TupleStruct>>(&mut v_str).unwrap()
});
let input = vec![E::NewTypeVariant(3)];
let mut _v_str = crate::to_string(&input).unwrap();
let input = vec![E::UnitVariant, E::UnitVariant];
let mut _v_str = crate::to_string(&input).unwrap();
let input = vec![
E::StructVariant { r: 0, g: 0, b: 0 },
E::StructVariant { r: 0, g: 0, b: 1 },
];
let mut _v_str = crate::to_string(&input).unwrap();
let input = vec![E::TupleVariant(0, 0, 0), E::TupleVariant(1, 1, 1)];
let mut _v_str = crate::to_string(&input).unwrap();
}
macro_rules! parsing_error {
($input:expr; $type:ty => $err:ident) => {{
let mut json_str = $input.to_string();
assert_eq!(
unsafe { crate::from_str::<$type>(&mut json_str) },
Err(SimdDeserializer::error(ErrorType::$err))
);
}};
}
#[test]
fn test_parsing_errors() {
parsing_error!(r#""3""#; i8 => ExpectedSigned);
parsing_error!(r#""3""#; i16 => ExpectedSigned);
parsing_error!(r#""3""#; i32 => ExpectedSigned);
parsing_error!(r#""3""#; i64 => ExpectedSigned);
parsing_error!(r#""3""#; u8 => ExpectedUnsigned);
parsing_error!(r#""3""#; u16 => ExpectedUnsigned);
parsing_error!(r#""3""#; u32 => ExpectedUnsigned);
parsing_error!(r#""3""#; u64 => ExpectedUnsigned);
parsing_error!("null"; i8 => ExpectedSigned);
parsing_error!("null"; i16 => ExpectedSigned);
parsing_error!("null"; i32 => ExpectedSigned);
parsing_error!("null"; i64 => ExpectedSigned);
parsing_error!("-3"; u8 => ExpectedUnsigned);
parsing_error!("-3"; u16 => ExpectedUnsigned);
parsing_error!("-3"; u32 => ExpectedUnsigned);
parsing_error!("-3"; u64 => ExpectedUnsigned);
parsing_error!("-3"; String => ExpectedString);
#[cfg(feature = "128bit")]
{
parsing_error!(r#""3""#; i128 => ExpectedSigned);
parsing_error!(r#""3""#; u128 => ExpectedUnsigned);
parsing_error!("null"; i128 => ExpectedSigned);
parsing_error!("-3"; u128 => ExpectedUnsigned);
}
parsing_error!("null"; f64 => ExpectedFloat);
}
macro_rules! ser_deser_map {
($key:expr => $value:expr, $type:ty) => {
let input = hashmap! {$key => $value};
let mut m_str = crate::to_string(&input).unwrap();
assert_eq!(m_str, sto_string(&input).unwrap());
assert_eq!(input, unsafe {
crate::from_str::<$type>(&mut m_str).unwrap()
});
};
}
#[test]
fn maps() {
let key_error = Err(Error::generic(ErrorType::KeyMustBeAString));
assert_eq!(crate::to_string(&hashmap! {b"1234" => 3_i8}), key_error);
assert_eq!(crate::to_string(&hashmap! {true => 3_i8}), key_error);
assert_eq!(
crate::to_string(&hashmap! {[3_u8, 4_u8] => 3_i8}),
key_error
);
assert_eq!(
crate::to_string(&hashmap! {None as Option<u8> => 3_i8}),
key_error
);
assert_eq!(crate::to_string(&hashmap! {Some(3_u8) => 3_i8}), key_error);
assert_eq!(crate::to_string(&hashmap! {() => 3_i8}), key_error);
assert_eq!(crate::to_string(&hashmap! {(3, 4) => 3_i8}), key_error);
assert_eq!(crate::to_string(&hashmap! {[3, 4] => 3_i8}), key_error);
assert_eq!(crate::to_string(&hashmap! {UnitStruct => 3_i8}), key_error);
assert_eq!(
crate::to_string(&hashmap! {TupleStruct(3, 3) => 3_i8}),
key_error
);
assert_eq!(
crate::to_string(&hashmap! {TestStruct2{value:3} => 3_i8}),
key_error
);
assert_eq!(
crate::to_string(&hashmap! {E::NewTypeVariant(0) => 3_i8}),
key_error
);
assert_eq!(
crate::to_string(&hashmap! {E::StructVariant{r:0, g:0, b:0} => 3_i8}),
key_error
);
assert_eq!(
crate::to_string(&hashmap! {E::StructVariant2{r:0, g:0, b:0} => 3_i8}),
key_error
);
assert_eq!(
crate::to_string(&hashmap! {E::TupleVariant(0, 0, 0) => 3_i8}),
key_error
);
assert_eq!(
crate::to_string(&hashmap! {vec![0, 0, 0] => 3_i8}),
key_error
);
let mut m = BTreeMap::new();
m.insert("value", 3_u8);
assert_eq!(crate::to_string(&hashmap! {m => 3_i8}), key_error);
let mut input = std::collections::HashMap::new();
input.insert(128_u8, "3");
let mut input_str = crate::to_string(&input).unwrap();
assert_eq!(input_str, sto_string(&input).unwrap());
assert_eq!(
unsafe { crate::from_str::<std::collections::HashMap<u8, i8>>(&mut input_str) },
Err(Error::new(0, None, ErrorType::ExpectedSigned))
);
assert_eq!(
unsafe { crate::from_str::<std::collections::HashMap<i8, String>>(&mut input_str) },
Err(Error::new(0, None, ErrorType::InvalidNumber))
);
assert_eq!(
unsafe { crate::from_str::<HashMap<Option<u8>, String>>(&mut input_str) },
Ok(hashmap! {Some(128_u8) => "3".to_string()})
);
ser_deser_map!('c' => 3_i8, HashMap<char, i8>);
ser_deser_map!(3_i8 => 3_i8, HashMap<i8, i8>);
ser_deser_map!(3_i16 => 3_i8, HashMap<i16, i8>);
ser_deser_map!(3_i32 => 3_i8, HashMap<i32, i8>);
ser_deser_map!(3_i64 => 3_i8, HashMap<i64, i8>);
ser_deser_map!(3_u8 => 3_i8, HashMap<u8, i8>);
ser_deser_map!(3_u16 => 3_i8, HashMap<u16, i8>);
ser_deser_map!(3_u32 => 3_i8, HashMap<u32, i8>);
ser_deser_map!(3_u64 => 3_i8, HashMap<u64, i8>);
#[cfg(feature = "128bit")]
{
ser_deser_map!(3_i128 => 3_i8, HashMap<i128, i8>);
ser_deser_map!(3_u128 => 3_i8, HashMap<u128, i8>);
}
ser_deser_map!(NewTypeStruct(1) => 3_i8, HashMap<NewTypeStruct, i8>);
ser_deser_map!(E::UnitVariant => 3_i8, HashMap<E, i8>);
}
}