diff --git a/Cargo.lock b/Cargo.lock index 5b95acda7..c5377eac7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -841,7 +841,7 @@ dependencies = [ [[package]] name = "soroban-env-common" version = "0.0.12" -source = "git+https://github.com/stellar/rs-soroban-env?rev=d803b0922d1d9eb4d3cfde5e6d574c7776c23388#d803b0922d1d9eb4d3cfde5e6d574c7776c23388" +source = "git+https://github.com/stellar/rs-soroban-env?rev=96ea6dcbb2a57208b2ba1dc202490b92d4ba537e#96ea6dcbb2a57208b2ba1dc202490b92d4ba537e" dependencies = [ "crate-git-revision", "serde", @@ -854,7 +854,7 @@ dependencies = [ [[package]] name = "soroban-env-guest" version = "0.0.12" -source = "git+https://github.com/stellar/rs-soroban-env?rev=d803b0922d1d9eb4d3cfde5e6d574c7776c23388#d803b0922d1d9eb4d3cfde5e6d574c7776c23388" +source = "git+https://github.com/stellar/rs-soroban-env?rev=96ea6dcbb2a57208b2ba1dc202490b92d4ba537e#96ea6dcbb2a57208b2ba1dc202490b92d4ba537e" dependencies = [ "soroban-env-common", "static_assertions", @@ -863,7 +863,7 @@ dependencies = [ [[package]] name = "soroban-env-host" version = "0.0.12" -source = "git+https://github.com/stellar/rs-soroban-env?rev=d803b0922d1d9eb4d3cfde5e6d574c7776c23388#d803b0922d1d9eb4d3cfde5e6d574c7776c23388" +source = "git+https://github.com/stellar/rs-soroban-env?rev=96ea6dcbb2a57208b2ba1dc202490b92d4ba537e#96ea6dcbb2a57208b2ba1dc202490b92d4ba537e" dependencies = [ "backtrace", "curve25519-dalek", @@ -885,7 +885,7 @@ dependencies = [ [[package]] name = "soroban-env-macros" version = "0.0.12" -source = "git+https://github.com/stellar/rs-soroban-env?rev=d803b0922d1d9eb4d3cfde5e6d574c7776c23388#d803b0922d1d9eb4d3cfde5e6d574c7776c23388" +source = "git+https://github.com/stellar/rs-soroban-env?rev=96ea6dcbb2a57208b2ba1dc202490b92d4ba537e#96ea6dcbb2a57208b2ba1dc202490b92d4ba537e" dependencies = [ "itertools", "proc-macro2", @@ -911,7 +911,7 @@ dependencies = [ [[package]] name = "soroban-native-sdk-macros" version = "0.0.12" -source = "git+https://github.com/stellar/rs-soroban-env?rev=d803b0922d1d9eb4d3cfde5e6d574c7776c23388#d803b0922d1d9eb4d3cfde5e6d574c7776c23388" +source = "git+https://github.com/stellar/rs-soroban-env?rev=96ea6dcbb2a57208b2ba1dc202490b92d4ba537e#96ea6dcbb2a57208b2ba1dc202490b92d4ba537e" dependencies = [ "itertools", "proc-macro2", diff --git a/Cargo.toml b/Cargo.toml index 98a357fa7..31ff50afb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,17 +37,17 @@ soroban-token-spec = { version = "0.4.3", path = "soroban-token-spec" } [workspace.dependencies.soroban-env-common] version = "0.0.12" git = "https://github.com/stellar/rs-soroban-env" -rev = "d803b0922d1d9eb4d3cfde5e6d574c7776c23388" +rev = "96ea6dcbb2a57208b2ba1dc202490b92d4ba537e" [workspace.dependencies.soroban-env-guest] version = "0.0.12" git = "https://github.com/stellar/rs-soroban-env" -rev = "d803b0922d1d9eb4d3cfde5e6d574c7776c23388" +rev = "96ea6dcbb2a57208b2ba1dc202490b92d4ba537e" [workspace.dependencies.soroban-env-host] version = "0.0.12" git = "https://github.com/stellar/rs-soroban-env" -rev = "d803b0922d1d9eb4d3cfde5e6d574c7776c23388" +rev = "96ea6dcbb2a57208b2ba1dc202490b92d4ba537e" [workspace.dependencies.stellar-strkey] version = "0.0.6" diff --git a/soroban-sdk/src/accounts.rs b/soroban-sdk/src/accounts.rs index b95b2f118..bc6354826 100644 --- a/soroban-sdk/src/accounts.rs +++ b/soroban-sdk/src/accounts.rs @@ -6,6 +6,7 @@ use core::{cmp::Ordering, fmt::Debug}; use crate::{ env::internal::xdr, env::internal::{Env as _, EnvBase as _, RawVal, RawValConvertible}, + unwrap::UnwrapInfallible, BytesN, ConversionError, Env, Object, TryFromVal, }; @@ -65,7 +66,11 @@ impl Accounts { /// Gets the account for the account ID. pub fn get(&self, id: &AccountId) -> Option { let env = id.env(); - if env.account_exists(id.to_object()).is_true() { + if env + .account_exists(id.to_object()) + .unwrap_infallible() + .is_true() + { Some(Account(id.clone())) } else { None @@ -120,7 +125,10 @@ impl PartialOrd for AccountId { impl Ord for AccountId { fn cmp(&self, other: &Self) -> core::cmp::Ordering { self.env.check_same_env(&other.env); - let v = self.env.obj_cmp(self.obj.to_raw(), other.obj.to_raw()); + let v = self + .env + .obj_cmp(self.obj.to_raw(), other.obj.to_raw()) + .unwrap_infallible(); v.cmp(&0) } } @@ -328,13 +336,17 @@ impl Account { /// Returns if the account exists. pub fn exists(id: &AccountId) -> bool { let env = id.env(); - env.account_exists(id.to_object()).is_true() + env.account_exists(id.to_object()) + .unwrap_infallible() + .is_true() } /// Returns the low threshold for the Stellar account. pub fn low_threshold(&self) -> u8 { let env = self.env(); - let val = env.account_get_low_threshold(self.to_object()); + let val = env + .account_get_low_threshold(self.to_object()) + .unwrap_infallible(); let threshold_u32 = unsafe { ::unchecked_from_val(val) }; threshold_u32 as u8 } @@ -342,7 +354,9 @@ impl Account { /// Returns the medium threshold for the Stellar account. pub fn medium_threshold(&self) -> u8 { let env = self.env(); - let val = env.account_get_medium_threshold(self.to_object()); + let val = env + .account_get_medium_threshold(self.to_object()) + .unwrap_infallible(); let threshold_u32 = unsafe { ::unchecked_from_val(val) }; threshold_u32 as u8 } @@ -350,7 +364,9 @@ impl Account { /// Returns the high threshold for the Stellar account. pub fn high_threshold(&self) -> u8 { let env = self.env(); - let val = env.account_get_high_threshold(self.to_object()); + let val = env + .account_get_high_threshold(self.to_object()) + .unwrap_infallible(); let threshold_u32 = unsafe { ::unchecked_from_val(val) }; threshold_u32 as u8 } @@ -359,7 +375,9 @@ impl Account { /// the signer does not exist for the account, returns zero (`0`). pub fn signer_weight(&self, signer: &BytesN<32>) -> u8 { let env = self.env(); - let val = env.account_get_signer_weight(self.to_object(), signer.to_object()); + let val = env + .account_get_signer_weight(self.to_object(), signer.to_object()) + .unwrap_infallible(); let weight_u32 = unsafe { ::unchecked_from_val(val) }; weight_u32 as u8 } diff --git a/soroban-sdk/src/bytes.rs b/soroban-sdk/src/bytes.rs index 0596a3396..58d841ff9 100644 --- a/soroban-sdk/src/bytes.rs +++ b/soroban-sdk/src/bytes.rs @@ -13,7 +13,7 @@ use super::{ ConversionError, Env, Object, RawVal, TryFromVal, }; -use crate::unwrap::UnwrapOptimized; +use crate::unwrap::{UnwrapInfallible, UnwrapOptimized}; #[cfg(doc)] use crate::{storage::Storage, Map, Vec}; @@ -158,7 +158,10 @@ impl PartialOrd for Bytes { impl Ord for Bytes { fn cmp(&self, other: &Self) -> core::cmp::Ordering { self.env.check_same_env(&other.env); - let v = self.env.obj_cmp(self.obj.to_raw(), other.obj.to_raw()); + let v = self + .env + .obj_cmp(self.obj.to_raw(), other.obj.to_raw()) + .unwrap_infallible(); v.cmp(&0) } } @@ -307,7 +310,7 @@ impl Bytes { /// Create an empty Bytes. #[inline(always)] pub fn new(env: &Env) -> Bytes { - let obj = env.bytes_new(); + let obj = env.bytes_new().unwrap_infallible(); unsafe { Self::unchecked_new(env.clone(), obj) } } @@ -328,7 +331,10 @@ impl Bytes { #[inline(always)] pub fn set(&mut self, i: u32, v: u8) { let v32: u32 = v.into(); - self.obj = self.env().bytes_put(self.obj, i.into(), v32.into()) + self.obj = self + .env() + .bytes_put(self.obj, i.into(), v32.into()) + .unwrap_infallible() } #[inline(always)] @@ -345,6 +351,7 @@ impl Bytes { let res = self .env() .bytes_get(self.obj, i.into()) + .unwrap_infallible() .try_into() .unwrap_optimized(); let res32: u32 = unsafe { <_ as RawValConvertible>::unchecked_from_val(res) }; @@ -353,12 +360,15 @@ impl Bytes { #[inline(always)] pub fn is_empty(&self) -> bool { - self.env().bytes_len(self.obj).is_u32_zero() + self.env() + .bytes_len(self.obj) + .unwrap_infallible() + .is_u32_zero() } #[inline(always)] pub fn len(&self) -> u32 { - let len = self.env().bytes_len(self.obj); + let len = self.env().bytes_len(self.obj).unwrap_infallible(); unsafe { <_ as RawValConvertible>::unchecked_from_val(len) } } @@ -373,7 +383,7 @@ impl Bytes { #[inline(always)] pub fn first_unchecked(&self) -> u8 { - let res = self.env().bytes_front(self.obj); + let res = self.env().bytes_front(self.obj).unwrap_infallible(); let res32: u32 = unsafe { <_ as RawValConvertible>::unchecked_from_val(res) }; res32 as u8 } @@ -389,7 +399,7 @@ impl Bytes { #[inline(always)] pub fn last_unchecked(&self) -> u8 { - let res = self.env().bytes_back(self.obj); + let res = self.env().bytes_back(self.obj).unwrap_infallible(); let res32: u32 = unsafe { <_ as RawValConvertible>::unchecked_from_val(res) }; res32 as u8 } @@ -406,26 +416,29 @@ impl Bytes { #[inline(always)] pub fn remove_unchecked(&mut self, i: u32) { - self.obj = self.env().bytes_del(self.obj, i.into()) + self.obj = self.env().bytes_del(self.obj, i.into()).unwrap_infallible() } #[inline(always)] pub fn push(&mut self, x: u8) { let x32: u32 = x.into(); - self.obj = self.env().bytes_push(self.obj, x32.into()) + self.obj = self + .env() + .bytes_push(self.obj, x32.into()) + .unwrap_infallible() } #[inline(always)] pub fn pop(&mut self) -> Option { let last = self.last()?; - self.obj = self.env().bytes_pop(self.obj); + self.obj = self.env().bytes_pop(self.obj).unwrap_infallible(); Some(last) } #[inline(always)] pub fn pop_unchecked(&mut self) -> u8 { let last = self.last_unchecked(); - self.obj = self.env().bytes_pop(self.obj); + self.obj = self.env().bytes_pop(self.obj).unwrap_infallible(); last } @@ -438,7 +451,10 @@ impl Bytes { #[inline(always)] pub fn insert(&mut self, i: u32, b: u8) { let b32: u32 = b.into(); - self.obj = self.env().bytes_insert(self.obj, i.into(), b32.into()) + self.obj = self + .env() + .bytes_insert(self.obj, i.into(), b32.into()) + .unwrap_infallible() } /// Insert the bytes in `bytes` into this [Bytes] starting at position @@ -482,7 +498,10 @@ impl Bytes { #[inline(always)] pub fn append(&mut self, other: &Bytes) { - self.obj = self.env().bytes_append(self.obj, other.obj) + self.obj = self + .env() + .bytes_append(self.obj, other.obj) + .unwrap_infallible() } #[inline(always)] @@ -534,7 +553,9 @@ impl Bytes { Bound::Unbounded => self.len(), }; let env = self.env(); - let bin = env.bytes_slice(self.obj, start_bound.into(), end_bound.into()); + let bin = env + .bytes_slice(self.obj, start_bound.into(), end_bound.into()) + .unwrap_infallible(); unsafe { Self::unchecked_new(env.clone(), bin) } } @@ -568,7 +589,7 @@ impl Iterator for BinIter { if self.0.is_empty() { None } else { - let val = self.0.env().bytes_front(self.0.obj); + let val = self.0.env().bytes_front(self.0.obj).unwrap_infallible(); self.0 = self.0.slice(1..); let val = unsafe { ::unchecked_from_val(val) } as u8; Some(val) @@ -587,7 +608,7 @@ impl DoubleEndedIterator for BinIter { if len == 0 { None } else { - let val = self.0.env().bytes_back(self.0.obj); + let val = self.0.env().bytes_back(self.0.obj).unwrap_infallible(); self.0 = self.0.slice(..len - 1); let val = unsafe { ::unchecked_from_val(val) } as u8; Some(val) diff --git a/soroban-sdk/src/crypto.rs b/soroban-sdk/src/crypto.rs index 2b61d8e6d..1a280c473 100644 --- a/soroban-sdk/src/crypto.rs +++ b/soroban-sdk/src/crypto.rs @@ -1,5 +1,5 @@ //! Crypto contains functions for cryptographic functions. -use crate::{env::internal, Bytes, BytesN, Env}; +use crate::{env::internal, unwrap::UnwrapInfallible, Bytes, BytesN, Env}; /// Crypto provides access to cryptographic functions. pub struct Crypto { @@ -18,7 +18,7 @@ impl Crypto { /// Returns the SHA-256 hash of the data. pub fn sha256(&self, data: &Bytes) -> BytesN<32> { let env = self.env(); - let bin = internal::Env::compute_hash_sha256(env, data.into()); + let bin = internal::Env::compute_hash_sha256(env, data.into()).unwrap_infallible(); unsafe { BytesN::unchecked_new(env.clone(), bin) } } diff --git a/soroban-sdk/src/deploy.rs b/soroban-sdk/src/deploy.rs index 8fa20a0e3..2ec9e9419 100644 --- a/soroban-sdk/src/deploy.rs +++ b/soroban-sdk/src/deploy.rs @@ -37,7 +37,7 @@ //! # #[cfg(not(feature = "testutils"))] //! # fn main() { } //! ``` -use crate::{env::internal::Env as _, Bytes, BytesN, Env, IntoVal}; +use crate::{env::internal::Env as _, unwrap::UnwrapInfallible, Bytes, BytesN, Env, IntoVal}; /// Deployer provides access to deploying contracts. pub struct Deployer { @@ -105,10 +105,12 @@ impl DeployerWithCurrentContract { /// Returns the deployed contract's ID. pub fn deploy(&self, wasm_hash: &impl IntoVal>) -> BytesN<32> { let env = &self.env; - let id = env.create_contract_from_contract( - wasm_hash.into_val(env).to_object(), - self.salt.to_object(), - ); + let id = env + .create_contract_from_contract( + wasm_hash.into_val(env).to_object(), + self.salt.to_object(), + ) + .unwrap_infallible(); unsafe { BytesN::<32>::unchecked_new(env.clone(), id) } } } diff --git a/soroban-sdk/src/env.rs b/soroban-sdk/src/env.rs index cac53f359..e33134c03 100644 --- a/soroban-sdk/src/env.rs +++ b/soroban-sdk/src/env.rs @@ -1,16 +1,38 @@ +use core::convert::Infallible; use core::convert::TryInto; #[cfg(target_family = "wasm")] pub mod internal { + use core::convert::Infallible; + pub use soroban_env_guest::*; pub type EnvImpl = Guest; + + // In the Guest case, Env::Error is already Infallible so there is no work + // to do to "reject an error": if an error occurs in the environment, the + // host will trap our VM and we'll never get here at all. + pub(crate) fn reject_err(_env: &Guest, r: Result) -> Result { + r + } } #[cfg(not(target_family = "wasm"))] pub mod internal { + use core::convert::Infallible; + pub use soroban_env_host::*; pub type EnvImpl = Host; + #[cfg(feature = "testutils")] + pub(crate) fn reject_err(env: &Host, r: Result) -> Result { + r.map_err(|e| env.escalate_error_to_panic(e)) + } + + #[cfg(not(feature = "testutils"))] + pub(crate) fn reject_err(_env: &Host, r: Result) -> Result { + r.map_err(|e| panic!("{:?}", e)) + } + #[doc(hidden)] impl Convert for super::Env where @@ -74,6 +96,7 @@ where } } +use crate::unwrap::UnwrapInfallible; use crate::unwrap::UnwrapOptimized; use crate::{ accounts::Accounts, address::Address, crypto::Crypto, deploy::Deployer, events::Events, @@ -122,14 +145,21 @@ impl Env { /// Get the invoking [Address] of the current executing contract. pub fn invoker(&self) -> Address { let invoker_type: InvokerType = internal::Env::get_invoker_type(self) + .unwrap_infallible() .try_into() .expect("unrecognized invoker type"); match invoker_type { InvokerType::Account => Address::Account(unsafe { - AccountId::unchecked_new(self.clone(), internal::Env::get_invoking_account(self)) + AccountId::unchecked_new( + self.clone(), + internal::Env::get_invoking_account(self).unwrap_infallible(), + ) }), InvokerType::Contract => Address::Contract(unsafe { - BytesN::unchecked_new(self.clone(), internal::Env::get_invoking_contract(self)) + BytesN::unchecked_new( + self.clone(), + internal::Env::get_invoking_contract(self).unwrap_infallible(), + ) }), } } @@ -182,7 +212,7 @@ impl Env { /// Get the 32-byte hash identifier of the current executing contract. pub fn current_contract(&self) -> BytesN<32> { - let id = internal::Env::get_current_contract(self); + let id = internal::Env::get_current_contract(self).unwrap_infallible(); unsafe { BytesN::<32>::unchecked_new(self.clone(), id) } } @@ -227,7 +257,7 @@ impl Env { /// # fn main() { } /// ``` pub fn call_stack(&self) -> Vec<(BytesN<32>, Symbol)> { - let stack = internal::Env::get_current_call_stack(self); + let stack = internal::Env::get_current_call_stack(self).unwrap_infallible(); unsafe { Vec::unchecked_new(self.clone(), stack) } } @@ -265,7 +295,8 @@ impl Env { where T: TryFromVal, { - let rv = internal::Env::call(self, contract_id.to_object(), *func, args.to_object()); + let rv = internal::Env::call(self, contract_id.to_object(), *func, args.to_object()) + .unwrap_infallible(); T::try_from_val(self, &rv) .map_err(|_| ConversionError) .unwrap() @@ -283,7 +314,8 @@ impl Env { T: TryFromVal, E: TryFrom, { - let rv = internal::Env::try_call(self, contract_id.to_object(), *func, args.to_object()); + let rv = internal::Env::try_call(self, contract_id.to_object(), *func, args.to_object()) + .unwrap_infallible(); match Status::try_from_val(self, &rv) { Ok(status) => Err(E::try_from(status)), Err(ConversionError) => Ok(T::try_from_val(self, &rv)), @@ -298,7 +330,7 @@ impl Env { #[doc(hidden)] pub fn log_value>(&self, v: V) { - internal::Env::log_value(self, v.into_val(self)); + internal::Env::log_value(self, v.into_val(self)).unwrap_infallible(); } } @@ -694,6 +726,13 @@ impl Env { #[doc(hidden)] impl internal::EnvBase for Env { + type Error = Infallible; + + #[cfg(feature = "testutils")] + fn escalate_error_to_panic(&self, e: Self::Error) -> ! { + panic!("{:?}", e) + } + fn as_mut_any(&mut self) -> &mut dyn core::any::Any { self } @@ -715,24 +754,42 @@ impl internal::EnvBase for Env { b: Object, b_pos: RawVal, mem: &[u8], - ) -> Result { - self.env_impl.bytes_copy_from_slice(b, b_pos, mem) + ) -> Result { + Ok(self + .env_impl + .bytes_copy_from_slice(b, b_pos, mem) + .unwrap_optimized()) } - fn bytes_copy_to_slice(&self, b: Object, b_pos: RawVal, mem: &mut [u8]) -> Result<(), Status> { - self.env_impl.bytes_copy_to_slice(b, b_pos, mem) + fn bytes_copy_to_slice( + &self, + b: Object, + b_pos: RawVal, + mem: &mut [u8], + ) -> Result<(), Self::Error> { + Ok(self + .env_impl + .bytes_copy_to_slice(b, b_pos, mem) + .unwrap_optimized()) } - fn bytes_new_from_slice(&self, mem: &[u8]) -> Result { - self.env_impl.bytes_new_from_slice(mem) + fn bytes_new_from_slice(&self, mem: &[u8]) -> Result { + Ok(self.env_impl.bytes_new_from_slice(mem).unwrap_optimized()) } - fn log_static_fmt_val(&self, fmt: &'static str, v: RawVal) -> Result<(), Status> { - self.env_impl.log_static_fmt_val(fmt, v) + fn log_static_fmt_val(&self, fmt: &'static str, v: RawVal) -> Result<(), Self::Error> { + Ok(self.env_impl.log_static_fmt_val(fmt, v).unwrap_optimized()) } - fn log_static_fmt_static_str(&self, fmt: &'static str, s: &'static str) -> Result<(), Status> { - self.env_impl.log_static_fmt_static_str(fmt, s) + fn log_static_fmt_static_str( + &self, + fmt: &'static str, + s: &'static str, + ) -> Result<(), Self::Error> { + Ok(self + .env_impl + .log_static_fmt_static_str(fmt, s) + .unwrap_optimized()) } fn log_static_fmt_val_static_str( @@ -740,8 +797,11 @@ impl internal::EnvBase for Env { fmt: &'static str, v: RawVal, s: &'static str, - ) -> Result<(), Status> { - self.env_impl.log_static_fmt_val_static_str(fmt, v, s) + ) -> Result<(), Self::Error> { + Ok(self + .env_impl + .log_static_fmt_val_static_str(fmt, v, s) + .unwrap_optimized()) } fn log_static_fmt_general( @@ -749,8 +809,11 @@ impl internal::EnvBase for Env { fmt: &'static str, v: &[RawVal], s: &[&'static str], - ) -> Result<(), Status> { - self.env_impl.log_static_fmt_general(fmt, v, s) + ) -> Result<(), Self::Error> { + Ok(self + .env_impl + .log_static_fmt_general(fmt, v, s) + .unwrap_optimized()) } } @@ -770,8 +833,8 @@ macro_rules! sdk_function_helper { {$mod_id:ident, fn $fn_id:ident($($arg:ident:$type:ty),*) -> $ret:ty} => { - fn $fn_id(&self, $($arg:$type),*) -> $ret { - self.env_impl.$fn_id($($arg),*) + fn $fn_id(&self, $($arg:$type),*) -> Result<$ret, Self::Error> { + internal::reject_err(&self.env_impl, self.env_impl.$fn_id($($arg),*)) } }; } diff --git a/soroban-sdk/src/events.rs b/soroban-sdk/src/events.rs index eeda88aba..d8f07baf2 100644 --- a/soroban-sdk/src/events.rs +++ b/soroban-sdk/src/events.rs @@ -5,6 +5,7 @@ use core::fmt::Debug; use crate::{contracttype, Bytes, BytesN, Map}; use crate::{ env::internal::{self}, + unwrap::UnwrapInfallible, ConversionError, Env, IntoVal, RawVal, TryFromVal, Vec, }; @@ -115,7 +116,8 @@ impl Events { D: IntoVal, { let env = self.env(); - internal::Env::contract_event(env, topics.into_val(env).to_object(), data.into_val(env)); + internal::Env::contract_event(env, topics.into_val(env).to_object(), data.into_val(env)) + .unwrap_infallible(); } } diff --git a/soroban-sdk/src/ledger.rs b/soroban-sdk/src/ledger.rs index 9fbcc8943..52bcae37d 100644 --- a/soroban-sdk/src/ledger.rs +++ b/soroban-sdk/src/ledger.rs @@ -1,6 +1,7 @@ //! Ledger contains types for retrieving information about the current ledger. use crate::{ env::internal::{self, RawValConvertible}, + unwrap::UnwrapInfallible, Bytes, Env, }; @@ -54,7 +55,7 @@ impl Ledger { /// Returns the version of the protocol that the ledger created with. pub fn protocol_version(&self) -> u32 { let env = self.env(); - let val = internal::Env::get_ledger_version(env); + let val = internal::Env::get_ledger_version(env).unwrap_infallible(); unsafe { u32::unchecked_from_val(val) } } @@ -64,7 +65,7 @@ impl Ledger { /// that is sequential, incremented by one for each new ledger. pub fn sequence(&self) -> u32 { let env = self.env(); - let val = internal::Env::get_ledger_sequence(env); + let val = internal::Env::get_ledger_sequence(env).unwrap_infallible(); unsafe { u32::unchecked_from_val(val) } } @@ -75,8 +76,8 @@ impl Ledger { /// at 00:00:00 UTC. pub fn timestamp(&self) -> u64 { let env = self.env(); - let obj = internal::Env::get_ledger_timestamp(env); - internal::Env::obj_to_u64(env, obj) + let obj = internal::Env::get_ledger_timestamp(env).unwrap_infallible(); + internal::Env::obj_to_u64(env, obj).unwrap_infallible() } /// Returns the network passphrase. @@ -88,7 +89,7 @@ impl Ledger { /// > Test SDF Network ; September 2015 pub fn network_passphrase(&self) -> Bytes { let env = self.env(); - let bin_obj = internal::Env::get_ledger_network_passphrase(env); + let bin_obj = internal::Env::get_ledger_network_passphrase(env).unwrap_infallible(); unsafe { Bytes::unchecked_new(env.clone(), bin_obj) } } } diff --git a/soroban-sdk/src/logging.rs b/soroban-sdk/src/logging.rs index ed63b04ff..bd9921417 100644 --- a/soroban-sdk/src/logging.rs +++ b/soroban-sdk/src/logging.rs @@ -5,6 +5,7 @@ use core::fmt::Debug; use crate::{ env::internal::{self, EnvBase}, + unwrap::UnwrapInfallible, Bytes, Env, IntoVal, RawVal, Vec, }; @@ -130,7 +131,8 @@ impl Logger { if cfg!(target_family = "wasm") { let fmt: Bytes = fmt.into_val(env); let args: Vec = Vec::from_slice(env, args); - internal::Env::log_fmt_values(env, fmt.to_object(), args.to_object()); + internal::Env::log_fmt_values(env, fmt.to_object(), args.to_object()) + .unwrap_infallible(); } else { env.log_static_fmt_general(fmt, args, &[]).unwrap(); } diff --git a/soroban-sdk/src/map.rs b/soroban-sdk/src/map.rs index d48232045..cfad394fd 100644 --- a/soroban-sdk/src/map.rs +++ b/soroban-sdk/src/map.rs @@ -1,6 +1,9 @@ use core::{cmp::Ordering, fmt::Debug, iter::FusedIterator, marker::PhantomData}; -use crate::iter::{UncheckedEnumerable, UncheckedIter}; +use crate::{ + iter::{UncheckedEnumerable, UncheckedIter}, + unwrap::UnwrapInfallible, +}; use super::{ env::internal::{Env as _, EnvBase as _, RawValConvertible}, @@ -125,7 +128,10 @@ where { fn cmp(&self, other: &Self) -> core::cmp::Ordering { self.env.check_same_env(&other.env); - let v = self.env.obj_cmp(self.obj.to_raw(), other.obj.to_raw()); + let v = self + .env + .obj_cmp(self.obj.to_raw(), other.obj.to_raw()) + .unwrap_infallible(); v.cmp(&0) } } @@ -281,7 +287,7 @@ where #[inline(always)] pub fn new(env: &Env) -> Map { - unsafe { Self::unchecked_new(env.clone(), env.map_new()) } + unsafe { Self::unchecked_new(env.clone(), env.map_new().unwrap_infallible()) } } #[inline(always)] @@ -296,7 +302,7 @@ where #[inline(always)] pub fn contains_key(&self, k: K) -> bool { let env = self.env(); - let has = env.map_has(self.obj, k.into_val(env)); + let has = env.map_has(self.obj, k.into_val(env)).unwrap_infallible(); has.is_true() } @@ -304,9 +310,9 @@ where pub fn get(&self, k: K) -> Option> { let env = self.env(); let k = k.into_val(env); - let has = env.map_has(self.obj, k); + let has = env.map_has(self.obj, k).unwrap_infallible(); if has.is_true() { - let v = env.map_get(self.obj, k); + let v = env.map_get(self.obj, k).unwrap_infallible(); Some(V::try_from_val(env, &v)) } else { None @@ -316,23 +322,25 @@ where #[inline(always)] pub fn get_unchecked(&self, k: K) -> Result { let env = self.env(); - let v = env.map_get(self.obj, k.into_val(env)); + let v = env.map_get(self.obj, k.into_val(env)).unwrap_infallible(); V::try_from_val(env, &v) } #[inline(always)] pub fn set(&mut self, k: K, v: V) { let env = self.env(); - self.obj = env.map_put(self.obj, k.into_val(env), v.into_val(env)); + self.obj = env + .map_put(self.obj, k.into_val(env), v.into_val(env)) + .unwrap_infallible(); } #[inline(always)] pub fn remove(&mut self, k: K) -> Option<()> { let env = self.env(); let k = k.into_val(env); - let has = env.map_has(self.obj, k); + let has = env.map_has(self.obj, k).unwrap_infallible(); if has.is_true() { - self.obj = env.map_del(self.obj, k); + self.obj = env.map_del(self.obj, k).unwrap_infallible(); Some(()) } else { None @@ -342,34 +350,34 @@ where #[inline(always)] pub fn remove_unchecked(&mut self, k: K) { let env = self.env(); - self.obj = env.map_del(self.obj, k.into_val(env)); + self.obj = env.map_del(self.obj, k.into_val(env)).unwrap_infallible(); } #[inline(always)] pub fn is_empty(&self) -> bool { let env = self.env(); - let len = env.map_len(self.obj); + let len = env.map_len(self.obj).unwrap_infallible(); len.is_u32_zero() } #[inline(always)] pub fn len(&self) -> u32 { let env = self.env(); - let len = env.map_len(self.obj); + let len = env.map_len(self.obj).unwrap_infallible(); unsafe { ::unchecked_from_val(len) } } #[inline(always)] pub fn keys(&self) -> Vec { let env = self.env(); - let vec = env.map_keys(self.obj); + let vec = env.map_keys(self.obj).unwrap_infallible(); Vec::::try_from_val(env, &vec).unwrap() } #[inline(always)] pub fn values(&self) -> Vec { let env = self.env(); - let vec = env.map_values(self.obj); + let vec = env.map_values(self.obj).unwrap_infallible(); Vec::::try_from_val(env, &vec).unwrap() } @@ -435,12 +443,12 @@ where fn next(&mut self) -> Option { let env = &self.0.env; - let key = env.map_min_key(self.0.obj); + let key = env.map_min_key(self.0.obj).unwrap_infallible(); if Status::try_from(key).is_ok() { return None; } - let value = env.map_get(self.0.obj, key); - self.0.obj = env.map_del(self.0.obj, key); + let value = env.map_get(self.0.obj, key).unwrap_infallible(); + self.0.obj = env.map_del(self.0.obj, key).unwrap_infallible(); Some(Ok(( match K::try_from_val(env, &key) { Ok(k) => k, @@ -468,12 +476,12 @@ where { fn next_back(&mut self) -> Option { let env = &self.0.env; - let key = env.map_max_key(self.0.obj); + let key = env.map_max_key(self.0.obj).unwrap_infallible(); if Status::try_from(key).is_ok() { return None; } - let value = env.map_get(self.0.obj, key); - self.0.obj = env.map_del(self.0.obj, key); + let value = env.map_get(self.0.obj, key).unwrap_infallible(); + self.0.obj = env.map_del(self.0.obj, key).unwrap_infallible(); Some(Ok(( match K::try_from_val(env, &key) { Ok(k) => k, diff --git a/soroban-sdk/src/serde.rs b/soroban-sdk/src/serde.rs index 49eca8d94..df1f7b5cd 100644 --- a/soroban-sdk/src/serde.rs +++ b/soroban-sdk/src/serde.rs @@ -22,7 +22,9 @@ //! assert_eq!(roundtrip, Ok(value)); //! ``` -use crate::{env::internal::Env as _, Bytes, Env, IntoVal, RawVal, TryFromVal}; +use crate::{ + env::internal::Env as _, unwrap::UnwrapInfallible, Bytes, Env, IntoVal, RawVal, TryFromVal, +}; /// Implemented by types that can be serialized to [Bytes]. /// @@ -45,7 +47,7 @@ where { fn serialize(self, env: &Env) -> Bytes { let val: RawVal = self.into_val(env); - let bin = env.serialize_to_bytes(val); + let bin = env.serialize_to_bytes(val).unwrap_infallible(); unsafe { Bytes::unchecked_new(env.clone(), bin) } } } @@ -57,7 +59,7 @@ where type Error = T::Error; fn deserialize(env: &Env, b: &Bytes) -> Result { - let t = env.deserialize_from_bytes(b.into()); + let t = env.deserialize_from_bytes(b.into()).unwrap_infallible(); T::try_from_val(env, &t) } } diff --git a/soroban-sdk/src/set.rs b/soroban-sdk/src/set.rs index 920653172..05f8e6a17 100644 --- a/soroban-sdk/src/set.rs +++ b/soroban-sdk/src/set.rs @@ -1,5 +1,7 @@ use core::{cmp::Ordering, fmt::Debug, iter::FusedIterator}; +use crate::unwrap::UnwrapInfallible; + use super::{ env::internal::Env as _, xdr::ScObjectType, ConversionError, Env, IntoVal, Map, Object, RawVal, TryFromVal, Vec, @@ -133,7 +135,10 @@ where if self.is_empty() { None } else { - Some(T::try_from_val(env, &env.map_min_key(self.to_object()))) + Some(T::try_from_val( + env, + &env.map_min_key(self.to_object()).unwrap_infallible(), + )) } } @@ -142,7 +147,10 @@ where if self.is_empty() { None } else { - Some(T::try_from_val(env, &env.map_max_key(self.to_object()))) + Some(T::try_from_val( + env, + &env.map_max_key(self.to_object()).unwrap_infallible(), + )) } } diff --git a/soroban-sdk/src/storage.rs b/soroban-sdk/src/storage.rs index 9a8a4481d..31139090d 100644 --- a/soroban-sdk/src/storage.rs +++ b/soroban-sdk/src/storage.rs @@ -3,6 +3,7 @@ use core::fmt::Debug; use crate::{ env::internal::{self, RawVal}, + unwrap::UnwrapInfallible, Env, IntoVal, TryFromVal, }; @@ -73,7 +74,7 @@ impl Storage { K: IntoVal, { let env = self.env(); - let rv = internal::Env::has_contract_data(env, key.into_val(env)); + let rv = internal::Env::has_contract_data(env, key.into_val(env)).unwrap_infallible(); rv.is_true() } @@ -98,9 +99,9 @@ impl Storage { { let env = self.env(); let key = key.into_val(env); - let has = internal::Env::has_contract_data(env, key); + let has = internal::Env::has_contract_data(env, key).unwrap_infallible(); if has.is_true() { - let rv = internal::Env::get_contract_data(env, key); + let rv = internal::Env::get_contract_data(env, key).unwrap_infallible(); Some(V::try_from_val(env, &rv)) } else { None @@ -121,7 +122,7 @@ impl Storage { V: TryFromVal, { let env = self.env(); - let rv = internal::Env::get_contract_data(env, key.into_val(env)); + let rv = internal::Env::get_contract_data(env, key.into_val(env)).unwrap_infallible(); V::try_from_val(env, &rv) } @@ -137,7 +138,8 @@ impl Storage { V: IntoVal, { let env = self.env(); - internal::Env::put_contract_data(env, key.into_val(env), val.into_val(env)); + internal::Env::put_contract_data(env, key.into_val(env), val.into_val(env)) + .unwrap_infallible(); } #[inline(always)] @@ -146,6 +148,6 @@ impl Storage { K: IntoVal, { let env = self.env(); - internal::Env::del_contract_data(env, key.into_val(env)); + internal::Env::del_contract_data(env, key.into_val(env)).unwrap_infallible(); } } diff --git a/soroban-sdk/src/unwrap.rs b/soroban-sdk/src/unwrap.rs index 3150ab4a4..52b03854c 100644 --- a/soroban-sdk/src/unwrap.rs +++ b/soroban-sdk/src/unwrap.rs @@ -1,3 +1,5 @@ +use core::convert::Infallible; + pub trait UnwrapOptimized { type Output; fn unwrap_optimized(self) -> Self::Output; @@ -32,3 +34,37 @@ impl UnwrapOptimized for Result { self.unwrap() } } + +pub trait UnwrapInfallible { + type Output; + fn unwrap_infallible(self) -> Self::Output; +} + +impl UnwrapInfallible for Result { + type Output = T; + + fn unwrap_infallible(self) -> Self::Output { + match self { + Ok(ok) => ok, + // In the following `Err(never)` branch we convert a type from + // `Infallible` to `!`. Both of these are empty types and are + // essentially synonyms in rust, they differ only due to historical + // reasons that will eventually be eliminated. `Infallible` is a + // version we can put in a structure, and `!` is one that gets some + // special control-flow treatments. + // + // Specifically: the type `!` of the resulting expression will be + // considered an acceptable inhabitant of any type -- including + // `Self::Output` -- since it's an impossible path to execute, this + // is considered a harmless convenience in the type system, a bit + // like defining zero-divided-by-anything as zero. + // + // We could also write an infinite `loop {}` here or + // `unreachable!()` or similar expressions of type `!`, but + // destructuring the `never` variable into an empty set of cases is + // the most honest since it's statically checked to _be_ infallible, + // not just an assertion of our hopes.) + Err(never) => match never {}, + } + } +} diff --git a/soroban-sdk/src/vec.rs b/soroban-sdk/src/vec.rs index 303fa350a..a666b6e8b 100644 --- a/soroban-sdk/src/vec.rs +++ b/soroban-sdk/src/vec.rs @@ -7,7 +7,10 @@ use core::{ ops::{Bound, RangeBounds}, }; -use crate::iter::{UncheckedEnumerable, UncheckedIter}; +use crate::{ + iter::{UncheckedEnumerable, UncheckedIter}, + unwrap::UnwrapInfallible, +}; use super::{ env::{internal::Env as _, internal::EnvBase as _, RawValConvertible}, @@ -138,7 +141,10 @@ where { fn cmp(&self, other: &Self) -> core::cmp::Ordering { self.env.check_same_env(&other.env); - let v = self.env.obj_cmp(self.obj.to_raw(), other.obj.to_raw()); + let v = self + .env + .obj_cmp(self.obj.to_raw(), other.obj.to_raw()) + .unwrap_infallible(); v.cmp(&0) } } @@ -392,7 +398,7 @@ where { #[inline(always)] pub fn new(env: &Env) -> Vec { - unsafe { Self::unchecked_new(env.clone(), env.vec_new(().into())) } + unsafe { Self::unchecked_new(env.clone(), env.vec_new(().into()).unwrap_infallible()) } } #[inline(always)] @@ -416,7 +422,7 @@ where pub fn get(&self, i: u32) -> Option> { if i < self.len() { let env = self.env(); - let val = env.vec_get(self.obj, i.into()); + let val = env.vec_get(self.obj, i.into()).unwrap_infallible(); Some(T::try_from_val(env, &val)) } else { None @@ -429,14 +435,16 @@ where T::Error: Debug, { let env = self.env(); - let val = env.vec_get(self.obj, i.into()); + let val = env.vec_get(self.obj, i.into()).unwrap_infallible(); T::try_from_val(env, &val) } #[inline(always)] pub fn set(&mut self, i: u32, v: T) { let env = self.env(); - self.obj = env.vec_put(self.obj, i.into(), v.into_val(env)); + self.obj = env + .vec_put(self.obj, i.into(), v.into_val(env)) + .unwrap_infallible(); } #[inline(always)] @@ -452,34 +460,36 @@ where #[inline(always)] pub fn remove_unchecked(&mut self, i: u32) { let env = self.env(); - self.obj = env.vec_del(self.obj, i.into()); + self.obj = env.vec_del(self.obj, i.into()).unwrap_infallible(); } #[inline(always)] pub fn is_empty(&self) -> bool { let env = self.env(); - let val = env.vec_len(self.obj); + let val = env.vec_len(self.obj).unwrap_infallible(); val.is_u32_zero() } #[inline(always)] pub fn len(&self) -> u32 { let env = self.env(); - let val = env.vec_len(self.obj); + let val = env.vec_len(self.obj).unwrap_infallible(); unsafe { <_ as RawValConvertible>::unchecked_from_val(val) } } #[inline(always)] pub fn push_front(&mut self, x: T) { let env = self.env(); - self.obj = env.vec_push_front(self.obj, x.into_val(env)); + self.obj = env + .vec_push_front(self.obj, x.into_val(env)) + .unwrap_infallible(); } #[inline(always)] pub fn pop_front(&mut self) -> Option> { let last = self.first()?; let env = self.env(); - self.obj = env.vec_pop_front(self.obj); + self.obj = env.vec_pop_front(self.obj).unwrap_infallible(); Some(last) } @@ -487,21 +497,23 @@ where pub fn pop_front_unchecked(&mut self) -> Result { let last = self.first_unchecked(); let env = self.env(); - self.obj = env.vec_pop_front(self.obj); + self.obj = env.vec_pop_front(self.obj).unwrap_infallible(); last } #[inline(always)] pub fn push_back(&mut self, x: T) { let env = self.env(); - self.obj = env.vec_push_back(self.obj, x.into_val(env)); + self.obj = env + .vec_push_back(self.obj, x.into_val(env)) + .unwrap_infallible(); } #[inline(always)] pub fn pop_back(&mut self) -> Option> { let last = self.last()?; let env = self.env(); - self.obj = env.vec_pop_back(self.obj); + self.obj = env.vec_pop_back(self.obj).unwrap_infallible(); Some(last) } @@ -509,7 +521,7 @@ where pub fn pop_back_unchecked(&mut self) -> Result { let last = self.last_unchecked(); let env = self.env(); - self.obj = env.vec_pop_back(self.obj); + self.obj = env.vec_pop_back(self.obj).unwrap_infallible(); last } @@ -537,7 +549,7 @@ where None } else { let env = &self.env; - let val = env.vec_front(self.obj); + let val = env.vec_front(self.obj).unwrap_infallible(); Some(T::try_from_val(env, &val)) } } @@ -545,7 +557,7 @@ where #[inline(always)] pub fn first_unchecked(&self) -> Result { let env = &self.env; - let val = env.vec_front(self.obj); + let val = env.vec_front(self.obj).unwrap_infallible(); T::try_from_val(env, &val) } @@ -555,7 +567,7 @@ where None } else { let env = self.env(); - let val = env.vec_back(self.obj); + let val = env.vec_back(self.obj).unwrap_infallible(); Some(T::try_from_val(env, &val)) } } @@ -563,20 +575,22 @@ where #[inline(always)] pub fn last_unchecked(&self) -> Result { let env = self.env(); - let val = env.vec_back(self.obj); + let val = env.vec_back(self.obj).unwrap_infallible(); T::try_from_val(env, &val) } #[inline(always)] pub fn insert(&mut self, i: u32, x: T) { let env = self.env(); - self.obj = env.vec_insert(self.obj, i.into(), x.into_val(env)); + self.obj = env + .vec_insert(self.obj, i.into(), x.into_val(env)) + .unwrap_infallible(); } #[inline(always)] pub fn append(&mut self, other: &Vec) { let env = self.env(); - self.obj = env.vec_append(self.obj, other.obj); + self.obj = env.vec_append(self.obj, other.obj).unwrap_infallible(); } #[inline(always)] @@ -609,7 +623,9 @@ where Bound::Unbounded => self.len(), }; let env = self.env(); - let obj = env.vec_slice(self.obj, start_bound.into(), end_bound.into()); + let obj = env + .vec_slice(self.obj, start_bound.into(), end_bound.into()) + .unwrap_infallible(); unsafe { Self::unchecked_new(env.clone(), obj) } } @@ -648,7 +664,9 @@ where pub fn contains(&self, item: impl Borrow) -> bool { let env = self.env(); let val = item.borrow().into_val(env); - !env.vec_first_index_of(self.obj, val).is_void() + !env.vec_first_index_of(self.obj, val) + .unwrap_infallible() + .is_void() } /// Returns the index of the first occurrence of the item. @@ -659,6 +677,7 @@ where let env = self.env(); let val = item.borrow().into_val(env); env.vec_first_index_of(self.obj, val) + .unwrap_infallible() .try_into_val(env) .unwrap() } @@ -671,6 +690,7 @@ where let env = self.env(); let val = item.borrow().into_val(env); env.vec_last_index_of(self.obj, val) + .unwrap_infallible() .try_into_val(env) .unwrap() } @@ -688,7 +708,7 @@ where pub fn binary_search(&self, item: impl Borrow) -> Result { let env = self.env(); let val = item.borrow().into_val(env); - let high_low = env.vec_binary_search(self.obj, val); + let high_low = env.vec_binary_search(self.obj, val).unwrap_infallible(); let high: u32 = (high_low >> u32::BITS) as u32; let low: u32 = high_low as u32; if high == 1 { @@ -746,7 +766,7 @@ where if len == 0 { None } else { - let val = self.0.env().vec_front(self.0.obj); + let val = self.0.env().vec_front(self.0.obj).unwrap_infallible(); self.0 = self.0.slice(1..); Some(T::try_from_val(self.0.env(), &val)) } @@ -770,7 +790,7 @@ where if len == 0 { None } else { - let val = self.0.env().vec_back(self.0.obj); + let val = self.0.env().vec_back(self.0.obj).unwrap_infallible(); self.0 = self.0.slice(..len - 1); Some(T::try_from_val(self.0.env(), &val)) }