diff --git a/contracts/cw3-fixed-multisig/src/state.rs b/contracts/cw3-fixed-multisig/src/state.rs index e3b35c27b..b596ef605 100644 --- a/contracts/cw3-fixed-multisig/src/state.rs +++ b/contracts/cw3-fixed-multisig/src/state.rs @@ -1,8 +1,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use std::convert::TryInto; -use cosmwasm_std::{Addr, BlockInfo, CosmosMsg, Empty, StdError, StdResult, Storage}; +use cosmwasm_std::{Addr, BlockInfo, CosmosMsg, Empty, StdResult, Storage}; use cw3::{Status, Vote}; use cw_storage_plus::{Item, Map}; @@ -66,12 +65,3 @@ pub fn next_id(store: &mut dyn Storage) -> StdResult { PROPOSAL_COUNT.save(store, &id)?; Ok(id) } - -pub fn parse_id(data: &[u8]) -> StdResult { - match data[0..8].try_into() { - Ok(bytes) => Ok(u64::from_be_bytes(bytes)), - Err(_) => Err(StdError::generic_err( - "Corrupted data found. 8 byte expected.", - )), - } -} diff --git a/contracts/cw3-flex-multisig/src/state.rs b/contracts/cw3-flex-multisig/src/state.rs index 844ec8408..013757beb 100644 --- a/contracts/cw3-flex-multisig/src/state.rs +++ b/contracts/cw3-flex-multisig/src/state.rs @@ -1,10 +1,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use std::convert::TryInto; -use cosmwasm_std::{ - Addr, BlockInfo, CosmosMsg, Decimal, Empty, StdError, StdResult, Storage, Uint128, -}; +use cosmwasm_std::{Addr, BlockInfo, CosmosMsg, Decimal, Empty, StdResult, Storage, Uint128}; use cw3::{Status, Vote}; use cw4::Cw4Contract; @@ -162,15 +159,6 @@ pub fn next_id(store: &mut dyn Storage) -> StdResult { Ok(id) } -pub fn parse_id(data: &[u8]) -> StdResult { - match data[0..8].try_into() { - Ok(bytes) => Ok(u64::from_be_bytes(bytes)), - Err(_) => Err(StdError::generic_err( - "Corrupted data found. 8 byte expected.", - )), - } -} - #[cfg(test)] mod test { use super::*; diff --git a/packages/storage-plus/src/de.rs b/packages/storage-plus/src/de.rs index 1d69df74e..60f6fcb57 100644 --- a/packages/storage-plus/src/de.rs +++ b/packages/storage-plus/src/de.rs @@ -6,6 +6,7 @@ use std::convert::TryInto; use cosmwasm_std::{Addr, StdError, StdResult}; +use crate::int_key::CwIntKey; use crate::keys::{IntKey, TimestampKey}; pub trait KeyDeserialize { @@ -106,7 +107,7 @@ macro_rules! integer_de { #[inline(always)] fn from_vec(value: Vec) -> StdResult { - 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()))?)) } })* @@ -122,7 +123,7 @@ macro_rules! intkey_de { #[inline(always)] fn from_vec(value: Vec) -> StdResult { - 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()))?)) } })* @@ -230,41 +231,109 @@ mod test { } #[test] - fn deserialize_integer_works() { - assert_eq!(>::from_slice(&[1]).unwrap(), 1u8); - assert_eq!(>::from_slice(&[128]).unwrap(), -1i8 << 7); - assert_eq!(>::from_slice(&[1, 0]).unwrap(), 1u16 << 8); + 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!( - >::from_slice(&[128, 0]).unwrap(), - -1i16 << (8 + 7) + 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_integer_works() { + assert_eq!(>::from_slice(&[1]).unwrap(), 1u8); + assert_eq!(>::from_slice(&[127]).unwrap(), -1i8); + assert_eq!(>::from_slice(&[128]).unwrap(), 0i8); + + assert_eq!(>::from_slice(&[1, 0]).unwrap(), 256u16); + assert_eq!(>::from_slice(&[128, 0]).unwrap(), 0i16); + assert_eq!(>::from_slice(&[127, 255]).unwrap(), -1i16); + assert_eq!( >::from_slice(&[1, 0, 0, 0]).unwrap(), - 1u32 << (3 * 8) + 16777216u32 ); + assert_eq!(>::from_slice(&[128, 0, 0, 0]).unwrap(), 0i32); assert_eq!( - >::from_slice(&[128, 0, 0, 0]).unwrap(), - -1i32 << (3 * 8 + 7) + >::from_slice(&[127, 255, 255, 255]).unwrap(), + -1i32 ); + assert_eq!( >::from_slice(&[1, 0, 0, 0, 0, 0, 0, 0]).unwrap(), - 1u64 << (7 * 8) + 72057594037927936u64 ); assert_eq!( >::from_slice(&[128, 0, 0, 0, 0, 0, 0, 0]).unwrap(), - -1i64 << (7 * 8 + 7) + 0i64 ); + assert_eq!( + >::from_slice(&[127, 255, 255, 255, 255, 255, 255, 255]).unwrap(), + -1i64 + ); + assert_eq!( >::from_slice(&[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]).unwrap(), - 1u128 << (15 * 8) + 1329227995784915872903807060280344576u128 + ); + assert_eq!( + >::from_slice(&[128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) + .unwrap(), + 0i128 ); assert_eq!( >::from_slice(&[ - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 + 127, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 ]) .unwrap(), -1i128 ); + assert_eq!( + >::from_slice(&[ + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 + ]) + .unwrap(), + 170141183460469231731687303715884105727i128, + ); } #[test] @@ -286,7 +355,7 @@ mod test { fn deserialize_timestamp_works() { assert_eq!( ::from_slice(&[1, 0, 0, 0, 0, 0, 0, 0]).unwrap(), - 1u64 << (7 * 8) + 72057594037927936 ); } diff --git a/packages/storage-plus/src/int_key.rs b/packages/storage-plus/src/int_key.rs new file mode 100644 index 000000000..7f7713369 --- /dev/null +++ b/packages/storage-plus/src/int_key.rs @@ -0,0 +1,131 @@ +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. +// TODO: Rename to `IntKey` after deprecating current `IntKey` (https://github.com/CosmWasm/cw-plus/issues/570) +pub trait CwIntKey: 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 CwIntKey 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 CwIntKey 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-plus/src/keys.rs b/packages/storage-plus/src/keys.rs index 15b7a6c19..63bedba2e 100644 --- a/packages/storage-plus/src/keys.rs +++ b/packages/storage-plus/src/keys.rs @@ -6,6 +6,7 @@ use std::marker::PhantomData; use crate::de::KeyDeserialize; use crate::helpers::namespaces_with_key; +use crate::int_key::CwIntKey; use crate::Endian; #[derive(Debug)] @@ -284,7 +285,7 @@ macro_rules! integer_key { type SuperSuffix = Self; fn key(&self) -> Vec { - vec![Key::$v(self.to_be_bytes())] + vec![Key::$v(self.to_cw_bytes())] } })* } @@ -296,7 +297,7 @@ macro_rules! integer_prefix { (for $($t:ty, $v:tt),+) => { $(impl<'a> Prefixer<'a> for $t { fn prefix(&self) -> Vec { - vec![Key::$v(self.to_be_bytes())] + vec![Key::$v(self.to_cw_bytes())] } })* } @@ -326,16 +327,26 @@ impl<'a, T: Endian> Prefixer<'a> for IntKey { } } +#[deprecated(note = "It is suggested to use `u8` as key type instead of the `U8Key` wrapper")] pub type U8Key = IntKey; +#[deprecated(note = "It is suggested to use `u16` as key type instead of the `U16Key` wrapper")] pub type U16Key = IntKey; +#[deprecated(note = "It is suggested to use `u32` as key type instead of the `U32Key` wrapper")] pub type U32Key = IntKey; +#[deprecated(note = "It is suggested to use `u64` as key type instead of the `U64Key` wrapper")] pub type U64Key = IntKey; +#[deprecated(note = "Consider using 64-bit keys instead of the `U128Key` wrapper")] pub type U128Key = IntKey; +#[deprecated(note = "It is suggested to use `i8` as key type instead of the `I8Key` wrapper")] pub type I8Key = IntKey; +#[deprecated(note = "It is suggested to use `i16` as key type instead of the `I16Key` wrapper")] pub type I16Key = IntKey; +#[deprecated(note = "It is suggested to use `i32` as key type instead of the `I32Key` wrapper")] pub type I32Key = IntKey; +#[deprecated(note = "It is suggested to use `i64` as key type instead of the `I64Key` wrapper")] pub type I64Key = IntKey; +#[deprecated(note = "Consider using 64-bit keys instead of the `I128Key` wrapper")] pub type I128Key = IntKey; /// It will cast one-particular int type into a Key via Vec, ensuring you don't mix up u32 and u64 @@ -351,16 +362,16 @@ pub struct IntKey { pub data: PhantomData, } -impl IntKey { +impl IntKey { pub fn new(val: T) -> Self { IntKey { - wrapped: val.to_be_bytes().into(), + wrapped: val.to_cw_bytes().into(), data: PhantomData, } } } -impl From for IntKey { +impl From for IntKey { fn from(val: T) -> Self { IntKey::new(val) } @@ -430,7 +441,7 @@ mod test { let k: U64Key = 134u64.into(); let path = k.key(); assert_eq!(1, path.len()); - assert_eq!(134u64.to_be_bytes(), path[0].as_ref()); + assert_eq!(134u64.to_cw_bytes(), path[0].as_ref()); } #[test] @@ -438,7 +449,7 @@ mod test { let k: U32Key = 4242u32.into(); let path = k.key(); assert_eq!(1, path.len()); - assert_eq!(4242u32.to_be_bytes(), path[0].as_ref()); + assert_eq!(4242u32.to_cw_bytes(), path[0].as_ref()); } #[test] @@ -446,12 +457,12 @@ mod test { let k: u8 = 42u8; let path = k.key(); assert_eq!(1, path.len()); - assert_eq!(42u8.to_be_bytes(), path[0].as_ref()); + 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_be_bytes(), path[0].as_ref()); + assert_eq!(42i8.to_cw_bytes(), path[0].as_ref()); } #[test] @@ -459,12 +470,12 @@ mod test { let k: u16 = 4242u16; let path = k.key(); assert_eq!(1, path.len()); - assert_eq!(4242u16.to_be_bytes(), path[0].as_ref()); + 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_be_bytes(), path[0].as_ref()); + assert_eq!(4242i16.to_cw_bytes(), path[0].as_ref()); } #[test] @@ -472,12 +483,12 @@ mod test { let k: u32 = 4242u32; let path = k.key(); assert_eq!(1, path.len()); - assert_eq!(4242u32.to_be_bytes(), path[0].as_ref()); + 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_be_bytes(), path[0].as_ref()); + assert_eq!(4242i32.to_cw_bytes(), path[0].as_ref()); } #[test] @@ -485,12 +496,12 @@ mod test { let k: u64 = 4242u64; let path = k.key(); assert_eq!(1, path.len()); - assert_eq!(4242u64.to_be_bytes(), path[0].as_ref()); + 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_be_bytes(), path[0].as_ref()); + assert_eq!(4242i64.to_cw_bytes(), path[0].as_ref()); } #[test] @@ -547,8 +558,8 @@ mod test { 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_be_bytes()); - assert_eq!(path[1].as_ref(), 87654u64.to_be_bytes()); + assert_eq!(path[0].as_ref(), 123u32.to_cw_bytes()); + assert_eq!(path[1].as_ref(), 87654u64.to_cw_bytes()); } #[test] @@ -558,8 +569,8 @@ mod test { 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_be_bytes()); - assert_eq!(path[1].as_ref(), 87654u64.to_be_bytes()); + assert_eq!(path[0].as_ref(), 123u32.to_cw_bytes()); + assert_eq!(path[1].as_ref(), 87654u64.to_cw_bytes()); } #[test] @@ -615,7 +626,8 @@ mod test { assert_eq!(pair.prefix(), vec![one.as_slice(), two.as_slice()]); let pair: (i8, &[u8]) = (123, b"random"); - let one: Vec = vec![123]; + // 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()]); } @@ -628,7 +640,8 @@ mod test { assert_eq!(pair.prefix(), vec![one.as_slice(), two.as_slice()]); let pair: (i16, &[u8]) = (12345, b"random"); - let one: Vec = vec![48, 57]; + // 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()]); } @@ -641,7 +654,9 @@ mod test { assert_eq!(pair.prefix(), vec![one.as_slice(), two.as_slice()]); let pair: (i64, &[u8]) = (12345, b"random"); - let one: Vec = vec![0, 0, 0, 0, 0, 0, 48, 57]; + // 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()]); } diff --git a/packages/storage-plus/src/lib.rs b/packages/storage-plus/src/lib.rs index 53bbba036..77665e2f7 100644 --- a/packages/storage-plus/src/lib.rs +++ b/packages/storage-plus/src/lib.rs @@ -4,6 +4,7 @@ mod helpers; mod indexed_map; mod indexed_snapshot; mod indexes; +mod int_key; mod item; mod iter_helpers; mod keys; @@ -24,7 +25,12 @@ pub use indexes::UniqueIndex; #[cfg(feature = "iterator")] pub use indexes::{index_string, index_string_tuple, index_triple, index_tuple, Index}; pub use item::Item; +// TODO: Remove along with `IntKey` +#[allow(deprecated)] pub use keys::{I128Key, I16Key, I32Key, I64Key, I8Key}; +// TODO: Remove along with `IntKey` +pub use int_key::CwIntKey; +#[allow(deprecated)] pub use keys::{Prefixer, PrimaryKey, U128Key, U16Key, U32Key, U64Key, U8Key}; pub use map::Map; pub use path::Path; diff --git a/packages/storage-plus/src/map.rs b/packages/storage-plus/src/map.rs index 320c7a64c..5bb9e91e5 100644 --- a/packages/storage-plus/src/map.rs +++ b/packages/storage-plus/src/map.rs @@ -254,6 +254,8 @@ mod test { #[cfg(feature = "iterator")] use cosmwasm_std::{Order, StdResult}; + use crate::int_key::CwIntKey; + #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] struct Data { pub name: String, @@ -263,6 +265,8 @@ mod test { const PEOPLE: Map<&[u8], Data> = Map::new("people"); #[cfg(feature = "iterator")] const PEOPLE_ID: Map = Map::new("people_id"); + #[cfg(feature = "iterator")] + const SIGNED_ID: Map = Map::new("signed_id"); const ALLOWANCE: Map<(&[u8], &[u8]), u64> = Map::new("allow"); @@ -297,7 +301,7 @@ mod test { ); assert_eq!(b"triple".to_vec().as_slice(), &key[2..8]); assert_eq!(b"john".to_vec().as_slice(), &key[10..14]); - assert_eq!(8u8.to_be_bytes(), &key[16..17]); + assert_eq!(8u8.to_cw_bytes(), &key[16..17]); assert_eq!(b"pedro".to_vec().as_slice(), &key[17..]); } @@ -568,6 +572,69 @@ mod test { assert_eq!(all, vec![(1234, data)]); } + #[test] + #[cfg(feature = "iterator")] + fn range_simple_signed_integer_key() { + let mut store = MockStorage::new(); + + // save and load on three keys + let data = Data { + name: "John".to_string(), + age: 32, + }; + SIGNED_ID.save(&mut store, -1234, &data).unwrap(); + + let data2 = Data { + name: "Jim".to_string(), + age: 44, + }; + SIGNED_ID.save(&mut store, -56, &data2).unwrap(); + + let data3 = Data { + name: "Jules".to_string(), + age: 55, + }; + SIGNED_ID.save(&mut store, 50, &data3).unwrap(); + + // let's try to iterate! + let all: StdResult> = SIGNED_ID + .range(&store, None, None, Order::Ascending) + .collect(); + let all = all.unwrap(); + assert_eq!(3, all.len()); + // order is correct + assert_eq!( + all, + vec![(-1234, data), (-56, data2.clone()), (50, data3.clone())] + ); + + // let's try to iterate over a range + let all: StdResult> = SIGNED_ID + .range( + &store, + Some(Bound::inclusive_int(-56i32)), + None, + Order::Ascending, + ) + .collect(); + let all = all.unwrap(); + assert_eq!(2, all.len()); + assert_eq!(all, vec![(-56, data2), (50, data3.clone())]); + + // let's try to iterate over a more restrictive range + let all: StdResult> = SIGNED_ID + .range( + &store, + Some(Bound::inclusive_int(-55i32)), + Some(Bound::inclusive_int(50i32)), + Order::Descending, + ) + .collect(); + let all = all.unwrap(); + assert_eq!(1, all.len()); + assert_eq!(all, vec![(50, data3)]); + } + #[test] #[cfg(feature = "iterator")] fn range_raw_composite_key() { diff --git a/packages/storage-plus/src/prefix.rs b/packages/storage-plus/src/prefix.rs index 5c210052a..38e4b7c78 100644 --- a/packages/storage-plus/src/prefix.rs +++ b/packages/storage-plus/src/prefix.rs @@ -8,6 +8,7 @@ use std::ops::Deref; use crate::de::KeyDeserialize; use crate::helpers::{namespaces_with_key, nested_namespaces_with_key}; +use crate::int_key::CwIntKey; use crate::iter_helpers::{concat, deserialize_kv, deserialize_v, trim}; use crate::keys::Key; use crate::{Endian, Prefixer}; @@ -34,13 +35,13 @@ impl Bound { } /// Turns an int, like Option into an inclusive bound - pub fn inclusive_int(limit: T) -> Self { - Bound::Inclusive(limit.to_be_bytes().into()) + pub fn inclusive_int(limit: T) -> Self { + Bound::Inclusive(limit.to_cw_bytes().into()) } /// Turns an int, like Option into an exclusive bound - pub fn exclusive_int(limit: T) -> Self { - Bound::Exclusive(limit.to_be_bytes().into()) + pub fn exclusive_int(limit: T) -> Self { + Bound::Exclusive(limit.to_cw_bytes().into()) } }