use core::{cell::Cell, marker::PhantomData};
use crate::runtime_core::consts::TAP_EVENTS;
pub use crate::observe::event::{Evidence, TapEvent};
struct RingBuffer<'a> {
head: Cell<usize>,
storage: *mut TapEvent,
_marker: PhantomData<&'a mut [TapEvent; TAP_EVENTS]>,
_no_send_sync: PhantomData<*mut ()>,
}
pub(crate) fn emit(ring: &TapRing<'_>, event: TapEvent) {
ring.push(event);
}
impl<'a> RingBuffer<'a> {
fn from_ptr(storage: *mut TapEvent) -> Self {
Self {
head: Cell::new(0),
storage,
_marker: PhantomData,
_no_send_sync: PhantomData,
}
}
fn push(&self, event: TapEvent) {
let head = self.head.get();
let idx = head % TAP_EVENTS;
self.head.set(head.wrapping_add(1));
unsafe {
self.storage.add(idx).write(event);
}
}
fn port(&self) -> RingPort<'_> {
let head = self.head.get();
let cursor = head.saturating_sub(TAP_EVENTS);
RingPort {
head: &self.head,
storage: self.storage.cast_const(),
cursor,
_marker: PhantomData,
}
}
}
struct RingPort<'a> {
head: &'a Cell<usize>,
storage: *const TapEvent,
cursor: usize,
_marker: PhantomData<&'a [TapEvent]>,
}
impl RingPort<'_> {
#[inline]
fn normalize_cursor(&mut self, head: usize) {
if head.wrapping_sub(self.cursor) > TAP_EVENTS {
self.cursor = head.wrapping_sub(TAP_EVENTS);
}
}
#[inline]
fn peek(&mut self) -> Option<TapEvent> {
let head = self.head.get();
self.normalize_cursor(head);
if self.cursor == head {
return None;
}
let index = self.cursor % TAP_EVENTS;
Some(unsafe {
core::ptr::read_volatile(self.storage.add(index))
})
}
#[inline]
fn advance(&mut self) {
self.cursor = self.cursor.wrapping_add(1);
}
fn next(&mut self) -> Option<TapEvent> {
let event = self.peek()?;
self.advance();
Some(event)
}
}
pub struct TapPort<'a> {
ring: RingPort<'a>,
}
impl Iterator for TapPort<'_> {
type Item = TapEvent;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.ring.next()
}
}
pub(crate) struct TapRing<'a> {
ring: RingBuffer<'a>,
}
impl<'a> TapRing<'a> {
pub(crate) fn from_storage(storage: &'a mut [TapEvent; TAP_EVENTS]) -> Self {
Self {
ring: RingBuffer::from_ptr(storage.as_mut_ptr()),
}
}
pub(crate) fn push(&self, event: TapEvent) {
self.ring.push(event);
}
pub(crate) fn port(&self) -> TapPort<'_> {
TapPort {
ring: self.ring.port(),
}
}
}