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}