simd_json/
value.rs

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