Skip to content

Commit

Permalink
util - with_shared_mut_ref
Browse files Browse the repository at this point in the history
  • Loading branch information
andrei-marinica committed Jul 5, 2023
1 parent fc6adf4 commit f071aee
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 0 deletions.
3 changes: 3 additions & 0 deletions vm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@ pub mod types;
pub mod vm_err_msg;
pub mod vm_hooks;
pub mod world_mock;
mod with_shared;

pub use world_mock::BlockchainMock;

// Re-exporting the executor, for convenience.
pub use multiversx_chain_vm_executor as executor;

use with_shared::with_shared_mut_ref;

Check warning on line 17 in vm/src/lib.rs

View workflow job for this annotation

GitHub Actions / Contracts / Wasm tests

unused import: `with_shared::with_shared_mut_ref`

Check warning on line 17 in vm/src/lib.rs

View workflow job for this annotation

GitHub Actions / Contracts / Rust tests

unused import: `with_shared::with_shared_mut_ref`

Check warning on line 17 in vm/src/lib.rs

View workflow job for this annotation

GitHub Actions / clippy

[clippy] vm/src/lib.rs#L17

warning: unused import: `with_shared::with_shared_mut_ref` --> vm/src/lib.rs:17:5 | 17 | use with_shared::with_shared_mut_ref; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `#[warn(unused_imports)]` on by default
Raw output
vm/src/lib.rs:17:5:w:warning: unused import: `with_shared::with_shared_mut_ref`
  --> vm/src/lib.rs:17:5
   |
17 | use with_shared::with_shared_mut_ref;
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: `#[warn(unused_imports)]` on by default


__END__

Check warning on line 17 in vm/src/lib.rs

View workflow job for this annotation

GitHub Actions / clippy

[clippy] vm/src/lib.rs#L17

warning: unused import: `with_shared::with_shared_mut_ref` --> vm/src/lib.rs:17:5 | 17 | use with_shared::with_shared_mut_ref; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `#[warn(unused_imports)]` on by default
Raw output
vm/src/lib.rs:17:5:w:warning: unused import: `with_shared::with_shared_mut_ref`
  --> vm/src/lib.rs:17:5
   |
17 | use with_shared::with_shared_mut_ref;
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: `#[warn(unused_imports)]` on by default


__END__

#[macro_use]
extern crate alloc;
77 changes: 77 additions & 0 deletions vm/src/with_shared.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
use std::rc::Rc;

/// Temporarily converts a mutable reference into a reference-counted smart pointer (`Rc`).
///
/// This only takes as long as the closure `f` is executed.
///
/// All subsequent Rc clones must be dropped before `f` terminates, otherwise the function will panic.
///
/// The `Clone` of the argument is not used, except to preserve memory consistency in case of failure.
pub fn with_shared_mut_ref<T, F, R>(t: &mut T, f: F) -> R

Check warning on line 10 in vm/src/with_shared.rs

View workflow job for this annotation

GitHub Actions / Contracts / Wasm tests

function `with_shared_mut_ref` is never used

Check warning on line 10 in vm/src/with_shared.rs

View workflow job for this annotation

GitHub Actions / Contracts / Rust tests

function `with_shared_mut_ref` is never used

Check warning on line 10 in vm/src/with_shared.rs

View workflow job for this annotation

GitHub Actions / clippy

[clippy] vm/src/with_shared.rs#L10

warning: function `with_shared_mut_ref` is never used --> vm/src/with_shared.rs:10:8 | 10 | pub fn with_shared_mut_ref<T, F, R>(t: &mut T, f: F) -> R | ^^^^^^^^^^^^^^^^^^^ | = note: `#[warn(dead_code)]` on by default
Raw output
vm/src/with_shared.rs:10:8:w:warning: function `with_shared_mut_ref` is never used
  --> vm/src/with_shared.rs:10:8
   |
10 | pub fn with_shared_mut_ref<T, F, R>(t: &mut T, f: F) -> R
   |        ^^^^^^^^^^^^^^^^^^^
   |
   = note: `#[warn(dead_code)]` on by default


__END__
where
T: Clone,
F: FnOnce(Rc<T>) -> R,
{
unsafe {
// forcefully extract the owned object from the mut ref (unsafe)
let obj = std::ptr::read(t);

// wrap the owned object
let obj_rc = Rc::new(obj);

// the main action
let result = f(obj_rc.clone());

// unwrapping the owned object
match Rc::try_unwrap(obj_rc) {
Ok(obj) => {
// Rc unwrapped successfully
// no need to write the owned object back to the location given by the pointer t,
// because it could not have changed in the mean time, it is already there

// though readonly, the object might have changed via cells,
// so it needs to be copied back
std::ptr::write(t, obj);
},
Err(obj_rc) => {
// could not unwrap, this means there are still references to obj elsewhere
// to avoid memory corruption, we perform a clone of the contents
let obj = (*obj_rc).clone();
std::ptr::write(t, obj);
panic!("failed to recover owned object from Rc")
},
}

result
}
}

#[cfg(test)]
mod test {
use std::cell::RefCell;

use super::with_shared_mut_ref;

#[test]
fn test_with_shared_1() {
let mut s = "test string".to_string();
let l = with_shared_mut_ref(&mut s, |s_rc| s_rc.len());
assert_eq!(s.len(), l);
}

#[test]
fn test_with_shared_2() {
let mut s = RefCell::new("test string".to_string());
with_shared_mut_ref(&mut s, |s_rc| {
s_rc.borrow_mut().push_str(" ... changed");
});
assert_eq!(s.borrow().as_str(), "test string ... changed");
}

#[test]
#[should_panic = "failed to recover owned object from Rc"]
fn test_with_shared_fail() {
let mut s = "test string".to_string();
let _illegal_clone = with_shared_mut_ref(&mut s, |s_rc| s_rc.clone());

Check warning on line 75 in vm/src/with_shared.rs

View workflow job for this annotation

GitHub Actions / clippy

[clippy] vm/src/with_shared.rs#L75

warning: redundant clone --> vm/src/with_shared.rs:75:69 | 75 | let _illegal_clone = with_shared_mut_ref(&mut s, |s_rc| s_rc.clone()); | ^^^^^^^^ help: remove this | note: this value is dropped without further use --> vm/src/with_shared.rs:75:65 | 75 | let _illegal_clone = with_shared_mut_ref(&mut s, |s_rc| s_rc.clone()); | ^^^^ = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#redundant_clone = note: `#[warn(clippy::redundant_clone)]` on by default
Raw output
vm/src/with_shared.rs:75:69:w:warning: redundant clone
  --> vm/src/with_shared.rs:75:69
   |
75 |         let _illegal_clone = with_shared_mut_ref(&mut s, |s_rc| s_rc.clone());
   |                                                                     ^^^^^^^^ help: remove this
   |
note: this value is dropped without further use
  --> vm/src/with_shared.rs:75:65
   |
75 |         let _illegal_clone = with_shared_mut_ref(&mut s, |s_rc| s_rc.clone());
   |                                                                 ^^^^
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#redundant_clone
   = note: `#[warn(clippy::redundant_clone)]` on by default


__END__
}
}

0 comments on commit f071aee

Please sign in to comment.