Base Code - The Rustonomicon
Description: The Dark Arts of Advanced and Unsafe Rust Programming

## Keyboard shortcuts

Press `←` or `→` to navigate between chapters

Press `S` or `/` to search in the book

Press `?` to show this help

Press `Esc` to hide this help

# Base Code

Now that we’ve decided the layout for our implementation of `Arc`, let’s create some basic code.

## Constructing the Arc

We’ll first need a way to construct an `Arc<T>`.

This is pretty simple, as we just need to box the `ArcInner<T>` and get a `NonNull<T>` pointer to it.

    impl<T> Arc<T> {
        pub fn new(data: T) -> Arc<T> {
            // We start the reference count at 1, as that first reference is the
            // current pointer.
            let boxed = Box::new(ArcInner {
                rc: AtomicUsize::new(1),
                data,
            });
            Arc {
                // It is okay to call `.unwrap()` here as we get a pointer from
                // `Box::into_raw` which is guaranteed to not be null.
                ptr: NonNull::new(Box::into_raw(boxed)).unwrap(),
                phantom: PhantomData,
            }
        }
    }

## Send and Sync

Since we’re building a concurrency primitive, we’ll need to be able to send it across threads. Thus, we can implement the `Send` and `Sync` marker traits. For more information on these, see the section on `Send` and `Sync`.

This is okay because:

- You can only get a mutable reference to the value inside an `Arc` if and only if it is the only `Arc` referencing that data (which only happens in `Drop`)
- We use atomics for the shared mutable reference counting

    unsafe impl<T: Sync + Send> Send for Arc<T> {}
    unsafe impl<T: Sync + Send> Sync for Arc<T> {}

We need to have the bound `T: Sync + Send` because if we did not provide those bounds, it would be possible to share values that are thread-unsafe across a thread boundary via an `Arc`, which could possibly cause data races or unsoundness.

For example, if those bounds were not present, `Arc<Rc<u32>>` would be `Sync` or `Send`, meaning that you could clone the `Rc` out of the `Arc` to send it across a thread (without creating an entirely new `Rc`), which would create data races as `Rc` is not thread-safe.

## Getting the `ArcInner`

To dereference the `NonNull<T>` pointer into a `&T`, we can call `NonNull::as_ref`. This is unsafe, unlike the typical `as_ref` function, so we must call it like this:

    unsafe { self.ptr.as_ref() }

We’ll be using this snippet a few times in this code (usually with an associated `let` binding).

This unsafety is okay because while this `Arc` is alive, we’re guaranteed that the inner pointer is valid.

## Deref

Alright. Now we can make `Arc`s (and soon will be able to clone and destroy them correctly), but how do we get to the data inside?

What we need now is an implementation of `Deref`.

We’ll need to import the trait:

    use std::ops::Deref;

And here’s the implementation:

    impl<T> Deref for Arc<T> {
        type Target = T;

        fn deref(&self) -> &T {
            let inner = unsafe { self.ptr.as_ref() };
            &inner.data
        }
    }

Pretty simple, eh? This simply dereferences the `NonNull` pointer to the `ArcInner<T>`, then gets a reference to the data inside.

## Code

Here’s all the code from this section:

    use std::ops::Deref;

    impl<T> Arc<T> {
        pub fn new(data: T) -> Arc<T> {
            // We start the reference count at 1, as that first reference is the
            // current pointer.
            let boxed = Box::new(ArcInner {
                rc: AtomicUsize::new(1),
                data,
            });
            Arc {
                // It is okay to call `.unwrap()` here as we get a pointer from
                // `Box::into_raw` which is guaranteed to not be null.
                ptr: NonNull::new(Box::into_raw(boxed)).unwrap(),
                phantom: PhantomData,
            }
        }
    }

    unsafe impl<T: Sync + Send> Send for Arc<T> {}
    unsafe impl<T: Sync + Send> Sync for Arc<T> {}

    impl<T> Deref for Arc<T> {
        type Target = T;

        fn deref(&self) -> &T {
            let inner = unsafe { self.ptr.as_ref() };
            &inner.data
        }
    }