1#![warn(
20 clippy::pedantic,
21 rust_2018_idioms,
22 missing_docs,
23 unused_qualifications,
24 unsafe_op_in_unsafe_fn
25)]
26
27use std::sync::atomic;
28use std::sync::atomic::AtomicBool;
29use try_rwlock::TryRwLock;
30
31mod concurrent_list;
32use concurrent_list::ConcurrentList;
33
34mod concurrent_slice;
35use concurrent_slice::ConcurrentSlice;
36
37mod concurrent_vec;
38use concurrent_vec::ConcurrentVec;
39
40mod inner;
41use inner::Inner;
42
43#[derive(Debug, Default)]
47pub struct Bin<'a> {
48 inner: TryRwLock<Inner<'a>>,
50 clear: AtomicBool,
52}
53
54impl<'a> Bin<'a> {
55 #[must_use]
57 pub const fn new() -> Self {
58 Self {
59 inner: TryRwLock::new(Inner::new()),
60 clear: AtomicBool::new(false),
61 }
62 }
63
64 pub fn add<T: Send + 'a>(&self, value: T) {
69 if let Some(inner) = self.inner.try_read() {
70 inner.add(value);
71 } else {
72 }
74
75 self.try_clear();
76 }
77
78 pub fn clear(&self) {
83 self.clear.store(true, atomic::Ordering::Relaxed);
84
85 self.try_clear();
86 }
87
88 fn try_clear(&self) {
90 if self.clear.load(atomic::Ordering::Relaxed) {
91 if let Some(mut inner) = self.inner.try_write() {
92 self.clear.store(false, atomic::Ordering::Relaxed);
93 inner.clear();
94 }
95 }
96 }
97
98 #[must_use]
100 pub fn size(&self) -> usize {
101 self.inner.try_read().map_or(0, |inner| inner.size())
102 }
103}
104
105impl<'a> Drop for Bin<'a> {
106 fn drop(&mut self) {
107 self.inner.get_mut().clear();
108 }
109}
110
111#[cfg(test)]
112mod tests {
113 use crate::test_util::assert_thread_safe;
114 use crate::test_util::CallOnDrop;
115 use crate::Bin;
116 use std::sync::atomic::AtomicBool;
117 use std::sync::atomic::Ordering::SeqCst;
118
119 #[test]
120 fn clear() {
121 let destructor_called = AtomicBool::new(false);
122
123 let bin = Bin::new();
124
125 bin.add(CallOnDrop(
126 || assert!(!destructor_called.swap(true, SeqCst)),
127 ));
128 assert!(!destructor_called.load(SeqCst));
129
130 bin.clear();
131 assert!(destructor_called.load(SeqCst));
132 }
133
134 #[test]
135 #[allow(clippy::extra_unused_lifetimes)]
136 fn thread_safe<'a>() {
137 assert_thread_safe::<Bin<'a>>();
138 }
139}
140
141#[cfg(test)]
142mod test_util {
143 pub(crate) fn assert_thread_safe<T: Send + Sync>() {}
144
145 pub(crate) struct CallOnDrop<T: FnMut()>(pub(crate) T);
146 impl<T: FnMut()> Drop for CallOnDrop<T> {
147 fn drop(&mut self) {
148 self.0();
149 }
150 }
151}