use std::{cell::Cell, intrinsics::unlikely};
use crate::{collections::SmallSet, values::Value};
pub(crate) struct ReprStackGuard;
pub(crate) struct JsonStackGuard;
impl Drop for ReprStackGuard {
fn drop(&mut self) {
let mut stack = REPR_STACK.take();
let popped = stack.pop();
debug_assert!(popped.is_some());
REPR_STACK.set(stack);
}
}
impl Drop for JsonStackGuard {
fn drop(&mut self) {
let mut stack = JSON_STACK.take();
let popped = stack.pop();
debug_assert!(popped.is_some());
JSON_STACK.set(stack);
}
}
struct ReleaseMemoryOnThreadExit;
impl Drop for ReleaseMemoryOnThreadExit {
fn drop(&mut self) {
REPR_STACK.take();
JSON_STACK.take();
}
}
thread_local! {
static RELEASE_MEMORY_ON_THREAD_EXIT: ReleaseMemoryOnThreadExit = ReleaseMemoryOnThreadExit;
}
#[cold]
#[inline(never)]
fn init_release_memory_on_thread_exit() {
RELEASE_MEMORY_ON_THREAD_EXIT.with(|_| {});
}
pub(crate) struct ReprCycle;
pub(crate) struct JsonCycle;
#[thread_local]
static REPR_STACK: Cell<SmallSet<usize>> = Cell::new(SmallSet::new());
#[thread_local]
static JSON_STACK: Cell<SmallSet<usize>> = Cell::new(SmallSet::new());
pub(crate) fn repr_stack_push(value: Value) -> Result<ReprStackGuard, ReprCycle> {
let mut stack = REPR_STACK.take();
if unlikely(stack.capacity() == 0) {
init_release_memory_on_thread_exit();
}
if unlikely(!stack.insert(value.ptr_value())) {
REPR_STACK.set(stack);
Err(ReprCycle)
} else {
REPR_STACK.set(stack);
Ok(ReprStackGuard)
}
}
pub(crate) fn json_stack_push(value: Value) -> Result<JsonStackGuard, JsonCycle> {
let mut stack = JSON_STACK.take();
if unlikely(stack.capacity() == 0) {
init_release_memory_on_thread_exit();
}
if unlikely(!stack.insert(value.ptr_value())) {
JSON_STACK.set(stack);
Err(JsonCycle)
} else {
JSON_STACK.set(stack);
Ok(JsonStackGuard)
}
}