Files
iris/tests/allocation.rs
T

127 lines
3.5 KiB
Rust

use iris::prelude::*;
use std::{
alloc::{GlobalAlloc, Layout, System},
cell::Cell,
time::{Duration, Instant},
};
struct CountingAllocator;
thread_local! {
static TRACKING: Cell<bool> = const { Cell::new(false) };
static ALLOCATIONS: Cell<usize> = const { Cell::new(0) };
}
fn note_allocation() {
TRACKING.with(|tracking| {
if tracking.get() {
ALLOCATIONS.with(|allocations| allocations.set(allocations.get() + 1));
}
});
}
unsafe impl GlobalAlloc for CountingAllocator {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
let ptr = unsafe { System.alloc(layout) };
note_allocation();
ptr
}
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
let ptr = unsafe { System.alloc_zeroed(layout) };
note_allocation();
ptr
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
unsafe { System.dealloc(ptr, layout) }
}
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
let ptr = unsafe { System.realloc(ptr, layout, new_size) };
note_allocation();
ptr
}
}
#[global_allocator]
static ALLOCATOR: CountingAllocator = CountingAllocator;
fn allocations_during(run: impl FnOnce()) -> usize {
ALLOCATIONS.with(|allocations| allocations.set(0));
TRACKING.with(|tracking| tracking.set(true));
run();
TRACKING.with(|tracking| tracking.set(false));
ALLOCATIONS.with(Cell::get)
}
struct TestRsc {
ui: Ui,
}
impl UiRsc for TestRsc {
fn ui(&self) -> &Ui {
&self.ui
}
fn ui_mut(&mut self) -> &mut Ui {
&mut self.ui
}
}
struct FrameRequester;
impl Widget for FrameRequester {
fn draw(&mut self, painter: &mut Painter) {
let paint = painter.paint(&PaintId::WHITE);
painter.primitive(RectPrimitive::color(paint));
painter.request_next_frame();
painter.set_size(Size::REST);
}
}
#[test]
fn a_warmed_self_redraw_allocates_nothing() {
let mut rsc = TestRsc { ui: Ui::default() };
let root = rsc.ui.widgets.add_strong(FrameRequester).any();
let mut render = UiRenderState::new();
render.resize((800.0, 600.0));
let start = Instant::now();
for frame in 0..3 {
assert!(render.update_at(&root, &mut rsc, start + Duration::from_millis(frame * 16),));
}
let allocations = allocations_during(|| {
assert!(render.update_at(&root, &mut rsc, start + Duration::from_millis(48),));
});
assert_eq!(allocations, 0);
}
#[test]
fn refreshing_retained_accessibility_allocates_nothing() {
let mut rsc = TestRsc { ui: Ui::default() };
let leaf = rsc.ui.widgets.add_strong(Rect::new(PaintId::WHITE));
rsc.ui.widgets.set_label(&leaf, "named".to_owned());
let offset = rsc.ui.widgets.add_strong(Offset {
inner: leaf.any(),
amt: UiVec2::ZERO,
});
let offset_id = offset.weak();
let root = offset.any();
let mut render = UiRenderState::new();
render.resize((800.0, 600.0));
render.update(&root, &mut rsc);
let mut access = AccessTree::new();
assert!(access.refresh(rsc.widgets(), &render, &rsc));
rsc.ui.widgets.get_mut(&offset_id).unwrap().amt = UiVec2::abs(Vec2::new(20.0, 0.0));
render.update(&root, &mut rsc);
let moved = allocations_during(|| assert!(access.refresh(rsc.widgets(), &render, &rsc)));
assert_eq!(moved, 0);
let unchanged = allocations_during(|| assert!(!access.refresh(rsc.widgets(), &render, &rsc)));
assert_eq!(unchanged, 0);
}