]>
Commit | Line | Data |
---|---|---|
5869c6ff XL |
1 | # Final Code |
2 | ||
3 | Here's the final code, with some added comments and re-ordered imports: | |
4 | ```rust | |
5 | use std::marker::PhantomData; | |
6 | use std::ops::Deref; | |
7 | use std::ptr::NonNull; | |
8 | use std::sync::atomic::{self, AtomicUsize, Ordering}; | |
9 | ||
10 | pub struct Arc<T> { | |
11 | ptr: NonNull<ArcInner<T>>, | |
12 | phantom: PhantomData<ArcInner<T>>, | |
13 | } | |
14 | ||
15 | pub struct ArcInner<T> { | |
16 | rc: AtomicUsize, | |
17 | data: T, | |
18 | } | |
19 | ||
20 | impl<T> Arc<T> { | |
21 | pub fn new(data: T) -> Arc<T> { | |
22 | // We start the reference count at 1, as that first reference is the | |
23 | // current pointer. | |
24 | let boxed = Box::new(ArcInner { | |
25 | rc: AtomicUsize::new(1), | |
26 | data, | |
27 | }); | |
28 | Arc { | |
29 | // It is okay to call `.unwrap()` here as we get a pointer from | |
30 | // `Box::into_raw` which is guaranteed to not be null. | |
31 | ptr: NonNull::new(Box::into_raw(boxed)).unwrap(), | |
32 | phantom: PhantomData, | |
33 | } | |
34 | } | |
35 | } | |
36 | ||
37 | unsafe impl<T: Sync + Send> Send for Arc<T> {} | |
38 | unsafe impl<T: Sync + Send> Sync for Arc<T> {} | |
39 | ||
40 | impl<T> Deref for Arc<T> { | |
41 | type Target = T; | |
42 | ||
43 | fn deref(&self) -> &T { | |
44 | let inner = unsafe { self.ptr.as_ref() }; | |
45 | &inner.data | |
46 | } | |
47 | } | |
48 | ||
49 | impl<T> Clone for Arc<T> { | |
50 | fn clone(&self) -> Arc<T> { | |
51 | let inner = unsafe { self.ptr.as_ref() }; | |
52 | // Using a relaxed ordering is alright here as we don't need any atomic | |
53 | // synchronization here as we're not modifying or accessing the inner | |
54 | // data. | |
55 | let old_rc = inner.rc.fetch_add(1, Ordering::Relaxed); | |
56 | ||
57 | if old_rc >= isize::MAX as usize { | |
58 | std::process::abort(); | |
59 | } | |
60 | ||
61 | Self { | |
62 | ptr: self.ptr, | |
63 | phantom: PhantomData, | |
64 | } | |
65 | } | |
66 | } | |
67 | ||
68 | impl<T> Drop for Arc<T> { | |
69 | fn drop(&mut self) { | |
70 | let inner = unsafe { self.ptr.as_ref() }; | |
71 | if inner.rc.fetch_sub(1, Ordering::Release) != 1 { | |
72 | return; | |
73 | } | |
74 | // This fence is needed to prevent reordering of the use and deletion | |
75 | // of the data. | |
76 | atomic::fence(Ordering::Acquire); | |
77 | // This is safe as we know we have the last pointer to the `ArcInner` | |
78 | // and that its pointer is valid. | |
79 | unsafe { Box::from_raw(self.ptr.as_ptr()); } | |
80 | } | |
81 | } | |
82 | ``` |