loom/sync/arc.rs
1use crate::rt;
2
3use std::borrow::Borrow;
4use std::pin::Pin;
5use std::{mem, ops, ptr};
6
7/// Mock implementation of `std::sync::Arc`.
8#[derive(Debug)]
9pub struct Arc<T: ?Sized> {
10 obj: std::sync::Arc<rt::Arc>,
11 value: std::sync::Arc<T>,
12}
13
14impl<T> Arc<T> {
15 /// Constructs a new `Arc<T>`.
16 #[track_caller]
17 pub fn new(value: T) -> Arc<T> {
18 let std = std::sync::Arc::new(value);
19
20 Arc::from_std(std)
21 }
22
23 /// Constructs a new `Pin<Arc<T>>`.
24 pub fn pin(data: T) -> Pin<Arc<T>> {
25 unsafe { Pin::new_unchecked(Arc::new(data)) }
26 }
27
28 /// Returns the inner value, if the `Arc` has exactly one strong reference.
29 #[track_caller]
30 pub fn try_unwrap(this: Arc<T>) -> Result<T, Arc<T>> {
31 if !this.obj.get_mut(location!()) {
32 return Err(this);
33 }
34
35 assert_eq!(1, std::sync::Arc::strong_count(&this.value));
36 // work around our inability to destruct the object normally,
37 // because of the `Drop` presense.
38 this.obj.ref_dec(location!());
39 this.unregister();
40
41 // Use the same pattern of unwrapping as `std` does.
42 // We can't normally move the field out of the object
43 // because it implements `drop`.
44 let arc_value = unsafe {
45 let _arc_obj = ptr::read(&this.obj);
46 let arc_value = ptr::read(&this.value);
47
48 mem::forget(this);
49
50 arc_value
51 };
52 match std::sync::Arc::try_unwrap(arc_value) {
53 Ok(value) => Ok(value),
54 Err(_) => unreachable!(),
55 }
56 }
57}
58
59impl<T: ?Sized> Arc<T> {
60 /// Converts `std::sync::Arc` to `loom::sync::Arc`.
61 ///
62 /// This is needed to create a `loom::sync::Arc<T>` where `T: !Sized`.
63 ///
64 /// ## Panics
65 ///
66 /// If the provided `Arc` has copies (i.e., if it is not unique).
67 ///
68 /// ## Examples
69 ///
70 /// While `std::sync::Arc` with `T: !Sized` can be created by coercing an
71 /// `std::sync::Arc` with a sized value:
72 ///
73 /// ```rust
74 /// let sized: std::sync::Arc<[u8; 3]> = std::sync::Arc::new([1, 2, 3]);
75 /// let _unsized: std::sync::Arc<[u8]> = sized; // coercion
76 /// ```
77 ///
78 /// `loom::sync::Arc` can't be created in the same way:
79 ///
80 /// ```compile_fail,E0308
81 /// use loom::sync::Arc;
82 ///
83 /// let sized: Arc<[u8; 3]> = Arc::new([1, 2, 3]);
84 /// let _unsized: Arc<[u8]> = sized; // error: mismatched types
85 /// ```
86 ///
87 /// This is because `std::sync::Arc` uses an unstable trait called `CoerceUnsized`
88 /// that loom can't use. To create `loom::sync::Arc` with an unsized inner value
89 /// first create a `std::sync::Arc` of an appropriate type and then use this method:
90 ///
91 /// ```rust
92 /// use loom::sync::Arc;
93 ///
94 /// # loom::model::model(|| {
95 /// let std: std::sync::Arc<[u8]> = std::sync::Arc::new([1, 2, 3]);
96 /// let loom: Arc<[u8]> = Arc::from_std(std);
97 ///
98 /// let std: std::sync::Arc<dyn Send + Sync> = std::sync::Arc::new([1, 2, 3]);
99 /// let loom: Arc<dyn Send + Sync> = Arc::from_std(std);
100 /// # });
101 /// ```
102 #[track_caller]
103 pub fn from_std(mut std: std::sync::Arc<T>) -> Self {
104 assert!(
105 std::sync::Arc::get_mut(&mut std).is_some(),
106 "Arc provided to `from_std` is not unique"
107 );
108
109 let obj = std::sync::Arc::new(rt::Arc::new(location!()));
110 let objc = std::sync::Arc::clone(&obj);
111
112 rt::execution(|e| {
113 e.arc_objs
114 .insert(std::sync::Arc::as_ptr(&std) as *const (), objc);
115 });
116
117 Arc { obj, value: std }
118 }
119
120 /// Gets the number of strong (`Arc`) pointers to this value.
121 #[track_caller]
122 pub fn strong_count(this: &Self) -> usize {
123 this.obj.strong_count()
124 }
125
126 /// Increments the strong reference count on the `Arc<T>` associated with the
127 /// provided pointer by one.
128 ///
129 /// # Safety
130 ///
131 /// The pointer must have been obtained through `Arc::into_raw`, and the
132 /// associated `Arc` instance must be valid (i.e. the strong count must be at
133 /// least 1) for the duration of this method.
134 #[track_caller]
135 pub unsafe fn increment_strong_count(ptr: *const T) {
136 // Retain Arc, but don't touch refcount by wrapping in ManuallyDrop
137 let arc = mem::ManuallyDrop::new(Arc::<T>::from_raw(ptr));
138 // Now increase refcount, but don't drop new refcount either
139 let _arc_clone: mem::ManuallyDrop<_> = arc.clone();
140 }
141
142 /// Decrements the strong reference count on the `Arc<T>` associated with the
143 /// provided pointer by one.
144 ///
145 /// # Safety
146 ///
147 /// The pointer must have been obtained through `Arc::into_raw`, and the
148 /// associated `Arc` instance must be valid (i.e. the strong count must be at
149 /// least 1) when invoking this method. This method can be used to release the final
150 /// `Arc` and backing storage, but **should not** be called after the final `Arc` has been
151 /// released.
152 #[track_caller]
153 pub unsafe fn decrement_strong_count(ptr: *const T) {
154 mem::drop(Arc::from_raw(ptr));
155 }
156
157 /// Returns a mutable reference to the inner value, if there are
158 /// no other `Arc` pointers to the same value.
159 #[track_caller]
160 pub fn get_mut(this: &mut Self) -> Option<&mut T> {
161 if this.obj.get_mut(location!()) {
162 assert_eq!(1, std::sync::Arc::strong_count(&this.value));
163 Some(std::sync::Arc::get_mut(&mut this.value).unwrap())
164 } else {
165 None
166 }
167 }
168
169 /// Returns `true` if the two `Arc`s point to the same value (not
170 /// just values that compare as equal).
171 pub fn ptr_eq(this: &Self, other: &Self) -> bool {
172 std::sync::Arc::ptr_eq(&this.value, &other.value)
173 }
174
175 /// Consumes the `Arc`, returning the wrapped pointer.
176 pub fn into_raw(this: Self) -> *const T {
177 let ptr = Self::as_ptr(&this);
178 mem::forget(this);
179 ptr
180 }
181
182 /// Provides a raw pointer to the data.
183 pub fn as_ptr(this: &Self) -> *const T {
184 std::sync::Arc::as_ptr(&this.value)
185 }
186
187 /// Constructs an `Arc` from a raw pointer.
188 ///
189 /// # Safety
190 ///
191 /// The raw pointer must have been previously returned by a call to
192 /// [`Arc<U>::into_raw`][into_raw] where `U` must have the same size and
193 /// alignment as `T`. This is trivially true if `U` is `T`.
194 /// Note that if `U` is not `T` but has the same size and alignment, this is
195 /// basically like transmuting references of different types. See
196 /// [`mem::transmute`][transmute] for more information on what
197 /// restrictions apply in this case.
198 ///
199 /// The user of `from_raw` has to make sure a specific value of `T` is only
200 /// dropped once.
201 ///
202 /// This function is unsafe because improper use may lead to memory unsafety,
203 /// even if the returned `Arc<T>` is never accessed.
204 ///
205 /// [into_raw]: Arc::into_raw
206 /// [transmute]: core::mem::transmute
207 #[track_caller]
208 pub unsafe fn from_raw(ptr: *const T) -> Self {
209 let inner = std::sync::Arc::from_raw(ptr);
210 let obj = rt::execution(|e| std::sync::Arc::clone(&e.arc_objs[&ptr.cast()]));
211 Arc { value: inner, obj }
212 }
213
214 /// Unregister this object before it's gone.
215 fn unregister(&self) {
216 rt::execution(|e| {
217 e.arc_objs
218 .remove(&std::sync::Arc::as_ptr(&self.value).cast())
219 .expect("Arc object was removed before dropping last Arc");
220 });
221 }
222}
223
224impl<T: ?Sized> ops::Deref for Arc<T> {
225 type Target = T;
226
227 fn deref(&self) -> &T {
228 &self.value
229 }
230}
231
232impl<T: ?Sized> Clone for Arc<T> {
233 #[track_caller]
234 fn clone(&self) -> Arc<T> {
235 self.obj.ref_inc(location!());
236
237 Arc {
238 value: self.value.clone(),
239 obj: self.obj.clone(),
240 }
241 }
242}
243
244impl<T: ?Sized> Drop for Arc<T> {
245 #[track_caller]
246 fn drop(&mut self) {
247 if self.obj.ref_dec(location!()) {
248 assert_eq!(
249 1,
250 std::sync::Arc::strong_count(&self.value),
251 "something odd is going on"
252 );
253 self.unregister();
254 }
255 }
256}
257
258impl<T: Default> Default for Arc<T> {
259 #[track_caller]
260 fn default() -> Arc<T> {
261 Arc::new(Default::default())
262 }
263}
264
265impl<T> From<T> for Arc<T> {
266 #[track_caller]
267 fn from(t: T) -> Self {
268 Arc::new(t)
269 }
270}
271
272impl<T: ?Sized> AsRef<T> for Arc<T> {
273 fn as_ref(&self) -> &T {
274 self
275 }
276}
277
278impl<T: ?Sized> Borrow<T> for Arc<T> {
279 fn borrow(&self) -> &T {
280 self
281 }
282}