#![warn(unused_extern_crates)]
#![deny(
clippy::all,
clippy::unwrap_used,
clippy::unnecessary_unwrap,
clippy::pedantic,
clippy::mod_module_files
)]
#![deny(missing_docs)]
#![allow(clippy::module_name_repetitions, clippy::inline_always)]
#![allow(clippy::trait_duplication_in_bounds)]
#![allow(clippy::type_repetition_in_bounds)]
extern crate serde as serde_ext;
mod error;
mod known_key;
mod macros;
pub mod prelude;
mod serde;
pub mod utils;
pub mod value;
pub use crate::serde::structurize;
pub use error::*;
pub use known_key::{Error as KnownKeyError, KnownKey};
pub use simd_json::{
json, json_typed, Buffers, ObjectHasher, StaticNode, TryTypeError, ValueBuilder, ValueType,
};
pub use value::{parse_to_value, parse_to_value_with_buffers, to_value, Object, Value};
use beef::Cow;
use simd_json::{prelude::*, Node};
use simd_json_derive::{Deserialize, Serialize, Tape};
pub const VEC_LIMIT_UPPER: usize = 32;
impl<'value> Serialize for Value<'value> {
fn json_write<W>(&self, writer: &mut W) -> std::io::Result<()>
where
W: std::io::Write,
{
self.write(writer)
}
}
impl<'value> ValueIntoString for Value<'value> {
type String = Cow<'value, str>;
fn into_string(self) -> Option<Cow<'value, str>> {
match self {
Self::String(s) => Some(s),
_ => None,
}
}
}
impl<'value> ValueIntoContainer for Value<'value> {
type Array = Vec<Value<'value>>;
type Object = Object<'value>;
fn into_array(self) -> Option<Vec<Value<'value>>> {
match self {
Self::Array(a) => Some(a),
_ => None,
}
}
fn into_object(self) -> Option<Object<'value>> {
match self {
Self::Object(o) => Some(*o),
_ => None,
}
}
}
struct ValueDeser<'input, 'tape>(&'tape mut Tape<'input>);
impl<'input, 'tape> ValueDeser<'input, 'tape> {
#[inline(always)]
fn parse(&mut self) -> simd_json::Result<Value<'input>> {
match self.0.next() {
Some(Node::Static(s)) => Ok(Value::Static(s)),
Some(Node::String(s)) => Ok(Value::from(s)),
Some(Node::Array { len, .. }) => Ok(self.parse_array(len)),
Some(Node::Object { len, .. }) => Ok(self.parse_map(len)),
None => Err(simd_json::Error::generic(simd_json::ErrorType::Eof)),
}
}
#[inline(always)]
#[allow(clippy::unwrap_used, clippy::uninit_vec)]
fn parse_array(&mut self, len: usize) -> Value<'input> {
let mut res = Vec::with_capacity(len);
unsafe {
res.set_len(len);
for i in 0..len {
std::ptr::write(res.get_unchecked_mut(i), self.parse().unwrap());
}
}
Value::Array(res)
}
#[inline(always)]
#[allow(clippy::unwrap_used)]
fn parse_map(&mut self, len: usize) -> Value<'input> {
let mut res = Object::with_capacity_and_hasher(len, ObjectHasher::default());
for _ in 0..len {
if let Node::String(key) = self.0.next().unwrap() {
res.insert_nocheck(key.into(), self.parse().unwrap());
} else {
unreachable!();
}
}
Value::from(res)
}
}
impl<'input> Deserialize<'input> for Value<'input> {
fn from_tape(tape: &mut crate::Tape<'input>) -> simd_json::Result<Self>
where
Self: Sized + 'input,
{
ValueDeser(tape).parse()
}
}
#[cfg(test)]
mod test {
#![allow(clippy::unwrap_used)]
use super::*;
use simd_json_derive::{Deserialize, Serialize};
#[test]
fn parse() {
#[derive(Deserialize, Serialize)]
struct TestStruct<'test> {
value: Value<'test>,
}
let mut v = br#"{"value":{"array":[1,1.0,true,null],"string":"badger"}}"#.to_vec();
let orig = String::from_utf8(v.clone()).unwrap();
let s = TestStruct::from_slice(&mut v).unwrap();
assert_eq!(
s.value,
literal!({"array": [1, 1.0,true,null], "string": "badger"})
);
assert_eq!(s.json_string().unwrap(), orig);
}
}