Skip to content

Commit 8ce31d1

Browse files
committed
Let Int256::new take an i128 argument
1 parent da133ba commit 8ce31d1

File tree

2 files changed

+67
-19
lines changed

2 files changed

+67
-19
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ and this project adheres to
4141
makes the use of `schemars` optional for contracts. ([#2201])
4242
- cosmwasm-std: Remove `schemars::JsonSchema` requirement from `CustomMsg`.
4343
([#2201])
44+
- cosmwasm-std: `Int256::new` now takes an `i128` argument instead of bytes. Use
45+
`Int256::from_be_bytes` if you need the old behaviour.
4446

4547
## Fixed
4648

packages/std/src/math/int256.rs

Lines changed: 65 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -29,19 +29,21 @@ use super::num_consts::NumConsts;
2929
///
3030
/// # Examples
3131
///
32-
/// Use `from` to create instances out of primitive uint types or `new` to provide big
33-
/// endian bytes:
32+
/// Use `new` to create instances out of i128, `from` for other primitive uint/int types
33+
/// or `from_be_bytes` to provide big endian bytes:
3434
///
3535
/// ```
3636
/// # use cosmwasm_std::Int256;
37-
/// let a = Int256::from(258u128);
38-
/// let b = Int256::new([
37+
/// let a = Int256::new(258i128);
38+
/// let b = Int256::from(258u16);
39+
/// let c = Int256::from_be_bytes([
3940
/// 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
4041
/// 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
4142
/// 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
4243
/// 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 2u8,
4344
/// ]);
4445
/// assert_eq!(a, b);
46+
/// assert_eq!(a, c);
4547
/// ```
4648
#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord, schemars::JsonSchema)]
4749
pub struct Int256(#[schemars(with = "String")] pub(crate) I256);
@@ -53,11 +55,30 @@ impl Int256 {
5355
pub const MAX: Int256 = Int256(I256::MAX);
5456
pub const MIN: Int256 = Int256(I256::MIN);
5557

56-
/// Creates a Int256(value) from a big endian representation. It's just an alias for
57-
/// `from_be_bytes`.
58+
/// Creates a Int256(value).
59+
///
60+
/// This method is less flexible than `from` but can be called in a const context.
61+
///
62+
/// Before CosmWasm 3 this took a byte array as an argument. You can get this behaviour
63+
/// with [`from_be_bytes`].
64+
///
65+
/// [`from_be_bytes`]: Self::from_be_bytes
5866
#[inline]
59-
pub const fn new(value: [u8; 32]) -> Self {
60-
Self::from_be_bytes(value)
67+
pub const fn new(value: i128) -> Self {
68+
// See https://en.wikipedia.org/wiki/Sign_extension
69+
let b = value.to_be_bytes();
70+
if value.is_negative() {
71+
Self::from_be_bytes([
72+
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
73+
0xFF, 0xFF, b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9], b[10],
74+
b[11], b[12], b[13], b[14], b[15],
75+
])
76+
} else {
77+
Self::from_be_bytes([
78+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, b[0], b[1], b[2], b[3], b[4], b[5],
79+
b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15],
80+
])
81+
}
6182
}
6283

6384
/// Creates a Int256(0)
@@ -588,22 +609,49 @@ mod tests {
588609

589610
#[test]
590611
fn int256_new_works() {
591-
let num = Int256::new([1; 32]);
612+
let num = Int256::new(1);
613+
assert_eq!(
614+
num.to_be_bytes(),
615+
[
616+
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,
617+
0, 0, 0, 1
618+
]
619+
);
620+
621+
let num = Int256::new(-1);
622+
assert_eq!(
623+
num.to_be_bytes(),
624+
[
625+
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
626+
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
627+
]
628+
);
629+
630+
for v in [0, 1, -4, 18, 875786576, -11763498739, i128::MAX, i128::MIN] {
631+
// From is implemented by bnum, so we test two independent implementations against each other
632+
let uut = Int256::new(v);
633+
assert_eq!(uut, Int256::from(v));
634+
}
635+
}
636+
637+
#[test]
638+
fn int256_from_be_bytes_works() {
639+
let num = Int256::from_be_bytes([1; 32]);
592640
let a: [u8; 32] = num.to_be_bytes();
593641
assert_eq!(a, [1; 32]);
594642

595643
let be_bytes = [
596644
0u8, 222u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
597645
0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 2u8, 3u8,
598646
];
599-
let num = Int256::new(be_bytes);
647+
let num = Int256::from_be_bytes(be_bytes);
600648
let resulting_bytes: [u8; 32] = num.to_be_bytes();
601649
assert_eq!(be_bytes, resulting_bytes);
602650
}
603651

604652
#[test]
605653
fn int256_not_works() {
606-
let num = Int256::new([1; 32]);
654+
let num = Int256::from_be_bytes([1; 32]);
607655
let a = (!num).to_be_bytes();
608656
assert_eq!(a, [254; 32]);
609657

@@ -640,12 +688,10 @@ mod tests {
640688
];
641689

642690
// These should all be the same.
643-
let num1 = Int256::new(be_bytes);
644-
let num2 = Int256::from_be_bytes(be_bytes);
645-
let num3 = Int256::from_le_bytes(le_bytes);
646-
assert_eq!(num1, Int256::from(65536u32 + 512 + 3));
647-
assert_eq!(num1, num2);
648-
assert_eq!(num1, num3);
691+
let a = Int256::from_be_bytes(be_bytes);
692+
let b = Int256::from_le_bytes(le_bytes);
693+
assert_eq!(a, Int256::from(65536u32 + 512 + 3));
694+
assert_eq!(a, b);
649695
}
650696

651697
#[test]
@@ -1059,12 +1105,12 @@ mod tests {
10591105

10601106
#[test]
10611107
fn int256_shr_works() {
1062-
let original = Int256::new([
1108+
let original = Int256::from_be_bytes([
10631109
0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
10641110
0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 4u8, 2u8,
10651111
]);
10661112

1067-
let shifted = Int256::new([
1113+
let shifted = Int256::from_be_bytes([
10681114
0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
10691115
0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 128u8, 1u8, 0u8,
10701116
]);

0 commit comments

Comments
 (0)