Coverage Report

Created: 2026-10-28 07:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/simd-json-0.17.0/src/value.rs
Line
Count
Source
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
54
pub mod borrowed;
55
/// Owned, lifetimeless version of the value for times when lifetimes are to be avoided
56
pub mod owned;
57
/// Tape implementation
58
pub mod tape;
59
60
pub mod lazy;
61
62
pub 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
};
66
pub 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
};
70
use crate::{Buffers, Deserializer, Result};
71
use halfbrown::HashMap;
72
use std::hash::Hash;
73
use std::marker::PhantomData;
74
use tape::Node;
75
pub use value_trait::*;
76
77
/// Hasher used for objects
78
#[cfg(feature = "known-key")]
79
pub type ObjectHasher = crate::known_key::NotSoRandomState;
80
/// Hasher used for objects
81
#[cfg(not(feature = "known-key"))]
82
pub 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.
93
0
pub fn deserialize<'de, Value, Key>(s: &'de mut [u8]) -> Result<Value>
94
0
where
95
0
    Value: ValueBuilder<'de> + From<Vec<Value>> + From<HashMap<Key, Value, ObjectHasher>> + 'de,
96
0
    Key: Hash + Eq + From<&'de str>,
97
{
98
0
    match Deserializer::from_slice(s) {
99
0
        Ok(de) => Ok(ValueDeserializer::from_deserializer(de).parse()),
100
0
        Err(e) => Err(e),
101
    }
102
0
}
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.
115
0
pub fn deserialize_with_buffers<'de, Value, Key>(
116
0
    s: &'de mut [u8],
117
0
    buffers: &mut Buffers,
118
0
) -> Result<Value>
119
0
where
120
0
    Value: ValueBuilder<'de> + From<Vec<Value>> + From<HashMap<Key, Value, ObjectHasher>> + 'de,
121
0
    Key: Hash + Eq + From<&'de str>,
122
{
123
0
    match Deserializer::from_slice_with_buffers(s, buffers) {
124
0
        Ok(de) => Ok(ValueDeserializer::from_deserializer(de).parse()),
125
0
        Err(e) => Err(e),
126
    }
127
0
}
128
129
struct ValueDeserializer<'de, Value, Key>
130
where
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
138
impl<'de, Value, Key> ValueDeserializer<'de, Value, Key>
139
where
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
0
    pub fn from_deserializer(de: Deserializer<'de>) -> Self {
148
0
        Self {
149
0
            de,
150
0
            _marker: PhantomData,
151
0
        }
152
0
    }
153
154
    #[cfg_attr(not(feature = "no-inline"), inline)]
155
0
    pub fn parse(&mut self) -> Value {
156
0
        match unsafe { self.de.next_() } {
157
0
            Node::Static(s) => Value::from(s),
158
0
            Node::String(s) => Value::from(s),
159
0
            Node::Array { len, count: _ } => self.parse_array(len),
160
0
            Node::Object { len, count: _ } => self.parse_map(len),
161
        }
162
0
    }
163
164
    #[cfg_attr(not(feature = "no-inline"), inline)]
165
0
    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
0
        let mut res: Vec<Value> = Vec::with_capacity(len);
170
0
        let res_ptr = res.as_mut_ptr();
171
        unsafe {
172
0
            for i in 0..len {
173
0
                res_ptr.add(i).write(self.parse());
174
0
            }
175
0
            res.set_len(len);
176
        }
177
0
        Value::from(res)
178
0
    }
179
180
    #[cfg_attr(not(feature = "no-inline"), inline)]
181
0
    fn parse_map(&mut self, len: usize) -> Value {
182
0
        let mut res: HashMap<Key, Value, ObjectHasher> =
183
0
            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
0
        for _ in 0..len {
188
0
            if let Node::String(key) = unsafe { self.de.next_() } {
189
0
                #[cfg(not(feature = "value-no-dup-keys"))]
190
0
                unsafe {
191
0
                    res.insert_nocheck(key.into(), self.parse());
192
0
                };
193
0
                #[cfg(feature = "value-no-dup-keys")]
194
0
                res.insert(key.into(), self.parse());
195
0
            } else {
196
0
                unreachable!("parse_map: key needs to be a string");
197
            }
198
        }
199
0
        Value::from(res)
200
0
    }
201
}