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!("failed to recover Owned ShareableMut from Shared, not all Rc pointers dropped")
98                    }
99                }
100            } else {
101                std::mem::forget(temp);
102                panic!("invalid ShareableMut state: Shared expected")
103            }
104        }
105    }
106
107    /// The main functionality of `Shared`.
108    ///
109    /// Temporarily makes the object immutable, and creates a Rc pointer to the contents, which can then be cloned.
110    ///
111    /// Important restriction: all Rc pointers creates from the one given to the closure `f` must be dropped before its execution ends.
112    /// Otherwise the operation will panic.
113    pub fn with_shared<F, R>(&mut self, f: F) -> R
114    where
115        F: FnOnce(Arc<T>) -> R,
116    {
117        self.wrap_arc_strict();
118
119        let result = f(self.get_arc());
120
121        self.unwrap_arc_strict();
122
123        result
124    }
125}
126
127#[cfg(test)]
128mod test {
129    #![allow(deprecated)]
130
131    use std::cell::RefCell;
132
133    use super::Shareable;
134
135    #[test]
136    fn test_shareable_mut_1() {
137        let mut s = Shareable::new("test string".to_string());
138        let l = s.with_shared(|s_arc| s_arc.len());
139        assert_eq!(s.len(), l);
140    }
141
142    #[test]
143    fn test_shareable_mut_2() {
144        let mut s = Shareable::new(RefCell::new("test string".to_string()));
145        s.with_shared(|s_arc| {
146            s_arc.borrow_mut().push_str(" ... changed");
147        });
148        assert_eq!(s.borrow().as_str(), "test string ... changed");
149        assert_eq!(s.into_inner().into_inner(), "test string ... changed");
150    }
151
152    #[test]
153    #[should_panic = "failed to recover Owned ShareableMut from Shared, not all Rc pointers dropped"]
154    fn test_shareable_mut_fail() {
155        let mut s = Shareable::new("test string".to_string());
156        let _illegally_extracted_arc = s.with_shared(|s_arc| s_arc);
157    }
158}