From d57a0ee033082a0f9678d1c390bdc26d78fd716e Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Wed, 7 Oct 2020 11:46:39 +0200 Subject: [PATCH] Add prefix --- .circleci/config.yml | 6 ++++ packages/storage-plus/Cargo.toml | 2 ++ packages/storage-plus/src/lib.rs | 3 ++ packages/storage-plus/src/map.rs | 13 ++++++++ packages/storage-plus/src/path.rs | 3 +- packages/storage-plus/src/prefix.rs | 51 +++++++++++++++++++++++++++++ 6 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 packages/storage-plus/src/prefix.rs diff --git a/.circleci/config.yml b/.circleci/config.yml index 832205b5c..404edd16e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -590,6 +590,12 @@ jobs: - run: name: Run unit tests command: cargo test --locked + - run: + name: Build library for native target (with iterator) + command: cargo build --locked --features iterator + - run: + name: Run unit tests (with iterator) + command: cargo test --locked --features iterator - save_cache: paths: - /usr/local/cargo/registry diff --git a/packages/storage-plus/Cargo.toml b/packages/storage-plus/Cargo.toml index 9877dc10f..e127a4c40 100644 --- a/packages/storage-plus/Cargo.toml +++ b/packages/storage-plus/Cargo.toml @@ -10,6 +10,8 @@ homepage = "https://cosmwasm.com" documentation = "https://docs.cosmwasm.com" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[features] +iterator = ["cosmwasm-std/iterator"] [dependencies] cosmwasm-std = { version = "0.11.0-alpha3" } diff --git a/packages/storage-plus/src/lib.rs b/packages/storage-plus/src/lib.rs index 7a8d20d45..2efd417c7 100644 --- a/packages/storage-plus/src/lib.rs +++ b/packages/storage-plus/src/lib.rs @@ -2,10 +2,13 @@ mod length_prefixed; mod map; mod namespace_helpers; mod path; +mod prefix; mod type_helpers; pub use map::Map; pub use path::Path; +#[cfg(feature = "iterator")] +pub use prefix::Prefix; #[cfg(test)] mod test { diff --git a/packages/storage-plus/src/map.rs b/packages/storage-plus/src/map.rs index 52e9223b5..def5ad11f 100644 --- a/packages/storage-plus/src/map.rs +++ b/packages/storage-plus/src/map.rs @@ -4,6 +4,8 @@ use std::marker::PhantomData; use crate::path::Path; +// TODO: where to add PREFIX_PK???? Only in an Indexed Map? + pub struct Map<'a, K, T> { namespaces: &'a [&'a [u8]], // see https://doc.rust-lang.org/std/marker/struct.PhantomData.html#unused-type-parameters for why this is needed @@ -30,6 +32,8 @@ where let (namespaces, key) = k.namespaced(self.namespaces); Path::new(namespaces, key) } + + // TODO: how to do range queries on the prefix... } pub trait PrimaryKey<'a> { @@ -54,6 +58,15 @@ impl<'a> PrimaryKey<'a> for (&'a [u8], &'a [u8]) { } } +impl<'a> PrimaryKey<'a> for (&'a [u8], &'a [u8], &'a [u8]) { + fn namespaced(&self, namespaces: &'a [&'a [u8]]) -> (Vec<&'a [u8]>, Vec) { + let mut spaces = namespaces.to_vec(); + spaces.extend_from_slice(&[self.0, self.1]); + // move the first parts into the namespace, last as key + (spaces, self.2.to_vec()) + } +} + #[cfg(test)] mod test { use super::*; diff --git a/packages/storage-plus/src/path.rs b/packages/storage-plus/src/path.rs index 6104c0ffd..38c5fb57f 100644 --- a/packages/storage-plus/src/path.rs +++ b/packages/storage-plus/src/path.rs @@ -6,8 +6,7 @@ use crate::length_prefixed::namespaces_with_key; use crate::type_helpers::{may_deserialize, must_deserialize}; use cosmwasm_std::{to_vec, StdResult, Storage}; -// TODO: where to add PREFIX_PK???? - +// TODO: build the final storage key (build_storage_key()) in the constructor, so cheap when we reuse pub struct Path<'a, T> where T: Serialize + DeserializeOwned, diff --git a/packages/storage-plus/src/prefix.rs b/packages/storage-plus/src/prefix.rs new file mode 100644 index 000000000..d80b5b43c --- /dev/null +++ b/packages/storage-plus/src/prefix.rs @@ -0,0 +1,51 @@ +#![cfg(feature = "iterator")] + +use serde::de::DeserializeOwned; +use serde::Serialize; +use std::marker::PhantomData; + +use crate::length_prefixed::namespaces_with_key; +use crate::namespace_helpers::range_with_prefix; +use crate::type_helpers::deserialize_kv; +use cosmwasm_std::{Order, StdResult, Storage, KV}; + +pub struct Prefix<'a, T> +where + T: Serialize + DeserializeOwned, +{ + // these are not prefixed + namespaces: Vec<&'a [u8]>, + // see https://doc.rust-lang.org/std/marker/struct.PhantomData.html#unused-type-parameters for why this is needed + data: PhantomData, +} + +impl<'a, T> Prefix<'a, T> +where + T: Serialize + DeserializeOwned, +{ + pub fn new(namespaces: Vec<&'a [u8]>) -> Self { + Prefix { + namespaces, + data: PhantomData, + } + } + + // TODO: parse out composite key prefix??? + pub fn range<'c, S: Storage>( + &'c self, + store: &'c S, + start: Option<&[u8]>, + end: Option<&[u8]>, + order: Order, + ) -> Box>> + 'c> { + let namespace = self.build_storage_prefix(); + let mapped = + range_with_prefix(store, &namespace, start, end, order).map(deserialize_kv::); + Box::new(mapped) + } + + /// This provides the raw storage prefix that we use for ranges + pub(crate) fn build_storage_prefix(&self) -> Vec { + namespaces_with_key(&self.namespaces, b"") + } +}