Skip to content

Commit

Permalink
Add fn to find out if Host can be finished (#1182)
Browse files Browse the repository at this point in the history
### What
Add fn to find out if Host can be finished.

### Why
So that the SDK can ask the Host if it has no more references left and
it is able to be finished without calling try_finish which is
destructive.

I plan to use this in:
- stellar/rs-soroban-sdk#1137
  • Loading branch information
leighmcculloch committed Nov 8, 2023
1 parent 4f4a7f3 commit 6d26ca6
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 0 deletions.
11 changes: 11 additions & 0 deletions soroban-env-host/src/host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -486,9 +486,20 @@ impl Host {
self.as_budget().with_shadow_mode(f, e)
}

/// Returns whether the Host can be finished by calling
/// [`Host::try_finish`].
///
/// Returns true if the host reference is unique, refcount = 1.
pub fn can_finish(&self) -> bool {
Rc::strong_count(&self.0) == 1
}

/// Accept a _unique_ (refcount = 1) host reference and destroy the
/// underlying [`HostImpl`], returning its finalized components containing
/// processing side effects to the caller as a tuple wrapped in `Ok(...)`.
///
/// Use [`Host::can_finish`] to determine before calling the function if it
/// will succeed.
pub fn try_finish(self) -> Result<(Storage, Events), HostError> {
let events = self.try_borrow_events()?.externalize(&self)?;
Rc::try_unwrap(self.0)
Expand Down
1 change: 1 addition & 0 deletions soroban-env-host/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,5 @@ mod symbol;
mod tuple;
mod vec;

mod finish;
mod metering_benchmark;
31 changes: 31 additions & 0 deletions soroban-env-host/src/test/finish.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use crate::Host;

#[test]
fn can_finish_on_one_reference() {
let host1 = Host::test_host_with_recording_footprint();
assert!(host1.can_finish());
assert!(host1.try_finish().is_ok());
}

#[test]
fn cant_finish_on_multiple_reference() {
let host1 = Host::test_host_with_recording_footprint();
let host2 = host1.clone();
assert!(!host1.can_finish());
assert!(!host2.can_finish());
assert!(host1.try_finish().is_err());
_ = host2;
}

#[test]
fn can_finish_on_reduced_to_one_reference_count() {
let host1 = Host::test_host_with_recording_footprint();
{
let host2 = host1.clone();
assert!(!host1.can_finish());
assert!(!host2.can_finish());
_ = host1;
}
assert!(host1.can_finish());
assert!(host1.try_finish().is_ok());
}

0 comments on commit 6d26ca6

Please sign in to comment.