multiversx_chain_vm/with_shared/
shareable.rs

1#![allow(deprecated)]
2
3use std::{
4    ops::{Deref, DerefMut},
5    sync::Arc,
6};
7
8/// Wraps an object and provides mutable access to it.
9///
10/// The point is that sometimes we want to stop mutability and proliferate reference-counted pointers to it.
11///
12/// This happens in a controlled environment, in the `with_shared` method closure argument.
13/// All reference-counted pointers are expected to be dropped until that closure finishes.
14#[deprecated(since = "0.57.0", note = "replaced by BlockchainVMRef and Arc")]
15pub enum Shareable<T> {
16    Owned(T),
17    Shared(Arc<T>),
18}
19
20impl<T> Shareable<T> {
21    pub fn new(t: T) -> Self {
22        Shareable::Owned(t)
23    }
24
25    /// Destroys the object and returns the contents.
26    pub fn into_inner(self) -> T {
27        if let Shareable::Owned(t) = self {
28            t
29        } else {
30            panic!("cannot access ShareableMut owned object")
31        }
32    }
33}
34
35impl<T> Default for Shareable<T>
36where
37    T: Default,
38{
39    fn default() -> Self {
40        Shareable::new(T::default())
41    }
42}
43
44impl<T> Deref for Shareable<T> {
45    type Target = T;
46
47    fn deref(&self) -> &Self::Target {
48        match self {
49            Shareable::Owned(t) => t,
50            Shareable::Shared(rc) => rc.deref(),
51        }
52    }
53}
54
55impl<T> DerefMut for Shareable<T> {
56    fn deref_mut(&mut self) -> &mut Self::Target {
57        match self {
58            Shareable::Owned(t) => t,
59            Shareable::Shared(_) => {
60                panic!("cannot mutably dereference ShareableMut when in Shared state")
61            }
62        }
63    }
64}
65
66impl<T> Shareable<T> {
67    fn get_arc(&self) -> Arc<T> {
68        if let Shareable::Shared(arc) = self {
69            arc.clone()
70        } else {
71            panic!("invalid ShareableMut state: Shared expected")
72        }
73    }
74
75    fn wrap_arc_strict(&mut self) {
76        unsafe {
77            let temp = std::ptr::read(self);
78            if let Shareable::Owned(t) = temp {
79                std::ptr::write(self, Shareable::Shared(Arc::new(t)));
80            } else {
81                std::mem::forget(temp);
82                panic!("invalid ShareableMut state: Owned expected")
83            }
84        }
85    }
86
87    fn unwrap_arc_strict(&mut self) {
88        unsafe {
89            let temp = std::ptr::read(self);
90            if let Shareable::Shared(arc) = temp {
91                match Arc::try_unwrap(arc) {
92                    Ok(t) => {
93                        std::ptr::write(self, Shareable::Owned(t));
94                    }
95                    Err(rc) => {
96                        std::mem::forget(rc);
97                        panic!(
98                            "failed to recover Owned ShareableMut from Shared, not all Rc pointers dropped"
99                        )
100                    }
101                }
102            } else {
103                std::mem::forget(temp);
104                panic!("invalid ShareableMut state: Shared expected")
105            }
106        }
107    }
108
109    /// The main functionality of `Shared`.
110    ///
111    /// Temporarily makes the object immutable, and creates a Rc pointer to the contents, which can then be cloned.
112    ///
113    /// Important restriction: all Rc pointers creates from the one given to the closure `f` must be dropped before its execution ends.
114    /// Otherwise the operation will panic.
115    pub fn with_shared<F, R>(&mut self, f: F) -> R
116    where
117        F: FnOnce(Arc<T>) -> R,
118    {
119        self.wrap_arc_strict();
120
121        let result = f(self.get_arc());
122
123        self.unwrap_arc_strict();
124
125        result
126    }
127}
128
129#[cfg(test)]
130mod test {
131    #![allow(deprecated)]
132
133    use std::cell::RefCell;
134
135    use super::Shareable;
136
137    #[test]
138    fn test_shareable_mut_1() {
139        let mut s = Shareable::new("test string".to_string());
140        let l = s.with_shared(|s_arc| s_arc.len());
141        assert_eq!(s.len(), l);
142    }
143
144    #[test]
145    fn test_shareable_mut_2() {
146        let mut s = Shareable::new(RefCell::new("test string".to_string()));
147        s.with_shared(|s_arc| {
148            s_arc.borrow_mut().push_str(" ... changed");
149        });
150        assert_eq!(s.borrow().as_str(), "test string ... changed");
151        assert_eq!(s.into_inner().into_inner(), "test string ... changed");
152    }
153
154    #[test]
155    #[should_panic = "failed to recover Owned ShareableMut from Shared, not all Rc pointers dropped"]
156    fn test_shareable_mut_fail() {
157        let mut s = Shareable::new("test string".to_string());
158        let _illegally_extracted_arc = s.with_shared(|s_arc| s_arc);
159    }
160}