mbarc_map/data_reference.rs
1use std::{
2 marker::PhantomData,
3 ops::Deref,
4 ptr::NonNull,
5 sync::{
6 atomic::{self, Ordering},
7 Mutex,
8 },
9};
10
11use crate::data_holder::DataHolder;
12use crate::MbarcMap;
13
14/// Atomic, reference counted pointer to data stored within an [MbarcMap].
15///
16/// A valid copy of DataReference should imply valid data being pointed to, regardless of the status of the owning [MbarcMap].
17///
18/// # Examples
19/// ```
20/// //In this snippet, Arc isn't really necessary, however it's generally recommended to wrap MbarcMap in an Arc as threading is its main use case
21/// //Very important to note that you do not need to wrap MbarcMap in a Mutex, and doing so is redundant
22/// use std::sync::{Arc, MutexGuard};
23/// use mbarc_map::{DataReference, MbarcMap};
24///
25/// let concurrent_map = Arc::new(MbarcMap::new());
26///
27/// let key: i64 = 2;
28/// let value: &str = "Hi";
29/// concurrent_map.insert(key, value);
30///
31/// //Retrieve the item we just put into the map, then drop the map itself
32/// let first_value: Option<DataReference<&str>> = concurrent_map.get(&key);
33/// drop(concurrent_map);
34///
35/// //Actual data reference
36/// let first_value: DataReference<&str> = first_value.unwrap();
37///
38/// //Since the map no longer exists, the only reference left is the one we're still holding
39/// assert_eq!(first_value.ref_count(), 1);
40/// //When the map is dropped all values within are marked as deleted (also the case if the individual item had been removed instead)
41/// assert!(first_value.is_marked_deleted());
42///
43/// //All values within this map are individually wrapped in a Mutex implicitly
44/// //DataReference derefs to this Mutex, and locking is necessary to actually interact with the value
45/// let first_value_lock: MutexGuard<&str> = first_value.lock().unwrap();
46/// assert_eq!(*first_value_lock, "Hi");
47///```
48pub struct DataReference<T> {
49 pub(crate) ptr: NonNull<DataHolder<T>>,
50 pub(crate) phantom: PhantomData<DataHolder<T>>,
51}
52
53impl<T> DataReference<T> {
54 pub(crate) fn raw_data(&self) -> &DataHolder<T> {
55 unsafe { self.ptr.as_ref() }
56 }
57
58 /// Has the individual element been marked as deleted?
59 ///
60 /// If this is true, that means this element has been removed from the owning [MbarcMap].
61 /// The actual data won't, however, be dropped until all references are gone.
62 ///
63 /// Important to note that this could change at any time, even if a lock is taken on the actual data itself.
64 /// You should not rely on this being 100% up-to-date in threaded code, but once this function returns true, it will not become false again.
65 pub fn is_marked_deleted(&self) -> bool {
66 self.raw_data().deleted()
67 }
68
69 /// Get a count of references to the pointed-to data.
70 ///
71 /// It is possible that this number can change even in the time it takes for this function to return.
72 /// You should not rely on this being 100% up-to-date in threaded code.
73 pub fn ref_count(&self) -> usize {
74 self.raw_data().ref_count()
75 }
76
77 pub(crate) fn increment_refcount(&self) {
78 self.raw_data().increment_refcount();
79 }
80
81 pub(crate) fn drop_impl(raw_ptr: NonNull<u8>) {
82 let inner = unsafe { raw_ptr.cast::<DataHolder<T>>().as_ref() };
83
84 if inner.ref_count.fetch_sub(1, Ordering::Release) != 1 {
85 return;
86 }
87
88 atomic::fence(Ordering::Acquire);
89
90 inner.owner.lock().unwrap().remove(&inner.owning_key);
91 }
92}
93
94unsafe impl<T: Sync + Send> Send for DataReference<T> {}
95unsafe impl<T: Sync + Send> Sync for DataReference<T> {}
96
97impl<T> Deref for DataReference<T> {
98 type Target = Mutex<T>;
99
100 fn deref(&self) -> &Self::Target {
101 &self.raw_data().data
102 }
103}
104
105impl<T> DataHolder<T> {
106 pub(crate) fn make_new_ref(&self) -> DataReference<T> {
107 self.increment_refcount();
108
109 DataReference {
110 ptr: NonNull::from(self),
111 phantom: PhantomData,
112 }
113 }
114}
115
116impl<T> Clone for DataReference<T> {
117 fn clone(&self) -> Self {
118 self.raw_data().make_new_ref()
119 }
120}
121
122impl<T> Drop for DataReference<T> {
123 fn drop(&mut self) {
124 DataReference::<T>::drop_impl(self.ptr.cast::<u8>());
125 }
126}