3 Now that we've decided the layout for our implementation of `Arc`, let's create
6 ## Constructing the Arc
8 We'll first need a way to construct an `Arc<T>`.
10 This is pretty simple, as we just need to box the `ArcInner<T>` and get a
11 `NonNull<T>` pointer to it.
15 pub fn new(data: T) -> Arc<T> {
16 // We start the reference count at 1, as that first reference is the
18 let boxed = Box::new(ArcInner {
19 rc: AtomicUsize::new(1),
23 // It is okay to call `.unwrap()` here as we get a pointer from
24 // `Box::into_raw` which is guaranteed to not be null.
25 ptr: NonNull::new(Box::into_raw(boxed)).unwrap(),
34 Since we're building a concurrency primitive, we'll need to be able to send it
35 across threads. Thus, we can implement the `Send` and `Sync` marker traits. For
36 more information on these, see [the section on `Send` and
37 `Sync`](send-and-sync.md).
40 * You can only get a mutable reference to the value inside an `Arc` if and only
41 if it is the only `Arc` referencing that data (which only happens in `Drop`)
42 * We use atomics for the shared mutable reference counting
45 unsafe impl<T: Sync + Send> Send for Arc<T> {}
46 unsafe impl<T: Sync + Send> Sync for Arc<T> {}
49 We need to have the bound `T: Sync + Send` because if we did not provide those
50 bounds, it would be possible to share values that are thread-unsafe across a
51 thread boundary via an `Arc`, which could possibly cause data races or
54 For example, if those bounds were not present, `Arc<Rc<u32>>` would be `Sync` or
55 `Send`, meaning that you could clone the `Rc` out of the `Arc` to send it across
56 a thread (without creating an entirely new `Rc`), which would create data races
57 as `Rc` is not thread-safe.
59 ## Getting the `ArcInner`
61 To dereference the `NonNull<T>` pointer into a `&T`, we can call
62 `NonNull::as_ref`. This is unsafe, unlike the typical `as_ref` function, so we
63 must call it like this:
65 unsafe { self.ptr.as_ref() }
68 We'll be using this snippet a few times in this code (usually with an associated
71 This unsafety is okay because while this `Arc` is alive, we're guaranteed that
72 the inner pointer is valid.
76 Alright. Now we can make `Arc`s (and soon will be able to clone and destroy them correctly), but how do we get
79 What we need now is an implementation of `Deref`.
81 We'll need to import the trait:
86 And here's the implementation:
88 impl<T> Deref for Arc<T> {
91 fn deref(&self) -> &T {
92 let inner = unsafe { self.ptr.as_ref() };
98 Pretty simple, eh? This simply dereferences the `NonNull` pointer to the
99 `ArcInner<T>`, then gets a reference to the data inside.
103 Here's all the code from this section:
108 pub fn new(data: T) -> Arc<T> {
109 // We start the reference count at 1, as that first reference is the
111 let boxed = Box::new(ArcInner {
112 rc: AtomicUsize::new(1),
116 // It is okay to call `.unwrap()` here as we get a pointer from
117 // `Box::into_raw` which is guaranteed to not be null.
118 ptr: NonNull::new(Box::into_raw(boxed)).unwrap(),
119 phantom: PhantomData,
124 unsafe impl<T: Sync + Send> Send for Arc<T> {}
125 unsafe impl<T: Sync + Send> Sync for Arc<T> {}
128 impl<T> Deref for Arc<T> {
131 fn deref(&self) -> &T {
132 let inner = unsafe { self.ptr.as_ref() };