Skip to main content

cw_storage_plus/
int_key.rs

1use std::mem;
2
3use cosmwasm_std::{Int128, Int64, Uint128, Uint64};
4
5/// Our int keys are simply the big-endian representation bytes for unsigned ints,
6/// but "sign-flipped" (xored msb) big-endian bytes for signed ints.
7///
8/// So that the representation of signed integers is in the right lexicographical order.
9pub trait IntKey: Sized + Copy {
10    type Buf: AsRef<[u8]> + AsMut<[u8]> + Into<Vec<u8>> + Default;
11
12    fn to_cw_bytes(&self) -> Self::Buf;
13    fn from_cw_bytes(bytes: Self::Buf) -> Self;
14}
15
16macro_rules! cw_uint_keys {
17    (for $($t:ty),+) => {
18        $(impl IntKey for $t {
19            type Buf = [u8; mem::size_of::<$t>()];
20
21            #[inline]
22            fn to_cw_bytes(&self) -> Self::Buf {
23                self.to_be_bytes()
24            }
25
26            #[inline]
27            fn from_cw_bytes(bytes: Self::Buf) -> Self {
28                Self::from_be_bytes(bytes)
29            }
30        })*
31    }
32}
33
34cw_uint_keys!(for u8, u16, u32, u64, u128);
35
36macro_rules! cw_int_keys {
37    (for $($t:ty, $ut:ty),+) => {
38        $(impl IntKey for $t {
39            type Buf = [u8; mem::size_of::<$t>()];
40
41            #[inline]
42            fn to_cw_bytes(&self) -> Self::Buf {
43                (*self as $ut ^ <$t>::MIN as $ut).to_be_bytes()
44            }
45
46            #[inline]
47            fn from_cw_bytes(bytes: Self::Buf) -> Self {
48                (Self::from_be_bytes(bytes) as $ut ^ <$t>::MIN as $ut) as _
49            }
50        })*
51    }
52}
53
54cw_int_keys!(for i8, u8, i16, u16, i32, u32, i64, u64, i128, u128);
55
56macro_rules! cw_uint_std_keys {
57    (for $($t:ty),+) => {
58        $(impl IntKey for $t {
59            type Buf = [u8; mem::size_of::<$t>()];
60
61            #[inline]
62            fn to_cw_bytes(&self) -> Self::Buf {
63                self.to_be_bytes()
64            }
65
66            #[inline]
67            fn from_cw_bytes(bytes: Self::Buf) -> Self {
68                Self::new(IntKey::from_cw_bytes(bytes))
69            }
70        })*
71    }
72}
73
74cw_uint_std_keys!(for Uint64, Uint128);
75
76macro_rules! cw_int_std_keys {
77    (for $($t:ty),+) => {
78        $(impl IntKey for $t {
79            type Buf = [u8; mem::size_of::<$t>()];
80
81            #[inline]
82            fn to_cw_bytes(&self) -> Self::Buf {
83                let mut bytes = self.to_be_bytes();
84                bytes[0] ^= 0x80;
85                bytes
86            }
87
88            #[inline]
89            fn from_cw_bytes(bytes: Self::Buf) -> Self {
90                Self::new(IntKey::from_cw_bytes(bytes))
91            }
92        })*
93    }
94}
95
96cw_int_std_keys!(for Int64, Int128);
97
98#[cfg(test)]
99mod test {
100    use super::*;
101
102    #[test]
103    fn x8_int_key_works() {
104        assert_eq!(0x42u8.to_cw_bytes(), [0x42]);
105        assert_eq!(0x42i8.to_cw_bytes(), [0xc2]);
106        assert_eq!((-0x3ei8).to_cw_bytes(), [0x42]);
107    }
108
109    #[test]
110    fn x16_int_key_works() {
111        assert_eq!(0x4243u16.to_cw_bytes(), [0x42, 0x43]);
112        assert_eq!(0x4243i16.to_cw_bytes(), [0xc2, 0x43]);
113        assert_eq!((-0x3dbdi16).to_cw_bytes(), [0x42, 0x43]);
114    }
115
116    #[test]
117    fn x32_int_key_works() {
118        assert_eq!(0x424344u32.to_cw_bytes(), [0x00, 0x42, 0x43, 0x44]);
119        assert_eq!(0x424344i32.to_cw_bytes(), [0x80, 0x42, 0x43, 0x44]);
120        assert_eq!((-0x7fbdbcbci32).to_cw_bytes(), [0x00, 0x42, 0x43, 0x44]);
121    }
122
123    #[test]
124    fn x64_int_key_works() {
125        assert_eq!(
126            0x42434445u64.to_cw_bytes(),
127            [0x00, 0x00, 0x00, 0x00, 0x42, 0x43, 0x44, 0x45]
128        );
129        assert_eq!(
130            0x42434445i64.to_cw_bytes(),
131            [0x80, 0x00, 0x00, 0x00, 0x42, 0x43, 0x44, 0x45]
132        );
133        assert_eq!(
134            (-0x7fffffffbdbcbbbbi64).to_cw_bytes(),
135            [0x00, 0x00, 0x00, 0x00, 0x42, 0x43, 0x44, 0x45]
136        );
137    }
138
139    #[test]
140    fn x128_int_key_works() {
141        assert_eq!(
142            0x4243444546u128.to_cw_bytes(),
143            [
144                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x43, 0x44,
145                0x45, 0x46
146            ]
147        );
148        assert_eq!(
149            0x4243444546i128.to_cw_bytes(),
150            [
151                0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x43, 0x44,
152                0x45, 0x46
153            ]
154        );
155        assert_eq!(
156            (-0x7fffffffffffffffffffffbdbcbbbabai128).to_cw_bytes(),
157            [
158                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x43, 0x44,
159                0x45, 0x46
160            ]
161        );
162    }
163
164    #[test]
165    fn unsigned_int_key_order() {
166        assert!(0u32.to_cw_bytes() < 652u32.to_cw_bytes());
167    }
168
169    #[test]
170    fn signed_int_key_order() {
171        assert!((-321i32).to_cw_bytes() < 0i32.to_cw_bytes());
172        assert!(0i32.to_cw_bytes() < 652i32.to_cw_bytes());
173    }
174}