use std::collections::HashMap;
use std::sync::atomic::{AtomicU32, Ordering};
use std::sync::{Arc, Mutex};
use chimeras::Frame;
use crate::poison::recover_lock;
pub(crate) trait FrameSource: Send + Sync + 'static {
fn snapshot(&self, id: u32) -> Option<(Frame, u32)>;
}
#[derive(Clone, Default)]
pub struct Registry {
pub(crate) inner: Arc<Mutex<HashMap<u32, LatestFrame>>>,
}
impl FrameSource for Registry {
fn snapshot(&self, id: u32) -> Option<(Frame, u32)> {
let guard = recover_lock(&self.inner);
guard.get(&id)?.snapshot_with_counter()
}
}
pub fn get_or_create_sink(registry: &Registry, id: u32) -> LatestFrame {
let mut guard = recover_lock(®istry.inner);
guard.entry(id).or_default().clone()
}
pub fn remove_sink(registry: &Registry, id: u32) {
let mut guard = recover_lock(®istry.inner);
guard.remove(&id);
}
#[derive(Clone, Default)]
pub struct LatestFrame {
pub(crate) frame: Arc<Mutex<Option<Frame>>>,
pub(crate) counter: Arc<AtomicU32>,
}
impl LatestFrame {
pub(crate) fn snapshot_with_counter(&self) -> Option<(Frame, u32)> {
let slot = recover_lock(&self.frame);
let frame = slot.as_ref()?.clone();
let counter = self.counter.load(Ordering::Acquire);
Some((frame, counter))
}
}
pub fn publish_frame(sink: &LatestFrame, frame: Frame) {
let mut slot = recover_lock(&sink.frame);
*slot = Some(frame);
sink.counter.fetch_add(1, Ordering::Release);
}