1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
/// This module holds the two dom implementations we use. We distinguish between
/// owned and borrowed. The difference being is that the borrowed value will
/// use `&str` as its string type, referencing the input, while owned will
/// allocate a new String for each value.
///
/// Note that since json strings allow for for escape sequences the borrowed
/// value does not implement zero copy parsing, it does however not allocate
/// new memory for strings.
///
/// This differs notably from serde's zero copy implementation as, unlike serde,
/// we do not require prior knowledge about string content to to take advantage
/// of it.
///
/// ## Usage
/// The value trait is meant to simplify interacting with DOM values, for both
/// creation as well as mutation and inspection.
///
/// Objects can be treated as hashmap's for the most part
/// ```rust
/// use simd_json::{OwnedValue as Value, prelude::*};
/// let mut v = Value::object();
/// v.insert("key", 42);
/// assert_eq!(v.get("key").unwrap(), &42);
/// assert_eq!(v["key"], &42);
/// assert_eq!(v.remove("key").unwrap().unwrap(), 42);
/// assert_eq!(v.get("key"), None);
/// ```
///
/// Arrays can be treated as vectors for the most part
///
/// ```rust
/// use simd_json::{OwnedValue as Value, prelude::*};
/// let mut v = Value::array();
/// v.push("zero");
/// v.push(1);
/// assert_eq!(v[0], &"zero");
/// assert_eq!(v.get_idx(1).unwrap(), &1);
/// assert_eq!(v.pop().unwrap().unwrap(), 1);
/// assert_eq!(v.pop().unwrap().unwrap(), "zero");
/// assert_eq!(v.pop().unwrap(), None);
/// ```
///
/// Nested changes are also possible:
/// ```rust
/// use simd_json::{OwnedValue as Value, prelude::*};
/// let mut o = Value::object();
/// o.insert("key", Value::array());
/// o["key"].push(Value::object());
/// o["key"][0].insert("other", "value");
/// assert_eq!(o.encode(), r#"{"key":[{"other":"value"}]}"#);
/// ```
/// Borrowed values, using Cow's for strings using in situ parsing strategies wherever possible
pub mod borrowed;
/// Owned, lifetimeless version of the value for times when lifetimes are to be avoided
pub mod owned;
/// Tape implementation
pub mod tape;
pub use self::borrowed::{
to_value as to_borrowed_value, to_value_with_buffers as to_borrowed_value_with_buffers,
Value as BorrowedValue,
};
pub use self::owned::{
to_value as to_owned_value, to_value_with_buffers as to_owned_value_with_buffers,
Value as OwnedValue,
};
use crate::{Deserializer, Result};
use halfbrown::HashMap;
use std::hash::Hash;
use std::marker::PhantomData;
use tape::Node;
pub use value_trait::*;
/// Parses a slice of bytes into a Value dom. This function will
/// rewrite the slice to de-escape strings.
/// As we reference parts of the input slice the resulting dom
/// has the same lifetime as the slice it was created from.
///
/// # Errors
///
/// Will return `Err` if `s` is invalid JSON.
pub fn deserialize<'de, Value, Key>(s: &'de mut [u8]) -> Result<Value>
where
Value: Builder<'de> + From<Vec<Value>> + From<HashMap<Key, Value>> + 'de,
Key: Hash + Eq + From<&'de str>,
{
match Deserializer::from_slice(s) {
Ok(de) => Ok(ValueDeserializer::from_deserializer(de).parse()),
Err(e) => Err(e),
}
}
struct ValueDeserializer<'de, Value, Key>
where
Value: Builder<'de> + From<Vec<Value>> + From<HashMap<Key, Value>> + 'de,
Key: Hash + Eq + From<&'de str>,
{
de: Deserializer<'de>,
_marker: PhantomData<(Value, Key)>,
}
impl<'de, Value, Key> ValueDeserializer<'de, Value, Key>
where
Value: Builder<'de> + From<&'de str> + From<Vec<Value>> + From<HashMap<Key, Value>> + 'de,
Key: Hash + Eq + From<&'de str>,
{
pub fn from_deserializer(de: Deserializer<'de>) -> Self {
Self {
de,
_marker: PhantomData::default(),
}
}
#[cfg_attr(not(feature = "no-inline"), inline(always))]
pub fn parse(&mut self) -> Value {
match unsafe { self.de.next_() } {
Node::Static(s) => Value::from(s),
Node::String(s) => Value::from(s),
Node::Array(len, _) => self.parse_array(len),
Node::Object(len, _) => self.parse_map(len),
}
}
#[cfg_attr(not(feature = "no-inline"), inline(always))]
fn parse_array(&mut self, len: usize) -> Value {
// Rust doesn't optimize the normal loop away here
// so we write our own avoiding the length
// checks during push
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());
}
}
Value::from(res)
}
#[cfg_attr(not(feature = "no-inline"), inline(always))]
fn parse_map(&mut self, len: usize) -> Value {
let mut res: HashMap<Key, Value> = HashMap::with_capacity(len);
// Since we checked if it's empty we know that we at least have one
// element so we eat this
for _ in 0..len {
if let Node::String(key) = unsafe { self.de.next_() } {
res.insert_nocheck(key.into(), self.parse());
} else {
unreachable!();
}
}
Value::from(res)
}
}