]> git.proxmox.com Git - rustc.git/blame - src/doc/nomicon/src/arc-final.md
New upstream version 1.54.0+dfsg1
[rustc.git] / src / doc / nomicon / src / arc-final.md
CommitLineData
5869c6ff
XL
1# Final Code
2
3Here's the final code, with some added comments and re-ordered imports:
4```rust
5use std::marker::PhantomData;
6use std::ops::Deref;
7use std::ptr::NonNull;
8use std::sync::atomic::{self, AtomicUsize, Ordering};
9
10pub struct Arc<T> {
11 ptr: NonNull<ArcInner<T>>,
12 phantom: PhantomData<ArcInner<T>>,
13}
14
15pub struct ArcInner<T> {
16 rc: AtomicUsize,
17 data: T,
18}
19
20impl<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
37unsafe impl<T: Sync + Send> Send for Arc<T> {}
38unsafe impl<T: Sync + Send> Sync for Arc<T> {}
39
40impl<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
49impl<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
68impl<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```