From 5fe75bca96fe09b7e6231efd06b4391a1b998feb Mon Sep 17 00:00:00 2001 From: Eshel Date: Tue, 14 Feb 2023 20:00:53 +0200 Subject: [PATCH 1/3] copied files that define PrimaryKey from cosmwasm-storage-plus --- packages/storage/src/de.rs | 268 +++++++++++++++++ packages/storage/src/helpers.rs | 194 ++++++++++++ packages/storage/src/int_key.rs | 130 ++++++++ packages/storage/src/keys.rs | 512 ++++++++++++++++++++++++++++++++ packages/storage/src/lib.rs | 5 + 5 files changed, 1109 insertions(+) create mode 100644 packages/storage/src/de.rs create mode 100644 packages/storage/src/helpers.rs create mode 100644 packages/storage/src/int_key.rs create mode 100644 packages/storage/src/keys.rs diff --git a/packages/storage/src/de.rs b/packages/storage/src/de.rs new file mode 100644 index 0000000..046d8b9 --- /dev/null +++ b/packages/storage/src/de.rs @@ -0,0 +1,268 @@ +use std::array::TryFromSliceError; +use std::convert::TryInto; + +use cosmwasm_std::{Addr, StdError, StdResult}; + +use crate::int_key::IntKey; + +pub trait KeyDeserialize { + type Output: Sized; + + fn from_vec(value: Vec) -> StdResult; + + fn from_slice(value: &[u8]) -> StdResult { + Self::from_vec(value.to_vec()) + } +} + +impl KeyDeserialize for () { + type Output = (); + + #[inline(always)] + fn from_vec(_value: Vec) -> StdResult { + Ok(()) + } +} + +impl KeyDeserialize for Vec { + type Output = Vec; + + #[inline(always)] + fn from_vec(value: Vec) -> StdResult { + Ok(value) + } +} + +impl KeyDeserialize for &Vec { + type Output = Vec; + + #[inline(always)] + fn from_vec(value: Vec) -> StdResult { + Ok(value) + } +} + +impl KeyDeserialize for &[u8] { + type Output = Vec; + + #[inline(always)] + fn from_vec(value: Vec) -> StdResult { + Ok(value) + } +} + +impl KeyDeserialize for String { + type Output = String; + + #[inline(always)] + fn from_vec(value: Vec) -> StdResult { + String::from_utf8(value).map_err(StdError::invalid_utf8) + } +} + +impl KeyDeserialize for &String { + type Output = String; + + #[inline(always)] + fn from_vec(value: Vec) -> StdResult { + Self::Output::from_vec(value) + } +} + +impl KeyDeserialize for &str { + type Output = String; + + #[inline(always)] + fn from_vec(value: Vec) -> StdResult { + Self::Output::from_vec(value) + } +} + +impl KeyDeserialize for Addr { + type Output = Addr; + + #[inline(always)] + fn from_vec(value: Vec) -> StdResult { + Ok(Addr::unchecked(String::from_vec(value)?)) + } +} + +impl KeyDeserialize for &Addr { + type Output = Addr; + + #[inline(always)] + fn from_vec(value: Vec) -> StdResult { + Self::Output::from_vec(value) + } +} + +macro_rules! integer_de { + (for $($t:ty),+) => { + $(impl KeyDeserialize for $t { + type Output = $t; + + #[inline(always)] + fn from_vec(value: Vec) -> StdResult { + Ok(<$t>::from_cw_bytes(value.as_slice().try_into() + .map_err(|err: TryFromSliceError| StdError::generic_err(err.to_string()))?)) + } + })* + } +} + +integer_de!(for i8, u8, i16, u16, i32, u32, i64, u64, i128, u128); + +fn parse_length(value: &[u8]) -> StdResult { + Ok(u16::from_be_bytes( + value + .try_into() + .map_err(|_| StdError::generic_err("Could not read 2 byte length"))?, + ) + .into()) +} + +impl KeyDeserialize for (T, U) { + type Output = (T::Output, U::Output); + + #[inline(always)] + fn from_vec(mut value: Vec) -> StdResult { + let mut tu = value.split_off(2); + let t_len = parse_length(&value)?; + let u = tu.split_off(t_len); + + Ok((T::from_vec(tu)?, U::from_vec(u)?)) + } +} + +impl KeyDeserialize for (T, U, V) { + type Output = (T::Output, U::Output, V::Output); + + #[inline(always)] + fn from_vec(mut value: Vec) -> StdResult { + let mut tuv = value.split_off(2); + let t_len = parse_length(&value)?; + let mut len_uv = tuv.split_off(t_len); + + let mut uv = len_uv.split_off(2); + let u_len = parse_length(&len_uv)?; + let v = uv.split_off(u_len); + + Ok((T::from_vec(tuv)?, U::from_vec(uv)?, V::from_vec(v)?)) + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::PrimaryKey; + + const BYTES: &[u8] = b"Hello"; + const STRING: &str = "Hello"; + + #[test] + #[allow(clippy::unit_cmp)] + fn deserialize_empty_works() { + assert_eq!(<()>::from_slice(BYTES).unwrap(), ()); + } + + #[test] + fn deserialize_bytes_works() { + assert_eq!(>::from_slice(BYTES).unwrap(), BYTES); + assert_eq!(<&Vec>::from_slice(BYTES).unwrap(), BYTES); + assert_eq!(<&[u8]>::from_slice(BYTES).unwrap(), BYTES); + } + + #[test] + fn deserialize_string_works() { + assert_eq!(::from_slice(BYTES).unwrap(), STRING); + assert_eq!(<&String>::from_slice(BYTES).unwrap(), STRING); + assert_eq!(<&str>::from_slice(BYTES).unwrap(), STRING); + } + + #[test] + fn deserialize_broken_string_errs() { + assert!(matches!( + ::from_slice(b"\xc3").err(), + Some(StdError::InvalidUtf8 { .. }) + )); + } + + #[test] + fn deserialize_addr_works() { + assert_eq!(::from_slice(BYTES).unwrap(), Addr::unchecked(STRING)); + assert_eq!(<&Addr>::from_slice(BYTES).unwrap(), Addr::unchecked(STRING)); + } + + #[test] + fn deserialize_broken_addr_errs() { + assert!(matches!( + ::from_slice(b"\xc3").err(), + Some(StdError::InvalidUtf8 { .. }) + )); + } + + #[test] + fn deserialize_naked_integer_works() { + assert_eq!(u8::from_slice(&[1]).unwrap(), 1u8); + assert_eq!(i8::from_slice(&[127]).unwrap(), -1i8); + assert_eq!(i8::from_slice(&[128]).unwrap(), 0i8); + + assert_eq!(u16::from_slice(&[1, 0]).unwrap(), 256u16); + assert_eq!(i16::from_slice(&[128, 0]).unwrap(), 0i16); + assert_eq!(i16::from_slice(&[127, 255]).unwrap(), -1i16); + + assert_eq!(u32::from_slice(&[1, 0, 0, 0]).unwrap(), 16777216u32); + assert_eq!(i32::from_slice(&[128, 0, 0, 0]).unwrap(), 0i32); + assert_eq!(i32::from_slice(&[127, 255, 255, 255]).unwrap(), -1i32); + + assert_eq!( + u64::from_slice(&[1, 0, 0, 0, 0, 0, 0, 0]).unwrap(), + 72057594037927936u64 + ); + assert_eq!(i64::from_slice(&[128, 0, 0, 0, 0, 0, 0, 0]).unwrap(), 0i64); + assert_eq!( + i64::from_slice(&[127, 255, 255, 255, 255, 255, 255, 255]).unwrap(), + -1i64 + ); + + assert_eq!( + u128::from_slice(&[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]).unwrap(), + 1329227995784915872903807060280344576u128 + ); + assert_eq!( + i128::from_slice(&[128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]).unwrap(), + 0i128 + ); + assert_eq!( + i128::from_slice(&[ + 127, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 + ]) + .unwrap(), + -1i128 + ); + assert_eq!( + i128::from_slice(&[ + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 + ]) + .unwrap(), + 170141183460469231731687303715884105727i128, + ); + } + + #[test] + fn deserialize_tuple_works() { + assert_eq!( + <(&[u8], &str)>::from_slice((BYTES, STRING).joined_key().as_slice()).unwrap(), + (BYTES.to_vec(), STRING.to_string()) + ); + } + + #[test] + fn deserialize_triple_works() { + assert_eq!( + <(&[u8], u32, &str)>::from_slice((BYTES, 1234u32, STRING).joined_key().as_slice()) + .unwrap(), + (BYTES.to_vec(), 1234, STRING.to_string()) + ); + } +} diff --git a/packages/storage/src/helpers.rs b/packages/storage/src/helpers.rs new file mode 100644 index 0000000..b87c662 --- /dev/null +++ b/packages/storage/src/helpers.rs @@ -0,0 +1,194 @@ +//! This module is an implemention of a namespacing scheme described +//! in https://github.com/webmaster128/key-namespacing#length-prefixed-keys +//! +//! Everything in this file is only responsible for building such keys +//! and is in no way specific to any kind of storage. + +use serde::de::DeserializeOwned; +use std::any::type_name; + +use crate::keys::Key; + +use cosmwasm_std::{ + from_slice, to_vec, Addr, Binary, ContractResult, CustomQuery, QuerierWrapper, QueryRequest, + StdError, StdResult, SystemResult, WasmQuery, +}; + +/// may_deserialize parses json bytes from storage (Option), returning Ok(None) if no data present +/// +/// value is an odd type, but this is meant to be easy to use with output from storage.get (Option>) +/// and value.map(|s| s.as_slice()) seems trickier than &value +pub(crate) fn may_deserialize( + value: &Option>, +) -> StdResult> { + match value { + Some(vec) => Ok(Some(from_slice(vec)?)), + None => Ok(None), + } +} + +/// must_deserialize parses json bytes from storage (Option), returning NotFound error if no data present +pub(crate) fn must_deserialize(value: &Option>) -> StdResult { + match value { + Some(vec) => from_slice(vec), + None => Err(StdError::not_found(type_name::())), + } +} + +/// This is equivalent concat(to_length_prefixed_nested(namespaces), key) +/// But more efficient when the intermediate namespaces often must be recalculated +pub(crate) fn namespaces_with_key(namespaces: &[&[u8]], key: &[u8]) -> Vec { + let mut size = key.len(); + for &namespace in namespaces { + size += namespace.len() + 2; + } + + let mut out = Vec::with_capacity(size); + for &namespace in namespaces { + out.extend_from_slice(&encode_length(namespace)); + out.extend_from_slice(namespace); + } + out.extend_from_slice(key); + out +} + +/// Customization of namespaces_with_key for when +/// there are multiple sets we do not want to combine just to call this +pub(crate) fn nested_namespaces_with_key( + top_names: &[&[u8]], + sub_names: &[Key], + key: &[u8], +) -> Vec { + let mut size = key.len(); + for &namespace in top_names { + size += namespace.len() + 2; + } + for namespace in sub_names { + size += namespace.as_ref().len() + 2; + } + + let mut out = Vec::with_capacity(size); + for &namespace in top_names { + out.extend_from_slice(&encode_length(namespace)); + out.extend_from_slice(namespace); + } + for namespace in sub_names { + out.extend_from_slice(&encode_length(namespace.as_ref())); + out.extend_from_slice(namespace.as_ref()); + } + out.extend_from_slice(key); + out +} + +/// Encodes the length of a given namespace as a 2 byte big endian encoded integer +pub(crate) fn encode_length(namespace: &[u8]) -> [u8; 2] { + if namespace.len() > 0xFFFF { + panic!("only supports namespaces up to length 0xFFFF") + } + let length_bytes = (namespace.len() as u32).to_be_bytes(); + [length_bytes[2], length_bytes[3]] +} + +/// Use this in Map/SnapshotMap/etc when you want to provide a QueryRaw helper. +/// This is similar to querier.query(WasmQuery::Raw{}), except it does NOT parse the +/// result, but return a possibly empty Binary to be handled by the calling code. +/// That is essential to handle b"" as None. +pub(crate) fn query_raw( + querier: &QuerierWrapper, + contract_addr: Addr, + key: Binary, +) -> StdResult { + let request: QueryRequest = WasmQuery::Raw { + contract_addr: contract_addr.into(), + key, + } + .into(); + + let raw = to_vec(&request).map_err(|serialize_err| { + StdError::generic_err(format!("Serializing QueryRequest: {}", serialize_err)) + })?; + match querier.raw_query(&raw) { + SystemResult::Err(system_err) => Err(StdError::generic_err(format!( + "Querier system error: {}", + system_err + ))), + SystemResult::Ok(ContractResult::Err(contract_err)) => Err(StdError::generic_err(format!( + "Querier contract error: {}", + contract_err + ))), + SystemResult::Ok(ContractResult::Ok(value)) => Ok(value), + } +} + +#[cfg(test)] +mod test { + use super::*; + use cosmwasm_std::{to_vec, StdError}; + use serde::{Deserialize, Serialize}; + + #[derive(Serialize, Deserialize, PartialEq, Debug)] + struct Person { + pub name: String, + pub age: i32, + } + + #[test] + fn encode_length_works() { + assert_eq!(encode_length(b""), *b"\x00\x00"); + assert_eq!(encode_length(b"a"), *b"\x00\x01"); + assert_eq!(encode_length(b"aa"), *b"\x00\x02"); + assert_eq!(encode_length(b"aaa"), *b"\x00\x03"); + assert_eq!(encode_length(&vec![1; 255]), *b"\x00\xff"); + assert_eq!(encode_length(&vec![1; 256]), *b"\x01\x00"); + assert_eq!(encode_length(&vec![1; 12345]), *b"\x30\x39"); + assert_eq!(encode_length(&vec![1; 65535]), *b"\xff\xff"); + } + + #[test] + #[should_panic(expected = "only supports namespaces up to length 0xFFFF")] + fn encode_length_panics_for_large_values() { + encode_length(&vec![1; 65536]); + } + + #[test] + fn may_deserialize_handles_some() { + let person = Person { + name: "Maria".to_string(), + age: 42, + }; + let value = to_vec(&person).unwrap(); + + let may_parse: Option = may_deserialize(&Some(value)).unwrap(); + assert_eq!(may_parse, Some(person)); + } + + #[test] + fn may_deserialize_handles_none() { + let may_parse = may_deserialize::(&None).unwrap(); + assert_eq!(may_parse, None); + } + + #[test] + fn must_deserialize_handles_some() { + let person = Person { + name: "Maria".to_string(), + age: 42, + }; + let value = to_vec(&person).unwrap(); + let loaded = Some(value); + + let parsed: Person = must_deserialize(&loaded).unwrap(); + assert_eq!(parsed, person); + } + + #[test] + fn must_deserialize_handles_none() { + let parsed = must_deserialize::(&None); + match parsed.unwrap_err() { + StdError::NotFound { kind, .. } => { + assert_eq!(kind, "secret_toolkit_storage::helpers::test::Person") + } + e => panic!("Unexpected error {}", e), + } + } +} diff --git a/packages/storage/src/int_key.rs b/packages/storage/src/int_key.rs new file mode 100644 index 0000000..0292674 --- /dev/null +++ b/packages/storage/src/int_key.rs @@ -0,0 +1,130 @@ +use std::mem; + +/// Our int keys are simply the big-endian representation bytes for unsigned ints, +/// but "sign-flipped" (xored msb) big-endian bytes for signed ints. +/// +/// So that the representation of signed integers is in the right lexicographical order. +pub trait IntKey: Sized + Copy { + type Buf: AsRef<[u8]> + AsMut<[u8]> + Into> + Default; + + fn to_cw_bytes(&self) -> Self::Buf; + fn from_cw_bytes(bytes: Self::Buf) -> Self; +} + +macro_rules! cw_uint_keys { + (for $($t:ty),+) => { + $(impl IntKey for $t { + type Buf = [u8; mem::size_of::<$t>()]; + + #[inline] + fn to_cw_bytes(&self) -> Self::Buf { + self.to_be_bytes() + } + + #[inline] + fn from_cw_bytes(bytes: Self::Buf) -> Self { + Self::from_be_bytes(bytes) + } + })* + } +} + +cw_uint_keys!(for u8, u16, u32, u64, u128); + +macro_rules! cw_int_keys { + (for $($t:ty, $ut:ty),+) => { + $(impl IntKey for $t { + type Buf = [u8; mem::size_of::<$t>()]; + + #[inline] + fn to_cw_bytes(&self) -> Self::Buf { + (*self as $ut ^ <$t>::MIN as $ut).to_be_bytes() + } + + #[inline] + fn from_cw_bytes(bytes: Self::Buf) -> Self { + (Self::from_be_bytes(bytes) as $ut ^ <$t>::MIN as $ut) as _ + } + })* + } +} + +cw_int_keys!(for i8, u8, i16, u16, i32, u32, i64, u64, i128, u128); + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn x8_int_key_works() { + assert_eq!(0x42u8.to_cw_bytes(), [0x42]); + assert_eq!(0x42i8.to_cw_bytes(), [0xc2]); + assert_eq!((-0x3ei8).to_cw_bytes(), [0x42]); + } + + #[test] + fn x16_int_key_works() { + assert_eq!(0x4243u16.to_cw_bytes(), [0x42, 0x43]); + assert_eq!(0x4243i16.to_cw_bytes(), [0xc2, 0x43]); + assert_eq!((-0x3dbdi16).to_cw_bytes(), [0x42, 0x43]); + } + + #[test] + fn x32_int_key_works() { + assert_eq!(0x424344u32.to_cw_bytes(), [0x00, 0x42, 0x43, 0x44]); + assert_eq!(0x424344i32.to_cw_bytes(), [0x80, 0x42, 0x43, 0x44]); + assert_eq!((-0x7fbdbcbci32).to_cw_bytes(), [0x00, 0x42, 0x43, 0x44]); + } + + #[test] + fn x64_int_key_works() { + assert_eq!( + 0x42434445u64.to_cw_bytes(), + [0x00, 0x00, 0x00, 0x00, 0x42, 0x43, 0x44, 0x45] + ); + assert_eq!( + 0x42434445i64.to_cw_bytes(), + [0x80, 0x00, 0x00, 0x00, 0x42, 0x43, 0x44, 0x45] + ); + assert_eq!( + (-0x7fffffffbdbcbbbbi64).to_cw_bytes(), + [0x00, 0x00, 0x00, 0x00, 0x42, 0x43, 0x44, 0x45] + ); + } + + #[test] + fn x128_int_key_works() { + assert_eq!( + 0x4243444546u128.to_cw_bytes(), + [ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x43, 0x44, + 0x45, 0x46 + ] + ); + assert_eq!( + 0x4243444546i128.to_cw_bytes(), + [ + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x43, 0x44, + 0x45, 0x46 + ] + ); + assert_eq!( + (-0x7fffffffffffffffffffffbdbcbbbabai128).to_cw_bytes(), + [ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x43, 0x44, + 0x45, 0x46 + ] + ); + } + + #[test] + fn unsigned_int_key_order() { + assert!(0u32.to_cw_bytes() < 652u32.to_cw_bytes()); + } + + #[test] + fn signed_int_key_order() { + assert!((-321i32).to_cw_bytes() < 0i32.to_cw_bytes()); + assert!(0i32.to_cw_bytes() < 652i32.to_cw_bytes()); + } +} diff --git a/packages/storage/src/keys.rs b/packages/storage/src/keys.rs new file mode 100644 index 0000000..cf7eff8 --- /dev/null +++ b/packages/storage/src/keys.rs @@ -0,0 +1,512 @@ +use cosmwasm_std::Addr; + +use crate::de::KeyDeserialize; +use crate::helpers::namespaces_with_key; +use crate::int_key::IntKey; + +#[derive(Debug)] +pub enum Key<'a> { + Ref(&'a [u8]), + Val8([u8; 1]), + Val16([u8; 2]), + Val32([u8; 4]), + Val64([u8; 8]), + Val128([u8; 16]), +} + +impl<'a> AsRef<[u8]> for Key<'a> { + fn as_ref(&self) -> &[u8] { + match self { + Key::Ref(r) => r, + Key::Val8(v) => v, + Key::Val16(v) => v, + Key::Val32(v) => v, + Key::Val64(v) => v, + Key::Val128(v) => v, + } + } +} + +impl<'a> PartialEq<&[u8]> for Key<'a> { + fn eq(&self, other: &&[u8]) -> bool { + self.as_ref() == *other + } +} + +/// `PrimaryKey` needs to be implemented for types that want to be a `Map` (or `Map`-like) key, +/// or part of a key. +/// +/// In particular, it defines a series of types that help iterating over parts of a (composite) key: +/// +/// `Prefix`: Prefix is eager. That is, except for empty keys, it's always "one less" than the full key. +/// `Suffix`: Suffix is the complement of prefix. +/// `SubPrefix`: Sub-prefix is "one less" than prefix. +/// `SuperSuffix`: Super-suffix is "one more" than suffix. The complement of sub-prefix. +/// +/// By example, for a 2-tuple `(T, U)`: +/// +/// `T`: Prefix. +/// `U`: Suffix. +/// `()`: Sub-prefix. +/// `(T, U)`: Super-suffix. +/// +/// `SubPrefix` and `SuperSuffix` only make real sense in the case of triples. Still, they need to be +/// consistently defined for all types. +pub trait PrimaryKey<'a>: Clone { + /// These associated types need to implement `Prefixer`, so that they can be useful arguments + /// for `prefix()`, `sub_prefix()`, and their key-deserializable variants. + type Prefix: Prefixer<'a>; + type SubPrefix: Prefixer<'a>; + + /// These associated types need to implement `KeyDeserialize`, so that they can be returned from + /// `range_de()` and friends. + type Suffix: KeyDeserialize; + type SuperSuffix: KeyDeserialize; + + /// returns a slice of key steps, which can be optionally combined + fn key(&self) -> Vec; + + fn joined_key(&self) -> Vec { + let keys = self.key(); + let l = keys.len(); + namespaces_with_key( + &keys[0..l - 1].iter().map(Key::as_ref).collect::>(), + keys[l - 1].as_ref(), + ) + } + + fn joined_extra_key(&self, key: &[u8]) -> Vec { + let keys = self.key(); + namespaces_with_key(&keys.iter().map(Key::as_ref).collect::>(), key) + } +} + +// Empty / no primary key +impl<'a> PrimaryKey<'a> for () { + type Prefix = Self; + type SubPrefix = Self; + type Suffix = Self; + type SuperSuffix = Self; + + fn key(&self) -> Vec { + vec![] + } +} + +impl<'a> PrimaryKey<'a> for &'a [u8] { + type Prefix = (); + type SubPrefix = (); + type Suffix = Self; + type SuperSuffix = Self; + + fn key(&self) -> Vec { + // this is simple, we don't add more prefixes + vec![Key::Ref(self)] + } +} + +// Provide a string version of this to raw encode strings +impl<'a> PrimaryKey<'a> for &'a str { + type Prefix = (); + type SubPrefix = (); + type Suffix = Self; + type SuperSuffix = Self; + + fn key(&self) -> Vec { + // this is simple, we don't add more prefixes + vec![Key::Ref(self.as_bytes())] + } +} + +// use generics for combining there - so we can use &[u8], Vec, or IntKey +impl<'a, T: PrimaryKey<'a> + Prefixer<'a> + KeyDeserialize, U: PrimaryKey<'a> + KeyDeserialize> + PrimaryKey<'a> for (T, U) +{ + type Prefix = T; + type SubPrefix = (); + type Suffix = U; + type SuperSuffix = Self; + + fn key(&self) -> Vec { + let mut keys = self.0.key(); + keys.extend(self.1.key()); + keys + } +} + +// use generics for combining there - so we can use &[u8], Vec, or IntKey +impl< + 'a, + T: PrimaryKey<'a> + Prefixer<'a>, + U: PrimaryKey<'a> + Prefixer<'a> + KeyDeserialize, + V: PrimaryKey<'a> + KeyDeserialize, + > PrimaryKey<'a> for (T, U, V) +{ + type Prefix = (T, U); + type SubPrefix = T; + type Suffix = V; + type SuperSuffix = (U, V); + + fn key(&self) -> Vec { + let mut keys = self.0.key(); + keys.extend(self.1.key()); + keys.extend(self.2.key()); + keys + } +} + +pub trait Prefixer<'a> { + /// returns 0 or more namespaces that should be length-prefixed and concatenated for range searches + fn prefix(&self) -> Vec; + + fn joined_prefix(&self) -> Vec { + let prefixes = self.prefix(); + namespaces_with_key(&prefixes.iter().map(Key::as_ref).collect::>(), &[]) + } +} + +impl<'a> Prefixer<'a> for () { + fn prefix(&self) -> Vec { + vec![] + } +} + +impl<'a> Prefixer<'a> for &'a [u8] { + fn prefix(&self) -> Vec { + vec![Key::Ref(self)] + } +} + +impl<'a, T: Prefixer<'a>, U: Prefixer<'a>> Prefixer<'a> for (T, U) { + fn prefix(&self) -> Vec { + let mut res = self.0.prefix(); + res.extend(self.1.prefix().into_iter()); + res + } +} + +impl<'a, T: Prefixer<'a>, U: Prefixer<'a>, V: Prefixer<'a>> Prefixer<'a> for (T, U, V) { + fn prefix(&self) -> Vec { + let mut res = self.0.prefix(); + res.extend(self.1.prefix().into_iter()); + res.extend(self.2.prefix().into_iter()); + res + } +} + +// Provide a string version of this to raw encode strings +impl<'a> Prefixer<'a> for &'a str { + fn prefix(&self) -> Vec { + vec![Key::Ref(self.as_bytes())] + } +} + +impl<'a> PrimaryKey<'a> for Vec { + type Prefix = (); + type SubPrefix = (); + type Suffix = Self; + type SuperSuffix = Self; + + fn key(&self) -> Vec { + vec![Key::Ref(self)] + } +} + +impl<'a> Prefixer<'a> for Vec { + fn prefix(&self) -> Vec { + vec![Key::Ref(self.as_ref())] + } +} + +impl<'a> PrimaryKey<'a> for String { + type Prefix = (); + type SubPrefix = (); + type Suffix = Self; + type SuperSuffix = Self; + + fn key(&self) -> Vec { + vec![Key::Ref(self.as_bytes())] + } +} + +impl<'a> Prefixer<'a> for String { + fn prefix(&self) -> Vec { + vec![Key::Ref(self.as_bytes())] + } +} + +/// type safe version to ensure address was validated before use. +impl<'a> PrimaryKey<'a> for &'a Addr { + type Prefix = (); + type SubPrefix = (); + type Suffix = Self; + type SuperSuffix = Self; + + fn key(&self) -> Vec { + // this is simple, we don't add more prefixes + vec![Key::Ref(self.as_ref().as_bytes())] + } +} + +impl<'a> Prefixer<'a> for &'a Addr { + fn prefix(&self) -> Vec { + vec![Key::Ref(self.as_bytes())] + } +} + +/// owned variant. +impl<'a> PrimaryKey<'a> for Addr { + type Prefix = (); + type SubPrefix = (); + type Suffix = Self; + type SuperSuffix = Self; + + fn key(&self) -> Vec { + // this is simple, we don't add more prefixes + vec![Key::Ref(self.as_bytes())] + } +} + +impl<'a> Prefixer<'a> for Addr { + fn prefix(&self) -> Vec { + vec![Key::Ref(self.as_bytes())] + } +} + +macro_rules! integer_key { + (for $($t:ty, $v:tt),+) => { + $(impl<'a> PrimaryKey<'a> for $t { + type Prefix = (); + type SubPrefix = (); + type Suffix = Self; + type SuperSuffix = Self; + + fn key(&self) -> Vec { + vec![Key::$v(self.to_cw_bytes())] + } + })* + } +} + +integer_key!(for i8, Val8, u8, Val8, i16, Val16, u16, Val16, i32, Val32, u32, Val32, i64, Val64, u64, Val64, i128, Val128, u128, Val128); + +macro_rules! integer_prefix { + (for $($t:ty, $v:tt),+) => { + $(impl<'a> Prefixer<'a> for $t { + fn prefix(&self) -> Vec { + vec![Key::$v(self.to_cw_bytes())] + } + })* + } +} + +integer_prefix!(for i8, Val8, u8, Val8, i16, Val16, u16, Val16, i32, Val32, u32, Val32, i64, Val64, u64, Val64, i128, Val128, u128, Val128); + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn naked_8key_works() { + let k: u8 = 42u8; + let path = k.key(); + assert_eq!(1, path.len()); + assert_eq!(42u8.to_cw_bytes(), path[0].as_ref()); + + let k: i8 = 42i8; + let path = k.key(); + assert_eq!(1, path.len()); + assert_eq!(42i8.to_cw_bytes(), path[0].as_ref()); + } + + #[test] + fn naked_16key_works() { + let k: u16 = 4242u16; + let path = k.key(); + assert_eq!(1, path.len()); + assert_eq!(4242u16.to_cw_bytes(), path[0].as_ref()); + + let k: i16 = 4242i16; + let path = k.key(); + assert_eq!(1, path.len()); + assert_eq!(4242i16.to_cw_bytes(), path[0].as_ref()); + } + + #[test] + fn naked_32key_works() { + let k: u32 = 4242u32; + let path = k.key(); + assert_eq!(1, path.len()); + assert_eq!(4242u32.to_cw_bytes(), path[0].as_ref()); + + let k: i32 = 4242i32; + let path = k.key(); + assert_eq!(1, path.len()); + assert_eq!(4242i32.to_cw_bytes(), path[0].as_ref()); + } + + #[test] + fn naked_64key_works() { + let k: u64 = 4242u64; + let path = k.key(); + assert_eq!(1, path.len()); + assert_eq!(4242u64.to_cw_bytes(), path[0].as_ref()); + + let k: i64 = 4242i64; + let path = k.key(); + assert_eq!(1, path.len()); + assert_eq!(4242i64.to_cw_bytes(), path[0].as_ref()); + } + + #[test] + fn naked_128key_works() { + let k: u128 = 4242u128; + let path = k.key(); + assert_eq!(1, path.len()); + assert_eq!(4242u128.to_cw_bytes(), path[0].as_ref()); + + let k: i128 = 4242i128; + let path = k.key(); + assert_eq!(1, path.len()); + assert_eq!(4242i128.to_cw_bytes(), path[0].as_ref()); + } + + #[test] + fn str_key_works() { + type K<'a> = &'a str; + + let k: K = "hello"; + let path = k.key(); + assert_eq!(1, path.len()); + assert_eq!(b"hello", path[0].as_ref()); + + let joined = k.joined_key(); + assert_eq!(joined, b"hello") + } + + #[test] + fn string_key_works() { + type K = String; + + let k: K = "hello".to_string(); + let path = k.key(); + assert_eq!(1, path.len()); + assert_eq!(b"hello", path[0].as_ref()); + + let joined = k.joined_key(); + assert_eq!(joined, b"hello") + } + + #[test] + fn nested_str_key_works() { + type K<'a> = (&'a str, &'a [u8]); + + let k: K = ("hello", b"world"); + let path = k.key(); + assert_eq!(2, path.len()); + assert_eq!(b"hello", path[0].as_ref()); + assert_eq!(b"world", path[1].as_ref()); + } + + #[test] + fn composite_byte_key() { + let k: (&[u8], &[u8]) = ("foo".as_bytes(), b"bar"); + let path = k.key(); + assert_eq!(2, path.len()); + assert_eq!(path, vec!["foo".as_bytes(), b"bar"],); + } + + #[test] + fn naked_composite_int_key() { + let k: (u32, u64) = (123, 87654); + let path = k.key(); + assert_eq!(2, path.len()); + assert_eq!(4, path[0].as_ref().len()); + assert_eq!(8, path[1].as_ref().len()); + assert_eq!(path[0].as_ref(), 123u32.to_cw_bytes()); + assert_eq!(path[1].as_ref(), 87654u64.to_cw_bytes()); + } + + #[test] + fn nested_composite_keys() { + // use this to ensure proper type-casts below + let first: &[u8] = b"foo"; + // this function tests how well the generics extend to "edge cases" + let k: ((&[u8], &[u8]), &[u8]) = ((first, b"bar"), b"zoom"); + let path = k.key(); + assert_eq!(3, path.len()); + assert_eq!(path, vec![first, b"bar", b"zoom"]); + + // ensure prefix also works + let dir = k.0.prefix(); + assert_eq!(2, dir.len()); + assert_eq!(dir, vec![first, b"bar"]); + } + + #[test] + fn naked_8bit_prefixes() { + let pair: (u8, &[u8]) = (123, b"random"); + let one: Vec = vec![123]; + let two: Vec = b"random".to_vec(); + assert_eq!(pair.prefix(), vec![one.as_slice(), two.as_slice()]); + + let pair: (i8, &[u8]) = (123, b"random"); + // Signed int keys are "sign-flipped" + let one: Vec = vec![123 ^ 0x80]; + let two: Vec = b"random".to_vec(); + assert_eq!(pair.prefix(), vec![one.as_slice(), two.as_slice()]); + } + + #[test] + fn naked_16bit_prefixes() { + let pair: (u16, &[u8]) = (12345, b"random"); + let one: Vec = vec![48, 57]; + let two: Vec = b"random".to_vec(); + assert_eq!(pair.prefix(), vec![one.as_slice(), two.as_slice()]); + + let pair: (i16, &[u8]) = (12345, b"random"); + // Signed int keys are "sign-flipped" + let one: Vec = vec![48 ^ 0x80, 57]; + let two: Vec = b"random".to_vec(); + assert_eq!(pair.prefix(), vec![one.as_slice(), two.as_slice()]); + } + + #[test] + fn naked_64bit_prefixes() { + let pair: (u64, &[u8]) = (12345, b"random"); + let one: Vec = vec![0, 0, 0, 0, 0, 0, 48, 57]; + let two: Vec = b"random".to_vec(); + assert_eq!(pair.prefix(), vec![one.as_slice(), two.as_slice()]); + + let pair: (i64, &[u8]) = (12345, b"random"); + // Signed int keys are "sign-flipped" + #[allow(clippy::identity_op)] + let one: Vec = vec![0 ^ 0x80, 0, 0, 0, 0, 0, 48, 57]; + let two: Vec = b"random".to_vec(); + assert_eq!(pair.prefix(), vec![one.as_slice(), two.as_slice()]); + } + + #[test] + fn naked_proper_prefixes() { + let pair: (u32, &[u8]) = (12345, b"random"); + let one: Vec = vec![0, 0, 48, 57]; + let two: Vec = b"random".to_vec(); + assert_eq!(pair.prefix(), vec![one.as_slice(), two.as_slice()]); + + let triple: (&str, u32, &[u8]) = ("begin", 12345, b"end"); + let one: Vec = b"begin".to_vec(); + let two: Vec = vec![0, 0, 48, 57]; + let three: Vec = b"end".to_vec(); + assert_eq!( + triple.prefix(), + vec![one.as_slice(), two.as_slice(), three.as_slice()] + ); + + // same works with owned variants (&str -> String, &[u8] -> Vec) + let owned_triple: (String, u32, Vec) = ("begin".to_string(), 12345, b"end".to_vec()); + assert_eq!( + owned_triple.prefix(), + vec![one.as_slice(), two.as_slice(), three.as_slice()] + ); + } +} diff --git a/packages/storage/src/lib.rs b/packages/storage/src/lib.rs index c6b0f14..7b37757 100644 --- a/packages/storage/src/lib.rs +++ b/packages/storage/src/lib.rs @@ -5,6 +5,10 @@ pub mod deque_store; pub mod item; pub mod keymap; pub mod keyset; +pub mod keys; +mod de; +mod helpers; +mod int_key; pub use append_store::AppendStore; pub use deque_store::DequeStore; @@ -13,6 +17,7 @@ pub use iter_options::WithoutIter; use iter_options::{IterOption, WithIter}; pub use keymap::{Keymap, KeymapBuilder}; pub use keyset::{Keyset, KeysetBuilder}; +pub use keys::{Key, Prefixer, PrimaryKey}; pub mod iter_options { pub struct WithIter; From 7da41a75b9e0a3ae0b99b7ca4dd9e4052ebdb45c Mon Sep 17 00:00:00 2001 From: Eshel Date: Sun, 19 Feb 2023 15:28:46 +0200 Subject: [PATCH 2/3] using keyDeserialize to allow for borrowed keys --- packages/storage/src/de.rs | 3 +- packages/storage/src/keymap.rs | 60 +++++++++++++++++++--------------- 2 files changed, 35 insertions(+), 28 deletions(-) diff --git a/packages/storage/src/de.rs b/packages/storage/src/de.rs index 046d8b9..c4d8aab 100644 --- a/packages/storage/src/de.rs +++ b/packages/storage/src/de.rs @@ -2,11 +2,12 @@ use std::array::TryFromSliceError; use std::convert::TryInto; use cosmwasm_std::{Addr, StdError, StdResult}; +use serde::{Serialize, de::DeserializeOwned}; use crate::int_key::IntKey; pub trait KeyDeserialize { - type Output: Sized; + type Output: Sized + DeserializeOwned + Serialize; fn from_vec(value: Vec) -> StdResult; diff --git a/packages/storage/src/keymap.rs b/packages/storage/src/keymap.rs index df39c12..02e9895 100644 --- a/packages/storage/src/keymap.rs +++ b/packages/storage/src/keymap.rs @@ -13,6 +13,7 @@ use cosmwasm_storage::to_length_prefixed; use secret_toolkit_serialization::{Bincode2, Serde}; use crate::{IterOption, WithIter, WithoutIter}; +use crate::de::KeyDeserialize; const INDEXES: &[u8] = b"indexes"; const MAP_LENGTH: &[u8] = b"length"; @@ -59,7 +60,7 @@ pub struct KeymapBuilder<'a, K, T, Ser = Bincode2, I = WithIter> { impl<'a, K, T, Ser> KeymapBuilder<'a, K, T, Ser, WithIter> where - K: Serialize + DeserializeOwned, + K: Serialize + KeyDeserialize, T: Serialize + DeserializeOwned, Ser: Serde, { @@ -117,7 +118,7 @@ where // This enables writing `.iter().skip(n).rev()` impl<'a, K, T, Ser> KeymapBuilder<'a, K, T, Ser, WithoutIter> where - K: Serialize + DeserializeOwned, + K: Serialize + KeyDeserialize, T: Serialize + DeserializeOwned, Ser: Serde, { @@ -137,7 +138,7 @@ where pub struct Keymap<'a, K, T, Ser = Bincode2, I = WithIter> where - K: Serialize + DeserializeOwned, + K: Serialize + KeyDeserialize, T: Serialize + DeserializeOwned, Ser: Serde, I: IterOption, @@ -154,7 +155,7 @@ where serialization_type: PhantomData, } -impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: Serde> +impl<'a, K: Serialize + KeyDeserialize, T: Serialize + DeserializeOwned, Ser: Serde> Keymap<'a, K, T, Ser> { /// constructor @@ -190,7 +191,7 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: } } -impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: Serde> +impl<'a, K: Serialize + KeyDeserialize, T: Serialize + DeserializeOwned, Ser: Serde> Keymap<'a, K, T, Ser, WithoutIter> { /// Serialize key @@ -232,7 +233,7 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: } } -impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: Serde> +impl<'a, K: Serialize + KeyDeserialize, T: Serialize + DeserializeOwned, Ser: Serde> Keymap<'a, K, T, Ser, WithIter> { /// Serialize key @@ -241,7 +242,7 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: } /// Deserialize key - fn deserialize_key(&self, key_data: &[u8]) -> StdResult { + fn deserialize_key(&self, key_data: &[u8]) -> StdResult { Ser::deserialize(key_data) } @@ -341,6 +342,11 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: self.load_impl(storage, &key_vec) } + fn get_from_deserialized_key(&self, storage: &dyn Storage, key: &K::Output) -> StdResult> { + let key_vec = Ser::serialize(key)?; + self.load_impl(storage, &key_vec) + } + /// user facing remove function pub fn remove(&self, storage: &mut dyn Storage, key: &K) -> StdResult<()> { let key_vec = self.serialize_key(key)?; @@ -444,7 +450,7 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: storage: &dyn Storage, start_page: u32, size: u32, - ) -> StdResult> { + ) -> StdResult> { let start_pos = start_page * size; let mut end_pos = start_pos + size - 1; @@ -470,7 +476,7 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: storage: &dyn Storage, start_page: u32, size: u32, - ) -> StdResult> { + ) -> StdResult> { let start_pos = start_page * size; let mut end_pos = start_pos + size - 1; @@ -496,7 +502,7 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: storage: &dyn Storage, start: u32, end: u32, - ) -> StdResult> { + ) -> StdResult> { let start_page = self.page_from_position(start); let end_page = self.page_from_position(end); @@ -529,7 +535,7 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: storage: &dyn Storage, start: u32, end: u32, - ) -> StdResult> { + ) -> StdResult> { let start_page = self.page_from_position(start); let end_page = self.page_from_position(end); @@ -572,7 +578,7 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: } } -impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: Serde> +impl<'a, K: Serialize + KeyDeserialize, T: Serialize + DeserializeOwned, Ser: Serde> PrefixedTypedStorage, Bincode2> for Keymap<'a, K, T, Ser, WithIter> { fn as_slice(&self) -> &[u8] { @@ -584,7 +590,7 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: } } -impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: Serde> +impl<'a, K: Serialize + KeyDeserialize, T: Serialize + DeserializeOwned, Ser: Serde> PrefixedTypedStorage for Keymap<'a, K, T, Ser, WithoutIter> { fn as_slice(&self) -> &[u8] { @@ -599,7 +605,7 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: /// An iterator over the keys of the Keymap. pub struct KeyIter<'a, K, T, Ser> where - K: Serialize + DeserializeOwned, + K: Serialize + KeyDeserialize, T: Serialize + DeserializeOwned, Ser: Serde, { @@ -612,7 +618,7 @@ where impl<'a, K, T, Ser> KeyIter<'a, K, T, Ser> where - K: Serialize + DeserializeOwned, + K: Serialize + KeyDeserialize, T: Serialize + DeserializeOwned, Ser: Serde, { @@ -635,11 +641,11 @@ where impl<'a, K, T, Ser> Iterator for KeyIter<'a, K, T, Ser> where - K: Serialize + DeserializeOwned, + K: Serialize + KeyDeserialize, T: Serialize + DeserializeOwned, Ser: Serde, { - type Item = StdResult; + type Item = StdResult; fn next(&mut self) -> Option { if self.start >= self.end { @@ -688,7 +694,7 @@ where impl<'a, K, T, Ser> DoubleEndedIterator for KeyIter<'a, K, T, Ser> where - K: Serialize + DeserializeOwned, + K: Serialize + KeyDeserialize, T: Serialize + DeserializeOwned, Ser: Serde, { @@ -734,7 +740,7 @@ where // This enables writing `.iter().skip(n).rev()` impl<'a, K, T, Ser> ExactSizeIterator for KeyIter<'a, K, T, Ser> where - K: Serialize + DeserializeOwned, + K: Serialize + KeyDeserialize, T: Serialize + DeserializeOwned, Ser: Serde, { @@ -745,7 +751,7 @@ where /// An iterator over the (key, item) pairs of the Keymap. Less efficient than just iterating over keys. pub struct KeyItemIter<'a, K, T, Ser> where - K: Serialize + DeserializeOwned, + K: Serialize + KeyDeserialize, T: Serialize + DeserializeOwned, Ser: Serde, { @@ -758,7 +764,7 @@ where impl<'a, K, T, Ser> KeyItemIter<'a, K, T, Ser> where - K: Serialize + DeserializeOwned, + K: Serialize + KeyDeserialize, T: Serialize + DeserializeOwned, Ser: Serde, { @@ -781,11 +787,11 @@ where impl<'a, K, T, Ser> Iterator for KeyItemIter<'a, K, T, Ser> where - K: Serialize + DeserializeOwned, + K: Serialize + KeyDeserialize, T: Serialize + DeserializeOwned, Ser: Serde, { - type Item = StdResult<(K, T)>; + type Item = StdResult<(K::Output, T)>; fn next(&mut self) -> Option { if self.start >= self.end { @@ -813,7 +819,7 @@ where self.start += 1; // turn key into pair let pair = match key { - Ok(k) => match self.keymap.get_from_key(self.storage, &k) { + Ok(k) => match self.keymap.get_from_deserialized_key(self.storage, &k) { Ok(internal_item) => match internal_item.get_item() { Ok(item) => Ok((k, item)), Err(e) => Err(e), @@ -845,7 +851,7 @@ where impl<'a, K, T, Ser> DoubleEndedIterator for KeyItemIter<'a, K, T, Ser> where - K: Serialize + DeserializeOwned, + K: Serialize + KeyDeserialize, T: Serialize + DeserializeOwned, Ser: Serde, { @@ -875,7 +881,7 @@ where } // turn key into pair let pair = match key { - Ok(k) => match self.keymap.get_from_key(self.storage, &k) { + Ok(k) => match self.keymap.get_from_deserialized_key(self.storage, &k) { Ok(internal_item) => match internal_item.get_item() { Ok(item) => Ok((k, item)), Err(e) => Err(e), @@ -902,7 +908,7 @@ where // This enables writing `.iter().skip(n).rev()` impl<'a, K, T, Ser> ExactSizeIterator for KeyItemIter<'a, K, T, Ser> where - K: Serialize + DeserializeOwned, + K: Serialize + KeyDeserialize, T: Serialize + DeserializeOwned, Ser: Serde, { From b96f86f2509334de4dbaaadb540a327941fa85c2 Mon Sep 17 00:00:00 2001 From: Eshel Date: Sun, 19 Feb 2023 15:37:12 +0200 Subject: [PATCH 3/3] removing unecessary files copied from cw-storage-plus --- packages/storage/src/de.rs | 22 +- packages/storage/src/helpers.rs | 194 ------------ packages/storage/src/int_key.rs | 130 -------- packages/storage/src/keys.rs | 512 -------------------------------- packages/storage/src/lib.rs | 6 +- 5 files changed, 2 insertions(+), 862 deletions(-) delete mode 100644 packages/storage/src/helpers.rs delete mode 100644 packages/storage/src/int_key.rs delete mode 100644 packages/storage/src/keys.rs diff --git a/packages/storage/src/de.rs b/packages/storage/src/de.rs index c4d8aab..e5c3673 100644 --- a/packages/storage/src/de.rs +++ b/packages/storage/src/de.rs @@ -4,8 +4,6 @@ use std::convert::TryInto; use cosmwasm_std::{Addr, StdError, StdResult}; use serde::{Serialize, de::DeserializeOwned}; -use crate::int_key::IntKey; - pub trait KeyDeserialize { type Output: Sized + DeserializeOwned + Serialize; @@ -104,7 +102,7 @@ macro_rules! integer_de { #[inline(always)] fn from_vec(value: Vec) -> StdResult { - Ok(<$t>::from_cw_bytes(value.as_slice().try_into() + Ok(<$t>::from_be_bytes(value.as_slice().try_into() .map_err(|err: TryFromSliceError| StdError::generic_err(err.to_string()))?)) } })* @@ -155,7 +153,6 @@ impl KeyDeserialize for #[cfg(test)] mod test { use super::*; - use crate::PrimaryKey; const BYTES: &[u8] = b"Hello"; const STRING: &str = "Hello"; @@ -249,21 +246,4 @@ mod test { 170141183460469231731687303715884105727i128, ); } - - #[test] - fn deserialize_tuple_works() { - assert_eq!( - <(&[u8], &str)>::from_slice((BYTES, STRING).joined_key().as_slice()).unwrap(), - (BYTES.to_vec(), STRING.to_string()) - ); - } - - #[test] - fn deserialize_triple_works() { - assert_eq!( - <(&[u8], u32, &str)>::from_slice((BYTES, 1234u32, STRING).joined_key().as_slice()) - .unwrap(), - (BYTES.to_vec(), 1234, STRING.to_string()) - ); - } } diff --git a/packages/storage/src/helpers.rs b/packages/storage/src/helpers.rs deleted file mode 100644 index b87c662..0000000 --- a/packages/storage/src/helpers.rs +++ /dev/null @@ -1,194 +0,0 @@ -//! This module is an implemention of a namespacing scheme described -//! in https://github.com/webmaster128/key-namespacing#length-prefixed-keys -//! -//! Everything in this file is only responsible for building such keys -//! and is in no way specific to any kind of storage. - -use serde::de::DeserializeOwned; -use std::any::type_name; - -use crate::keys::Key; - -use cosmwasm_std::{ - from_slice, to_vec, Addr, Binary, ContractResult, CustomQuery, QuerierWrapper, QueryRequest, - StdError, StdResult, SystemResult, WasmQuery, -}; - -/// may_deserialize parses json bytes from storage (Option), returning Ok(None) if no data present -/// -/// value is an odd type, but this is meant to be easy to use with output from storage.get (Option>) -/// and value.map(|s| s.as_slice()) seems trickier than &value -pub(crate) fn may_deserialize( - value: &Option>, -) -> StdResult> { - match value { - Some(vec) => Ok(Some(from_slice(vec)?)), - None => Ok(None), - } -} - -/// must_deserialize parses json bytes from storage (Option), returning NotFound error if no data present -pub(crate) fn must_deserialize(value: &Option>) -> StdResult { - match value { - Some(vec) => from_slice(vec), - None => Err(StdError::not_found(type_name::())), - } -} - -/// This is equivalent concat(to_length_prefixed_nested(namespaces), key) -/// But more efficient when the intermediate namespaces often must be recalculated -pub(crate) fn namespaces_with_key(namespaces: &[&[u8]], key: &[u8]) -> Vec { - let mut size = key.len(); - for &namespace in namespaces { - size += namespace.len() + 2; - } - - let mut out = Vec::with_capacity(size); - for &namespace in namespaces { - out.extend_from_slice(&encode_length(namespace)); - out.extend_from_slice(namespace); - } - out.extend_from_slice(key); - out -} - -/// Customization of namespaces_with_key for when -/// there are multiple sets we do not want to combine just to call this -pub(crate) fn nested_namespaces_with_key( - top_names: &[&[u8]], - sub_names: &[Key], - key: &[u8], -) -> Vec { - let mut size = key.len(); - for &namespace in top_names { - size += namespace.len() + 2; - } - for namespace in sub_names { - size += namespace.as_ref().len() + 2; - } - - let mut out = Vec::with_capacity(size); - for &namespace in top_names { - out.extend_from_slice(&encode_length(namespace)); - out.extend_from_slice(namespace); - } - for namespace in sub_names { - out.extend_from_slice(&encode_length(namespace.as_ref())); - out.extend_from_slice(namespace.as_ref()); - } - out.extend_from_slice(key); - out -} - -/// Encodes the length of a given namespace as a 2 byte big endian encoded integer -pub(crate) fn encode_length(namespace: &[u8]) -> [u8; 2] { - if namespace.len() > 0xFFFF { - panic!("only supports namespaces up to length 0xFFFF") - } - let length_bytes = (namespace.len() as u32).to_be_bytes(); - [length_bytes[2], length_bytes[3]] -} - -/// Use this in Map/SnapshotMap/etc when you want to provide a QueryRaw helper. -/// This is similar to querier.query(WasmQuery::Raw{}), except it does NOT parse the -/// result, but return a possibly empty Binary to be handled by the calling code. -/// That is essential to handle b"" as None. -pub(crate) fn query_raw( - querier: &QuerierWrapper, - contract_addr: Addr, - key: Binary, -) -> StdResult { - let request: QueryRequest = WasmQuery::Raw { - contract_addr: contract_addr.into(), - key, - } - .into(); - - let raw = to_vec(&request).map_err(|serialize_err| { - StdError::generic_err(format!("Serializing QueryRequest: {}", serialize_err)) - })?; - match querier.raw_query(&raw) { - SystemResult::Err(system_err) => Err(StdError::generic_err(format!( - "Querier system error: {}", - system_err - ))), - SystemResult::Ok(ContractResult::Err(contract_err)) => Err(StdError::generic_err(format!( - "Querier contract error: {}", - contract_err - ))), - SystemResult::Ok(ContractResult::Ok(value)) => Ok(value), - } -} - -#[cfg(test)] -mod test { - use super::*; - use cosmwasm_std::{to_vec, StdError}; - use serde::{Deserialize, Serialize}; - - #[derive(Serialize, Deserialize, PartialEq, Debug)] - struct Person { - pub name: String, - pub age: i32, - } - - #[test] - fn encode_length_works() { - assert_eq!(encode_length(b""), *b"\x00\x00"); - assert_eq!(encode_length(b"a"), *b"\x00\x01"); - assert_eq!(encode_length(b"aa"), *b"\x00\x02"); - assert_eq!(encode_length(b"aaa"), *b"\x00\x03"); - assert_eq!(encode_length(&vec![1; 255]), *b"\x00\xff"); - assert_eq!(encode_length(&vec![1; 256]), *b"\x01\x00"); - assert_eq!(encode_length(&vec![1; 12345]), *b"\x30\x39"); - assert_eq!(encode_length(&vec![1; 65535]), *b"\xff\xff"); - } - - #[test] - #[should_panic(expected = "only supports namespaces up to length 0xFFFF")] - fn encode_length_panics_for_large_values() { - encode_length(&vec![1; 65536]); - } - - #[test] - fn may_deserialize_handles_some() { - let person = Person { - name: "Maria".to_string(), - age: 42, - }; - let value = to_vec(&person).unwrap(); - - let may_parse: Option = may_deserialize(&Some(value)).unwrap(); - assert_eq!(may_parse, Some(person)); - } - - #[test] - fn may_deserialize_handles_none() { - let may_parse = may_deserialize::(&None).unwrap(); - assert_eq!(may_parse, None); - } - - #[test] - fn must_deserialize_handles_some() { - let person = Person { - name: "Maria".to_string(), - age: 42, - }; - let value = to_vec(&person).unwrap(); - let loaded = Some(value); - - let parsed: Person = must_deserialize(&loaded).unwrap(); - assert_eq!(parsed, person); - } - - #[test] - fn must_deserialize_handles_none() { - let parsed = must_deserialize::(&None); - match parsed.unwrap_err() { - StdError::NotFound { kind, .. } => { - assert_eq!(kind, "secret_toolkit_storage::helpers::test::Person") - } - e => panic!("Unexpected error {}", e), - } - } -} diff --git a/packages/storage/src/int_key.rs b/packages/storage/src/int_key.rs deleted file mode 100644 index 0292674..0000000 --- a/packages/storage/src/int_key.rs +++ /dev/null @@ -1,130 +0,0 @@ -use std::mem; - -/// Our int keys are simply the big-endian representation bytes for unsigned ints, -/// but "sign-flipped" (xored msb) big-endian bytes for signed ints. -/// -/// So that the representation of signed integers is in the right lexicographical order. -pub trait IntKey: Sized + Copy { - type Buf: AsRef<[u8]> + AsMut<[u8]> + Into> + Default; - - fn to_cw_bytes(&self) -> Self::Buf; - fn from_cw_bytes(bytes: Self::Buf) -> Self; -} - -macro_rules! cw_uint_keys { - (for $($t:ty),+) => { - $(impl IntKey for $t { - type Buf = [u8; mem::size_of::<$t>()]; - - #[inline] - fn to_cw_bytes(&self) -> Self::Buf { - self.to_be_bytes() - } - - #[inline] - fn from_cw_bytes(bytes: Self::Buf) -> Self { - Self::from_be_bytes(bytes) - } - })* - } -} - -cw_uint_keys!(for u8, u16, u32, u64, u128); - -macro_rules! cw_int_keys { - (for $($t:ty, $ut:ty),+) => { - $(impl IntKey for $t { - type Buf = [u8; mem::size_of::<$t>()]; - - #[inline] - fn to_cw_bytes(&self) -> Self::Buf { - (*self as $ut ^ <$t>::MIN as $ut).to_be_bytes() - } - - #[inline] - fn from_cw_bytes(bytes: Self::Buf) -> Self { - (Self::from_be_bytes(bytes) as $ut ^ <$t>::MIN as $ut) as _ - } - })* - } -} - -cw_int_keys!(for i8, u8, i16, u16, i32, u32, i64, u64, i128, u128); - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn x8_int_key_works() { - assert_eq!(0x42u8.to_cw_bytes(), [0x42]); - assert_eq!(0x42i8.to_cw_bytes(), [0xc2]); - assert_eq!((-0x3ei8).to_cw_bytes(), [0x42]); - } - - #[test] - fn x16_int_key_works() { - assert_eq!(0x4243u16.to_cw_bytes(), [0x42, 0x43]); - assert_eq!(0x4243i16.to_cw_bytes(), [0xc2, 0x43]); - assert_eq!((-0x3dbdi16).to_cw_bytes(), [0x42, 0x43]); - } - - #[test] - fn x32_int_key_works() { - assert_eq!(0x424344u32.to_cw_bytes(), [0x00, 0x42, 0x43, 0x44]); - assert_eq!(0x424344i32.to_cw_bytes(), [0x80, 0x42, 0x43, 0x44]); - assert_eq!((-0x7fbdbcbci32).to_cw_bytes(), [0x00, 0x42, 0x43, 0x44]); - } - - #[test] - fn x64_int_key_works() { - assert_eq!( - 0x42434445u64.to_cw_bytes(), - [0x00, 0x00, 0x00, 0x00, 0x42, 0x43, 0x44, 0x45] - ); - assert_eq!( - 0x42434445i64.to_cw_bytes(), - [0x80, 0x00, 0x00, 0x00, 0x42, 0x43, 0x44, 0x45] - ); - assert_eq!( - (-0x7fffffffbdbcbbbbi64).to_cw_bytes(), - [0x00, 0x00, 0x00, 0x00, 0x42, 0x43, 0x44, 0x45] - ); - } - - #[test] - fn x128_int_key_works() { - assert_eq!( - 0x4243444546u128.to_cw_bytes(), - [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x43, 0x44, - 0x45, 0x46 - ] - ); - assert_eq!( - 0x4243444546i128.to_cw_bytes(), - [ - 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x43, 0x44, - 0x45, 0x46 - ] - ); - assert_eq!( - (-0x7fffffffffffffffffffffbdbcbbbabai128).to_cw_bytes(), - [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x43, 0x44, - 0x45, 0x46 - ] - ); - } - - #[test] - fn unsigned_int_key_order() { - assert!(0u32.to_cw_bytes() < 652u32.to_cw_bytes()); - } - - #[test] - fn signed_int_key_order() { - assert!((-321i32).to_cw_bytes() < 0i32.to_cw_bytes()); - assert!(0i32.to_cw_bytes() < 652i32.to_cw_bytes()); - } -} diff --git a/packages/storage/src/keys.rs b/packages/storage/src/keys.rs deleted file mode 100644 index cf7eff8..0000000 --- a/packages/storage/src/keys.rs +++ /dev/null @@ -1,512 +0,0 @@ -use cosmwasm_std::Addr; - -use crate::de::KeyDeserialize; -use crate::helpers::namespaces_with_key; -use crate::int_key::IntKey; - -#[derive(Debug)] -pub enum Key<'a> { - Ref(&'a [u8]), - Val8([u8; 1]), - Val16([u8; 2]), - Val32([u8; 4]), - Val64([u8; 8]), - Val128([u8; 16]), -} - -impl<'a> AsRef<[u8]> for Key<'a> { - fn as_ref(&self) -> &[u8] { - match self { - Key::Ref(r) => r, - Key::Val8(v) => v, - Key::Val16(v) => v, - Key::Val32(v) => v, - Key::Val64(v) => v, - Key::Val128(v) => v, - } - } -} - -impl<'a> PartialEq<&[u8]> for Key<'a> { - fn eq(&self, other: &&[u8]) -> bool { - self.as_ref() == *other - } -} - -/// `PrimaryKey` needs to be implemented for types that want to be a `Map` (or `Map`-like) key, -/// or part of a key. -/// -/// In particular, it defines a series of types that help iterating over parts of a (composite) key: -/// -/// `Prefix`: Prefix is eager. That is, except for empty keys, it's always "one less" than the full key. -/// `Suffix`: Suffix is the complement of prefix. -/// `SubPrefix`: Sub-prefix is "one less" than prefix. -/// `SuperSuffix`: Super-suffix is "one more" than suffix. The complement of sub-prefix. -/// -/// By example, for a 2-tuple `(T, U)`: -/// -/// `T`: Prefix. -/// `U`: Suffix. -/// `()`: Sub-prefix. -/// `(T, U)`: Super-suffix. -/// -/// `SubPrefix` and `SuperSuffix` only make real sense in the case of triples. Still, they need to be -/// consistently defined for all types. -pub trait PrimaryKey<'a>: Clone { - /// These associated types need to implement `Prefixer`, so that they can be useful arguments - /// for `prefix()`, `sub_prefix()`, and their key-deserializable variants. - type Prefix: Prefixer<'a>; - type SubPrefix: Prefixer<'a>; - - /// These associated types need to implement `KeyDeserialize`, so that they can be returned from - /// `range_de()` and friends. - type Suffix: KeyDeserialize; - type SuperSuffix: KeyDeserialize; - - /// returns a slice of key steps, which can be optionally combined - fn key(&self) -> Vec; - - fn joined_key(&self) -> Vec { - let keys = self.key(); - let l = keys.len(); - namespaces_with_key( - &keys[0..l - 1].iter().map(Key::as_ref).collect::>(), - keys[l - 1].as_ref(), - ) - } - - fn joined_extra_key(&self, key: &[u8]) -> Vec { - let keys = self.key(); - namespaces_with_key(&keys.iter().map(Key::as_ref).collect::>(), key) - } -} - -// Empty / no primary key -impl<'a> PrimaryKey<'a> for () { - type Prefix = Self; - type SubPrefix = Self; - type Suffix = Self; - type SuperSuffix = Self; - - fn key(&self) -> Vec { - vec![] - } -} - -impl<'a> PrimaryKey<'a> for &'a [u8] { - type Prefix = (); - type SubPrefix = (); - type Suffix = Self; - type SuperSuffix = Self; - - fn key(&self) -> Vec { - // this is simple, we don't add more prefixes - vec![Key::Ref(self)] - } -} - -// Provide a string version of this to raw encode strings -impl<'a> PrimaryKey<'a> for &'a str { - type Prefix = (); - type SubPrefix = (); - type Suffix = Self; - type SuperSuffix = Self; - - fn key(&self) -> Vec { - // this is simple, we don't add more prefixes - vec![Key::Ref(self.as_bytes())] - } -} - -// use generics for combining there - so we can use &[u8], Vec, or IntKey -impl<'a, T: PrimaryKey<'a> + Prefixer<'a> + KeyDeserialize, U: PrimaryKey<'a> + KeyDeserialize> - PrimaryKey<'a> for (T, U) -{ - type Prefix = T; - type SubPrefix = (); - type Suffix = U; - type SuperSuffix = Self; - - fn key(&self) -> Vec { - let mut keys = self.0.key(); - keys.extend(self.1.key()); - keys - } -} - -// use generics for combining there - so we can use &[u8], Vec, or IntKey -impl< - 'a, - T: PrimaryKey<'a> + Prefixer<'a>, - U: PrimaryKey<'a> + Prefixer<'a> + KeyDeserialize, - V: PrimaryKey<'a> + KeyDeserialize, - > PrimaryKey<'a> for (T, U, V) -{ - type Prefix = (T, U); - type SubPrefix = T; - type Suffix = V; - type SuperSuffix = (U, V); - - fn key(&self) -> Vec { - let mut keys = self.0.key(); - keys.extend(self.1.key()); - keys.extend(self.2.key()); - keys - } -} - -pub trait Prefixer<'a> { - /// returns 0 or more namespaces that should be length-prefixed and concatenated for range searches - fn prefix(&self) -> Vec; - - fn joined_prefix(&self) -> Vec { - let prefixes = self.prefix(); - namespaces_with_key(&prefixes.iter().map(Key::as_ref).collect::>(), &[]) - } -} - -impl<'a> Prefixer<'a> for () { - fn prefix(&self) -> Vec { - vec![] - } -} - -impl<'a> Prefixer<'a> for &'a [u8] { - fn prefix(&self) -> Vec { - vec![Key::Ref(self)] - } -} - -impl<'a, T: Prefixer<'a>, U: Prefixer<'a>> Prefixer<'a> for (T, U) { - fn prefix(&self) -> Vec { - let mut res = self.0.prefix(); - res.extend(self.1.prefix().into_iter()); - res - } -} - -impl<'a, T: Prefixer<'a>, U: Prefixer<'a>, V: Prefixer<'a>> Prefixer<'a> for (T, U, V) { - fn prefix(&self) -> Vec { - let mut res = self.0.prefix(); - res.extend(self.1.prefix().into_iter()); - res.extend(self.2.prefix().into_iter()); - res - } -} - -// Provide a string version of this to raw encode strings -impl<'a> Prefixer<'a> for &'a str { - fn prefix(&self) -> Vec { - vec![Key::Ref(self.as_bytes())] - } -} - -impl<'a> PrimaryKey<'a> for Vec { - type Prefix = (); - type SubPrefix = (); - type Suffix = Self; - type SuperSuffix = Self; - - fn key(&self) -> Vec { - vec![Key::Ref(self)] - } -} - -impl<'a> Prefixer<'a> for Vec { - fn prefix(&self) -> Vec { - vec![Key::Ref(self.as_ref())] - } -} - -impl<'a> PrimaryKey<'a> for String { - type Prefix = (); - type SubPrefix = (); - type Suffix = Self; - type SuperSuffix = Self; - - fn key(&self) -> Vec { - vec![Key::Ref(self.as_bytes())] - } -} - -impl<'a> Prefixer<'a> for String { - fn prefix(&self) -> Vec { - vec![Key::Ref(self.as_bytes())] - } -} - -/// type safe version to ensure address was validated before use. -impl<'a> PrimaryKey<'a> for &'a Addr { - type Prefix = (); - type SubPrefix = (); - type Suffix = Self; - type SuperSuffix = Self; - - fn key(&self) -> Vec { - // this is simple, we don't add more prefixes - vec![Key::Ref(self.as_ref().as_bytes())] - } -} - -impl<'a> Prefixer<'a> for &'a Addr { - fn prefix(&self) -> Vec { - vec![Key::Ref(self.as_bytes())] - } -} - -/// owned variant. -impl<'a> PrimaryKey<'a> for Addr { - type Prefix = (); - type SubPrefix = (); - type Suffix = Self; - type SuperSuffix = Self; - - fn key(&self) -> Vec { - // this is simple, we don't add more prefixes - vec![Key::Ref(self.as_bytes())] - } -} - -impl<'a> Prefixer<'a> for Addr { - fn prefix(&self) -> Vec { - vec![Key::Ref(self.as_bytes())] - } -} - -macro_rules! integer_key { - (for $($t:ty, $v:tt),+) => { - $(impl<'a> PrimaryKey<'a> for $t { - type Prefix = (); - type SubPrefix = (); - type Suffix = Self; - type SuperSuffix = Self; - - fn key(&self) -> Vec { - vec![Key::$v(self.to_cw_bytes())] - } - })* - } -} - -integer_key!(for i8, Val8, u8, Val8, i16, Val16, u16, Val16, i32, Val32, u32, Val32, i64, Val64, u64, Val64, i128, Val128, u128, Val128); - -macro_rules! integer_prefix { - (for $($t:ty, $v:tt),+) => { - $(impl<'a> Prefixer<'a> for $t { - fn prefix(&self) -> Vec { - vec![Key::$v(self.to_cw_bytes())] - } - })* - } -} - -integer_prefix!(for i8, Val8, u8, Val8, i16, Val16, u16, Val16, i32, Val32, u32, Val32, i64, Val64, u64, Val64, i128, Val128, u128, Val128); - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn naked_8key_works() { - let k: u8 = 42u8; - let path = k.key(); - assert_eq!(1, path.len()); - assert_eq!(42u8.to_cw_bytes(), path[0].as_ref()); - - let k: i8 = 42i8; - let path = k.key(); - assert_eq!(1, path.len()); - assert_eq!(42i8.to_cw_bytes(), path[0].as_ref()); - } - - #[test] - fn naked_16key_works() { - let k: u16 = 4242u16; - let path = k.key(); - assert_eq!(1, path.len()); - assert_eq!(4242u16.to_cw_bytes(), path[0].as_ref()); - - let k: i16 = 4242i16; - let path = k.key(); - assert_eq!(1, path.len()); - assert_eq!(4242i16.to_cw_bytes(), path[0].as_ref()); - } - - #[test] - fn naked_32key_works() { - let k: u32 = 4242u32; - let path = k.key(); - assert_eq!(1, path.len()); - assert_eq!(4242u32.to_cw_bytes(), path[0].as_ref()); - - let k: i32 = 4242i32; - let path = k.key(); - assert_eq!(1, path.len()); - assert_eq!(4242i32.to_cw_bytes(), path[0].as_ref()); - } - - #[test] - fn naked_64key_works() { - let k: u64 = 4242u64; - let path = k.key(); - assert_eq!(1, path.len()); - assert_eq!(4242u64.to_cw_bytes(), path[0].as_ref()); - - let k: i64 = 4242i64; - let path = k.key(); - assert_eq!(1, path.len()); - assert_eq!(4242i64.to_cw_bytes(), path[0].as_ref()); - } - - #[test] - fn naked_128key_works() { - let k: u128 = 4242u128; - let path = k.key(); - assert_eq!(1, path.len()); - assert_eq!(4242u128.to_cw_bytes(), path[0].as_ref()); - - let k: i128 = 4242i128; - let path = k.key(); - assert_eq!(1, path.len()); - assert_eq!(4242i128.to_cw_bytes(), path[0].as_ref()); - } - - #[test] - fn str_key_works() { - type K<'a> = &'a str; - - let k: K = "hello"; - let path = k.key(); - assert_eq!(1, path.len()); - assert_eq!(b"hello", path[0].as_ref()); - - let joined = k.joined_key(); - assert_eq!(joined, b"hello") - } - - #[test] - fn string_key_works() { - type K = String; - - let k: K = "hello".to_string(); - let path = k.key(); - assert_eq!(1, path.len()); - assert_eq!(b"hello", path[0].as_ref()); - - let joined = k.joined_key(); - assert_eq!(joined, b"hello") - } - - #[test] - fn nested_str_key_works() { - type K<'a> = (&'a str, &'a [u8]); - - let k: K = ("hello", b"world"); - let path = k.key(); - assert_eq!(2, path.len()); - assert_eq!(b"hello", path[0].as_ref()); - assert_eq!(b"world", path[1].as_ref()); - } - - #[test] - fn composite_byte_key() { - let k: (&[u8], &[u8]) = ("foo".as_bytes(), b"bar"); - let path = k.key(); - assert_eq!(2, path.len()); - assert_eq!(path, vec!["foo".as_bytes(), b"bar"],); - } - - #[test] - fn naked_composite_int_key() { - let k: (u32, u64) = (123, 87654); - let path = k.key(); - assert_eq!(2, path.len()); - assert_eq!(4, path[0].as_ref().len()); - assert_eq!(8, path[1].as_ref().len()); - assert_eq!(path[0].as_ref(), 123u32.to_cw_bytes()); - assert_eq!(path[1].as_ref(), 87654u64.to_cw_bytes()); - } - - #[test] - fn nested_composite_keys() { - // use this to ensure proper type-casts below - let first: &[u8] = b"foo"; - // this function tests how well the generics extend to "edge cases" - let k: ((&[u8], &[u8]), &[u8]) = ((first, b"bar"), b"zoom"); - let path = k.key(); - assert_eq!(3, path.len()); - assert_eq!(path, vec![first, b"bar", b"zoom"]); - - // ensure prefix also works - let dir = k.0.prefix(); - assert_eq!(2, dir.len()); - assert_eq!(dir, vec![first, b"bar"]); - } - - #[test] - fn naked_8bit_prefixes() { - let pair: (u8, &[u8]) = (123, b"random"); - let one: Vec = vec![123]; - let two: Vec = b"random".to_vec(); - assert_eq!(pair.prefix(), vec![one.as_slice(), two.as_slice()]); - - let pair: (i8, &[u8]) = (123, b"random"); - // Signed int keys are "sign-flipped" - let one: Vec = vec![123 ^ 0x80]; - let two: Vec = b"random".to_vec(); - assert_eq!(pair.prefix(), vec![one.as_slice(), two.as_slice()]); - } - - #[test] - fn naked_16bit_prefixes() { - let pair: (u16, &[u8]) = (12345, b"random"); - let one: Vec = vec![48, 57]; - let two: Vec = b"random".to_vec(); - assert_eq!(pair.prefix(), vec![one.as_slice(), two.as_slice()]); - - let pair: (i16, &[u8]) = (12345, b"random"); - // Signed int keys are "sign-flipped" - let one: Vec = vec![48 ^ 0x80, 57]; - let two: Vec = b"random".to_vec(); - assert_eq!(pair.prefix(), vec![one.as_slice(), two.as_slice()]); - } - - #[test] - fn naked_64bit_prefixes() { - let pair: (u64, &[u8]) = (12345, b"random"); - let one: Vec = vec![0, 0, 0, 0, 0, 0, 48, 57]; - let two: Vec = b"random".to_vec(); - assert_eq!(pair.prefix(), vec![one.as_slice(), two.as_slice()]); - - let pair: (i64, &[u8]) = (12345, b"random"); - // Signed int keys are "sign-flipped" - #[allow(clippy::identity_op)] - let one: Vec = vec![0 ^ 0x80, 0, 0, 0, 0, 0, 48, 57]; - let two: Vec = b"random".to_vec(); - assert_eq!(pair.prefix(), vec![one.as_slice(), two.as_slice()]); - } - - #[test] - fn naked_proper_prefixes() { - let pair: (u32, &[u8]) = (12345, b"random"); - let one: Vec = vec![0, 0, 48, 57]; - let two: Vec = b"random".to_vec(); - assert_eq!(pair.prefix(), vec![one.as_slice(), two.as_slice()]); - - let triple: (&str, u32, &[u8]) = ("begin", 12345, b"end"); - let one: Vec = b"begin".to_vec(); - let two: Vec = vec![0, 0, 48, 57]; - let three: Vec = b"end".to_vec(); - assert_eq!( - triple.prefix(), - vec![one.as_slice(), two.as_slice(), three.as_slice()] - ); - - // same works with owned variants (&str -> String, &[u8] -> Vec) - let owned_triple: (String, u32, Vec) = ("begin".to_string(), 12345, b"end".to_vec()); - assert_eq!( - owned_triple.prefix(), - vec![one.as_slice(), two.as_slice(), three.as_slice()] - ); - } -} diff --git a/packages/storage/src/lib.rs b/packages/storage/src/lib.rs index 7b37757..b5d5b91 100644 --- a/packages/storage/src/lib.rs +++ b/packages/storage/src/lib.rs @@ -5,10 +5,7 @@ pub mod deque_store; pub mod item; pub mod keymap; pub mod keyset; -pub mod keys; -mod de; -mod helpers; -mod int_key; +pub mod de; pub use append_store::AppendStore; pub use deque_store::DequeStore; @@ -17,7 +14,6 @@ pub use iter_options::WithoutIter; use iter_options::{IterOption, WithIter}; pub use keymap::{Keymap, KeymapBuilder}; pub use keyset::{Keyset, KeysetBuilder}; -pub use keys::{Key, Prefixer, PrimaryKey}; pub mod iter_options { pub struct WithIter;