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}