use crate::sync::{AtomicBool, AtomicU32, Ordering, TrackedCell};
use core::cell::Cell;
use core::marker::PhantomData;
use core::mem::MaybeUninit;
const SLOT_MASK: u32 = 0b11;
const READY_BIT: u32 = 0b100;
const PRODUCER_SLOT_XOR: u32 = 1;
const CONSUMER_SLOT_XOR: u32 = 2;
#[derive(Clone, Copy)]
struct Entry<T: Copy> {
generation: u32,
value: T,
}
#[derive(Clone, Copy)]
struct ProducerState {
back_encoded: u32,
next_generation: u32,
}
#[derive(Clone, Copy)]
struct ConsumerState {
front_encoded: u32,
last_generation: u32,
}
#[cfg(not(loom))]
const fn slot_array<T: Copy>() -> [TrackedCell<MaybeUninit<Entry<T>>>; 3] {
[const { TrackedCell::new(MaybeUninit::uninit()) }; 3]
}
#[cfg(loom)]
fn slot_array<T: Copy>() -> [TrackedCell<MaybeUninit<Entry<T>>>; 3] {
core::array::from_fn(|_| TrackedCell::new(MaybeUninit::uninit()))
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[must_use]
pub struct PublishReport {
pub generation: u32,
pub replaced_unread: bool,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[must_use]
pub struct LatestItem<T> {
pub value: T,
pub generation: u32,
pub skipped: u32,
}
pub struct LatestBuf<T: Copy> {
exchange: AtomicU32,
slots: [TrackedCell<MaybeUninit<Entry<T>>>; 3],
producer_state: TrackedCell<ProducerState>,
consumer_state: TrackedCell<ConsumerState>,
producer_taken: AtomicBool,
consumer_taken: AtomicBool,
}
unsafe impl<T: Copy + Send> Sync for LatestBuf<T> {}
impl<T: Copy> LatestBuf<T> {
#[cfg(not(loom))]
pub const fn new() -> Self {
Self {
exchange: AtomicU32::new(0),
slots: slot_array(),
producer_state: TrackedCell::new(ProducerState {
back_encoded: 0,
next_generation: 0,
}),
consumer_state: TrackedCell::new(ConsumerState {
front_encoded: 0,
last_generation: 0,
}),
producer_taken: AtomicBool::new(false),
consumer_taken: AtomicBool::new(false),
}
}
#[cfg(loom)]
pub fn new() -> Self {
Self {
exchange: AtomicU32::new(0),
slots: slot_array(),
producer_state: TrackedCell::new(ProducerState {
back_encoded: 0,
next_generation: 0,
}),
consumer_state: TrackedCell::new(ConsumerState {
front_encoded: 0,
last_generation: 0,
}),
producer_taken: AtomicBool::new(false),
consumer_taken: AtomicBool::new(false),
}
}
#[inline]
pub fn try_producer(&self) -> Option<Producer<'_, T>> {
if self.producer_taken.swap(true, Ordering::AcqRel) {
None
} else {
Some(Producer {
buf: self,
_not_sync: PhantomData,
})
}
}
#[inline]
pub fn try_consumer(&self) -> Option<Consumer<'_, T>> {
if self.consumer_taken.swap(true, Ordering::AcqRel) {
None
} else {
Some(Consumer {
buf: self,
_not_sync: PhantomData,
})
}
}
#[inline(always)]
const fn encode(slot: u32, ready: bool) -> u32 {
slot | if ready { READY_BIT } else { 0 }
}
#[inline(always)]
const fn slot(state: u32) -> usize {
(state & SLOT_MASK) as usize
}
#[inline(always)]
const fn ready(state: u32) -> bool {
state & READY_BIT != 0
}
#[inline(always)]
const fn producer_slot(encoded: u32) -> u32 {
encoded ^ PRODUCER_SLOT_XOR
}
#[inline(always)]
const fn encode_producer_slot(slot: u32) -> u32 {
slot ^ PRODUCER_SLOT_XOR
}
#[inline(always)]
const fn consumer_slot(encoded: u32) -> u32 {
encoded ^ CONSUMER_SLOT_XOR
}
#[inline(always)]
const fn encode_consumer_slot(slot: u32) -> u32 {
slot ^ CONSUMER_SLOT_XOR
}
#[inline(always)]
const fn next_generation(current: u32) -> u32 {
match current.wrapping_add(1) {
0 => 1,
generation => generation,
}
}
#[inline(always)]
const fn generation_distance(from: u32, to: u32) -> u32 {
let raw = to.wrapping_sub(from);
if to < from { raw - 1 } else { raw }
}
}
impl<T: Copy> Default for LatestBuf<T> {
fn default() -> Self {
Self::new()
}
}
impl<T: Copy> core::fmt::Debug for LatestBuf<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("LatestBuf").finish_non_exhaustive()
}
}
pub struct Producer<'a, T: Copy> {
buf: &'a LatestBuf<T>,
_not_sync: PhantomData<Cell<()>>,
}
impl<T: Copy> Producer<'_, T> {
#[inline]
pub fn publish(&self, value: T) -> PublishReport {
let (back, generation) = self.buf.producer_state.with_mut(|state| unsafe {
let state = &mut *state;
let generation = LatestBuf::<T>::next_generation(state.next_generation);
state.next_generation = generation;
(
LatestBuf::<T>::producer_slot(state.back_encoded),
generation,
)
});
self.buf.slots[back as usize].with_mut(|slot| unsafe {
(*slot).write(Entry { generation, value });
});
let previous = self
.buf
.exchange
.swap(LatestBuf::<T>::encode(back, true), Ordering::AcqRel);
self.buf.producer_state.with_mut(|state| unsafe {
(*state).back_encoded = LatestBuf::<T>::encode_producer_slot(previous & SLOT_MASK);
});
PublishReport {
generation,
replaced_unread: LatestBuf::<T>::ready(previous),
}
}
}
impl<T: Copy> Drop for Producer<'_, T> {
fn drop(&mut self) {
self.buf.producer_taken.store(false, Ordering::Release);
}
}
impl<T: Copy> core::fmt::Debug for Producer<'_, T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("latest_buf::Producer").finish()
}
}
pub struct Consumer<'a, T: Copy> {
buf: &'a LatestBuf<T>,
_not_sync: PhantomData<Cell<()>>,
}
impl<T: Copy> Consumer<'_, T> {
#[inline]
pub fn take_latest(&self) -> Option<LatestItem<T>> {
if !LatestBuf::<T>::ready(self.buf.exchange.load(Ordering::Acquire)) {
return None;
}
let front = self
.buf
.consumer_state
.with(|state| unsafe { LatestBuf::<T>::consumer_slot((*state).front_encoded) });
let previous = self
.buf
.exchange
.swap(LatestBuf::<T>::encode(front, false), Ordering::AcqRel);
let claimed = previous & SLOT_MASK;
self.buf.consumer_state.with_mut(|state| unsafe {
(*state).front_encoded = LatestBuf::<T>::encode_consumer_slot(claimed);
});
if !LatestBuf::<T>::ready(previous) {
return None;
}
let entry = self.buf.slots[LatestBuf::<T>::slot(previous)]
.with(|slot| unsafe { (*slot).assume_init_read() });
let skipped = self.buf.consumer_state.with_mut(|state| unsafe {
let state = &mut *state;
let distance =
LatestBuf::<T>::generation_distance(state.last_generation, entry.generation);
state.last_generation = entry.generation;
distance.saturating_sub(1)
});
Some(LatestItem {
value: entry.value,
generation: entry.generation,
skipped,
})
}
}
impl<T: Copy> Drop for Consumer<'_, T> {
fn drop(&mut self) {
self.buf.consumer_taken.store(false, Ordering::Release);
}
}
impl<T: Copy> core::fmt::Debug for Consumer<'_, T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("latest_buf::Consumer").finish()
}
}
impl<T: Copy> crate::traits::LatestSink<T> for Producer<'_, T> {
#[inline]
fn publish_latest(&mut self, value: T) -> PublishReport {
self.publish(value)
}
}
impl<T: Copy> crate::traits::LatestSource<T> for Consumer<'_, T> {
#[inline]
fn try_take_latest(&mut self) -> Option<LatestItem<T>> {
self.take_latest()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn starts_empty_and_takes_each_publication_at_most_once() {
let channel = LatestBuf::<u32>::new();
let producer = channel.try_producer().unwrap();
let consumer = channel.try_consumer().unwrap();
assert_eq!(consumer.take_latest(), None);
assert_eq!(producer.publish(7).generation, 1);
assert_eq!(
consumer.take_latest(),
Some(LatestItem {
value: 7,
generation: 1,
skipped: 0
})
);
assert_eq!(consumer.take_latest(), None);
}
#[test]
fn replacement_is_reported_on_both_endpoints() {
let channel = LatestBuf::<u32>::new();
let producer = channel.try_producer().unwrap();
let consumer = channel.try_consumer().unwrap();
assert!(!producer.publish(10).replaced_unread);
assert!(producer.publish(20).replaced_unread);
assert!(producer.publish(30).replaced_unread);
assert_eq!(
consumer.take_latest(),
Some(LatestItem {
value: 30,
generation: 3,
skipped: 2
})
);
}
#[test]
fn handle_reacquisition_continues_role_state() {
let channel = LatestBuf::<u32>::new();
{
let producer = channel.try_producer().unwrap();
assert_eq!(producer.publish(1).generation, 1);
}
let producer = channel.try_producer().unwrap();
assert_eq!(
producer.publish(2),
PublishReport {
generation: 2,
replaced_unread: true
}
);
{
let consumer = channel.try_consumer().unwrap();
assert_eq!(consumer.take_latest().unwrap().skipped, 1);
}
let _ = producer.publish(3);
let _ = producer.publish(4);
let consumer = channel.try_consumer().unwrap();
assert_eq!(
consumer.take_latest(),
Some(LatestItem {
value: 4,
generation: 4,
skipped: 1
})
);
}
#[test]
fn role_acquisition_is_unique_and_handles_are_send() {
fn assert_send<T: Send>() {}
assert_send::<Producer<'_, u32>>();
assert_send::<Consumer<'_, u32>>();
let channel = LatestBuf::<u32>::new();
let producer = channel.try_producer().unwrap();
let consumer = channel.try_consumer().unwrap();
assert!(channel.try_producer().is_none());
assert!(channel.try_consumer().is_none());
drop(producer);
drop(consumer);
assert!(channel.try_producer().is_some());
assert!(channel.try_consumer().is_some());
}
#[cfg(not(loom))]
#[test]
fn static_channel_yields_static_sendable_handles() {
static CHANNEL: LatestBuf<u32> = LatestBuf::new();
fn producer() -> Producer<'static, u32> {
CHANNEL.try_producer().unwrap()
}
fn consumer() -> Consumer<'static, u32> {
CHANNEL.try_consumer().unwrap()
}
let producer = producer();
let consumer = consumer();
let _ = producer.publish(42);
assert_eq!(consumer.take_latest().unwrap().value, 42);
}
#[test]
fn generation_wrap_skips_zero_and_counts_gap_exactly() {
let channel = LatestBuf::<u32>::new();
channel.producer_state.with_mut(|state| unsafe {
(*state).next_generation = u32::MAX - 1;
});
channel.consumer_state.with_mut(|state| unsafe {
(*state).last_generation = u32::MAX - 1;
});
let producer = channel.try_producer().unwrap();
let consumer = channel.try_consumer().unwrap();
assert_eq!(producer.publish(1).generation, u32::MAX);
assert_eq!(producer.publish(2).generation, 1);
assert_eq!(
consumer.take_latest(),
Some(LatestItem {
value: 2,
generation: 1,
skipped: 1
})
);
assert_eq!(LatestBuf::<u32>::generation_distance(u32::MAX, 1), 1);
}
#[test]
fn full_generation_cycle_uses_documented_approximation() {
assert_eq!(LatestBuf::<u32>::generation_distance(17, 17), 0);
let channel = LatestBuf::<u32>::new();
channel.producer_state.with_mut(|state| unsafe {
(*state).next_generation = 16;
});
channel.consumer_state.with_mut(|state| unsafe {
(*state).last_generation = 17;
});
let producer = channel.try_producer().unwrap();
let consumer = channel.try_consumer().unwrap();
assert_eq!(producer.publish(99).generation, 17);
assert_eq!(
consumer.take_latest(),
Some(LatestItem {
value: 99,
generation: 17,
skipped: 0,
})
);
}
#[test]
fn generic_payload_can_be_a_complete_block() {
let channel = LatestBuf::<[u16; 4]>::new();
let producer = channel.try_producer().unwrap();
let consumer = channel.try_consumer().unwrap();
let _ = producer.publish([1, 2, 3, 4]);
assert_eq!(consumer.take_latest().unwrap().value, [1, 2, 3, 4]);
}
#[test]
fn concurrent_publication_never_returns_torn_value() {
let channel = LatestBuf::<[u32; 4]>::new();
let total = crate::test_support::iterations(50_000);
std::thread::scope(|scope| {
scope.spawn(|| {
let producer = channel.try_producer().unwrap();
for value in 1..=total {
let _ = producer.publish([value; 4]);
}
});
let consumer = channel.try_consumer().unwrap();
let mut last_generation = 0;
while last_generation < total {
if let Some(item) = consumer.take_latest() {
assert!(item.generation > last_generation);
assert_eq!(item.value, [item.value[0]; 4]);
last_generation = item.generation;
} else {
std::thread::yield_now();
}
}
});
}
}