Skip to content

Commit

Permalink
Implement range_{keys, values} using new imports
Browse files Browse the repository at this point in the history
  • Loading branch information
chipshort committed Aug 24, 2023
1 parent b92782b commit 39701b5
Showing 1 changed file with 80 additions and 7 deletions.
87 changes: 80 additions & 7 deletions packages/std/src/imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,16 +133,89 @@ impl Storage for ExternalStorage {
end: Option<&[u8]>,
order: Order,
) -> Box<dyn Iterator<Item = Record>> {
// There is lots of gotchas on turning options into regions for FFI, thus this design
// See: https://github.com/CosmWasm/cosmwasm/pull/509
let start_region = start.map(build_region);
let end_region = end.map(build_region);
let start_region_addr = get_optional_region_address(&start_region.as_ref());
let end_region_addr = get_optional_region_address(&end_region.as_ref());
let iterator_id = unsafe { db_scan(start_region_addr, end_region_addr, order as i32) };
let iterator_id = create_iter(start, end, order);
let iter = ExternalIterator { iterator_id };
Box::new(iter)
}

#[cfg(all(feature = "cosmwasm_1_4", feature = "iterator"))]
fn range_keys<'a>(
&'a self,
start: Option<&[u8]>,
end: Option<&[u8]>,
order: Order,
) -> Box<dyn Iterator<Item = Vec<u8>> + 'a> {
let iterator_id = create_iter(start, end, order);
let iter = ExternalPartialIterator {
iterator_id,
iter_type: PartialType::Keys,
};
Box::new(iter)
}

#[cfg(all(feature = "cosmwasm_1_4", feature = "iterator"))]
fn range_values<'a>(
&'a self,
start: Option<&[u8]>,
end: Option<&[u8]>,
order: Order,
) -> Box<dyn Iterator<Item = Vec<u8>> + 'a> {
let iterator_id = create_iter(start, end, order);
let iter = ExternalPartialIterator {
iterator_id,
partial_type: PartialType::Values,
};
Box::new(iter)
}
}

#[cfg(all(feature = "cosmwasm_1_4", feature = "iterator"))]
fn create_iter(start: Option<&[u8]>, end: Option<&[u8]>, order: Order) -> u32 {
// There is lots of gotchas on turning options into regions for FFI, thus this design
// See: https://github.com/CosmWasm/cosmwasm/pull/509
let start_region = start.map(build_region);
let end_region = end.map(build_region);
let start_region_addr = get_optional_region_address(&start_region.as_ref());
let end_region_addr = get_optional_region_address(&end_region.as_ref());
unsafe { db_scan(start_region_addr, end_region_addr, order as i32) }
}

#[cfg(all(feature = "cosmwasm_1_4", feature = "iterator"))]
enum PartialType {
Keys,
Values,
}

/// ExternalPartialIterator makes a call out to `next_key` or `next_value`
/// depending on its `partial_type`.
/// Compared to `ExternalIterator`, it allows iterating only over the keys or
/// values instead of both.
#[cfg(all(feature = "cosmwasm_1_4", feature = "iterator"))]
struct ExternalPartialIterator {
iterator_id: u32,
partial_type: PartialType,
}

#[cfg(all(feature = "cosmwasm_1_4", feature = "iterator"))]
impl Iterator for ExternalPartialIterator {
type Item = Vec<u8>;

fn next(&mut self) -> Option<Self::Item> {
// here we differentiate between the two types
let next_result = match self.partial_type {
PartialType::Keys => unsafe { db_next_key(self.iterator_id) },
PartialType::Values => unsafe { db_next_value(self.iterator_id) },
};

if next_result == 0 {
// iterator is done
return None;
}

let data_region = next_result as *mut Region;
let data = unsafe { consume_region(data_region) };
Some(data)
}
}

#[cfg(feature = "iterator")]
Expand Down

0 comments on commit 39701b5

Please sign in to comment.