Skip to content

Commit

Permalink
Merge pull request #2351 from CosmWasm/from_be_bytes-from_le_bytes
Browse files Browse the repository at this point in the history
Implement from_be_bytes/from_le_bytes for Uint64 and Uint128
  • Loading branch information
chipshort authored Jan 28, 2025
2 parents f503569 + 23de2fc commit 7ef262e
Show file tree
Hide file tree
Showing 6 changed files with 271 additions and 79 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,12 @@ and this project adheres to
`From<Int128> for i128` ([#2268])
- cosmwasm-std: Deprecate `abort` feature. The panic handler is now always
enabled. ([#2337])
- cosmwasm-std: Implement `Uint128::from_{be,le}_bytes` and
`Uint64::from_{be,le}_bytes`. ([#2269])

[#2268]: https://github.com/CosmWasm/cosmwasm/issues/2268
[#2337]: https://github.com/CosmWasm/cosmwasm/issues/2337
[#2269]: https://github.com/CosmWasm/cosmwasm/issues/2269

## Fixed

Expand Down
29 changes: 29 additions & 0 deletions packages/std/src/math/conversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,35 @@ macro_rules! try_from_int_to_uint {
}
pub(crate) use try_from_int_to_uint;

macro_rules! from_and_to_bytes {
($inner: ty, $byte_size: literal) => {
/// Constructs new value from big endian bytes
#[must_use]
pub const fn from_be_bytes(data: [u8; $byte_size]) -> Self {
Self(<$inner>::from_be_bytes(data))
}

/// Constructs new value from little endian bytes
#[must_use]
pub const fn from_le_bytes(data: [u8; $byte_size]) -> Self {
Self(<$inner>::from_le_bytes(data))
}

/// Returns a copy of the number as big endian bytes.
#[must_use = "this returns the result of the operation, without modifying the original"]
pub const fn to_be_bytes(self) -> [u8; $byte_size] {
self.0.to_be_bytes()
}

/// Returns a copy of the number as little endian bytes.
#[must_use = "this returns the result of the operation, without modifying the original"]
pub const fn to_le_bytes(self) -> [u8; $byte_size] {
self.0.to_le_bytes()
}
};
}
pub(crate) use from_and_to_bytes;

#[cfg(test)]
mod tests {
use super::*;
Expand Down
83 changes: 56 additions & 27 deletions packages/std/src/math/int128.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ use crate::{
};

use super::conversion::{
forward_try_from, primitive_to_wrapped_int, try_from_int_to_int, wrapped_int_to_primitive,
forward_try_from, from_and_to_bytes, primitive_to_wrapped_int, try_from_int_to_int,
wrapped_int_to_primitive,
};
use super::impl_int_serde;
use super::num_consts::NumConsts;
Expand Down Expand Up @@ -67,27 +68,7 @@ impl Int128 {
self.0
}

#[must_use]
pub const fn from_be_bytes(data: [u8; 16]) -> Self {
Self(i128::from_be_bytes(data))
}

#[must_use]
pub const fn from_le_bytes(data: [u8; 16]) -> Self {
Self(i128::from_le_bytes(data))
}

/// Returns a copy of the number as big endian bytes.
#[must_use = "this returns the result of the operation, without modifying the original"]
pub const fn to_be_bytes(self) -> [u8; 16] {
self.0.to_be_bytes()
}

/// Returns a copy of the number as little endian bytes.
#[must_use = "this returns the result of the operation, without modifying the original"]
pub const fn to_le_bytes(self) -> [u8; 16] {
self.0.to_le_bytes()
}
from_and_to_bytes!(i128, 16);

#[must_use]
pub const fn is_zero(&self) -> bool {
Expand Down Expand Up @@ -521,16 +502,64 @@ mod tests {

#[test]
fn int128_from_be_bytes_works() {
let num = Int128::from_be_bytes([1; 16]);
// zero
let original = [0; 16];
let num = Int128::from_be_bytes(original);
assert!(num.is_zero());

// one
let original = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1];
let num = Int128::from_be_bytes(original);
assert_eq!(num.i128(), 1);

// 258
let original = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2];
let num = Int128::from_be_bytes(original);
assert_eq!(num.i128(), 258);

// 2x roundtrip
let original = [1; 16];
let num = Int128::from_be_bytes(original);
let a: [u8; 16] = num.to_be_bytes();
assert_eq!(a, [1; 16]);
assert_eq!(a, original);

let be_bytes = [
let original = [
0u8, 222u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 2u8, 3u8,
];
let num = Int128::from_be_bytes(be_bytes);
let num = Int128::from_be_bytes(original);
let resulting_bytes: [u8; 16] = num.to_be_bytes();
assert_eq!(be_bytes, resulting_bytes);
assert_eq!(resulting_bytes, original);
}

#[test]
fn int128_from_le_bytes_works() {
// zero
let original = [0; 16];
let num = Int128::from_le_bytes(original);
assert!(num.is_zero());

// one
let original = [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
let num = Int128::from_le_bytes(original);
assert_eq!(num.i128(), 1);

// 258
let original = [2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
let num = Int128::from_le_bytes(original);
assert_eq!(num.i128(), 258);

// 2x roundtrip
let original = [1; 16];
let num = Int128::from_le_bytes(original);
let a: [u8; 16] = num.to_le_bytes();
assert_eq!(a, original);

let original = [
0u8, 222u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 2u8, 3u8,
];
let num = Int128::from_le_bytes(original);
let resulting_bytes: [u8; 16] = num.to_le_bytes();
assert_eq!(resulting_bytes, original);
}

#[test]
Expand Down
83 changes: 55 additions & 28 deletions packages/std/src/math/int64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ use crate::{
};

use super::conversion::{
forward_try_from, primitive_to_wrapped_int, try_from_int_to_int, wrapped_int_to_primitive,
forward_try_from, from_and_to_bytes, primitive_to_wrapped_int, try_from_int_to_int,
wrapped_int_to_primitive,
};
use super::impl_int_serde;
use super::num_consts::NumConsts;
Expand Down Expand Up @@ -67,27 +68,7 @@ impl Int64 {
self.0
}

#[must_use]
pub const fn from_be_bytes(data: [u8; 8]) -> Self {
Self(i64::from_be_bytes(data))
}

#[must_use]
pub const fn from_le_bytes(data: [u8; 8]) -> Self {
Self(i64::from_le_bytes(data))
}

/// Returns a copy of the number as big endian bytes.
#[must_use = "this returns the result of the operation, without modifying the original"]
pub const fn to_be_bytes(self) -> [u8; 8] {
self.0.to_be_bytes()
}

/// Returns a copy of the number as little endian bytes.
#[must_use = "this returns the result of the operation, without modifying the original"]
pub const fn to_le_bytes(self) -> [u8; 8] {
self.0.to_le_bytes()
}
from_and_to_bytes!(i64, 8);

#[must_use]
pub const fn is_zero(&self) -> bool {
Expand Down Expand Up @@ -511,14 +492,60 @@ mod tests {

#[test]
fn int64_from_be_bytes_works() {
let num = Int64::from_be_bytes([1; 8]);
// zero
let original = [0; 8];
let num = Int64::from_be_bytes(original);
assert!(num.is_zero());

// one
let original = [0, 0, 0, 0, 0, 0, 0, 1];
let num = Int64::from_be_bytes(original);
assert_eq!(num.i64(), 1);

// 258
let original = [0, 0, 0, 0, 0, 0, 1, 2];
let num = Int64::from_be_bytes(original);
assert_eq!(num.i64(), 258);

// 2x roundtrip
let original = [1; 8];
let num = Int64::from_be_bytes(original);
let a: [u8; 8] = num.to_be_bytes();
assert_eq!(a, [1; 8]);
assert_eq!(a, original);

let be_bytes = [0u8, 222u8, 0u8, 0u8, 0u8, 1u8, 2u8, 3u8];
let num = Int64::from_be_bytes(be_bytes);
let resulting_bytes: [u8; 8] = num.to_be_bytes();
assert_eq!(be_bytes, resulting_bytes);
let original = [0u8, 222u8, 0u8, 0u8, 0u8, 1u8, 2u8, 3u8];
let num = Int64::from_be_bytes(original);
let a: [u8; 8] = num.to_be_bytes();
assert_eq!(a, original);
}

#[test]
fn int64_from_le_bytes_works() {
// zero
let original = [0; 8];
let num = Int64::from_le_bytes(original);
assert!(num.is_zero());

// one
let original = [1, 0, 0, 0, 0, 0, 0, 0];
let num = Int64::from_le_bytes(original);
assert_eq!(num.i64(), 1);

// 258
let original = [2, 1, 0, 0, 0, 0, 0, 0];
let num = Int64::from_le_bytes(original);
assert_eq!(num.i64(), 258);

// 2x roundtrip
let original = [1; 8];
let num = Int64::from_le_bytes(original);
let a: [u8; 8] = num.to_le_bytes();
assert_eq!(a, original);

let original = [0u8, 222u8, 0u8, 0u8, 0u8, 1u8, 2u8, 3u8];
let num = Int64::from_le_bytes(original);
let a: [u8; 8] = num.to_le_bytes();
assert_eq!(a, original);
}

#[test]
Expand Down
78 changes: 66 additions & 12 deletions packages/std/src/math/uint128.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ use crate::{
Uint256, Uint64,
};

use super::conversion::{forward_try_from, primitive_to_wrapped_int, wrapped_int_to_primitive};
use super::conversion::{
forward_try_from, from_and_to_bytes, primitive_to_wrapped_int, wrapped_int_to_primitive,
};
use super::impl_int_serde;
use super::num_consts::NumConsts;

Expand Down Expand Up @@ -73,17 +75,7 @@ impl Uint128 {
self.0
}

/// Returns a copy of the number as big endian bytes.
#[must_use = "this returns the result of the operation, without modifying the original"]
pub const fn to_be_bytes(self) -> [u8; 16] {
self.0.to_be_bytes()
}

/// Returns a copy of the number as little endian bytes.
#[must_use = "this returns the result of the operation, without modifying the original"]
pub const fn to_le_bytes(self) -> [u8; 16] {
self.0.to_le_bytes()
}
from_and_to_bytes!(u128, 16);

#[must_use]
pub const fn is_zero(&self) -> bool {
Expand Down Expand Up @@ -605,6 +597,68 @@ mod tests {
);
}

#[test]
fn uint128_from_be_bytes_works() {
// zero
let original = [0; 16];
let num = Uint128::from_be_bytes(original);
assert!(num.is_zero());

// one
let original = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1];
let num = Uint128::from_be_bytes(original);
assert_eq!(num.u128(), 1);

// 258
let original = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2];
let num = Uint128::from_be_bytes(original);
assert_eq!(num.u128(), 258);

// 2x roundtrip
let original = [1; 16];
let num = Uint128::from_be_bytes(original);
let a: [u8; 16] = num.to_be_bytes();
assert_eq!(a, original);

let original = [
0u8, 222u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 2u8, 3u8,
];
let num = Uint128::from_be_bytes(original);
let resulting_bytes: [u8; 16] = num.to_be_bytes();
assert_eq!(resulting_bytes, original);
}

#[test]
fn uint128_from_le_bytes_works() {
// zero
let original = [0; 16];
let num = Uint128::from_le_bytes(original);
assert!(num.is_zero());

// one
let original = [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
let num = Uint128::from_le_bytes(original);
assert_eq!(num.u128(), 1);

// 258
let original = [2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
let num = Uint128::from_le_bytes(original);
assert_eq!(num.u128(), 258);

// 2x roundtrip
let original = [1; 16];
let num = Uint128::from_le_bytes(original);
let a: [u8; 16] = num.to_le_bytes();
assert_eq!(a, original);

let original = [
0u8, 222u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 2u8, 3u8,
];
let num = Uint128::from_le_bytes(original);
let resulting_bytes: [u8; 16] = num.to_le_bytes();
assert_eq!(resulting_bytes, original);
}

#[test]
fn uint128_convert_into() {
let original = Uint128(12345);
Expand Down
Loading

0 comments on commit 7ef262e

Please sign in to comment.