qubit_json/value/safe_json_value.rs
1// =============================================================================
2// Copyright (c) 2026 Haixing Hu.
3//
4// SPDX-License-Identifier: Apache-2.0
5//
6// Licensed under the Apache License, Version 2.0.
7// =============================================================================
8//! A JSON value whose owned-tree operations use explicit work stacks.
9
10#[cfg(test)]
11use std::cell::Cell;
12use std::fmt;
13use std::mem::ManuallyDrop;
14
15use serde_json::Value;
16
17use super::internal::JsonValueCopyFrame;
18use super::internal::SafeValueBuilder;
19use super::internal::debug_value;
20use super::internal::values_equal;
21
22/// An owned JSON value whose clone, equality, debug formatting, and drop use
23/// protected tree operations.
24///
25/// This protection does not extend to arbitrary recursive operations on a
26/// borrowed or extracted [`serde_json::Value`]. [`as_value`](Self::as_value)
27/// returns a shared borrow tied to this owner; callers remain responsible for
28/// the stack behavior of recursive operations they invoke through that borrow.
29/// [`into_value`](Self::into_value) gives up the protected owner and transfers
30/// responsibility for the resulting tree's lifetime to the caller.
31///
32/// Serde interoperability uses `stacker` and still depends on the concrete
33/// serializer or deserializer, which may impose its own recursion limits. The
34/// owner does not enforce an exact heap-memory limit.
35/// Its deserializer accepts `i128` and `u128` events when their values fit the
36/// JSON integer range, maps `None` to `null`, and transparently unwraps `Some`
37/// and newtype payloads.
38///
39/// The tree protection and the meaning of values produced by `Deserialize`
40/// are separate concerns. A direct Serde bridge cannot identify whether a
41/// map-shaped event came from an ordinary object or an upstream deserializer's
42/// private number representation. With `serde_json`'s `arbitrary_precision`
43/// feature, number shapes produced by that bridge can therefore differ from
44/// those produced without the feature. When decoding JSON text and preserving
45/// its numeric meaning is important, use [`JsonDecoder::decode_value_str`]
46/// (or the corresponding byte and reader methods) instead.
47///
48/// Direct deserialization also rejects duplicate object keys after decoding
49/// their string escapes. It does not normalize Unicode. In contrast,
50/// [`Self::new`] takes an existing [`serde_json::Value`] as-is: if an upstream
51/// deserializer has already merged duplicate keys, this type cannot recover
52/// them.
53///
54/// [`JsonDecoder::decode_value_str`]: crate::decode::JsonDecoder::decode_value_str
55///
56/// # Examples
57///
58/// ```
59/// use qubit_json::value::SafeJsonValue;
60/// use serde_json::json;
61///
62/// let owner = SafeJsonValue::new(json!({"items": [1, 2]}));
63/// let copy = owner.clone();
64/// assert_eq!(owner, copy);
65/// assert_eq!(owner.as_value()["items"][0], 1);
66/// let shallow_raw = copy.into_value();
67/// assert!(shallow_raw.is_object());
68/// assert!(serde_json::from_str::<SafeJsonValue>(r#"{"a":1,"\u0061":2}"#).is_err());
69/// ```
70pub struct SafeJsonValue {
71 /// The root is optional so protected operations can take it before cleanup.
72 root: Option<Value>,
73}
74
75impl SafeJsonValue {
76 /// Takes ownership of a JSON tree without traversing it or admitting it to
77 /// a budget.
78 ///
79 /// # Parameters
80 ///
81 /// * `value` - JSON tree whose ownership is transferred to this owner.
82 ///
83 /// # Returns
84 ///
85 /// An owner for the supplied tree. Construction does not copy or allocate.
86 #[must_use]
87 #[inline]
88 pub fn new(value: Value) -> Self {
89 Self { root: Some(value) }
90 }
91
92 /// Copies an entire JSON tree using an explicit traversal stack.
93 ///
94 /// This operation allocates work-stack storage and result storage for the
95 /// copied tree; it does not impose a budget on the source tree.
96 ///
97 /// # Parameters
98 ///
99 /// * `value` - JSON tree to copy.
100 ///
101 /// # Returns
102 ///
103 /// An independently owned copy of the complete tree.
104 #[must_use]
105 pub fn copy_from(value: &Value) -> Self {
106 #[cfg(test)]
107 COPY_FROM_CALLS.with(|calls| calls.set(calls.get() + 1));
108
109 let mut frames: Vec<JsonValueCopyFrame<'_>> = Vec::new();
110 let mut builders: Vec<SafeValueBuilder> = Vec::new();
111 let mut next_value = Some(value);
112 let mut completed_value = None;
113 loop {
114 if let Some(source) = next_value.take() {
115 match source {
116 Value::Array(values) => {
117 let mut frame = JsonValueCopyFrame::array(values);
118 if let Some(child) = frame.next_value() {
119 if frame.has_remaining() {
120 frame.start_builder(&mut builders);
121 }
122 frames.push(frame);
123 next_value = Some(child);
124 } else {
125 completed_value = Some(frame.finish_empty());
126 }
127 }
128 Value::Object(values) => {
129 let mut frame = JsonValueCopyFrame::object(values);
130 if let Some(child) = frame.next_value() {
131 if frame.has_remaining() {
132 frame.start_builder(&mut builders);
133 }
134 frames.push(frame);
135 next_value = Some(child);
136 } else {
137 completed_value = Some(frame.finish_empty());
138 }
139 }
140 leaf => completed_value = Some(Self::new(leaf.clone())),
141 }
142 }
143
144 if let Some(child) = completed_value.take() {
145 let Some(parent) = frames.last_mut() else {
146 return child;
147 };
148 if let Some(completed_parent) = parent.push_child(child, &mut builders) {
149 frames.pop().expect("a completed child has a parent frame");
150 completed_value = Some(completed_parent);
151 } else if let Some(source) = parent.next_value() {
152 next_value = Some(source);
153 } else {
154 completed_value = Some(
155 frames
156 .pop()
157 .expect("a completed child has a parent frame")
158 .finish(&mut builders),
159 );
160 }
161 }
162 }
163 }
164
165 /// Returns a shared borrow of the underlying JSON tree for
166 /// interoperability.
167 ///
168 /// The returned borrow is tied to this owner. Recursive operations
169 /// performed through it are the caller's responsibility and may use the
170 /// backend's stack behavior.
171 ///
172 /// # Returns
173 ///
174 /// The underlying tree borrowed for no longer than this owner.
175 #[must_use]
176 #[inline]
177 pub fn as_value(&self) -> &Value {
178 self.root.as_ref().expect("owner root is present")
179 }
180
181 /// Transfers the tree and its destruction responsibility to the caller.
182 ///
183 /// The returned `Value` is no longer protected by this owner; recursive
184 /// operations and destruction are the caller's responsibility.
185 ///
186 /// # Returns
187 ///
188 /// The previously owned JSON tree.
189 #[must_use]
190 #[inline]
191 pub fn into_value(self) -> Value {
192 let mut this = ManuallyDrop::new(self);
193 this.root.take().expect("owner root is present")
194 }
195}
196
197impl Clone for SafeJsonValue {
198 /// Copies the complete JSON tree through the owner's guarded traversal.
199 fn clone(&self) -> Self {
200 Self::copy_from(self.as_value())
201 }
202}
203
204impl PartialEq for SafeJsonValue {
205 /// Compares two complete JSON trees without recursive descent.
206 ///
207 /// # Parameters
208 ///
209 /// * `other` - JSON owner whose tree is compared with this owner's tree.
210 ///
211 /// # Returns
212 ///
213 /// `true` when both trees contain equal JSON values.
214 fn eq(&self, other: &Self) -> bool {
215 values_equal(self.as_value(), other.as_value())
216 }
217}
218
219impl Eq for SafeJsonValue {}
220
221impl fmt::Debug for SafeJsonValue {
222 /// Formats the complete JSON tree through the owner's stack-safe formatter.
223 ///
224 /// # Parameters
225 ///
226 /// * `formatter` - Formatter that receives the tree's debug representation.
227 ///
228 /// # Returns
229 ///
230 /// The formatter's result, including any formatting error.
231 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
232 debug_value(self.as_value(), formatter)
233 }
234}
235
236impl Drop for SafeJsonValue {
237 /// Destroys the owned tree iteratively, with an allocation-free fallback.
238 fn drop(&mut self) {
239 if let Some(mut root) = self.root.take() {
240 drop_tree(&mut root);
241 }
242 }
243}
244
245/// Drops a value tree iteratively, falling back to allocation-free traversal.
246///
247/// # Parameters
248///
249/// * `root` - Root value whose descendants must be destroyed without recursive
250/// container drops.
251pub(super) fn drop_tree(root: &mut Value) {
252 let mut pending = Vec::new();
253 if !try_reserve_drop_work(&mut pending, 1) {
254 drop_tree_slow(root);
255 return;
256 }
257 pending.push(std::mem::replace(root, Value::Null));
258 while let Some(value) = pending.pop() {
259 match value {
260 Value::Array(mut values) => {
261 if !try_reserve_drop_work(&mut pending, values.len()) {
262 for child in &mut values {
263 drop_tree_slow(child);
264 }
265 for child in &mut pending {
266 drop_tree_slow(child);
267 }
268 return;
269 }
270 pending.append(&mut values);
271 }
272 Value::Object(mut values) => {
273 if !try_reserve_drop_work(&mut pending, values.len()) {
274 for child in values.values_mut() {
275 drop_tree_slow(child);
276 }
277 for child in &mut pending {
278 drop_tree_slow(child);
279 }
280 return;
281 }
282 pending.extend(values.into_values());
283 }
284 shallow => drop(shallow),
285 }
286 }
287}
288
289/// Attempts to grow the explicit cleanup stack without panicking on allocation
290/// failure.
291///
292/// # Parameters
293///
294/// * `pending` - Cleanup stack whose capacity is to be increased.
295/// * `additional` - Minimum additional number of elements to reserve.
296///
297/// # Returns
298///
299/// `true` if the requested capacity is available; otherwise, `false`.
300fn try_reserve_drop_work(pending: &mut Vec<Value>, additional: usize) -> bool {
301 #[cfg(test)]
302 if FAIL_DROP_RESERVE_AFTER.with(|remaining| match remaining.get() {
303 Some(0) => {
304 remaining.set(None);
305 true
306 }
307 Some(count) => {
308 remaining.set(Some(count - 1));
309 false
310 }
311 None => false,
312 }) {
313 return false;
314 }
315 pending.try_reserve(additional).is_ok()
316}
317
318#[cfg(test)]
319thread_local! {
320 static COPY_FROM_CALLS: Cell<usize> = const { Cell::new(0) };
321 static FAIL_DROP_RESERVE_AFTER: Cell<Option<usize>> = const { Cell::new(None) };
322 static PANIC_AFTER_INSERT: Cell<Option<usize>> = const { Cell::new(None) };
323}
324
325#[cfg(test)]
326impl SafeJsonValue {
327 pub(crate) fn take_copy_from_calls_for_test() -> usize {
328 COPY_FROM_CALLS.with(|calls| calls.replace(0))
329 }
330
331 pub(crate) fn fail_drop_reserve_after_for_test(successful_reserves: usize) {
332 FAIL_DROP_RESERVE_AFTER.with(|remaining| remaining.set(Some(successful_reserves)));
333 }
334
335 pub(crate) fn assert_drop_reserve_failure_consumed_for_test() {
336 assert!(FAIL_DROP_RESERVE_AFTER.with(Cell::get).is_none());
337 }
338
339 pub(crate) fn panic_after_guarded_inserts_for_test(count: usize) {
340 PANIC_AFTER_INSERT.with(|remaining| remaining.set(Some(count)));
341 }
342
343 pub(crate) fn assert_guarded_insert_panic_consumed_for_test() {
344 assert!(PANIC_AFTER_INSERT.with(|remaining| remaining.get().is_none()));
345 }
346}
347
348/// Injects an unwind after guarded inserts in tests; this is a no-op in builds.
349pub(super) fn maybe_panic_after_guarded_insert() {
350 #[cfg(test)]
351 PANIC_AFTER_INSERT.with(|remaining| {
352 if let Some(count) = remaining.get() {
353 if count <= 1 {
354 remaining.set(None);
355 panic!("injected unwind while building a protected JSON value");
356 }
357 remaining.set(Some(count - 1));
358 }
359 });
360}
361
362/// Cleans a tree without allocating by repeatedly removing leaves in place.
363///
364/// # Parameters
365///
366/// * `root` - Root value to clean in place using only shallow leaf drops.
367fn drop_tree_slow(root: &mut Value) {
368 loop {
369 let mut current = std::ptr::from_mut(root);
370 loop {
371 // SAFETY: `current` always points into `root`; no collection is
372 // structurally changed while its child pointer is being followed.
373 let value = unsafe { &mut *current };
374 let child = match value {
375 Value::Array(values) => {
376 values.retain(|value| !value.is_null());
377 values.first_mut().map(std::ptr::from_mut)
378 }
379 Value::Object(values) => {
380 values.retain(|_, value| !value.is_null());
381 values.values_mut().next().map(std::ptr::from_mut)
382 }
383 _ => None,
384 };
385 if let Some(child) = child {
386 current = child;
387 continue;
388 }
389 // SAFETY: `current` was obtained from the current tree and points
390 // at a leaf or empty container, whose destruction is shallow.
391 let old = unsafe { std::mem::replace(&mut *current, Value::Null) };
392 drop(old);
393 break;
394 }
395 if root.is_null() {
396 break;
397 }
398 }
399}