Skip to content

Commit 06eab90

Browse files
authored
Merge pull request #1110 from CosmWasm/const-conversions
Const conversions Uint128 -> Uint256 and Uint256 -> Uint512
2 parents 64aaddb + 58974bb commit 06eab90

File tree

6 files changed

+101
-16
lines changed

6 files changed

+101
-16
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ and this project adheres to
1414
the contract call was executed in.
1515
- cosmwasm-std: Implement `ops::Mul` for `Decimal` and `Decimal256`.
1616
- cosmwasm-std: New const methods `Uint128::to_be_bytes`/`::to_le_bytes`.
17+
- cosmwasm-std: New const conversion methods `Uint256::from_uint128` and
18+
`Uint512::from_uint256`.
1719

1820
### Changed
1921

@@ -34,6 +36,7 @@ and this project adheres to
3436
such that `Decimal::numerator` and `::denominator` now return `Uint128`.
3537
- cosmwasm-std: Make methods `Uint256::to_be_bytes`/`::to_le_bytes` const.
3638
- cosmwasm-std: Make methods `Uint512::to_be_bytes`/`::to_le_bytes` const.
39+
- cosmwasm-std: Make method `Uint512::from_le_bytes` const.
3740

3841
### Removed
3942

packages/std/src/math/decimal.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,6 @@ impl Decimal {
2121
const DECIMAL_FRACTIONAL: Uint128 = Uint128::new(1_000_000_000_000_000_000u128); // 1*10**18
2222
const DECIMAL_FRACTIONAL_SQUARED: Uint128 =
2323
Uint128::new(1_000_000_000_000_000_000_000_000_000_000_000_000u128); // (1*10**18)**2 = 1*10**36
24-
const DECIMAL_FRACTIONAL_UINT256: Uint256 = Uint256::from_be_bytes([
25-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 224, 182, 179,
26-
167, 100, 0, 0,
27-
]); // Python: `[b for b in (1*10**18).to_bytes(32, "big")]`
2824
const DECIMAL_PLACES: usize = 18; // This needs to be an even number.
2925

3026
pub const MAX: Self = Self(Uint128::MAX);
@@ -220,8 +216,8 @@ impl ops::Mul for Decimal {
220216
// (a.numerator() * b.numerator()) / (a.denominator() * b.denominator())
221217
// = (a.numerator() * b.numerator()) / a.denominator() / b.denominator()
222218

223-
let result_as_uint256 =
224-
self.numerator().full_mul(other.numerator()) / Self::DECIMAL_FRACTIONAL_UINT256;
219+
let result_as_uint256 = self.numerator().full_mul(other.numerator())
220+
/ Uint256::from_uint128(Self::DECIMAL_FRACTIONAL); // from_uint128 is a const method and should be "free"
225221
match result_as_uint256.try_into() {
226222
Ok(result) => Self(result),
227223
Err(_) => panic!("attempt to multiply with overflow"),

packages/std/src/math/decimal256.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,6 @@ impl Decimal256 {
3232
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 151, 206, 123, 201, 7, 21, 179,
3333
75, 159, 16, 0, 0, 0, 0,
3434
]);
35-
const DECIMAL_FRACTIONAL_UINT512: Uint512 = Uint512::from_be_bytes([
36-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
37-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 224, 182,
38-
179, 167, 100, 0, 0,
39-
]); // Python: `[b for b in (1*10**18).to_bytes(32, "big")]`
4035

4136
pub const MAX: Self = Self(Uint256::MAX);
4237

@@ -231,8 +226,8 @@ impl ops::Mul for Decimal256 {
231226
// (a.numerator() * b.numerator()) / (a.denominator() * b.denominator())
232227
// = (a.numerator() * b.numerator()) / a.denominator() / b.denominator()
233228

234-
let result_as_uint512 =
235-
self.numerator().full_mul(other.numerator()) / Self::DECIMAL_FRACTIONAL_UINT512;
229+
let result_as_uint512 = self.numerator().full_mul(other.numerator())
230+
/ Uint512::from_uint256(Self::DECIMAL_FRACTIONAL); // from_uint256 is a const method and should be "free"
236231
match result_as_uint512.try_into() {
237232
Ok(result) => Self(result),
238233
Err(_) => panic!("attempt to multiply with overflow"),

packages/std/src/math/uint128.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ impl Uint128 {
4747
}
4848

4949
/// Returns a copy of the internal data
50-
pub fn u128(&self) -> u128 {
50+
pub const fn u128(&self) -> u128 {
5151
self.0
5252
}
5353

packages/std/src/math/uint256.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,18 @@ impl Uint256 {
9999
Uint256(U256(words))
100100
}
101101

102+
/// A conversion from `Uint128` that, unlike the one provided by the `From` trait,
103+
/// can be used in a `const` context.
104+
pub const fn from_uint128(num: Uint128) -> Self {
105+
let bytes = num.to_le_bytes();
106+
107+
Self::from_le_bytes([
108+
bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
109+
bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15],
110+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
111+
])
112+
}
113+
102114
/// Returns a copy of the number as big endian bytes.
103115
pub const fn to_be_bytes(self) -> [u8; 32] {
104116
let words = [
@@ -1006,6 +1018,19 @@ mod tests {
10061018
);
10071019
}
10081020

1021+
#[test]
1022+
fn uint256_from_uint128() {
1023+
assert_eq!(
1024+
Uint256::from_uint128(Uint128::new(123)),
1025+
Uint256::from_str("123").unwrap()
1026+
);
1027+
1028+
assert_eq!(
1029+
Uint256::from_uint128(Uint128::new(9785746283745)),
1030+
Uint256::from_str("9785746283745").unwrap()
1031+
);
1032+
}
1033+
10091034
#[test]
10101035
fn uint256_implements_display() {
10111036
let a = Uint256::from(12345u32);

packages/std/src/math/uint512.rs

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,48 @@ impl Uint512 {
9595
Self(U512(words))
9696
}
9797

98-
pub fn from_le_bytes(value: [u8; 64]) -> Self {
99-
Uint512(U512::from_little_endian(&value))
98+
pub const fn from_le_bytes(data: [u8; 64]) -> Self {
99+
let words: [u64; 8] = [
100+
u64::from_le_bytes([
101+
data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
102+
]),
103+
u64::from_le_bytes([
104+
data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15],
105+
]),
106+
u64::from_le_bytes([
107+
data[16], data[17], data[18], data[19], data[20], data[21], data[22], data[23],
108+
]),
109+
u64::from_le_bytes([
110+
data[24], data[25], data[26], data[27], data[28], data[29], data[30], data[31],
111+
]),
112+
u64::from_le_bytes([
113+
data[32], data[33], data[34], data[35], data[36], data[37], data[38], data[39],
114+
]),
115+
u64::from_le_bytes([
116+
data[40], data[41], data[42], data[43], data[44], data[45], data[46], data[47],
117+
]),
118+
u64::from_le_bytes([
119+
data[48], data[49], data[50], data[51], data[52], data[53], data[54], data[55],
120+
]),
121+
u64::from_le_bytes([
122+
data[56], data[57], data[58], data[59], data[60], data[61], data[62], data[63],
123+
]),
124+
];
125+
Self(U512(words))
126+
}
127+
128+
/// A conversion from `Uint256` that, unlike the one provided by the `From` trait,
129+
/// can be used in a `const` context.
130+
pub const fn from_uint256(num: Uint256) -> Self {
131+
let bytes = num.to_le_bytes();
132+
Self::from_le_bytes([
133+
bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
134+
bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15],
135+
bytes[16], bytes[17], bytes[18], bytes[19], bytes[20], bytes[21], bytes[22], bytes[23],
136+
bytes[24], bytes[25], bytes[26], bytes[27], bytes[28], bytes[29], bytes[30], bytes[31],
137+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
138+
0, 0, 0,
139+
])
100140
}
101141

102142
/// Returns a copy of the number as big endian bytes.
@@ -719,6 +759,32 @@ mod tests {
719759
);
720760
}
721761

762+
#[test]
763+
fn uint512_from_uint256() {
764+
assert_eq!(
765+
Uint512::from_uint256(Uint256::from_str("123").unwrap()),
766+
Uint512::from_str("123").unwrap()
767+
);
768+
769+
assert_eq!(
770+
Uint512::from_uint256(Uint256::from_str("9785746283745").unwrap()),
771+
Uint512::from_str("9785746283745").unwrap()
772+
);
773+
774+
assert_eq!(
775+
Uint512::from_uint256(
776+
Uint256::from_str(
777+
"97857462837575757832978493758398593853985452378423874623874628736482736487236"
778+
)
779+
.unwrap()
780+
),
781+
Uint512::from_str(
782+
"97857462837575757832978493758398593853985452378423874623874628736482736487236"
783+
)
784+
.unwrap()
785+
);
786+
}
787+
722788
#[test]
723789
fn uint512_implements_display() {
724790
let a = Uint512::from(12345u32);

0 commit comments

Comments
 (0)