]> git.proxmox.com Git - rustc.git/blob - src/doc/nomicon/src/arc-mutex/arc-base.md
New upstream version 1.55.0+dfsg1
[rustc.git] / src / doc / nomicon / src / arc-mutex / arc-base.md
1 # Base Code
2
3 Now that we've decided the layout for our implementation of `Arc`, let's create
4 some basic code.
5
6 ## Constructing the Arc
7
8 We'll first need a way to construct an `Arc<T>`.
9
10 This is pretty simple, as we just need to box the `ArcInner<T>` and get a
11 `NonNull<T>` pointer to it.
12
13 <!-- ignore: simplified code -->
14 ```rust,ignore
15 impl<T> Arc<T> {
16 pub fn new(data: T) -> Arc<T> {
17 // We start the reference count at 1, as that first reference is the
18 // current pointer.
19 let boxed = Box::new(ArcInner {
20 rc: AtomicUsize::new(1),
21 data,
22 });
23 Arc {
24 // It is okay to call `.unwrap()` here as we get a pointer from
25 // `Box::into_raw` which is guaranteed to not be null.
26 ptr: NonNull::new(Box::into_raw(boxed)).unwrap(),
27 phantom: PhantomData,
28 }
29 }
30 }
31 ```
32
33 ## Send and Sync
34
35 Since we're building a concurrency primitive, we'll need to be able to send it
36 across threads. Thus, we can implement the `Send` and `Sync` marker traits. For
37 more information on these, see [the section on `Send` and
38 `Sync`](../send-and-sync.md).
39
40 This is okay because:
41 * You can only get a mutable reference to the value inside an `Arc` if and only
42 if it is the only `Arc` referencing that data (which only happens in `Drop`)
43 * We use atomics for the shared mutable reference counting
44
45 <!-- ignore: simplified code -->
46 ```rust,ignore
47 unsafe impl<T: Sync + Send> Send for Arc<T> {}
48 unsafe impl<T: Sync + Send> Sync for Arc<T> {}
49 ```
50
51 We need to have the bound `T: Sync + Send` because if we did not provide those
52 bounds, it would be possible to share values that are thread-unsafe across a
53 thread boundary via an `Arc`, which could possibly cause data races or
54 unsoundness.
55
56 For example, if those bounds were not present, `Arc<Rc<u32>>` would be `Sync` or
57 `Send`, meaning that you could clone the `Rc` out of the `Arc` to send it across
58 a thread (without creating an entirely new `Rc`), which would create data races
59 as `Rc` is not thread-safe.
60
61 ## Getting the `ArcInner`
62
63 To dereference the `NonNull<T>` pointer into a `&T`, we can call
64 `NonNull::as_ref`. This is unsafe, unlike the typical `as_ref` function, so we
65 must call it like this:
66
67 <!-- ignore: simplified code -->
68 ```rust,ignore
69 unsafe { self.ptr.as_ref() }
70 ```
71
72 We'll be using this snippet a few times in this code (usually with an associated
73 `let` binding).
74
75 This unsafety is okay because while this `Arc` is alive, we're guaranteed that
76 the inner pointer is valid.
77
78 ## Deref
79
80 Alright. Now we can make `Arc`s (and soon will be able to clone and destroy them correctly), but how do we get
81 to the data inside?
82
83 What we need now is an implementation of `Deref`.
84
85 We'll need to import the trait:
86
87 <!-- ignore: simplified code -->
88 ```rust,ignore
89 use std::ops::Deref;
90 ```
91
92 And here's the implementation:
93
94 <!-- ignore: simplified code -->
95 ```rust,ignore
96 impl<T> Deref for Arc<T> {
97 type Target = T;
98
99 fn deref(&self) -> &T {
100 let inner = unsafe { self.ptr.as_ref() };
101 &inner.data
102 }
103 }
104 ```
105
106 Pretty simple, eh? This simply dereferences the `NonNull` pointer to the
107 `ArcInner<T>`, then gets a reference to the data inside.
108
109 ## Code
110
111 Here's all the code from this section:
112
113 <!-- ignore: simplified code -->
114 ```rust,ignore
115 use std::ops::Deref;
116
117 impl<T> Arc<T> {
118 pub fn new(data: T) -> Arc<T> {
119 // We start the reference count at 1, as that first reference is the
120 // current pointer.
121 let boxed = Box::new(ArcInner {
122 rc: AtomicUsize::new(1),
123 data,
124 });
125 Arc {
126 // It is okay to call `.unwrap()` here as we get a pointer from
127 // `Box::into_raw` which is guaranteed to not be null.
128 ptr: NonNull::new(Box::into_raw(boxed)).unwrap(),
129 phantom: PhantomData,
130 }
131 }
132 }
133
134 unsafe impl<T: Sync + Send> Send for Arc<T> {}
135 unsafe impl<T: Sync + Send> Sync for Arc<T> {}
136
137
138 impl<T> Deref for Arc<T> {
139 type Target = T;
140
141 fn deref(&self) -> &T {
142 let inner = unsafe { self.ptr.as_ref() };
143 &inner.data
144 }
145 }
146 ```