Files
dioxus/packages/core/src/bumpframe.rs
T

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);
}
}