multiversx_chain_vm/with_shared/
with_shared_mut_ref.rs

1use std::rc::Rc;
2
3/// Temporarily converts a mutable reference into a reference-counted smart pointer (`Rc`).
4///
5/// This only takes as long as the closure `f` is executed.
6///
7/// All subsequent Rc clones must be dropped before `f` terminates, otherwise the function will panic.
8///
9/// The `Clone` of the argument is not used, except to preserve memory consistency in case of failure.
10///
11/// See the `Shared` type for a safer implementation, which does not require `Clone`.
12#[deprecated(
13    since = "0.57.0",
14    note = "not currently used, has not been used in some time, only kept for reference"
15)]
16pub fn with_shared_mut_ref<T, F, R>(t: &mut T, f: F) -> R
17where
18    T: Clone,
19    F: FnOnce(Rc<T>) -> R,
20{
21    unsafe {
22        // forcefully extract the owned object from the mut ref (unsafe)
23        let obj = std::ptr::read(t);
24
25        // wrap the owned object
26        let obj_rc = Rc::new(obj);
27
28        // the main action
29        let result = f(obj_rc.clone());
30
31        // unwrapping the owned object
32        match Rc::try_unwrap(obj_rc) {
33            Ok(obj) => {
34                // Rc unwrapped successfully
35                // no need to write the owned object back to the location given by the pointer t,
36                // because it could not have changed in the mean time, it is already there
37
38                // though readonly, the object might have changed via cells,
39                // so it needs to be copied back
40                std::ptr::write(t, obj);
41            }
42            Err(obj_rc) => {
43                // could not unwrap, this means there are still references to obj elsewhere
44                // to avoid memory corruption, we perform a clone of the contents
45                let obj = (*obj_rc).clone();
46                std::ptr::write(t, obj);
47                panic!("failed to recover owned object from Rc")
48            }
49        }
50
51        result
52    }
53}
54
55#[cfg(test)]
56mod test {
57    use std::cell::RefCell;
58
59    use super::with_shared_mut_ref;
60
61    #[test]
62    fn test_with_shared_mut_ref_1() {
63        let mut s = "test string".to_string();
64        let l = with_shared_mut_ref(&mut s, |s_rc| s_rc.len());
65        assert_eq!(s.len(), l);
66    }
67
68    #[test]
69    fn test_with_shared_mut_ref_2() {
70        let mut s = RefCell::new("test string".to_string());
71        with_shared_mut_ref(&mut s, |s_rc| {
72            s_rc.borrow_mut().push_str(" ... changed");
73        });
74        assert_eq!(s.borrow().as_str(), "test string ... changed");
75    }
76
77    #[test]
78    #[should_panic = "failed to recover owned object from Rc"]
79    fn test_with_shared_mut_ref_fail() {
80        let mut s = "test string".to_string();
81        let _illegally_extracted_rc = with_shared_mut_ref(&mut s, |s_rc| s_rc);
82    }
83}