diff --git a/packages/std/src/imports.rs b/packages/std/src/imports.rs index 8f99e6941..7df3f22c9 100644 --- a/packages/std/src/imports.rs +++ b/packages/std/src/imports.rs @@ -200,6 +200,15 @@ struct ExternalPartialIterator { impl Iterator for ExternalPartialIterator { type Item = Vec; + /// The default implementation calls `next` repeatedly, + /// which we can do a little more efficiently by using `db_next_key` instead. + /// It is used by `skip`, so it allows cheaper skipping. + #[cfg(feature = "cosmwasm_1_4")] + fn nth(&mut self, n: usize) -> Option { + skip_iter(self.iterator_id, n); + self.next() + } + fn next(&mut self) -> Option { // here we differentiate between the two types let next_result = match self.partial_type { @@ -229,6 +238,15 @@ struct ExternalIterator { impl Iterator for ExternalIterator { type Item = Record; + /// The default implementation calls `next` repeatedly, + /// which we can do a little more efficiently by using `db_next_key` instead. + /// It is used by `skip`, so it allows cheaper skipping. + #[cfg(feature = "cosmwasm_1_4")] + fn nth(&mut self, n: usize) -> Option { + skip_iter(self.iterator_id, n); + self.next() + } + fn next(&mut self) -> Option { let next_result = unsafe { db_next(self.iterator_id) }; let kv_region_ptr = next_result as *mut Region; @@ -242,6 +260,20 @@ impl Iterator for ExternalIterator { } } +/// Helper function to skip `count` elements of an iterator. +#[cfg(all(feature = "iterator", feature = "cosmwasm_1_4"))] +fn skip_iter(iter_id: u32, count: usize) { + for _ in 0..count { + let region = unsafe { db_next_key(iter_id) }; + if region == 0 { + // early return + return; + } + // just deallocate the region + unsafe { consume_region(region as *mut Region) }; + } +} + /// A stateless convenience wrapper around imports provided by the VM #[derive(Copy, Clone)] pub struct ExternalApi {}