simplify code that locks log buffer for reading

This commit is contained in:
Chris Beck
2025-12-05 20:27:55 -07:00
parent 3c88ba80a5
commit 74baa63f50
3 changed files with 19 additions and 16 deletions
+2 -1
View File
@@ -39,6 +39,7 @@ impl<T> CircularBuffer<T> {
}
/// Returns the number of elements in the buffer.
#[allow(unused)]
pub fn len(&self) -> usize {
self.buf.len()
}
@@ -56,7 +57,7 @@ impl<T> CircularBuffer<T> {
}
/// Returns an iterator over the elements, from oldest to newest.
pub fn iter(&self) -> impl DoubleEndedIterator<Item = &T> {
pub fn iter(&self) -> impl DoubleEndedIterator<Item = &T> + ExactSizeIterator {
self.buf.iter()
}
+12 -11
View File
@@ -41,18 +41,19 @@ impl LogBuffer {
buf.clear();
}
/// Iterate over all messages without modifying the buffer.
/// Access the buffer contents via an iterator.
///
/// Messages are passed to `f` in reverse order (newest first).
pub fn for_each(&self, mut f: impl FnMut(&LogMessage)) {
/// The iterator yields messages in reverse order (newest first) and
/// implements `ExactSizeIterator`, so `iter.len()` returns the count.
// NOTE: We use `&mut dyn ExactSizeIterator` rather than `impl FnOnce(impl ExactSizeIterator)`
// because Rust doesn't allow nested `impl Trait` in that position. A generic parameter
// `F: FnOnce(I) where I: ExactSizeIterator` doesn't work either because `I` would be
// caller-determined, but we need to pass our concrete iterator type. HRTB with the
// concrete type (`F: for<'a> FnOnce(Rev<vec_deque::Iter<'a, T>>)`) works but leaks
// implementation details.
pub fn with_iter<R>(&self, f: impl FnOnce(&mut dyn ExactSizeIterator<Item = &LogMessage>) -> R) -> R {
let buf = self.buf.lock().unwrap();
for log_msg in buf.iter().rev() {
f(log_msg);
}
}
/// Returns the number of messages currently in the buffer.
pub fn len(&self) -> usize {
self.buf.lock().unwrap().len()
let mut iter = buf.iter().rev();
f(&mut iter)
}
}
+5 -4
View File
@@ -129,10 +129,11 @@ impl LogHandler {
use std::fmt::Write;
writeln!(&mut text, "=== [{origin}] ===").unwrap();
writeln!(&mut text, "{} log messages (newest first):", buffer.len()).unwrap();
buffer.for_each(|log_msg| {
self.write_log_msg(&mut text, log_msg, now);
buffer.with_iter(|iter| {
writeln!(&mut text, "{} log messages (newest first):", iter.len()).unwrap();
for log_msg in iter {
self.write_log_msg(&mut text, log_msg, now);
}
});
text.push('\n');
}