qubit-json 0.12.3

Resource-aware infrastructure for lenient and strict JSON processing
Documentation
// =============================================================================
//    Copyright (c) 2026 Haixing Hu.
//
//    SPDX-License-Identifier: Apache-2.0
//
//    Licensed under the Apache License, Version 2.0.
// =============================================================================
//! Defines the lazy child cursor for mutable JSON traversal.
//!
//! # Safety invariants
//!
//! A cursor is created only after the visitor has returned its mutable borrow
//! of the parent node. From that point until the cursor is dropped, traversal
//! never exposes the parent again and never changes the array length, object
//! key set, or backing container allocation. A yielded child frame completes
//! and is removed before the cursor advances. Replacing a child `Value` is
//! allowed because it does not structurally modify its parent container.

use std::ptr::NonNull;

use serde_json::Value;
use serde_json::map::IterMut;

use super::MutFrame;
use super::OwnedLocation;

/// Lazily yields mutable children without detaching their parent container.
pub(in crate::value::traverse) enum MutChildCursor {
    /// Cursor over mutable array entries.
    Array {
        /// Pointer to the parent vector whose entries are borrowed one at a
        /// time.
        values: NonNull<Vec<Value>>,
        /// Index of the next array entry to visit.
        next: usize,
    },
    /// Cursor over mutable object entries.
    Object {
        /// Suspended iterator over the parent object's entries.
        iter: IterMut<'static>,
    },
    /// Marker for scalar values without children.
    Empty,
}

impl MutChildCursor {
    /// Creates a cursor whose references remain inside the borrowed root.
    ///
    /// # Parameters
    ///
    /// * `value` - Non-null pointer to the root value borrowed exclusively for
    ///   this traversal. The root must remain alive and structurally unchanged
    ///   while the cursor is in use.
    ///
    /// # Returns
    ///
    /// A cursor over the root's direct children, or an empty cursor for a
    /// scalar value.
    ///
    /// # Safety
    ///
    /// The pointer must identify a live value inside the exclusively borrowed
    /// root and have no conflicting borrow. The value must remain stable, with
    /// its container structure and backing allocation unchanged, until this
    /// cursor and every frame it yields are dropped. Ancestor frames must
    /// remain suspended while this cursor is active.
    #[must_use]
    pub(in crate::value::traverse) unsafe fn new(mut value: NonNull<Value>) -> Self {
        // SAFETY: the pointer originates from the caller's exclusive root
        // borrow, and no child cursor or visitor borrow of this node is live.
        match unsafe { value.as_mut() } {
            Value::Array(values) => Self::Array {
                values: NonNull::from(values),
                next: 0,
            },
            Value::Object(entries) => {
                let iter = entries.iter_mut();
                // SAFETY: the map structure and key set remain unchanged while
                // this iterator is suspended. A yielded child value may be
                // replaced without invalidating the map iterator.
                let iter = unsafe { std::mem::transmute::<IterMut<'_>, IterMut<'static>>(iter) };
                Self::Object { iter }
            }
            Value::Null | Value::Bool(_) | Value::Number(_) | Value::String(_) => Self::Empty,
        }
    }

    /// Returns the next child and its traversal metadata.
    ///
    /// # Parameters
    ///
    /// * `parent_depth` - Depth assigned to the node whose children this cursor
    ///   visits.
    ///
    /// # Returns
    ///
    /// `Some` with the next child frame, or `None` when the cursor is empty or
    /// has no remaining children.
    ///
    /// # Safety
    ///
    /// The parent container must remain alive and structurally stable while
    /// the cursor is active. No conflicting read or write access to the parent
    /// or its cursor-managed children may occur through any other path; only
    /// the currently yielded child frame may exclusively access its child.
    /// All previously yielded child frames and their descendants must be
    /// dropped before advancing this cursor.
    ///
    /// # Panics
    ///
    /// Panics when `parent_depth` is `usize::MAX` and the child depth cannot be
    /// represented.
    pub(in crate::value::traverse) unsafe fn next(
        &mut self,
        parent_depth: usize,
    ) -> Option<MutFrame> {
        let depth = parent_depth
            .checked_add(1)
            .expect("a materialized JSON tree cannot have usize::MAX nesting depth");
        match self {
            Self::Array { values, next } => {
                // SAFETY: the parent vector is structurally unchanged while its
                // cursor is live, and the previously yielded child frame has
                // completed before the cursor advances.
                let values = unsafe { values.as_mut() };
                let index = *next;
                let child = values.get_mut(index)?;
                *next = next.checked_add(1)?;
                // SAFETY: this child belongs to the stable parent array, and
                // the cursor will not advance again until the child frame drops.
                Some(unsafe { MutFrame::child(OwnedLocation::ArrayElement(index), depth, child) })
            }
            Self::Object { iter } => iter.next().map(|(key, child)| {
                // SAFETY: the iterator yields a disjoint value in the stable
                // parent object; it advances again only after this frame drops.
                unsafe { MutFrame::child(OwnedLocation::ObjectValue(key.clone()), depth, child) }
            }),
            Self::Empty => None,
        }
    }
}