Skip to content

Commit

Permalink
Add bytes conversions and move array conversions to std lib (#5180)
Browse files Browse the repository at this point in the history
## Description
Add bytes conversions and move array conversions to std lib

## Checklist

- [ ] I have linked to any relevant issues.
- [ ] I have commented my code, particularly in hard-to-understand
areas.
- [ ] I have updated the documentation where relevant (API docs, the
reference, and the Sway book).
- [ ] I have added tests that prove my fix is effective or that my
feature works.
- [ ] I have added (or requested a maintainer to add) the necessary
`Breaking*` or `New Feature` labels where relevant.
- [ ] I have done my best to ensure that my PR adheres to [the Fuel Labs
Code Review
Standards](https://github.com/FuelLabs/rfcs/blob/master/text/code-standards/external-contributors.md).
- [ ] I have requested a review from the relevant team or maintainers.
  • Loading branch information
SwayStar123 authored Oct 13, 2023
1 parent ae8a39c commit 13517ea
Show file tree
Hide file tree
Showing 14 changed files with 2,227 additions and 1,000 deletions.
1,000 changes: 0 additions & 1,000 deletions sway-lib-core/src/primitive_conversions.sw

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions sway-lib-std/src/array_conversions.sw
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
library;

pub mod u16;
pub mod u32;
pub mod u64;
pub mod b256;
pub mod u256;
201 changes: 201 additions & 0 deletions sway-lib-std/src/array_conversions/b256.sw
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
library;

use ::array_conversions::u64::*;
use ::assert::assert;

impl b256 {
/// Converts the `b256` to a sequence of little-endian bytes.
///
/// # Returns
///
/// * [[u8; 32]] - An array of 32 `u8` bytes that compose the `b256`.
///
/// # Examples
///
/// ```sway
/// fn foo() {
/// let bytes = [32_u8, 31_u8, 30_u8, 29_u8, 28_u8, 27_u8, 26_u8, 25_u8, 24_u8, 23_u8,
/// 22_u8, 21_u8, 20_u8, 19_u8, 18_u8, 17_u8, 16_u8, 15_u8, 14_u8, 13_u8,
/// 12_u8, 11_u8, 10_u8, 9_u8, 8_u8, 7_u8, 6_u8, 5_u8, 4_u8, 3_u8,
/// 2_u8, 1_u8];
///
/// let x = b256::from_le_bytes(bytes);
///
/// assert(x == 0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20);
/// }
/// ```
pub fn to_le_bytes(self) -> [u8; 32] {
let (a, b, c, d): (u64, u64, u64, u64) = asm(r1: self) {r1: (u64, u64, u64, u64)};
let a = a.to_le_bytes();
let b = b.to_le_bytes();
let c = c.to_le_bytes();
let d = d.to_le_bytes();

let (a,b,c,d) = (d,c,b,a);

let output = [a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7],
b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7],
c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7],
d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7]];

output
}

/// Converts a sequence of little-endian bytes to a `b256`.
///
/// # Arguments
///
/// * `bytes`: [[u8; 32]] - A sequence of 32 `u8` bytes that represent a `b256`.
///
/// # Returns
///
/// * [b256] - The resulting `b256` value.
///
/// # Examples
///
/// ```sway
/// fn foo() {
/// let bytes = [32_u8, 31_u8, 30_u8, 29_u8, 28_u8, 27_u8, 26_u8, 25_u8, 24_u8, 23_u8,
/// 22_u8, 21_u8, 20_u8, 19_u8, 18_u8, 17_u8, 16_u8, 15_u8, 14_u8, 13_u8,
/// 12_u8, 11_u8, 10_u8, 9_u8, 8_u8, 7_u8, 6_u8, 5_u8, 4_u8, 3_u8,
/// 2_u8, 1_u8];
///
/// let x = b256::from_le_bytes(bytes);
///
/// assert(x == 0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20);
/// ```
pub fn from_le_bytes(bytes: [u8; 32]) -> Self {
let a = u64::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7]]);
let b = u64::from_le_bytes([bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15]]);
let c = u64::from_le_bytes([bytes[16], bytes[17], bytes[18], bytes[19], bytes[20], bytes[21], bytes[22], bytes[23]]);
let d = u64::from_le_bytes([bytes[24], bytes[25], bytes[26], bytes[27], bytes[28], bytes[29], bytes[30], bytes[31]]);

let result = (d, c, b, a);

asm(r1: result) {
r1: b256
}
}

/// Converts the `b256` to a sequence of big-endian bytes.
///
/// # Returns
///
/// * [[u8; 32]] - An array of 32 `u8` bytes that compose the `b256`.
///
/// # Examples
///
/// ```sway
/// fn foo() {
/// let x: b256 = 0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20;
/// let bytes = x.to_be_bytes();
///
/// let mut i: u8 = 0;
/// while i < 32_u8 {
/// assert(bytes[i.as_u64()] == i + 1_u8);
/// i += 1_u8;
/// }
/// }
/// ```
pub fn to_be_bytes(self) -> [u8; 32] {
let (a, b, c, d): (u64, u64, u64, u64) = asm(r1: self) {r1: (u64, u64, u64, u64)};
let a = a.to_be_bytes();
let b = b.to_be_bytes();
let c = c.to_be_bytes();
let d = d.to_be_bytes();

let output = [a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7],
b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7],
c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7],
d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7]];

output
}

/// Converts a sequence of big-endian bytes to a `b256`.
///
/// # Arguments
///
/// * `bytes`: [[u8; 32]] - A sequence of 32 `u8` bytes that represent a `b256`.
///
/// # Returns
///
/// * [b256] - The resulting `b256` value.
///
/// # Examples
///
/// ```sway
/// fn foo() {
/// let bytes = [1_u8, 2_u8, 3_u8, 4_u8, 5_u8, 6_u8, 7_u8, 8_u8, 9_u8, 10_u8,
/// 11_u8, 12_u8, 13_u8, 14_u8, 15_u8, 16_u8, 17_u8, 18_u8, 19_u8, 20_u8,
/// 21_u8, 22_u8, 23_u8, 24_u8, 25_u8, 26_u8, 27_u8, 28_u8, 29_u8, 30_u8,
/// 31_u8, 32_u8];
/// let x = b256::from_be_bytes(bytes);
///
/// assert(x == 0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20);
/// }
/// ```
pub fn from_be_bytes(bytes: [u8; 32]) -> Self {
let a = u64::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7]]);
let b = u64::from_be_bytes([bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15]]);
let c = u64::from_be_bytes([bytes[16], bytes[17], bytes[18], bytes[19], bytes[20], bytes[21], bytes[22], bytes[23]]);
let d = u64::from_be_bytes([bytes[24], bytes[25], bytes[26], bytes[27], bytes[28], bytes[29], bytes[30], bytes[31]]);

let result = (a, b, c, d);

asm(r1: result) {
r1: b256
}
}
}

#[test]
fn test_b256_from_le_bytes() {
let bytes = [32_u8, 31_u8, 30_u8, 29_u8, 28_u8, 27_u8, 26_u8, 25_u8, 24_u8, 23_u8,
22_u8, 21_u8, 20_u8, 19_u8, 18_u8, 17_u8, 16_u8, 15_u8, 14_u8, 13_u8,
12_u8, 11_u8, 10_u8, 9_u8, 8_u8, 7_u8, 6_u8, 5_u8, 4_u8, 3_u8,
2_u8, 1_u8];

let x = b256::from_le_bytes(bytes);

assert(x == 0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20);
}

#[test]
fn test_b256_to_le_bytes() {
let x: b256 = 0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20;

let bytes = x.to_le_bytes();

let mut i: u8 = 0;
while i < 32_u8 {
assert(bytes[i.as_u64()] == 32_u8 - i);
i += 1_u8;
}

}

#[test]
fn test_b256_from_be_bytes() {
let bytes = [1_u8, 2_u8, 3_u8, 4_u8, 5_u8, 6_u8, 7_u8, 8_u8, 9_u8, 10_u8,
11_u8, 12_u8, 13_u8, 14_u8, 15_u8, 16_u8, 17_u8, 18_u8, 19_u8, 20_u8,
21_u8, 22_u8, 23_u8, 24_u8, 25_u8, 26_u8, 27_u8, 28_u8, 29_u8, 30_u8,
31_u8, 32_u8];

let x = b256::from_be_bytes(bytes);

assert(x == 0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20);
}

#[test]
fn test_b256_to_be_bytes() {
let x: b256 = 0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20;

let bytes = x.to_be_bytes();

let mut i: u8 = 0;
while i < 32_u8 {
assert(bytes[i.as_u64()] == i + 1_u8);
i += 1_u8;
}
}
158 changes: 158 additions & 0 deletions sway-lib-std/src/array_conversions/u16.sw
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
library;

use ::assert::assert;

impl u16 {
/// Converts the `u16` to a sequence of little-endian bytes.
///
/// # Returns
///
/// * [[u8; 2]] - An array of 2 `u8` bytes that compose the `u16`.
///
/// # Examples
///
/// ```sway
/// fn foo() {
/// let x: u16 = 513;
/// let result = x.to_le_bytes();
///
/// assert(result[0] == 1_u8);
/// assert(result[1] == 2_u8);
/// }
/// ```
pub fn to_le_bytes(self) -> [u8; 2] {
let output = [0_u8, 0_u8];

asm(input: self, off: 0xFF, i: 0x8, output: output, r1) {
and r1 input off;
sw output r1 i0;

srl r1 input i;
and r1 r1 off;
sw output r1 i1;

output: [u8; 2]
}
}

/// Converts a sequence of little-endian bytes to a `u16`.
///
/// # Arguments
///
/// * `bytes`: [[u8; 2]] - A sequence of 2 `u8` bytes that represent a `u16`.
///
/// # Returns
///
/// * [u16] - The resulting `u16` value.
///
/// # Examples
///
/// ```sway
/// fn foo() {
/// let bytes = [1_u8, 2_u8];
/// let result = u16::from_le_bytes(bytes);
///
/// assert(result == 513_u16);
/// }
/// ```
pub fn from_le_bytes(bytes: [u8; 2]) -> Self {
asm(a: bytes[0], b: bytes[1], i: 0x8, r1) {
sll r1 b i;
or r1 a r1;
r1: u16
}
}

/// Converts the `u16` to a sequence of big-endian bytes.
///
/// # Returns
///
/// * [[u8; 2]] - An array of 2 `u8` bytes that compose the `u16`.
///
/// # Examples
///
/// ```sway
/// fn foo() {
/// let x: u16 = 513;
/// let result = x.to_be_bytes();
///
/// assert(result[0] == 2_u8);
/// assert(result[1] == 1_u8);
/// }
/// ```
pub fn to_be_bytes(self) -> [u8; 2] {
let output = [0_u8, 0_u8];

asm(input: self, off: 0xFF, i: 0x8, output: output, r1) {
srl r1 input i;
sw output r1 i0;

and r1 input off;
sw output r1 i1;

output: [u8; 2]
}
}

/// Converts a sequence of big-endian bytes to a `u16`.
///
/// # Arguments
///
/// * `bytes`: [[u8; 2]] - A sequence of 2 `u8` bytes that represent a `u16`.
///
/// # Returns
///
/// * [u32] - The resulting `u16` value.
///
/// # Examples
///
/// ```sway
/// fn foo() {
/// let bytes = [2_u8, 1_u8];
/// let result = u16::from_be_bytes(bytes);
///
/// assert(result == 513_u16);
/// }
/// ```
pub fn from_be_bytes(bytes: [u8; 2]) -> Self {
asm(a: bytes[0], b: bytes[1], i: 0x8, r1) {
sll r1 a i;
or r1 r1 b;
r1: u16
}
}
}

#[test]
fn test_u16_to_le_bytes() {
let x: u16 = 513;
let result = x.to_le_bytes();

assert(result[0] == 1_u8);
assert(result[1] == 2_u8);
}

#[test]
fn test_u16_from_le_bytes() {
let bytes = [1_u8, 2_u8];
let result = u16::from_le_bytes(bytes);

assert(result == 513_u16);
}

#[test]
fn test_u16_to_be_bytes() {
let x: u16 = 513;
let result = x.to_be_bytes();

assert(result[0] == 2_u8);
assert(result[1] == 1_u8);
}

#[test]
fn test_u16_from_be_bytes() {
let bytes = [2_u8, 1_u8];
let result = u16::from_be_bytes(bytes);

assert(result == 513_u16);
}
Loading

0 comments on commit 13517ea

Please sign in to comment.