use crate::recorder::{
HandleId, Recorder, RecorderSnapshot, collect_sorted,
messages::{self, SlotDisplayFormatter},
};
use slotmap::Key;
use std::fmt::Write;
pub fn all_handles_released<K: Key>(recorder: &Recorder<K>) {
if recorder.slots.is_empty() {
return;
}
let slot_count = recorder.slots.len();
let mut out = String::new();
for (key, record) in collect_sorted(&recorder.slots) {
debug_assert!(!record.handles.is_empty());
let message = messages::handles_leaked(*key, record);
write!(out, "{message}").unwrap();
}
panic!("refslots: {slot_count} slots with undropped handles\n\n{out}");
}
pub fn handles_released<K: Key>(recorder: &Recorder<K>, key: K) {
let Some(record) = recorder.slots.get(&key) else { return };
debug_assert!(!record.handles.is_empty());
let out = messages::handles_leaked(key, record);
panic!(
"refslots: {} has {} undropped handles\n\n{out}",
SlotDisplayFormatter { label: record.label, key },
record.handles.len()
);
}
pub fn handles_released_since<K: Key>(recorder: &Recorder<K>, snapshot: &RecorderSnapshot<K>) {
let mut out = String::new();
let mut new_handle_count = 0;
for (key, record) in collect_sorted(&recorder.slots) {
let count = count_handles_created_since(record.handles.keys(), snapshot.next_handle_id);
if count > 0 {
let message = messages::new_handles(*key, record, count);
writeln!(out, "{message}").unwrap();
new_handle_count += count;
}
}
if new_handle_count > 0 {
panic!("refslots: {new_handle_count} live handles created since last snapshot\n\n{out}");
}
}
fn count_handles_created_since<'a, I>(handles: I, min_handle_id: u64) -> usize
where
I: Iterator<Item = &'a HandleId>,
{
handles.filter(|id| id.0 >= min_handle_id).count()
}
#[cfg(test)]
mod tests {
use super::*;
use crate::recorder::tests::{Recorder, make_key, record_create, shutdown};
mod all_handles_released {
use super::*;
#[test]
fn released() {
let mut recorder = Recorder::default();
let key = make_key(1);
let handle_id = record_create(&mut recorder, key);
recorder.record_drop_handle(key, handle_id);
all_handles_released(&recorder);
}
#[test]
#[should_panic(expected = "1 slots with undropped handles")]
fn unreleased() {
let mut recorder = Recorder::default();
let key = make_key(1);
record_create(&mut recorder, key);
all_handles_released(&recorder);
shutdown(&mut recorder);
}
#[test]
fn empty() {
let recorder = Recorder::default();
all_handles_released(&recorder);
}
}
mod handles_released {
use super::*;
#[test]
fn released() {
let mut recorder = Recorder::default();
let key = make_key(1);
let handle_id = record_create(&mut recorder, key);
recorder.record_drop_handle(key, handle_id);
handles_released(&recorder, key);
}
#[test]
#[should_panic(expected = "1 undropped handle")]
fn unreleased() {
let mut recorder = Recorder::default();
let key = make_key(1);
record_create(&mut recorder, key);
handles_released(&recorder, key);
shutdown(&mut recorder);
}
#[test]
fn empty() {
let recorder = Recorder::default();
let key = make_key(1);
handles_released(&recorder, key);
}
}
mod handles_released_since {
use super::*;
#[test]
fn released_slot() {
let mut recorder = Recorder::default();
record_create(&mut recorder, make_key(1));
let snapshot = recorder.snapshot();
let key = make_key(2);
let handle_id = record_create(&mut recorder, key);
recorder.record_drop_handle(key, handle_id);
handles_released_since(&recorder, &snapshot);
shutdown(&mut recorder);
}
#[test]
#[should_panic(expected = "1 live handles created since last snapshot")]
fn unreleased_slot() {
let mut recorder = Recorder::default();
record_create(&mut recorder, make_key(1));
let snapshot = recorder.snapshot();
record_create(&mut recorder, make_key(2));
handles_released_since(&recorder, &snapshot);
shutdown(&mut recorder);
}
#[test]
fn released_handle() {
let mut recorder = Recorder::default();
let key = make_key(1);
record_create(&mut recorder, key);
let snapshot = recorder.snapshot();
let handle_id = record_create(&mut recorder, key);
recorder.record_drop_handle(key, handle_id);
handles_released_since(&recorder, &snapshot);
shutdown(&mut recorder);
}
#[test]
#[should_panic(expected = "1 live handles created since last snapshot")]
fn unreleased_handle() {
let mut recorder = Recorder::default();
let key = make_key(1);
record_create(&mut recorder, key);
let snapshot = recorder.snapshot();
record_create(&mut recorder, key);
handles_released_since(&recorder, &snapshot);
shutdown(&mut recorder);
}
#[test]
fn unchanged() {
let mut recorder = Recorder::default();
record_create(&mut recorder, make_key(1));
let snapshot = recorder.snapshot();
handles_released_since(&recorder, &snapshot);
shutdown(&mut recorder);
}
#[test]
fn empty() {
let recorder = Recorder::default();
let snapshot = recorder.snapshot();
handles_released_since(&recorder, &snapshot);
}
}
}