use std::cell::RefCell;
use crate::region::Region;
use crate::static_arena::static_arena;
use crate::{GcPtr, Trace};
pub(crate) enum AllocCtx {
Static,
Region(*mut Region),
}
unsafe impl Send for AllocCtx {}
thread_local! {
pub(crate) static ALLOC_CTX: RefCell<Vec<AllocCtx>> = const { RefCell::new(Vec::new()) };
}
pub(crate) fn alloc_in_ctx<T: Trace + 'static>(value: T) -> GcPtr<T> {
ALLOC_CTX.with(|ctx| {
let ctx = ctx.borrow();
match ctx.last() {
None | Some(AllocCtx::Static) => static_arena().alloc(value),
Some(AllocCtx::Region(ptr)) => {
unsafe { &mut **ptr }.alloc(value)
}
}
})
}
pub struct ScratchGuard {
region: Box<Region>,
in_ctx: bool,
}
impl ScratchGuard {
pub fn new() -> Self {
let mut region = Box::new(Region::new());
let ptr = region.as_mut() as *mut Region;
ALLOC_CTX.with(|ctx| ctx.borrow_mut().push(AllocCtx::Region(ptr)));
Self {
region,
in_ctx: true,
}
}
pub fn pop_for_return(&mut self) {
if self.in_ctx {
ALLOC_CTX.with(|ctx| ctx.borrow_mut().pop());
self.in_ctx = false;
}
}
}
impl Default for ScratchGuard {
fn default() -> Self {
Self::new()
}
}
impl Drop for ScratchGuard {
fn drop(&mut self) {
if self.in_ctx {
ALLOC_CTX.with(|ctx| ctx.borrow_mut().pop());
}
self.region.reset();
}
}
pub struct StaticCtxGuard;
impl StaticCtxGuard {
pub fn new() -> Self {
ALLOC_CTX.with(|ctx| ctx.borrow_mut().push(AllocCtx::Static));
Self
}
}
impl Default for StaticCtxGuard {
fn default() -> Self {
Self::new()
}
}
impl Drop for StaticCtxGuard {
fn drop(&mut self) {
ALLOC_CTX.with(|ctx| ctx.borrow_mut().pop());
}
}