119 lines
3.5 KiB
Rust
119 lines
3.5 KiB
Rust
use crate::innerlude::*;
|
|
use bumpalo::Bump;
|
|
use std::cell::Cell;
|
|
|
|
pub struct ActiveFrame {
|
|
// We use a "generation" for users of contents in the bump frames to ensure their data isn't broken
|
|
pub generation: Cell<usize>,
|
|
|
|
// The double-buffering situation that we will use
|
|
pub frames: [BumpFrame; 2],
|
|
}
|
|
|
|
pub struct BumpFrame {
|
|
pub bump: Bump,
|
|
pub(crate) head_node: VNode<'static>,
|
|
|
|
// used internally for debugging
|
|
_name: &'static str,
|
|
}
|
|
|
|
impl ActiveFrame {
|
|
pub fn new() -> Self {
|
|
let frame_a = BumpFrame {
|
|
bump: Bump::new(),
|
|
head_node: NodeFactory::unstable_place_holder(),
|
|
_name: "wip",
|
|
};
|
|
let frame_b = BumpFrame {
|
|
bump: Bump::new(),
|
|
head_node: NodeFactory::unstable_place_holder(),
|
|
_name: "fin",
|
|
};
|
|
Self {
|
|
generation: 0.into(),
|
|
frames: [frame_a, frame_b],
|
|
}
|
|
}
|
|
|
|
pub unsafe fn reset_wip_frame(&mut self) {
|
|
self.wip_frame_mut().bump.reset()
|
|
}
|
|
|
|
pub fn update_head_node<'a>(&mut self, node: VNode<'a>) {
|
|
self.wip_frame_mut().head_node = unsafe { std::mem::transmute(node) };
|
|
}
|
|
|
|
/// The "work in progress frame" represents the frame that is currently being worked on.
|
|
pub fn wip_frame(&self) -> &BumpFrame {
|
|
match self.generation.get() & 1 == 0 {
|
|
true => &self.frames[0],
|
|
false => &self.frames[1],
|
|
}
|
|
}
|
|
|
|
pub fn wip_frame_mut(&mut self) -> &mut BumpFrame {
|
|
match self.generation.get() & 1 == 0 {
|
|
true => &mut self.frames[0],
|
|
false => &mut self.frames[1],
|
|
}
|
|
}
|
|
|
|
/// The finished frame represents the frame that has been "finished" and cannot be modified again
|
|
pub fn finished_frame(&self) -> &BumpFrame {
|
|
match self.generation.get() & 1 == 1 {
|
|
true => &self.frames[0],
|
|
false => &self.frames[1],
|
|
}
|
|
}
|
|
|
|
pub fn finished_frame_mut(&mut self) -> &mut BumpFrame {
|
|
match self.generation.get() & 1 == 1 {
|
|
true => &mut self.frames[0],
|
|
false => &mut self.frames[1],
|
|
}
|
|
}
|
|
/// Give out our self-referential item with our own borrowed lifetime
|
|
pub fn fin_head<'b>(&'b self) -> &'b VNode<'b> {
|
|
let cur_head = &self.finished_frame().head_node;
|
|
unsafe { std::mem::transmute::<&VNode<'static>, &VNode<'b>>(cur_head) }
|
|
}
|
|
|
|
/// Give out our self-referential item with our own borrowed lifetime
|
|
pub fn wip_head<'b>(&'b self) -> &'b VNode<'b> {
|
|
let cur_head = &self.wip_frame().head_node;
|
|
unsafe { std::mem::transmute::<&VNode<'static>, &VNode<'b>>(cur_head) }
|
|
}
|
|
|
|
pub fn cycle_frame(&mut self) {
|
|
self.generation.set(self.generation.get() + 1);
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
//! These tests are bad. I don't have a good way of properly testing the ActiveFrame stuff
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_bump_frame() {
|
|
let mut frames = ActiveFrame::new();
|
|
|
|
// just cycle a few times and make sure we get the right frames out
|
|
for _ in 0..5 {
|
|
let fin = frames.finished_frame();
|
|
let wip = frames.wip_frame();
|
|
assert_eq!(wip._name, "wip");
|
|
assert_eq!(fin._name, "fin");
|
|
frames.cycle_frame();
|
|
|
|
let fin = frames.finished_frame();
|
|
let wip = frames.wip_frame();
|
|
assert_eq!(wip._name, "fin");
|
|
assert_eq!(fin._name, "wip");
|
|
frames.cycle_frame();
|
|
}
|
|
assert_eq!(frames.generation.get(), 10);
|
|
}
|
|
}
|