Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

move key instead of borrowing #78

Open
wants to merge 4 commits into
base: match-cw-storage-plus-map-support-borrowed-key
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 12 additions & 13 deletions packages/storage/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ To insert, remove, read from the keymap, do the following:
#
# let mut deps = mock_dependencies();
# let info = mock_info("sender", &[]);
# pub static ADDR_VOTE: Keymap<Addr, Foo> = KeymapBuilder::new(b"page_vote").with_page_size(13).build();
# pub static ADDR_VOTE: Keymap<&Addr, Foo> = KeymapBuilder::new(b"page_vote").with_page_size(13).build();
#
let user_addr: Addr = info.sender;

Expand Down Expand Up @@ -384,7 +384,7 @@ Here are some select examples from the unit tests:
fn test_keymap_iter_keys() -> StdResult<()> {
let mut storage = MockStorage::new();

let keymap: Keymap<String, Foo> = Keymap::new(b"test");
let keymap: Keymap<&str, Foo> = Keymap::new(b"test");
let foo1 = Foo {
string: "string one".to_string(),
number: 1111,
Expand All @@ -394,19 +394,19 @@ fn test_keymap_iter_keys() -> StdResult<()> {
number: 1111,
};

let key1 = "key1".to_string();
let key2 = "key2".to_string();
let key1 = "key1";
let key2 = "key2";

keymap.insert(&mut storage, &key1, &foo1)?;
keymap.insert(&mut storage, &key2, &foo2)?;
keymap.insert(&mut storage, key1, &foo1)?;
keymap.insert(&mut storage, key2, &foo2)?;

let mut x = keymap.iter_keys(&storage)?;
let (len, _) = x.size_hint();
assert_eq!(len, 2);

assert_eq!(x.next().unwrap()?, key1);

assert_eq!(x.next().unwrap()?, key2);
// slice types convert to owned types when iterating over keys
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's because

pub trait KeyDeserialize {
    type Output: ... + DeserializeOwned + ...;
    ...
}

right?

assert_eq!(x.next().unwrap()?, key1.to_string());
assert_eq!(x.next().unwrap()?, key2.to_string());

Ok(())
}
Expand All @@ -422,7 +422,7 @@ fn test_keymap_iter_keys() -> StdResult<()> {
fn test_keymap_iter() -> StdResult<()> {
let mut storage = MockStorage::new();

let keymap: Keymap<Vec<u8>, Foo> = Keymap::new(b"test");
let keymap: Keymap<&[u8], Foo> = Keymap::new(b"test");
let foo1 = Foo {
string: "string one".to_string(),
number: 1111,
Expand All @@ -432,15 +432,14 @@ fn test_keymap_iter() -> StdResult<()> {
number: 1111,
};

keymap.insert(&mut storage, &b"key1".to_vec(), &foo1)?;
keymap.insert(&mut storage, &b"key2".to_vec(), &foo2)?;
keymap.insert(&mut storage, b"key1", &foo1)?;
keymap.insert(&mut storage, b"key2", &foo2)?;

let mut x = keymap.iter(&storage)?;
let (len, _) = x.size_hint();
assert_eq!(len, 2);

assert_eq!(x.next().unwrap()?.1, foo1);

assert_eq!(x.next().unwrap()?.1, foo2);

Ok(())
Expand Down
3 changes: 2 additions & 1 deletion packages/storage/src/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ 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;
Expand Down Expand Up @@ -102,7 +103,7 @@ macro_rules! integer_de {

#[inline(always)]
fn from_vec(value: Vec<u8>) -> StdResult<Self::Output> {
Ok(<$t>::from_be_bytes(value.as_slice().try_into()
Ok(<$t>::from_cw_bytes(value.as_slice().try_into()
.map_err(|err: TryFromSliceError| StdError::generic_err(err.to_string()))?))
}
})*
Expand Down
130 changes: 130 additions & 0 deletions packages/storage/src/int_key.rs
Original file line number Diff line number Diff line change
@@ -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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a cool trick, but irrelevant for Secret (since we don't have iterators)
I wonder if that's needed

pub trait IntKey: Sized + Copy {
type Buf: AsRef<[u8]> + AsMut<[u8]> + Into<Vec<u8>> + 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());
}
}
Loading