From a21448edf9bfc25e862053d30ca60eb51b243d38 Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Tue, 31 Dec 2024 11:31:34 +0200 Subject: [PATCH] ManagedVec is_single_item, some refactor --- .../src/types/managed/wrapped/managed_vec.rs | 38 +++++++++++++------ framework/scenario/tests/managed_vec_test.rs | 17 ++++++++- 2 files changed, 42 insertions(+), 13 deletions(-) diff --git a/framework/base/src/types/managed/wrapped/managed_vec.rs b/framework/base/src/types/managed/wrapped/managed_vec.rs index ebb0f0d157..0b32d308e1 100644 --- a/framework/base/src/types/managed/wrapped/managed_vec.rs +++ b/framework/base/src/types/managed/wrapped/managed_vec.rs @@ -139,15 +139,20 @@ where self.byte_len() == 0 } - pub fn try_get(&self, index: usize) -> Option> { + /// Internal function that loads the payload for an item. + /// + /// Payload passed as mutable reference, to avoid copying of bytes around the stack. + fn load_item_payload(&self, index: usize, payload: &mut T::PAYLOAD) -> bool { let byte_index = index * T::payload_size(); - let mut payload = T::PAYLOAD::new_buffer(); - if self - .buffer + self.buffer .load_slice(byte_index, payload.payload_slice_mut()) .is_ok() - { + } + + pub fn try_get(&self, index: usize) -> Option> { + let mut payload = T::PAYLOAD::new_buffer(); + if self.load_item_payload(index, &mut payload) { unsafe { Some(T::borrow_from_payload(&payload)) } } else { None @@ -182,21 +187,30 @@ where } } + /// If it contains precisely one item, will return `Some` with a reference to that item. + /// + /// Will return `None` for zero or more than one item. + pub fn is_single_item(&self) -> Option> { + let mut payload = T::PAYLOAD::new_buffer(); + if self.len() == 1 { + let _ = self.load_item_payload(0, &mut payload); + unsafe { Some(T::borrow_from_payload(&payload)) } + } else { + None + } + } + pub fn get_mut(&mut self, index: usize) -> ManagedVecRefMut { ManagedVecRefMut::new(self.get_handle(), index) } pub(super) unsafe fn get_unsafe(&self, index: usize) -> T { - let byte_index = index * T::payload_size(); let mut payload = T::PAYLOAD::new_buffer(); - if self - .buffer - .load_slice(byte_index, payload.payload_slice_mut()) - .is_err() - { + if self.load_item_payload(index, &mut payload) { + T::read_from_payload(&payload) + } else { M::error_api_impl().signal_error(INDEX_OUT_OF_RANGE_MSG); } - T::read_from_payload(&payload) } pub fn set(&mut self, index: usize, item: T) -> Result<(), InvalidSliceError> { diff --git a/framework/scenario/tests/managed_vec_test.rs b/framework/scenario/tests/managed_vec_test.rs index b11fe76788..86dfc76802 100644 --- a/framework/scenario/tests/managed_vec_test.rs +++ b/framework/scenario/tests/managed_vec_test.rs @@ -1,6 +1,6 @@ use std::ops::Deref; -use multiversx_sc::types::{BigUint, ManagedVec}; +use multiversx_sc::types::{BigUint, ManagedRef, ManagedVec}; use multiversx_sc_scenario::api::StaticApi; #[test] @@ -595,3 +595,18 @@ fn test_managed_vec_get_mut() { assert_eq!(*managed_vec.get(0), 200u32); assert_eq!(*managed_vec.get(1), 300u32); } + +#[test] +fn test_is_single_item() { + let mut managed_vec = ManagedVec::>::new(); + assert!(managed_vec.is_single_item().is_none()); + + managed_vec.push(BigUint::::from(1u32)); + assert_eq!( + managed_vec.is_single_item(), + Some(ManagedRef::new(&BigUint::::from(1u32))) + ); + + managed_vec.push(BigUint::::from(2u32)); + assert!(managed_vec.is_single_item().is_none()); +}