1use std::borrow::Borrow;
23use std::fmt;
24use std::ops::Deref;
25
26use std::sync::{Arc, Condvar, Mutex, MutexGuard, Weak};
27
28use std::fmt::{Error, Formatter};
29
30struct Items<T> {
31 alive_count: usize,
32 items: Vec<Weak<InnerTrackedObject<T>>>,
33}
34
35impl<T> Default for Items<T> {
36 fn default() -> Self {
37 Items {
38 alive_count: 0,
39 items: Vec::new(),
40 }
41 }
42}
43
44impl<T> Items<T> {
45 fn record_birth(&mut self) {
46 self.alive_count += 1;
47 }
48
49 fn record_death(&mut self) {
50 self.alive_count -= 1;
51 }
52
53 fn len(&mut self) -> usize {
54 self.alive_count()
55 }
56
57 fn list_arc(&mut self) -> Vec<TrackedObject<T>> {
58 self.items
59 .iter()
60 .flat_map(|weak| weak.upgrade())
61 .map(|v| TrackedObject { inner: v })
62 .collect()
63 }
64
65 fn gc_if_needed(&mut self) {
66 if !self.should_gc() {
67 return;
68 }
69 let mut i = 0;
70 while i < self.items.len() {
71 let should_remove = self.items[i].strong_count() == 0;
72 if should_remove {
73 self.items.swap_remove(i);
74 } else {
75 i += 1;
76 }
77 }
78 }
79
80 fn alive_count(&self) -> usize {
81 self.alive_count
82 }
83
84 fn should_gc(&self) -> bool {
85 self.alive_count * 2 <= self.items.len()
86 }
87}
88
89struct InnerInventory<T> {
90 items: Mutex<Items<T>>,
91 condvar: Condvar,
92}
93
94pub struct Inventory<T> {
96 inner: Arc<InnerInventory<T>>,
97}
98
99impl<T> Default for Inventory<T> {
100 fn default() -> Self {
101 Inventory {
102 inner: Arc::new(InnerInventory {
103 items: Mutex::new(Items::default()),
104 condvar: Condvar::new(),
105 }),
106 }
107 }
108}
109
110impl<T> Clone for Inventory<T> {
111 fn clone(&self) -> Self {
112 Inventory {
113 inner: self.inner.clone(),
114 }
115 }
116}
117
118impl<T> Inventory<T> {
119 pub fn new() -> Inventory<T> {
121 Inventory::default()
122 }
123
124 fn lock_items(&self) -> MutexGuard<Items<T>> {
125 let mut guard = self.inner.items.lock().unwrap();
126 guard.gc_if_needed();
127 guard
128 }
129
130 pub fn len(&self) -> usize {
132 self.lock_items().len()
133 }
134
135 pub fn list(&self) -> Vec<TrackedObject<T>> {
189 self.lock_items().list_arc()
190 }
191
192 pub fn wait_until_empty(&self) {
203 self.wait_until_predicate(|count| count == 0)
204 }
205
206 pub fn wait_until_predicate<F: Fn(usize) -> bool>(&self, predicate_on_count: F) {
215 let mut count = self.lock_items();
216 while !predicate_on_count(count.alive_count()) {
217 count = self.inner.condvar.wait(count).unwrap();
218 }
219 }
220
221 pub fn track(&self, item: T) -> TrackedObject<T> {
223 let item_arc = Arc::new(InnerTrackedObject {
224 census: self.clone(),
225 item,
226 });
227 let item_weak = Arc::downgrade(&item_arc);
228 let mut items_lock = self.lock_items();
229 items_lock.items.push(item_weak);
230 items_lock.record_birth();
231 self.inner.condvar.notify_all();
232 TrackedObject { inner: item_arc }
233 }
234}
235
236#[derive(Clone)]
245pub struct TrackedObject<T> {
246 inner: Arc<InnerTrackedObject<T>>,
247}
248
249struct InnerTrackedObject<T> {
250 census: Inventory<T>,
251 item: T,
252}
253
254impl<T: fmt::Debug> fmt::Debug for TrackedObject<T> {
255 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
256 write!(f, "Tracked({:?})", self.inner.item)
257 }
258}
259
260impl<T> TrackedObject<T> {
261 pub fn map<F>(&self, f: F) -> TrackedObject<T>
279 where
280 F: FnOnce(&T) -> T,
281 {
282 let t = f(self);
283 self.inner.census.track(t)
284 }
285}
286
287impl<T> Drop for InnerTrackedObject<T> {
288 fn drop(&mut self) {
289 let mut lock = self.census.lock_items();
290 lock.record_death();
291 self.census.inner.condvar.notify_all();
292 }
293}
294
295impl<T> Deref for TrackedObject<T> {
296 type Target = T;
297
298 fn deref(&self) -> &T {
299 &self.inner.item
300 }
301}
302
303impl<T> AsRef<T> for TrackedObject<T> {
304 fn as_ref(&self) -> &T {
305 &self.inner.item
306 }
307}
308
309impl<T> Borrow<T> for TrackedObject<T> {
310 fn borrow(&self) -> &T {
311 &self.inner.item
312 }
313}
314
315#[cfg(test)]
316mod tests {
317
318 use super::Inventory;
319 use std::sync::mpsc::channel;
320 use std::sync::{Arc, Barrier};
321 use std::thread;
322
323 #[test]
324 fn test_census_map() {
325 let census = Inventory::new();
326 let a = census.track(1);
327 let _b = a.map(|v| v * 7);
328 assert_eq!(census.len(), 2);
329 assert_eq!(
330 census.list().into_iter().map(|m| *m).collect::<Vec<_>>(),
331 vec![1, 7]
332 );
333 }
334
335 #[test]
336 fn test_census() {
337 let census = Inventory::new();
338 let _a = census.track(1);
339 let _b = census.track(3);
340 assert_eq!(census.len(), 2,);
341 assert_eq!(
342 census.list().into_iter().map(|m| *m).collect::<Vec<_>>(),
343 vec![1, 3]
344 );
345 }
346
347 #[test]
348 fn test_census_2() {
349 let census = Inventory::new();
350 {
351 let _a = census.track(1);
352 let _b = census.track(3);
353 }
355 assert_eq!(census.len(), 0);
356 assert!(census.list().is_empty());
357 }
358
359 #[test]
360 fn test_census_3() {
361 let census = Inventory::new();
362 let a = census.track(1);
363 let _a2 = a.clone();
364 drop(a);
365 assert_eq!(census.len(), 1);
366 assert_eq!(
367 census.list().into_iter().map(|m| *m).collect::<Vec<_>>(),
368 vec![1]
369 );
370 }
371
372 #[test]
373 fn test_census_list_extends_life() {
374 let census = Inventory::new();
375 let a = census.track(1);
376 let living = census.list();
377 assert_eq!(living.len(), 1);
378 drop(a);
379 let living_2 = census.list();
380 assert_eq!(living_2.len(), 1);
381 drop(living_2);
382 drop(living);
383 assert_eq!(census.len(), 0);
384 assert!(census.list().is_empty());
385 }
386
387 #[test]
388 fn test_census_race_condition() {
389 let census = Inventory::new();
390 let census_clone = census.clone();
391 thread::spawn(move || {
392 for _ in 0..1_000 {
393 let _a = census_clone.track(1);
394 }
395 });
396 for i in 0..10_000 {
397 println!("i {}", i);
398 census.list();
399 }
400 }
401
402 #[test]
403 fn test_census_concurrent_drop() {
404 let census = Inventory::new();
405 let mut senders = Vec::new();
406 let mut handles = Vec::new();
407 let barrier = Arc::new(Barrier::new(2));
408 for _ in 0..2 {
409 let (send, recv) = channel();
410 let barrier = barrier.clone();
411 handles.push(thread::spawn(move || {
412 for obj in recv {
413 barrier.wait();
414 drop(obj);
415 }
416 }));
417 senders.push(send);
418 }
419 for i in 0..50_000 {
420 let tracked = census.track(i);
421 for send in &senders {
422 send.send(tracked.clone()).unwrap();
423 }
424 }
425 drop(senders);
426 for handle in handles {
427 handle.join().unwrap();
428 }
429 assert_eq!(census.len(), 0);
430 }
431
432 fn test_census_changes_iter_util(el: usize) {
433 let census = Inventory::new();
434 for i in 0..el {
435 let tracked = census.track(i);
436 thread::spawn(move || {
437 let _tracked = tracked;
438 });
439 }
440 census.wait_until_empty();
441 assert_eq!(census.len(), 0);
442 assert!(census.list().is_empty());
443 }
444
445 #[test]
446 fn test_census_changes_iter_many() {
447 for i in 1..200 {
448 test_census_changes_iter_util(i);
449 }
450 }
451}