1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
use core::hint;
use core::mem;
use core::ops::Deref;
use alloc::sync::Arc;
use alloc::sync::Weak;
use parking_lot::Mutex;
use parking_lot::RwLock;
use parking_lot::RwLockReadGuard;
/// `Listener` implements the emitter side of the [Output Tracking pattern].
///
/// [Output Tracking]: https://www.jamesshore.com/v2/projects/nullables/testing-without-mocks#output-tracking
pub struct Listener<T> {
trackers: Mutex<Vec<Weak<RwLock<Vec<T>>>>>,
}
impl<T> Listener<T> {
/// Emit a new event to attached listeners.
pub fn emit(&self, event: &T)
where
T: Clone,
{
let should_prune = self
.trackers
.lock()
.iter()
.fold(false, |should_prune, tracker| {
let Some(tracker) = tracker.upgrade() else {
return true;
};
tracker.write().push(event.clone());
should_prune
});
if should_prune {
self.prune();
}
}
/// Create a new [`Tracker`], connected to this listener.
pub fn track(&self) -> Tracker<T> {
let events = Arc::default();
self.trackers.lock().push(Arc::downgrade(&events));
Tracker { events }
}
}
impl<T> Listener<T> {
fn prune(&self) {
self.trackers.lock().retain(|arc| 0 < arc.strong_count());
}
}
impl<T> Default for Listener<T> {
fn default() -> Self {
let trackers = Mutex::default();
Self { trackers }
}
}
/// `Tracker` implements the receiver side of the [Output Tracking pattern].
///
/// [Output Tracking]: https://www.jamesshore.com/v2/projects/nullables/testing-without-mocks#output-tracking
#[derive(Clone, Debug)]
pub struct Tracker<T> {
events: Arc<RwLock<Vec<T>>>,
}
impl<T> Tracker<T> {
/// Consume all current events.
///
/// The consumed events will not be returned by future invocations of `data` or `consume`.
#[must_use]
pub fn consume(&self) -> Vec<T> {
let mut events = self.events.write();
mem::take(&mut events)
}
/// Get a read-only view of tracked data so far.
///
/// <div class="warning">
///
/// This will block the sender side while the returned handle exists, so it should not be held for a long time.
/// Alternatively, you can copy out of the returned view or use [`Tracker::consume`] if you do not need to retain the
/// data.
///
/// </div>
#[must_use]
pub fn data(&self) -> TrackerData<T> {
TrackerData(self.events.read())
}
/// Stop listening on this `Tracker`.
///
/// This returns any remaining events in the tracker.
#[must_use]
pub fn stop(mut self) -> Vec<T> {
loop {
match Arc::try_unwrap(self.events) {
Ok(events) => return events.into_inner(),
Err(ev) => {
self.events = ev;
hint::spin_loop();
}
};
}
}
}
/// `TrackerData` is a read-only view of data tracked in an [`OutputTracker`] so far.
///
/// <div class="warning">
///
/// This will block the sender side while the handle exists, so it should not be held for a long time.
/// Alternatively, you can copy out of the returned view or use [`Tracker::consume`] if you do not need to retain the
/// data.
///
/// </div>
#[derive(Debug)]
pub struct TrackerData<'l, T>(RwLockReadGuard<'l, Vec<T>>);
impl<T> Deref for TrackerData<'_, T> {
type Target = [T];
fn deref(&self) -> &Self::Target {
&self.0
}
}