use crate::frame::Frame;
pub struct FrameCallback {
inner: Box<dyn for<'a> Fn(&Frame<'a>) + Send + Sync + 'static>,
}
impl FrameCallback {
pub fn new<F>(f: F) -> Self
where
F: for<'a> Fn(&Frame<'a>) + Send + Sync + 'static,
{
Self { inner: Box::new(f) }
}
pub fn invoke(&self, frame: &Frame<'_>) {
(self.inner)(frame);
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::frame::PixelFormat;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
#[test]
fn frame_callback_dispatches_to_closure() {
let counter = Arc::new(AtomicUsize::new(0));
let counter_clone = counter.clone();
let cb = FrameCallback::new(move |_frame| {
counter_clone.fetch_add(1, Ordering::SeqCst);
});
let data = vec![0u8; 16];
let frame = Frame::new(&data, 4, 4, PixelFormat::Mono8, 0, 0);
cb.invoke(&frame);
cb.invoke(&frame);
assert_eq!(counter.load(Ordering::SeqCst), 2);
}
#[test]
fn frame_callback_receives_frame_metadata() {
let seen = Arc::new(std::sync::Mutex::new(None));
let seen_clone = seen.clone();
let cb = FrameCallback::new(move |frame: &Frame<'_>| {
*seen_clone.lock().unwrap() = Some((
frame.width,
frame.height,
frame.pixel_format,
frame.frame_id,
frame.timestamp_ns,
frame.data().to_vec(),
));
});
let data = vec![9u8, 8, 7];
cb.invoke(&Frame::new(&data, 3, 1, PixelFormat::Bgr8, 42, 11));
let got = seen.lock().unwrap().clone().expect("callback not called");
assert_eq!(got.0, 3);
assert_eq!(got.1, 1);
assert_eq!(got.2, PixelFormat::Bgr8);
assert_eq!(got.3, 11);
assert_eq!(got.4, 42);
assert_eq!(got.5, vec![9, 8, 7]);
}
}