]> git.proxmox.com Git - rustc.git/blob - src/doc/nomicon/src/arc-base.md
New upstream version 1.51.0+dfsg1
[rustc.git] / src / doc / nomicon / src / 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 ```rust,ignore
14 impl<T> Arc<T> {
15 pub fn new(data: T) -> Arc<T> {
16 // We start the reference count at 1, as that first reference is the
17 // current pointer.
18 let boxed = Box::new(ArcInner {
19 rc: AtomicUsize::new(1),
20 data,
21 });
22 Arc {
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(),
26 phantom: PhantomData,
27 }
28 }
29 }
30 ```
31
32 ## Send and Sync
33
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).
38
39 This is okay because:
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
43
44 ```rust,ignore
45 unsafe impl<T: Sync + Send> Send for Arc<T> {}
46 unsafe impl<T: Sync + Send> Sync for Arc<T> {}
47 ```
48
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
52 unsoundness.
53
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.
58
59 ## Getting the `ArcInner`
60
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:
64 ```rust,ignore
65 unsafe { self.ptr.as_ref() }
66 ```
67
68 We'll be using this snippet a few times in this code (usually with an associated
69 `let` binding).
70
71 This unsafety is okay because while this `Arc` is alive, we're guaranteed that
72 the inner pointer is valid.
73
74 ## Deref
75
76 Alright. Now we can make `Arc`s (and soon will be able to clone and destroy them correctly), but how do we get
77 to the data inside?
78
79 What we need now is an implementation of `Deref`.
80
81 We'll need to import the trait:
82 ```rust,ignore
83 use std::ops::Deref;
84 ```
85
86 And here's the implementation:
87 ```rust,ignore
88 impl<T> Deref for Arc<T> {
89 type Target = T;
90
91 fn deref(&self) -> &T {
92 let inner = unsafe { self.ptr.as_ref() };
93 &inner.data
94 }
95 }
96 ```
97
98 Pretty simple, eh? This simply dereferences the `NonNull` pointer to the
99 `ArcInner<T>`, then gets a reference to the data inside.
100
101 ## Code
102
103 Here's all the code from this section:
104 ```rust,ignore
105 use std::ops::Deref;
106
107 impl<T> Arc<T> {
108 pub fn new(data: T) -> Arc<T> {
109 // We start the reference count at 1, as that first reference is the
110 // current pointer.
111 let boxed = Box::new(ArcInner {
112 rc: AtomicUsize::new(1),
113 data,
114 });
115 Arc {
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,
120 }
121 }
122 }
123
124 unsafe impl<T: Sync + Send> Send for Arc<T> {}
125 unsafe impl<T: Sync + Send> Sync for Arc<T> {}
126
127
128 impl<T> Deref for Arc<T> {
129 type Target = T;
130
131 fn deref(&self) -> &T {
132 let inner = unsafe { self.ptr.as_ref() };
133 &inner.data
134 }
135 }
136 ```