mod de;
mod value;
pub use self::value::*;
use crate::numberparse::Number;
use crate::{stry, Deserializer, Error, ErrorType, Result};
use crate::{BorrowedValue, OwnedValue};
use serde_ext::Deserialize;
use std::convert::{TryFrom, TryInto};
use std::fmt;
type ConvertResult<T> = std::result::Result<T, SerdeConversionError>;
#[derive(Debug)]
pub enum SerdeConversionError {
NanOrInfinity,
IntegerTooLarge,
Oops,
}
impl std::fmt::Display for SerdeConversionError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use SerdeConversionError::*;
match self {
NanOrInfinity => write!(f, "JSON can not represent NAN or Infinity values"),
IntegerTooLarge => write!(f, "Integer value is too large to fit in a i64"),
Oops => write!(
f,
"Unreachable code is reachable, oops - please open a bug with simdjson-rs"
),
}
}
}
impl std::error::Error for SerdeConversionError {}
#[cfg_attr(not(feature = "no-inline"), inline(always))]
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(always))]
pub 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)
}
impl std::error::Error for Error {}
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(always))]
fn next(&mut self) -> Result<u8> {
unsafe {
self.idx += 1;
if let Some(idx) = self.structural_indexes.get(self.idx) {
self.iidx = *idx as usize;
let r = *self.input.get_unchecked(self.iidx);
Ok(r)
} else {
Err(self.error(ErrorType::Syntax))
}
}
}
#[cfg_attr(not(feature = "no-inline"), inline(always))]
fn peek(&self) -> Result<u8> {
if let Some(idx) = self.structural_indexes.get(self.idx + 1) {
unsafe { Ok(*self.input.get_unchecked(*idx as usize)) }
} else {
Err(self.error(ErrorType::UnexpectedEnd))
}
}
#[cfg_attr(not(feature = "no-inline"), inline(always))]
fn parse_signed(&mut self) -> Result<i64> {
match self.next_() {
b'-' => match stry!(self.parse_number(true)) {
Number::I64(n) => Ok(n),
_ => Err(self.error(ErrorType::ExpectedSigned)),
},
b'0'..=b'9' => match stry!(self.parse_number(false)) {
Number::I64(n) => Ok(n),
_ => Err(self.error(ErrorType::ExpectedSigned)),
},
_ => Err(self.error(ErrorType::ExpectedSigned)),
}
}
#[cfg_attr(not(feature = "no-inline"), inline(always))]
fn parse_unsigned(&mut self) -> Result<u64> {
#[allow(clippy::cast_sign_loss)]
match self.next_() {
b'0'..=b'9' => match stry!(self.parse_number(false)) {
Number::I64(n) => Ok(n as u64),
_ => Err(self.error(ErrorType::ExpectedUnsigned)),
},
_ => Err(self.error(ErrorType::ExpectedUnsigned)),
}
}
#[cfg_attr(not(feature = "no-inline"), inline(always))]
fn parse_double(&mut self) -> Result<f64> {
#[allow(clippy::cast_possible_wrap, clippy::cast_precision_loss)]
match self.next_() {
b'-' => match stry!(self.parse_number(true)) {
Number::F64(n) => Ok(n),
Number::I64(n) => Ok(n as f64),
},
b'0'..=b'9' => match stry!(self.parse_number(false)) {
Number::F64(n) => Ok(n),
Number::I64(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::Null,
Value::Bool(b) => Self::Bool(b),
Value::Number(b) => {
if let Some(n) = b.as_i64() {
Self::I64(n)
} else if let Some(n) = b.as_u64() {
if n > i64::max_value() as u64 {
return Err(SerdeConversionError::IntegerTooLarge);
}
#[allow(clippy::cast_possible_wrap)]
Self::I64(n as i64)
} else if let Some(n) = b.as_f64() {
Self::F64(n)
} else {
return Err(SerdeConversionError::Oops);
}
}
Value::String(b) => Self::String(b),
Value::Array(a) => Self::Array(
a.into_iter()
.map(|v| v.try_into())
.collect::<ConvertResult<Vec<Self>>>()?,
),
Value::Object(o) => Self::Object(
o.into_iter()
.map(|(k, v)| Ok((k, v.try_into()?)))
.collect::<ConvertResult<crate::value::owned::Object>>()?,
),
})
}
}
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::Null => Value::Null,
Self::Bool(b) => Value::Bool(b),
Self::I64(n) => Value::Number(n.into()),
Self::F64(n) => {
if let Some(n) = serde_json::Number::from_f64(n) {
Value::Number(n)
} else {
return Err(SerdeConversionError::NanOrInfinity);
}
}
Self::String(b) => Value::String(b.to_string()),
Self::Array(a) => Value::Array(
a.into_iter()
.map(|v| v.try_into())
.collect::<ConvertResult<Vec<Value>>>()?,
),
Self::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>>>()?,
),
})
}
}
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;
Ok(match item {
Value::Null => BorrowedValue::Null,
Value::Bool(b) => BorrowedValue::Bool(b),
Value::Number(b) => {
if let Some(n) = b.as_i64() {
BorrowedValue::I64(n)
} else if let Some(n) = b.as_u64() {
if n > i64::max_value() as u64 {
return Err(SerdeConversionError::IntegerTooLarge);
}
#[allow(clippy::cast_possible_wrap)]
BorrowedValue::I64(n as i64)
} else if let Some(n) = b.as_f64() {
BorrowedValue::F64(n)
} else {
return Err(SerdeConversionError::Oops);
}
}
Value::String(b) => BorrowedValue::String(b.into()),
Value::Array(a) => BorrowedValue::Array(
a.into_iter()
.map(|v| v.try_into())
.collect::<ConvertResult<Vec<BorrowedValue>>>()?,
),
Value::Object(o) => BorrowedValue::Object(
o.into_iter()
.map(|(k, v)| Ok((k.into(), v.try_into()?)))
.collect::<ConvertResult<crate::value::borrowed::Object>>()?,
),
})
}
}
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::Null => Value::Null,
BorrowedValue::Bool(b) => Value::Bool(b),
BorrowedValue::I64(n) => Value::Number(n.into()),
BorrowedValue::F64(n) => {
if let Some(n) = serde_json::Number::from_f64(n) {
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(|v| v.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::result_unwrap_used)]
use crate::{json, BorrowedValue, OwnedValue};
use serde_json::{json as sjson, Value as SerdeValue};
use std::convert::TryInto;
#[test]
fn convert_owned_value() {
let v: OwnedValue = json!({
"int": 42,
"float": 7.2,
"neg-int": -23,
"string": "string",
"bool": true,
"null": null,
"object": {
"array": [42, 7, -23, false, null, {"key": "value"}],
}
});
let s: SerdeValue = sjson!({
"int": 42,
"float": 7.2,
"neg-int": -23,
"string": "string",
"bool": true,
"null": null,
"object": {
"array": [42, 7, -23, false, null, {"key": "value"}],
}
});
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);
}
#[test]
fn convert_borrowed_value() {
let v: BorrowedValue = json!({
"int": 42,
"float": 7.2,
"neg-int": -23,
"string": "string",
"bool": true,
"null": null,
"object": {
"array": [42, 7, -23, false, null, {"key": "value"}],
}
})
.into();
let s: SerdeValue = sjson!({
"int": 42,
"float": 7.2,
"neg-int": -23,
"string": "string",
"bool": true,
"null": null,
"object": {
"array": [42, 7, -23, false, null, {"key": "value"}],
}
});
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);
}
}