#[macro_export]
macro_rules! make_sequencable_arena {
($module:ident, $root:ident) => {
make_sequencable_arena!(@impl pub(self), pub(super), $module, $root);
};
($vis:vis $module:ident, $root:ident) => {
make_sequencable_arena!(@impl $vis, $vis, $module, $root);
};
(@impl $modvis:vis, $innervis:vis, $module:ident, $root:ident) => {
$modvis mod $module {
use std::any::Any;
use std::marker::PhantomData;
use gc_arena::{make_arena, ArenaParameters, Collect, GcCell, MutationContext};
use gc_sequence::{Sequence, SequenceExt};
use super::$root;
#[derive(Collect)]
#[collect(empty_drop)]
struct InnerRoot<'gc> {
root: $root<'gc>,
current_sequence: GcCell<
'gc,
Option<Box<dyn Sequence<'gc, Output = Box<dyn Any + 'static>> + 'gc>>,
>,
}
make_arena!(InnerArena, InnerRoot);
$innervis struct Arena(InnerArena);
impl Arena {
#[allow(unused)]
$innervis fn new<F>(arena_parameters: ArenaParameters, f: F) -> Arena
where
F: for<'gc> FnOnce(MutationContext<'gc, '_>) -> $root<'gc>,
{
Arena(InnerArena::new(arena_parameters, move |mc| InnerRoot {
root: f(mc),
current_sequence: GcCell::allocate(mc, None),
}))
}
#[allow(unused)]
$innervis fn try_new<F, E>(arena_parameters: ArenaParameters, f: F) -> Result<Arena, E>
where
F: for<'gc> FnOnce(MutationContext<'gc, '_>) -> Result<$root<'gc>, E>,
{
Ok(Arena(InnerArena::try_new(arena_parameters, move |mc| {
Ok(InnerRoot {
root: f(mc)?,
current_sequence: GcCell::allocate(mc, None),
})
})?))
}
#[allow(unused)]
$innervis fn mutate<F, R>(&mut self, f: F) -> R
where
F: for<'gc> FnOnce(MutationContext<'gc, '_>, &$root<'gc>) -> R,
{
self.0.mutate(move |mc, root| f(mc, &root.root))
}
#[allow(unused)]
$innervis fn sequence<F, O>(mut self, f: F) -> Sequencer<O>
where
O: 'static,
F: for<'gc> FnOnce(&$root<'gc>) -> Box<dyn Sequence<'gc, Output = O> + 'gc>,
{
self.0.mutate(move |mc, root| {
*root.current_sequence.write(mc) =
Some(f(&root.root).map(|r| -> Box<Any> { Box::new(r) }).boxed());
});
Sequencer(self.0, PhantomData)
}
#[allow(unused)]
#[inline]
$innervis fn total_allocated(&self) -> usize {
self.0.total_allocated()
}
#[allow(unused)]
#[inline]
$innervis fn allocation_debt(&self) -> f64 {
self.0.allocation_debt()
}
#[allow(unused)]
#[inline]
$innervis fn collect_debt(&mut self) {
self.0.collect_debt()
}
#[allow(unused)]
$innervis fn collect_all(&mut self) {
self.0.collect_all()
}
}
$innervis struct Sequencer<O>(InnerArena, PhantomData<O>);
impl<O> Sequencer<O>
where
O: 'static,
{
#[allow(unused)]
$innervis fn step(mut self) -> Result<(Arena, O), Sequencer<O>> {
let r = self.0.mutate(move |mc, root| {
root.current_sequence.write(mc).as_mut().unwrap().step(mc)
});
if let Some(r) = r {
self.0.mutate(|mc, root| {
*root.current_sequence.write(mc) = None;
});
Ok((
Arena(self.0),
*Box::<dyn Any + 'static>::downcast(r).unwrap(),
))
} else {
Err(self)
}
}
$innervis fn abort(mut self) -> Arena {
self.0.mutate(|mc, root| {
*root.current_sequence.write(mc) = None;
});
Arena(self.0)
}
#[allow(unused)]
#[inline]
$innervis fn total_allocated(&self) -> usize {
self.0.total_allocated()
}
#[allow(unused)]
#[inline]
$innervis fn allocation_debt(&self) -> f64 {
self.0.allocation_debt()
}
#[allow(unused)]
#[inline]
$innervis fn collect_debt(&mut self) {
self.0.collect_debt()
}
#[allow(unused)]
$innervis fn collect_all(&mut self) {
self.0.collect_all()
}
}
}
};
}