1use crate::ser::allocator::Arena;
2
3#[cfg(feature = "std")]
4mod detail {
5 use core::cell::Cell;
6
7 use crate::ser::allocator::Arena;
8
9 thread_local! {
10 static THREAD_ARENA: Cell<Option<Arena>> = const { Cell::new(None) };
11 }
12
13 pub fn with_arena<T>(f: impl FnOnce(&mut Arena) -> T) -> T {
14 THREAD_ARENA.with(|thread_arena| {
15 let mut arena = thread_arena.take().unwrap_or_default();
16
17 let result = f(&mut arena);
18 let capacity = arena.shrink();
19
20 if let Some(other) = thread_arena.take() {
21 if other.capacity() > capacity {
22 arena = other;
23 }
24 }
25 thread_arena.set(Some(arena));
26
27 result
28 })
29 }
30
31 #[inline]
32 pub fn clear_arena() {
33 THREAD_ARENA.take();
34 }
35}
36
37#[cfg(all(not(feature = "std"), target_has_atomic = "ptr",))]
38mod detail {
39 use core::{
40 ptr::{self, NonNull},
41 sync::atomic::{AtomicPtr, Ordering},
42 };
43
44 use crate::ser::allocator::Arena;
45
46 static GLOBAL_ARENA: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut());
47
48 pub fn with_arena<T>(f: impl FnOnce(&mut Arena) -> T) -> T {
49 let ptr = GLOBAL_ARENA.swap(ptr::null_mut(), Ordering::AcqRel);
50
51 let mut arena = if let Some(raw) = NonNull::new(ptr) {
52 unsafe { Arena::from_raw(raw) }
53 } else {
54 Arena::new()
55 };
56
57 let result = f(&mut arena);
58 arena.shrink();
59
60 let raw = arena.into_raw();
61
62 let swap = GLOBAL_ARENA.compare_exchange(
63 ptr::null_mut(),
64 raw.as_ptr(),
65 Ordering::AcqRel,
66 Ordering::Relaxed,
67 );
68 if swap.is_err() {
69 unsafe {
72 drop(Arena::from_raw(raw));
73 }
74 }
75
76 result
77 }
78
79 #[inline]
80 pub fn clear_arena() {
81 let ptr = GLOBAL_ARENA.swap(ptr::null_mut(), Ordering::AcqRel);
82
83 if let Some(raw) = NonNull::new(ptr) {
84 unsafe {
85 drop(Arena::from_raw(raw));
86 }
87 }
88 }
89}
90
91#[cfg(all(not(feature = "std"), not(target_has_atomic = "ptr"),))]
92mod detail {
93 use crate::ser::allocator::Arena;
94
95 pub fn with_arena<T>(f: impl FnOnce(&mut Arena) -> T) -> T {
96 let mut arena = Arena::new();
97 f(&mut arena)
98 }
99
100 #[inline]
101 pub fn clear_arena() {}
102}
103
104pub fn with_arena<T>(f: impl FnOnce(&mut Arena) -> T) -> T {
111 detail::with_arena(f)
112}
113
114#[inline]
120pub fn clear_arena() {
121 detail::clear_arena()
122}