#![allow(deprecated)] use super::Rb; use crate::{ CachingProd, Cons, Prod, storage::Array, traits::*, wrap::{FrozenCons, FrozenProd, Wrap}, }; use core::{cell::Cell, mem}; #[test] fn producer_publishes_without_commit() { let mut rb = Rb::>::default(); let (prod, mut cons) = rb.split_ref(); let mut prod = prod.freeze(); prod.try_push(0).unwrap(); prod.try_push(1).unwrap(); assert_eq!(cons.try_pop(), Some(0)); // The cached producer must fetch progress when its old snapshot is full. prod.try_push(2).unwrap(); prod.commit(); prod.fetch(); prod.sync(); assert_eq!(cons.try_pop(), Some(1)); assert_eq!(cons.try_pop(), Some(2)); assert_eq!(cons.try_pop(), None); } #[test] fn discard_does_not_retract_published_items() { let mut rb = Rb::>::default(); let (prod, mut cons) = rb.split_ref(); let mut prod = prod.freeze(); prod.try_push(0).unwrap(); prod.discard(); assert_eq!(cons.try_pop(), Some(0)); prod.try_push(1).unwrap(); assert_eq!(cons.try_pop(), Some(1)); // Discarding after the consumer has advanced must not rewind the write index. prod.discard(); assert_eq!(cons.try_pop(), None); prod.try_push(2).unwrap(); assert_eq!(cons.try_pop(), Some(2)); } #[test] fn consumer_publishes_without_commit() { let mut rb = Rb::>::default(); let (mut prod, cons) = rb.split_ref(); let mut cons = cons.freeze(); prod.push_slice(&[0, 1]); // The consumer starts with an empty cached snapshot and must fetch automatically. assert_eq!(cons.try_pop(), Some(0)); prod.try_push(2).unwrap(); cons.commit(); cons.fetch(); cons.sync(); assert_eq!(cons.try_pop(), Some(1)); assert_eq!(cons.try_pop(), Some(2)); assert_eq!(cons.try_pop(), None); } struct CountDrop<'a>(&'a Cell); impl Drop for CountDrop<'_> { fn drop(&mut self) { self.0.set(self.0.get() + 1); } } #[test] fn forgotten_consumer_does_not_drop_items_twice() { for mode in 0..3 { for offset in [0, 3] { let drops: [Cell; 3] = core::array::from_fn(|_| Cell::new(0)); let mut rb = Rb::, 4>>::default(); for _ in 0..offset { rb.try_push(CountDrop(&drops[0])).ok().unwrap(); drop(rb.try_pop().unwrap()); } drops[0].set(0); let mut prod = CachingProd::new(&rb); for counter in &drops { prod.try_push(CountDrop(counter)).ok().unwrap(); } let mut cons = match mode { 0 => crate::CachingCons::new(&rb).freeze(), 1 => Cons::new(&rb).freeze(), _ => FrozenCons::new(&rb), }; let item = cons.try_pop().unwrap(); mem::forget(cons); drop(item); drop(prod); assert_eq!(rb.occupied_len(), 2); assert_eq!(drops[0].get(), 1); drop(rb); for counter in &drops { assert_eq!(counter.get(), 1); } } } } #[test] fn forgotten_producer_keeps_items_owned_by_buffer() { let drops = Cell::new(0); let rb = Rb::, 2>>::default(); let mut prod = FrozenProd::new(&rb); prod.try_push(CountDrop(&drops)).ok().unwrap(); mem::forget(prod); assert_eq!(rb.occupied_len(), 1); drop(rb); assert_eq!(drops.get(), 1); } #[test] fn conversion_and_extraction_preserve_endpoint_rights() { let rb = Rb::>::default(); let prod = Prod::new(&rb).freeze(); let cons = Cons::new(&rb).freeze(); let obs = prod.observe(); assert!(obs.write_is_held() && obs.read_is_held()); let rb_ref = prod.into_rb_ref(); assert!(!obs.write_is_held() && obs.read_is_held()); let mut prod = FrozenProd::new(rb_ref); prod.try_push(1).unwrap(); drop(prod); drop(cons); assert!(!obs.write_is_held() && !obs.read_is_held()); let mut cons = FrozenCons::new(&rb); assert_eq!(cons.try_pop(), Some(1)); }