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
use std::cell::RefCell;
use std::rc::Rc;

pub struct Shared<T: ?Sized> {
    rc: Rc<RefCell<T>>,
}

impl<T> Shared<T> {
    pub fn new(val: T) -> Self {
        Shared {
            rc: Rc::new(RefCell::new(val)),
        }
    }
}

impl<T: ?Sized> Shared<T> {
    /// Allows constructing an instance of Shared with a `?Sized T`.
    // Note: this leaks implemmentation details, but this is necessary as `CoerceUnsized` is unstable.
    pub(crate) fn new_dyn(val: Rc<RefCell<T>>) -> Self {
        Shared { rc: val }
    }
}

impl<T: ?Sized> Shared<T> {
    /// Executes the given function with an immutable reference to the wrapped value.
    ///
    /// # Arguments
    ///
    /// * `func` - The function to execute with a reference to the wrapped value.
    ///
    /// # Panics
    ///
    /// Panics if the wrapped value is being used by an `exec_mut` call.
    /// This is only possible if the method was called on a different `Shared` variable corresponding to the same shared value.
    ///
    /// # Example
    ///
    /// ```
    /// # use avalanche::shared::Shared;
    /// let num = Shared::new(10u8);
    /// let squared = num.exec(|&n| n * n);
    /// assert_eq!(squared, 100);
    /// ```
    pub fn exec<Ret, F: FnOnce(&T) -> Ret>(&self, f: F) -> Ret {
        f(&self.rc.borrow())
    }

    /// Executes the given function with a mutable reference to the wrapped value.
    ///
    /// # Arguments
    ///
    /// * `func` - The function to execute with a reference to the wrapped value.
    ///
    /// # Panics
    /// Panics if the wrapped value is being used by another `exec` or `exec_mut` call.
    /// This is only possible if the method was called on a different `Shared` variable corresponding to the same shared value.
    ///
    /// # Example
    ///
    /// ```
    /// # use avalanche::shared::Shared;
    /// let sequence = Shared::new([1u8, 2, 3]);
    /// sequence.exec_mut(|nums| nums.iter_mut().for_each(|num| *num *= *num));
    /// sequence.exec(|nums| assert_eq!(nums, &[1, 4, 9]));
    /// ```
    pub fn exec_mut<Ret, F: FnOnce(&mut T) -> Ret>(&self, f: F) -> Ret {
        f(&mut self.rc.borrow_mut())
    }
}

impl<T: ?Sized> Clone for Shared<T> {
    fn clone(&self) -> Self {
        Shared {
            rc: self.rc.clone(),
        }
    }
}

impl<T: Default> Default for Shared<T> {
    fn default() -> Self {
        Self::new(Default::default())
    }
}
impl<T> From<T> for Shared<T> {
    fn from(val: T) -> Self {
        Self::new(val)
    }
}