Pointers_Study_With_Core_Concepts/
rc.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
//! Basic implementation of Rc shared pointer

use crate::cell::MyCell;
use std::{marker::PhantomData, ops::Deref, ptr::NonNull};

/// # Required to use PhantomData
/// It tells the compiler that when you drop the Rc
/// an RcInner<T> might be dropped, and you need to check that.
/// In other words, it marks the RcInner<T> as owned by the Rc.

/// # Info
/// Doesn't impl Sync and Send because
/// if you would send the Rc to a different thread then both
/// of the threads would possibly drop it at the same time,
/// which is not okay (cell is not thread safe).
///
/// Never provides mutability.
///
/// Allows you to have multiple shared refs.
///
/// Gets deallocated when the last one goes away.
/// # Common Usage
/// Useful in data structures where you might have
/// one element be present in multiple places
/// e.g when you have something like config
/// and you dont want to make many copies of it.

pub struct MyRc<T> {
    inner: NonNull<RcInner<T>>,
    _marker: PhantomData<RcInner<T>>,
}

/// # Struct to store T value and ref count of the Rc
pub struct RcInner<T> {
    value: T,
    ref_count: MyCell<usize>,
}

impl<T> MyRc<T> {
    pub fn new(value: T) -> Self {
        let inner = Box::new(RcInner {
            ref_count: MyCell::new(1),
            value: value,
        });

        MyRc {
            // SAFE because box cannot give us a nullptr
            inner: unsafe { NonNull::new_unchecked(Box::into_raw(inner)) },
            _marker: PhantomData,
        }
    }
}

impl<T> Clone for MyRc<T> {
    fn clone(&self) -> Self {
        let inner = unsafe { self.inner.as_ref() };
        let current_refs = inner.ref_count.get();
        inner.ref_count.set(current_refs + 1);
        MyRc {
            inner: self.inner,
            _marker: PhantomData,
        }
    }
}

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

    fn deref(&self) -> &Self::Target {
        //SAFE because inner struct is deallocated only when
        //the last Rc goes away
        &unsafe { self.inner.as_ref() }.value
    }
}

impl<T> Drop for MyRc<T> {
    fn drop(&mut self) {
        let inner = unsafe { self.inner.as_ref() };
        let current_refs = inner.ref_count.get();
        if current_refs == 1 {
            drop(inner);
            //SAFE because we are keeping the ref count
            //and will drop the pointer when the last rc goes away
            unsafe { Box::from_raw(self.inner.as_ptr()) };
        } else {
            inner.ref_count.set(current_refs - 1)
        }
    }
}