use super::config::Config;
use super::metrics::Metrics;
use super::mutator::Mutator;
use super::trace::Trace;
use crate::trace::Collector;
use alloc::boxed::Box;
use alloc::sync::Arc;
use higher_kinded_types::ForLt;
pub struct Arena<R: ForLt + 'static>
where
for<'a> <R as ForLt>::Of<'a>: Trace,
{
collector: Arc<Collector>,
root: Box<R::Of<'static>>,
#[cfg(feature = "multi_threaded")]
monitor_thread: Option<std::thread::JoinHandle<()>>,
}
impl<R: ForLt + 'static> Arena<R>
where
for<'a> <R as ForLt>::Of<'a>: Trace,
{
pub fn new<F>(f: F) -> Self
where
F: for<'gc> FnOnce(&'gc Mutator<'gc>) -> R::Of<'gc>,
{
let config = Config::default();
Self::new_with_config(config, f)
}
pub fn new_with_config<F>(config: Config, f: F) -> Self
where
F: for<'gc> FnOnce(&'gc Mutator<'gc>) -> R::Of<'gc>,
{
let collector = Arc::new(Collector::new(config));
let collector_ref: &'static Collector = unsafe { &*(&*collector as *const Collector) };
let mutator = Mutator::new(collector_ref);
let mutator_ref: &'static Mutator<'static> =
unsafe { &*(&mutator as *const Mutator<'static>) };
let root = Box::new(f(mutator_ref));
drop(mutator);
#[cfg(feature = "multi_threaded")]
{
let monitor_thread = collector.clone().spawn_monitor_thread(root.as_ref());
Self {
collector,
root,
monitor_thread,
}
}
#[cfg(not(feature = "multi_threaded"))]
{
Self { collector, root }
}
}
pub fn mutate<F>(&self, f: F)
where
F: for<'gc> FnOnce(&'gc Mutator<'gc>, &'gc R::Of<'gc>),
{
let mutator = self.new_mutator();
let root = unsafe { self.scoped_root() };
f(&mutator, root);
#[cfg(not(feature = "multi_threaded"))]
{
drop(mutator);
if self.collector.major_trigger() {
self.major_collect();
} else if self.collector.minor_trigger() {
self.minor_collect();
}
}
}
pub fn view<F>(&self, f: F)
where
F: for<'gc> FnOnce(&'gc R::Of<'gc>),
{
let root = unsafe { self.scoped_root() };
f(root);
}
pub fn major_collect(&self) {
self.collector.major_collect(self.root.as_ref());
}
pub fn minor_collect(&self) {
self.collector.minor_collect(self.root.as_ref());
}
pub fn metrics(&self) -> &Metrics {
self.collector.metrics()
}
unsafe fn scoped_root<'gc>(&self) -> &'gc R::Of<'gc> {
core::mem::transmute::<&R::Of<'static>, &R::Of<'gc>>(self.root.as_ref())
}
fn new_mutator<'a>(&'a self) -> Mutator<'a> {
Mutator::new(&*self.collector)
}
}
#[cfg(feature = "multi_threaded")]
impl<R: ForLt + 'static> Drop for Arena<R>
where
for<'a> <R as ForLt>::Of<'a>: Trace,
{
fn drop(&mut self) {
self.collector.shutdown();
if let Some(handle) = self.monitor_thread.take() {
let _ = handle.join();
}
}
}