qubit-json 0.12.4

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.
// =============================================================================
//! Shared public-API adapters for encoder tests.

use std::fmt::Debug;
use std::mem::replace;
use std::panic::AssertUnwindSafe;
use std::panic::catch_unwind;
use std::panic::resume_unwind;

use qubit_budget::ResourceQuantity;
use qubit_budget::json::JsonEncodeLimits;
use qubit_budget::json::JsonEncodeSession;
use qubit_io::Output;
use qubit_json::encode::JsonEncodeError;
use qubit_json::encode::JsonEncoder;
use serde::Serialize;

/// Encodes one value through the stateful encoder API.
///
/// The session is temporarily moved into the encoder. If encoding panics, the
/// updated session is restored before the panic is resumed.
pub(crate) fn encode<T, R, Q>(
    value: &T,
    session: &mut JsonEncodeSession<'_, R, Q>,
) -> Result<Vec<u8>, JsonEncodeError<R, Q>>
where
    T: Serialize + ?Sized,
    R: Clone + Debug + 'static,
    Q: ResourceQuantity + 'static,
{
    let placeholder = JsonEncodeSession::from_limits(JsonEncodeLimits::<R, Q>::builder().build());
    let owned = replace(session, placeholder);
    let mut encoder = JsonEncoder::new(owned);
    let result = catch_unwind(AssertUnwindSafe(|| encoder.to_vec(value)));
    *session = encoder.into_session();
    match result {
        Ok(result) => result,
        Err(payload) => resume_unwind(payload),
    }
}

/// Writes one buffered document through the stateful encoder API.
///
/// The session is temporarily moved into the encoder. If writing panics, the
/// updated session is restored before the panic is resumed.
pub(crate) fn write_buffered<W, T, R, Q>(
    mut writer: W,
    value: &T,
    session: &mut JsonEncodeSession<'_, R, Q>,
) -> Result<(), JsonEncodeError<R, Q>>
where
    W: Output<Item = u8>,
    T: Serialize + ?Sized,
    R: Clone + Debug + 'static,
    Q: ResourceQuantity + 'static,
{
    let placeholder = JsonEncodeSession::from_limits(JsonEncodeLimits::<R, Q>::builder().build());
    let owned = replace(session, placeholder);
    let mut encoder = JsonEncoder::new(owned);
    let result = catch_unwind(AssertUnwindSafe(|| encoder.write_buffered(&mut writer, value)));
    *session = encoder.into_session();
    match result {
        Ok(result) => result,
        Err(payload) => resume_unwind(payload),
    }
}

/// Streams one document through the stateful encoder API.
///
/// The session is temporarily moved into the encoder. If writing panics, the
/// updated session is restored before the panic is resumed.
pub(crate) fn write_incremental<W, T, R, Q>(
    mut writer: W,
    value: &T,
    session: &mut JsonEncodeSession<'_, R, Q>,
) -> Result<(), JsonEncodeError<R, Q>>
where
    W: Output<Item = u8>,
    T: Serialize + ?Sized,
    R: Clone + Debug + 'static,
    Q: ResourceQuantity + 'static,
{
    let placeholder = JsonEncodeSession::from_limits(JsonEncodeLimits::<R, Q>::builder().build());
    let owned = replace(session, placeholder);
    let mut encoder = JsonEncoder::new(owned);
    let result = catch_unwind(AssertUnwindSafe(|| encoder.write_incremental(&mut writer, value)));
    *session = encoder.into_session();
    match result {
        Ok(result) => result,
        Err(payload) => resume_unwind(payload),
    }
}