diff --git a/sway_libs/src/lib.sw b/sway_libs/src/lib.sw index 656f16d1..9b8f6943 100644 --- a/sway_libs/src/lib.sw +++ b/sway_libs/src/lib.sw @@ -1,4 +1,11 @@ library sway_libs; dep merkle_proof/binary_merkle_proof; +dep signed_integers/signed_integers; +dep signed_integers/i8; +dep signed_integers/i16; +dep signed_integers/i32; +dep signed_integers/i64; +dep signed_integers/i128; +dep signed_integers/i256; dep string/string; diff --git a/sway_libs/src/signed_integers/README.md b/sway_libs/src/signed_integers/README.md new file mode 100644 index 00000000..39c0697f --- /dev/null +++ b/sway_libs/src/signed_integers/README.md @@ -0,0 +1,47 @@ +# Overview + +The Signed Integers library provides an interface to use signed numbers in Sway. It has 6 distinct types: `I8`, `I16`, `I32`, `I64`, `I128`, `I256`. These types are stack allocated. + +These types are stored as unsigned integers, therefore either `u64` or a number of them. Therefore the size can be known at compile time and the length is static. + +For more information please see the [specification](./SPECIFICATION.md). + +# Using the Library + +## Getting Started + +In order to use the `Signed Integers` type it must be added to the Forc.toml file and then imported into your Sway project. To add Sway-libs as a dependency to the Forc.toml in your project, please see the [README.md](../../../README.md). + +```rust +use sway_libs::i8::I8; +``` + +Once imported, a `Signed Integer` type can be instantiated defining a new variable and calling the `new` function. + +```rust +let mut i8_value = ~I8::new(); +``` + +## Basic Functionality + +Basic arithmetic operations are working as usual + +```rust +// Add 2 signed values +let i8_value_3 = i8_value_1 + i8_value_2; + +// Subtract one signed value from another +let i8_value_3 = i8_value_1 - i8_value_2; +``` + +Helper functions + +```rust +// To get a negative value from an unsigned value +let neg_value = ~I8::neg_from(); + +// Maximum value +let max_i8_value = ~I8::max(); +``` + +For more information please see the [specification](./SPECIFICATION.md). diff --git a/sway_libs/src/signed_integers/SPECIFICATION.md b/sway_libs/src/signed_integers/SPECIFICATION.md new file mode 100644 index 00000000..c933fa94 --- /dev/null +++ b/sway_libs/src/signed_integers/SPECIFICATION.md @@ -0,0 +1,35 @@ +# Overview + +This document provides an overview of the Signed Integers library. + +It outlines the use cases, i.e. specification, and describes how to implement the library. + +## Use Cases + +The Signed Integers library can be used anytime a one needs negative numbers. + +## Public Functions + +### `bits()` + +The size of this type in bits. + +### `from_uint()` + +Helper function to get a positive value from unsigned number + +### `max()` + +The largest value that can be represented by this type. + +### `min()` + +The smallest value that can be represented by this integer type. + +### `neg_from` + +Helper function to get a negative value of unsigned number + +### Basic arithmetic operations + +`+`, `-`, `*`, `/` diff --git a/sway_libs/src/signed_integers/common.sw b/sway_libs/src/signed_integers/common.sw new file mode 100644 index 00000000..4676812e --- /dev/null +++ b/sway_libs/src/signed_integers/common.sw @@ -0,0 +1,10 @@ +library common; + +pub trait TwosComplement { + fn twos_complement(self) -> Self; +} + + +pub enum Error { + ZeroDivisor: (), +} diff --git a/sway_libs/src/signed_integers/i128.sw b/sway_libs/src/signed_integers/i128.sw new file mode 100644 index 00000000..c5358802 --- /dev/null +++ b/sway_libs/src/signed_integers/i128.sw @@ -0,0 +1,185 @@ +library i128; + +use std::u128::U128; +use ::signed_integers::common::Error; +use ::signed_integers::common::TwosComplement; + +/// The 128-bit signed integer type. +/// Represented as an underlying U128 value. +/// Actual value is underlying value minus 2 ^ 127 +/// Max value is 2 ^ 127 - 1, min value is - 2 ^ 127 +pub struct I128 { + underlying: U128, +} + +pub trait From { + /// Function for creating I128 from U128 + fn from(underlying: U128) -> Self; +} + +impl From for I128 { + /// Helper function to get a signed number from with an underlying + fn from(underlying: U128) -> Self { + Self { underlying } + } +} + +impl core::ops::Eq for I128 { + fn eq(self, other: Self) -> bool { + self.underlying == other.underlying + } +} + +impl core::ops::Ord for I128 { + fn gt(self, other: Self) -> bool { + self.underlying > other.underlying + } + + fn lt(self, other: Self) -> bool { + self.underlying < other.underlying + } +} + +impl I128 { + /// The underlying value that corresponds to zero signed value + pub fn indent() -> U128 { + U128 { + upper: 1, + lower: 0, + } + } +} + +impl I128 { + /// The size of this type in bits. + pub fn bits() -> u32 { + 128 + } + + /// Helper function to get a positive value from unsigned number + fn from_uint(value: U128) -> Self { + // as the minimal value of I128 is -~I128::indent() (1 << 63) we should add ~I128::indent() (1 << 63) + let underlying: U128 = value + ~Self::indent(); + Self { underlying } + } + + /// The largest value that can be represented by this type, + pub fn max() -> Self { + Self { + underlying: ~U128::max(), + } + } + + /// The smallest value that can be represented by this integer type. + pub fn min() -> Self { + Self { + underlying: ~U128::min(), + } + } + + /// Helper function to get a negative value of unsigned number + pub fn neg_from(value: U128) -> Self { + Self { + underlying: ~Self::indent() - value, + } + } + + /// Initializes a new, zeroed I128. + pub fn new() -> Self { + Self { + underlying: ~Self::indent(), + } + } +} + +impl core::ops::Add for I128 { + /// Add a I128 to a I128. Panics on overflow. + fn add(self, other: Self) -> Self { + // subtract 1 << 63 to avoid double move + ~Self::from(self.underlying - ~Self::indent() + other.underlying) + } +} + +impl core::ops::Divide for I128 { + /// Divide a I128 by a I128. Panics if divisor is zero. + fn divide(self, divisor: Self) -> Self { + require(divisor != ~Self::new(), Error::ZeroDivisor); + let mut res = ~Self::new(); + if (self.underlying > ~Self::indent() + || self.underlying == ~Self::indent()) + && divisor.underlying > ~Self::indent() + { + res = ~Self::from((self.underlying - ~Self::indent()) / (divisor.underlying - ~Self::indent()) + ~Self::indent()); + } else if self.underlying < ~Self::indent() + && divisor.underlying < ~Self::indent() + { + res = ~Self::from((~Self::indent() - self.underlying) / (~Self::indent() - divisor.underlying) + ~Self::indent()); + } else if (self.underlying > ~Self::indent() + || self.underlying == ~Self::indent()) + && divisor.underlying < ~Self::indent() + { + res = ~Self::from(~Self::indent() - (self.underlying - ~Self::indent()) / (~Self::indent() - divisor.underlying)); + } else if self.underlying < ~Self::indent() + && divisor.underlying > ~Self::indent() + { + res = ~Self::from(~Self::indent() - (~Self::indent() - self.underlying) / (divisor.underlying - ~Self::indent())); + } + res + } +} + +impl core::ops::Multiply for I128 { + /// Multiply a I128 with a I128. Panics of overflow. + fn multiply(self, other: Self) -> Self { + let mut res = ~Self::new(); + if (self.underlying > ~Self::indent() + || self.underlying == ~Self::indent()) + && (other.underlying > ~Self::indent() + || other.underlying == ~Self::indent()) + { + res = ~Self::from((self.underlying - ~Self::indent()) * (other.underlying - ~Self::indent()) + ~Self::indent()); + } else if self.underlying < ~Self::indent() + && other.underlying < ~Self::indent() + { + res = ~Self::from((~Self::indent() - self.underlying) * (~Self::indent() - other.underlying) + ~Self::indent()); + } else if (self.underlying > ~Self::indent() + || self.underlying == ~Self::indent()) + && other.underlying < ~Self::indent() + { + res = ~Self::from(~Self::indent() - (self.underlying - ~Self::indent()) * (~Self::indent() - other.underlying)); + } else if self.underlying < ~Self::indent() + && (other.underlying > ~Self::indent() + || other.underlying == ~Self::indent()) + { + res = ~Self::from(~Self::indent() - (other.underlying - ~Self::indent()) * (~Self::indent() - self.underlying)); + } + res + } +} + +impl core::ops::Subtract for I128 { + /// Subtract a I128 from a I128. Panics of overflow. + fn subtract(self, other: Self) -> Self { + let mut res = ~Self::new(); + if self > other { + // add 1 << 63 to avoid loosing the move + res = ~Self::from(self.underlying - other.underlying + ~Self::indent()); + } else { + // subtract from 1 << 63 as we are getting a negative value + res = ~Self::from(~Self::indent() - (other.underlying - self.underlying)); + } + res + } +} + +impl TwosComplement for I128 { + fn twos_complement(self) -> Self { + let u128_one = U128 { + upper: 0, + lower: 1, + }; + let one = ~I128::from_uint(u128_one); + let res = !self - one; + res + } +} diff --git a/sway_libs/src/signed_integers/i16.sw b/sway_libs/src/signed_integers/i16.sw new file mode 100644 index 00000000..e4c43a59 --- /dev/null +++ b/sway_libs/src/signed_integers/i16.sw @@ -0,0 +1,172 @@ +library i16; + +use core::num::*; +use ::signed_integers::common::Error; +use ::signed_integers::common::TwosComplement; + +/// The 16-bit signed integer type. +/// Represented as an underlying u16 value. +/// Actual value is underlying value minus 2 ^ 15 +/// Max value is 2 ^ 15 - 1, min value is - 2 ^ 15 +pub struct I16 { + underlying: u16, +} + +pub trait From { + /// Function for creating I16 from u16 + fn from(underlying: u16) -> Self; +} + +impl From for I16 { + /// Helper function to get a signed number from with an underlying + fn from(underlying: u16) -> Self { + Self { underlying } + } +} + +impl core::ops::Eq for I16 { + fn eq(self, other: Self) -> bool { + self.underlying == other.underlying + } +} + +impl core::ops::Ord for I16 { + fn gt(self, other: Self) -> bool { + self.underlying > other.underlying + } + + fn lt(self, other: Self) -> bool { + self.underlying < other.underlying + } +} + +impl I16 { + /// The underlying value that corresponds to zero signed value + pub fn indent() -> u16 { + 32768u16 + } +} + +impl I16 { + /// The size of this type in bits. + pub fn bits() -> u32 { + 16 + } + + /// Helper function to get a positive value from unsigned number + fn from_uint(value: u16) -> Self { + // as the minimal value of I16 is -~I16::indent() (1 << 15) we should add ~I16::indent() (1 << 15) + let underlying: u16 = value + ~Self::indent(); + Self { underlying } + } + + /// The largest value that can be represented by this type, + pub fn max() -> Self { + Self { + underlying: ~u16::max(), + } + } + + /// The smallest value that can be represented by this integer type. + pub fn min() -> Self { + Self { + underlying: ~u16::min(), + } + } + + /// Helper function to get a negative value of unsigned number + pub fn neg_from(value: u16) -> Self { + Self { + underlying: ~Self::indent() - value, + } + } + + /// Initializes a new, zeroed I16. + pub fn new() -> Self { + Self { + underlying: ~Self::indent(), + } + } +} + +impl core::ops::Add for I16 { + /// Add a I16 to a I16. Panics on overflow. + fn add(self, other: Self) -> Self { + // subtract 1 << 15 to avoid double move + ~Self::from(self.underlying - ~Self::indent() + other.underlying) + } +} + +impl core::ops::Divide for I16 { + /// Divide a I16 by a I16. Panics if divisor is zero. + fn divide(self, divisor: Self) -> Self { + require(divisor != ~Self::new(), Error::ZeroDivisor); + let mut res = ~Self::new(); + if self.underlying >= ~Self::indent() + && divisor.underlying > ~Self::indent() + { + res = ~Self::from((self.underlying - ~Self::indent()) / (divisor.underlying - ~Self::indent()) + ~Self::indent()); + } else if self.underlying < ~Self::indent() + && divisor.underlying < ~Self::indent() + { + res = ~Self::from((~Self::indent() - self.underlying) / (~Self::indent() - divisor.underlying) + ~Self::indent()); + } else if self.underlying >= ~Self::indent() + && divisor.underlying < ~Self::indent() + { + res = ~Self::from(~Self::indent() - (self.underlying - ~Self::indent()) / (~Self::indent() - divisor.underlying)); + } else if self.underlying < ~Self::indent() + && divisor.underlying > ~Self::indent() + { + res = ~Self::from(~Self::indent() - (~Self::indent() - self.underlying) / (divisor.underlying - ~Self::indent())); + } + res + } +} + +impl core::ops::Multiply for I16 { + /// Multiply a I16 with a I16. Panics of overflow. + fn multiply(self, other: Self) -> Self { + let mut res = ~Self::new(); + if self.underlying >= ~Self::indent() + && other.underlying >= ~Self::indent() + { + res = ~Self::from((self.underlying - ~Self::indent()) * (other.underlying - ~Self::indent()) + ~Self::indent()); + } else if self.underlying < ~Self::indent() + && other.underlying < ~Self::indent() + { + res = ~Self::from((~Self::indent() - self.underlying) * (~Self::indent() - other.underlying) + ~Self::indent()); + } else if self.underlying >= ~Self::indent() + && other.underlying < ~Self::indent() + { + res = ~Self::from(~Self::indent() - (self.underlying - ~Self::indent()) * (~Self::indent() - other.underlying)); + } else if self.underlying < ~Self::indent() + && other.underlying >= ~Self::indent() + { + res = ~Self::from(~Self::indent() - (other.underlying - ~Self::indent()) * (~Self::indent() - self.underlying)); + } + res + } +} + +impl core::ops::Subtract for I16 { + /// Subtract a I16 from a I16. Panics of overflow. + fn subtract(self, other: Self) -> Self { + let mut res = ~Self::new(); + if self > other { + // add 1 << 15 to avoid loosing the move + res = ~Self::from(self.underlying - other.underlying + ~Self::indent()); + } else { + // subtract from 1 << 15 as we are getting a negative value + res = ~Self::from(~Self::indent() - (other.underlying - self.underlying)); + } + res + } +} + +impl TwosComplement for I16 { + fn twos_complement(self) -> Self { + let one = ~I16::from_uint(1u16); + let res = !self - one; + res + } +} diff --git a/sway_libs/src/signed_integers/i256.sw b/sway_libs/src/signed_integers/i256.sw new file mode 100644 index 00000000..abff77e2 --- /dev/null +++ b/sway_libs/src/signed_integers/i256.sw @@ -0,0 +1,189 @@ +library i256; + +use std::u256::U256; +use ::signed_integers::common::Error; +use ::signed_integers::common::TwosComplement; + +/// The 128-bit signed integer type. +/// Represented as an underlying U256 value. +/// Actual value is underlying value minus 2 ^ 255 +/// Max value is 2 ^ 255 - 1, min value is - 2 ^ 255 +pub struct I256 { + underlying: U256, +} + +pub trait From { + /// Function for creating I256 from U256 + fn from(underlying: U256) -> Self; +} + +impl From for I256 { + /// Helper function to get a signed number from with an underlying + fn from(underlying: U256) -> Self { + Self { underlying } + } +} + +impl core::ops::Eq for I256 { + fn eq(self, other: Self) -> bool { + self.underlying == other.underlying + } +} + +impl core::ops::Ord for I256 { + fn gt(self, other: Self) -> bool { + self.underlying > other.underlying + } + + fn lt(self, other: Self) -> bool { + self.underlying < other.underlying + } +} + +impl I256 { + /// The underlying value that corresponds to zero signed value + pub fn indent() -> U256 { + U256 { + a: 0, + b: 1, + c: 0, + d: 0, + } + } +} + +impl I256 { + /// The size of this type in bits. + pub fn bits() -> u32 { + 128 + } + + /// Helper function to get a positive value from unsigned number + fn from_uint(value: U256) -> Self { + // as the minimal value of I256 is -~I256::indent() (1 << 63) we should add ~I256::indent() (1 << 63) + let underlying: U256 = value + ~Self::indent(); + Self { underlying } + } + + /// The largest value that can be represented by this type, + pub fn max() -> Self { + Self { + underlying: ~U256::max(), + } + } + + /// The smallest value that can be represented by this integer type. + pub fn min() -> Self { + Self { + underlying: ~U256::min(), + } + } + + /// Helper function to get a negative value of unsigned number + pub fn neg_from(value: U256) -> Self { + Self { + underlying: ~Self::indent() - value, + } + } + + /// Initializes a new, zeroed I256. + pub fn new() -> Self { + Self { + underlying: ~Self::indent(), + } + } +} + +impl core::ops::Add for I256 { + /// Add a I256 to a I256. Panics on overflow. + fn add(self, other: Self) -> Self { + // subtract 1 << 63 to avoid double move + ~Self::from(self.underlying - ~Self::indent() + other.underlying) + } +} + +impl core::ops::Divide for I256 { + /// Divide a I256 by a I256. Panics if divisor is zero. + fn divide(self, divisor: Self) -> Self { + require(divisor != ~Self::new(), Error::ZeroDivisor); + let mut res = ~Self::new(); + if (self.underlying > ~Self::indent() + || self.underlying == ~Self::indent()) + && divisor.underlying > ~Self::indent() + { + res = ~Self::from((self.underlying - ~Self::indent()) / (divisor.underlying - ~Self::indent()) + ~Self::indent()); + } else if self.underlying < ~Self::indent() + && divisor.underlying < ~Self::indent() + { + res = ~Self::from((~Self::indent() - self.underlying) / (~Self::indent() - divisor.underlying) + ~Self::indent()); + } else if (self.underlying > ~Self::indent() + || self.underlying == ~Self::indent()) + && divisor.underlying < ~Self::indent() + { + res = ~Self::from(~Self::indent() - (self.underlying - ~Self::indent()) / (~Self::indent() - divisor.underlying)); + } else if self.underlying < ~Self::indent() + && divisor.underlying > ~Self::indent() + { + res = ~Self::from(~Self::indent() - (~Self::indent() - self.underlying) / (divisor.underlying - ~Self::indent())); + } + res + } +} + +impl core::ops::Multiply for I256 { + /// Multiply a I256 with a I256. Panics of overflow. + fn multiply(self, other: Self) -> Self { + let mut res = ~Self::new(); + if (self.underlying > ~Self::indent() + || self.underlying == ~Self::indent()) + && (other.underlying > ~Self::indent() + || other.underlying == ~Self::indent()) + { + res = ~Self::from((self.underlying - ~Self::indent()) * (other.underlying - ~Self::indent()) + ~Self::indent()); + } else if self.underlying < ~Self::indent() + && other.underlying < ~Self::indent() + { + res = ~Self::from((~Self::indent() - self.underlying) * (~Self::indent() - other.underlying) + ~Self::indent()); + } else if (self.underlying > ~Self::indent() + || self.underlying == ~Self::indent()) + && other.underlying < ~Self::indent() + { + res = ~Self::from(~Self::indent() - (self.underlying - ~Self::indent()) * (~Self::indent() - other.underlying)); + } else if self.underlying < ~Self::indent() + && (other.underlying > ~Self::indent() + || other.underlying == ~Self::indent()) + { + res = ~Self::from(~Self::indent() - (other.underlying - ~Self::indent()) * (~Self::indent() - self.underlying)); + } + res + } +} + +impl core::ops::Subtract for I256 { + /// Subtract a I256 from a I256. Panics of overflow. + fn subtract(self, other: Self) -> Self { + let mut res = ~Self::new(); + if self > other { + // add 1 << 63 to avoid loosing the move + res = ~Self::from(self.underlying - other.underlying + ~Self::indent()); + } else { + // subtract from 1 << 63 as we are getting a negative value + res = ~Self::from(~Self::indent() - (other.underlying - self.underlying)); + } + res + } +} + +impl TwosComplement for I256 { + fn twos_complement(self) -> Self { + let u128_one = U256 { + a: 0, + b: 0, + c: 0, + d: 1, + }; + let one = ~I256::from_uint(u128_one); + let res = !self - one; + res + } +} diff --git a/sway_libs/src/signed_integers/i32.sw b/sway_libs/src/signed_integers/i32.sw new file mode 100644 index 00000000..76de98d4 --- /dev/null +++ b/sway_libs/src/signed_integers/i32.sw @@ -0,0 +1,172 @@ +library i32; + +use core::num::*; +use ::signed_integers::common::Error; +use ::signed_integers::common::TwosComplement; + +/// The 32-bit signed integer type. +/// Represented as an underlying u32 value. +/// Actual value is underlying value minus 2 ^ 31 +/// Max value is 2 ^ 31 - 1, min value is - 2 ^ 31 +pub struct I32 { + underlying: u32, +} + +pub trait From { + /// Function for creating I32 from u32 + fn from(underlying: u32) -> Self; +} + +impl From for I32 { + /// Helper function to get a signed number from with an underlying + fn from(underlying: u32) -> Self { + Self { underlying } + } +} + +impl core::ops::Eq for I32 { + fn eq(self, other: Self) -> bool { + self.underlying == other.underlying + } +} + +impl core::ops::Ord for I32 { + fn gt(self, other: Self) -> bool { + self.underlying > other.underlying + } + + fn lt(self, other: Self) -> bool { + self.underlying < other.underlying + } +} + +impl I32 { + /// The underlying value that corresponds to zero signed value + pub fn indent() -> u32 { + 2147483648u32 + } +} + +impl I32 { + /// The size of this type in bits. + pub fn bits() -> u32 { + 32 + } + + /// Helper function to get a positive value from unsigned number + fn from_uint(value: u32) -> Self { + // as the minimal value of I32 is 2147483648 (1 << 31) we should add ~I32::indent() (1 << 31) + let underlying: u32 = value + ~Self::indent(); + Self { underlying } + } + + /// The largest value that can be represented by this type, + pub fn max() -> Self { + Self { + underlying: ~u32::max(), + } + } + + /// The smallest value that can be represented by this integer type. + pub fn min() -> Self { + Self { + underlying: ~u32::min(), + } + } + + /// Helper function to get a negative value of unsigned numbers + pub fn neg_from(value: u32) -> Self { + Self { + underlying: ~Self::indent() - value, + } + } + + /// Initializes a new, zeroed I32. + pub fn new() -> Self { + Self { + underlying: ~Self::indent(), + } + } +} + +impl core::ops::Add for I32 { + /// Add a I32 to a I32. Panics on overflow. + fn add(self, other: Self) -> Self { + // subtract 1 << 31 to avoid double move + ~Self::from(self.underlying - ~Self::indent() + other.underlying) + } +} + +impl core::ops::Subtract for I32 { + /// Subtract a I32 from a I32. Panics of overflow. + fn subtract(self, other: Self) -> Self { + let mut res = ~Self::new(); + if self > other { + // add 1 << 31 to avoid loosing the move + res = ~Self::from(self.underlying - other.underlying + ~Self::indent()); + } else { + // subtract from 1 << 31 as we are getting a negative value + res = ~Self::from(~Self::indent() - (other.underlying - self.underlying)); + } + res + } +} + +impl core::ops::Multiply for I32 { + /// Multiply a I32 with a I32. Panics of overflow. + fn multiply(self, other: Self) -> Self { + let mut res = ~Self::new(); + if self.underlying >= ~Self::indent() + && other.underlying >= ~Self::indent() + { + res = ~Self::from((self.underlying - ~Self::indent()) * (other.underlying - ~Self::indent()) + ~Self::indent()); + } else if self.underlying < ~Self::indent() + && other.underlying < ~Self::indent() + { + res = ~Self::from((~Self::indent() - self.underlying) * (~Self::indent() - other.underlying) + ~Self::indent()); + } else if self.underlying >= ~Self::indent() + && other.underlying < ~Self::indent() + { + res = ~Self::from(~Self::indent() - (self.underlying - ~Self::indent()) * (~Self::indent() - other.underlying)); + } else if self.underlying < ~Self::indent() + && other.underlying >= ~Self::indent() + { + res = ~Self::from(~Self::indent() - (other.underlying - ~Self::indent()) * (~Self::indent() - self.underlying)); + } + res + } +} + +impl core::ops::Divide for I32 { + /// Divide a I32 by a I32. Panics if divisor is zero. + fn divide(self, divisor: Self) -> Self { + require(divisor != ~Self::new(), Error::ZeroDivisor); + let mut res = ~Self::new(); + if self.underlying >= ~Self::indent() + && divisor.underlying > ~Self::indent() + { + res = ~Self::from((self.underlying - ~Self::indent()) / (divisor.underlying - ~Self::indent()) + ~Self::indent()); + } else if self.underlying < ~Self::indent() + && divisor.underlying < ~Self::indent() + { + res = ~Self::from((~Self::indent() - self.underlying) / (~Self::indent() - divisor.underlying) + ~Self::indent()); + } else if self.underlying >= ~Self::indent() + && divisor.underlying < ~Self::indent() + { + res = ~Self::from(~Self::indent() - (self.underlying - ~Self::indent()) / (~Self::indent() - divisor.underlying)); + } else if self.underlying < ~Self::indent() + && divisor.underlying > ~Self::indent() + { + res = ~Self::from(~Self::indent() - (~Self::indent() - self.underlying) / (divisor.underlying - ~Self::indent())); + } + res + } +} + +impl TwosComplement for I32 { + fn twos_complement(self) -> Self { + let one = ~I32::from_uint(1u32); + let res = !self - one; + res + } +} diff --git a/sway_libs/src/signed_integers/i64.sw b/sway_libs/src/signed_integers/i64.sw new file mode 100644 index 00000000..355a736c --- /dev/null +++ b/sway_libs/src/signed_integers/i64.sw @@ -0,0 +1,172 @@ +library i64; + +use core::num::*; +use ::signed_integers::common::Error; +use ::signed_integers::common::TwosComplement; + +/// The 64-bit signed integer type. +/// Represented as an underlying u64 value. +/// Actual value is underlying value minus 2 ^ 63 +/// Max value is 2 ^ 63 - 1, min value is - 2 ^ 63 +pub struct I64 { + underlying: u64, +} + +pub trait From { + /// Function for creating I64 from u64 + fn from(underlying: u64) -> Self; +} + +impl From for I64 { + /// Helper function to get a signed number from with an underlying + fn from(underlying: u64) -> Self { + Self { underlying } + } +} + +impl core::ops::Eq for I64 { + fn eq(self, other: Self) -> bool { + self.underlying == other.underlying + } +} + +impl core::ops::Ord for I64 { + fn gt(self, other: Self) -> bool { + self.underlying > other.underlying + } + + fn lt(self, other: Self) -> bool { + self.underlying < other.underlying + } +} + +impl I64 { + /// The underlying value that corresponds to zero signed value + pub fn indent() -> u64 { + 9223372036854775808u64 + } +} + +impl I64 { + /// The size of this type in bits. + pub fn bits() -> u32 { + 64 + } + + /// Helper function to get a positive value from unsigned number + fn from_uint(value: u64) -> Self { + // as the minimal value of I64 is -~I64::indent() (1 << 63) we should add ~I64::indent() (1 << 63) + let underlying: u64 = value + ~Self::indent(); + Self { underlying } + } + + /// The largest value that can be represented by this type, + pub fn max() -> Self { + Self { + underlying: ~u64::max(), + } + } + + /// The smallest value that can be represented by this integer type. + pub fn min() -> Self { + Self { + underlying: ~u64::min(), + } + } + + /// Helper function to get a negative value of unsigned number + pub fn neg_from(value: u64) -> Self { + Self { + underlying: ~Self::indent() - value, + } + } + + /// Initializes a new, zeroed I64. + pub fn new() -> Self { + Self { + underlying: ~Self::indent(), + } + } +} + +impl core::ops::Add for I64 { + /// Add a I64 to a I64. Panics on overflow. + fn add(self, other: Self) -> Self { + // subtract 1 << 63 to avoid double move + ~Self::from(self.underlying - ~Self::indent() + other.underlying) + } +} + +impl core::ops::Subtract for I64 { + /// Subtract a I64 from a I64. Panics of overflow. + fn subtract(self, other: Self) -> Self { + let mut res = ~Self::new(); + if self > other { + // add 1 << 63 to avoid loosing the move + res = ~Self::from(self.underlying - other.underlying + ~Self::indent()); + } else { + // subtract from 1 << 63 as we are getting a negative value + res = ~Self::from(~Self::indent() - (other.underlying - self.underlying)); + } + res + } +} + +impl core::ops::Multiply for I64 { + /// Multiply a I64 with a I64. Panics of overflow. + fn multiply(self, other: Self) -> Self { + let mut res = ~Self::new(); + if self.underlying >= ~Self::indent() + && other.underlying >= ~Self::indent() + { + res = ~Self::from((self.underlying - ~Self::indent()) * (other.underlying - ~Self::indent()) + ~Self::indent()); + } else if self.underlying < ~Self::indent() + && other.underlying < ~Self::indent() + { + res = ~Self::from((~Self::indent() - self.underlying) * (~Self::indent() - other.underlying) + ~Self::indent()); + } else if self.underlying >= ~Self::indent() + && other.underlying < ~Self::indent() + { + res = ~Self::from(~Self::indent() - (self.underlying - ~Self::indent()) * (~Self::indent() - other.underlying)); + } else if self.underlying < ~Self::indent() + && other.underlying >= ~Self::indent() + { + res = ~Self::from(~Self::indent() - (other.underlying - ~Self::indent()) * (~Self::indent() - self.underlying)); + } + res + } +} + +impl core::ops::Divide for I64 { + /// Divide a I64 by a I64. Panics if divisor is zero. + fn divide(self, divisor: Self) -> Self { + require(divisor != ~Self::new(), Error::ZeroDivisor); + let mut res = ~Self::new(); + if self.underlying >= ~Self::indent() + && divisor.underlying > ~Self::indent() + { + res = ~Self::from((self.underlying - ~Self::indent()) / (divisor.underlying - ~Self::indent()) + ~Self::indent()); + } else if self.underlying < ~Self::indent() + && divisor.underlying < ~Self::indent() + { + res = ~Self::from((~Self::indent() - self.underlying) / (~Self::indent() - divisor.underlying) + ~Self::indent()); + } else if self.underlying >= ~Self::indent() + && divisor.underlying < ~Self::indent() + { + res = ~Self::from(~Self::indent() - (self.underlying - ~Self::indent()) / (~Self::indent() - divisor.underlying)); + } else if self.underlying < ~Self::indent() + && divisor.underlying > ~Self::indent() + { + res = ~Self::from(~Self::indent() - (~Self::indent() - self.underlying) / (divisor.underlying - ~Self::indent())); + } + res + } +} + +impl TwosComplement for I64 { + fn twos_complement(self) -> Self { + let one = ~I64::from_uint(1u64); + let res = !self - one; + res + } +} diff --git a/sway_libs/src/signed_integers/i8.sw b/sway_libs/src/signed_integers/i8.sw new file mode 100644 index 00000000..22addf84 --- /dev/null +++ b/sway_libs/src/signed_integers/i8.sw @@ -0,0 +1,168 @@ +library i8; + +use core::num::*; +use ::signed_integers::common::Error; +use ::signed_integers::common::TwosComplement; + +/// The 8-bit signed integer type. +/// Represented as an underlying u8 value. +/// Actual value is underlying value minus 2 ^ 7 +/// Max value is 2 ^ 7 - 1, min value is - 2 ^ 7 +pub struct I8 { + underlying: u8, +} + +pub trait From { + /// Function for creating I8 from u8 + fn from(underlying: u8) -> Self; +} + +impl From for I8 { + /// Helper function to get a signed number from with an underlying + fn from(underlying: u8) -> Self { + Self { underlying } + } +} + +impl core::ops::Eq for I8 { + fn eq(self, other: Self) -> bool { + self.underlying == other.underlying + } +} + +impl core::ops::Ord for I8 { + fn gt(self, other: Self) -> bool { + self.underlying > other.underlying + } + + fn lt(self, other: Self) -> bool { + self.underlying < other.underlying + } +} + +impl I8 { + /// The underlying value that corresponds to zero signed value + pub fn indent() -> u8 { + 128u8 + } +} + +impl I8 { + /// The size of this type in bits. + pub fn bits() -> u32 { + 8 + } + + /// Helper function to get a positive value from unsigned number + fn from_uint(value: u8) -> Self { + let underlying: u8 = value + ~Self::indent(); // as the minimal value of I8 is -~I8::indent() (1 << 7) we should add ~I8::indent() (1 << 7) + Self { underlying } + } + + /// The largest value that can be represented by this type, + pub fn max() -> Self { + Self { + underlying: ~u8::max(), + } + } + + /// The smallest value that can be represented by this integer type. + pub fn min() -> Self { + Self { + underlying: ~u8::min(), + } + } + + /// Helper function to get a negative value of unsigned number + pub fn neg_from(value: u8) -> Self { + Self { + underlying: ~Self::indent() - value, + } + } + + /// Initializes a new, zeroed I8. + pub fn new() -> Self { + Self { + underlying: ~Self::indent(), + } + } +} + +impl core::ops::Add for I8 { + /// Add a I8 to a I8. Panics on overflow. + fn add(self, other: Self) -> Self { + ~Self::from(self.underlying - ~Self::indent() + other.underlying) // subtract 1 << 7 to avoid double move + } +} + +impl core::ops::Divide for I8 { + /// Divide a I8 by a I8. Panics if divisor is zero. + fn divide(self, divisor: Self) -> Self { + require(divisor != ~Self::new(), Error::ZeroDivisor); + let mut res = ~Self::new(); + if self.underlying >= ~Self::indent() + && divisor.underlying > ~Self::indent() + { + res = ~Self::from((self.underlying - ~Self::indent()) / (divisor.underlying - ~Self::indent()) + ~Self::indent()); + } else if self.underlying < ~Self::indent() + && divisor.underlying < ~Self::indent() + { + res = ~Self::from((~Self::indent() - self.underlying) / (~Self::indent() - divisor.underlying) + ~Self::indent()); + } else if self.underlying >= ~Self::indent() + && divisor.underlying < ~Self::indent() + { + res = ~Self::from(~Self::indent() - (self.underlying - ~Self::indent()) / (~Self::indent() - divisor.underlying)); + } else if self.underlying < ~Self::indent() + && divisor.underlying > ~Self::indent() + { + res = ~Self::from(~Self::indent() - (~Self::indent() - self.underlying) / (divisor.underlying - ~Self::indent())); + } + res + } +} + +impl core::ops::Multiply for I8 { + /// Multiply a I8 with a I8. Panics of overflow. + fn multiply(self, other: Self) -> Self { + let mut res = ~Self::new(); + if self.underlying >= ~Self::indent() + && other.underlying >= ~Self::indent() + { + res = ~Self::from((self.underlying - ~Self::indent()) * (other.underlying - ~Self::indent()) + ~Self::indent()); + } else if self.underlying < ~Self::indent() + && other.underlying < ~Self::indent() + { + res = ~Self::from((~Self::indent() - self.underlying) * (~Self::indent() - other.underlying) + ~Self::indent()); + } else if self.underlying >= ~Self::indent() + && other.underlying < ~Self::indent() + { + res = ~Self::from(~Self::indent() - (self.underlying - ~Self::indent()) * (~Self::indent() - other.underlying)); + } else if self.underlying < ~Self::indent() + && other.underlying >= ~Self::indent() + { + res = ~Self::from(~Self::indent() - (other.underlying - ~Self::indent()) * (~Self::indent() - self.underlying)); + } + res + } +} + +impl core::ops::Subtract for I8 { + /// Subtract a I8 from a I8. Panics of overflow. + fn subtract(self, other: Self) -> Self { + let mut res = ~Self::new(); + if self > other { + res = ~Self::from(self.underlying - other.underlying + ~Self::indent()); // add 1 << 7 to avoid loosing the move + } else { + res = ~Self::from(~Self::indent() - (other.underlying - self.underlying)); // subtract from 1 << 7 as we are getting a negative value + } + res + } +} + +impl TwosComplement for I8 { + fn twos_complement(self) -> Self { + let one = ~I8::from_uint(1u8); + let res = !self - one; + res + } +} diff --git a/sway_libs/src/signed_integers/signed_integers.sw b/sway_libs/src/signed_integers/signed_integers.sw new file mode 100644 index 00000000..df751464 --- /dev/null +++ b/sway_libs/src/signed_integers/signed_integers.sw @@ -0,0 +1,10 @@ +library signed_integers; + +dep common; + +dep i8; +dep i16; +dep i32; +dep i64; +dep i128; +dep i256; diff --git a/tests/src/test_projects/signed_integers/i128_test/.gitignore b/tests/src/test_projects/signed_integers/i128_test/.gitignore new file mode 100644 index 00000000..77d3844f --- /dev/null +++ b/tests/src/test_projects/signed_integers/i128_test/.gitignore @@ -0,0 +1,2 @@ +out +target diff --git a/tests/src/test_projects/signed_integers/i128_test/Forc.toml b/tests/src/test_projects/signed_integers/i128_test/Forc.toml new file mode 100644 index 00000000..5c815bc2 --- /dev/null +++ b/tests/src/test_projects/signed_integers/i128_test/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "i128_test" + +[dependencies] +sway_libs = { path = "../../../../../sway_libs" } diff --git a/tests/src/test_projects/signed_integers/i128_test/src/main.sw b/tests/src/test_projects/signed_integers/i128_test/src/main.sw new file mode 100644 index 00000000..59c7efbd --- /dev/null +++ b/tests/src/test_projects/signed_integers/i128_test/src/main.sw @@ -0,0 +1,64 @@ +script; + +use std::assert::assert; +use sway_libs::i128::I128; +use std::u128::U128; +use core::num::*; + +fn main() -> bool { + let u128_one = U128 { + upper: 0, + lower: 1, + }; + let u128_two = U128 { + upper: 0, + lower: 2, + }; + let one = ~I128::from_uint(u128_one); + let mut res = one + ~I128::from_uint(u128_one); + assert(res == ~I128::from_uint(u128_two)); + + let u128_10 = U128 { + upper: 0, + lower: 10, + }; + let u128_11 = U128 { + upper: 0, + lower: 11, + }; + res = ~I128::from_uint(u128_10) - ~I128::from_uint(u128_11); + assert(res.underlying.lower == ~u64::max()); + + res = ~I128::from_uint(u128_10) * ~I128::neg_from(u128_one); + assert(res == ~I128::neg_from(u128_10)); + + res = ~I128::from_uint(u128_10) * ~I128::from_uint(u128_10); + let u128_100 = U128 { + upper: 0, + lower: 100, + }; + assert(res == ~I128::from_uint(u128_100)); + + let u128_lower_max_u64 = U128 { + upper: 0, + lower: ~u64::max(), + }; + + res = ~I128::from_uint(u128_10) / ~I128::from(u128_lower_max_u64); + assert(res == ~I128::neg_from(u128_10)); + + let u128_5 = U128 { + upper: 0, + lower: 5, + }; + + let u128_2 = U128 { + upper: 0, + lower: 2, + }; + + res = ~I128::from_uint(u128_10) / ~I128::from_uint(u128_5); + assert(res == ~I128::from_uint(u128_2)); + + true +} diff --git a/tests/src/test_projects/signed_integers/i16_test/.gitignore b/tests/src/test_projects/signed_integers/i16_test/.gitignore new file mode 100644 index 00000000..77d3844f --- /dev/null +++ b/tests/src/test_projects/signed_integers/i16_test/.gitignore @@ -0,0 +1,2 @@ +out +target diff --git a/tests/src/test_projects/signed_integers/i16_test/Forc.toml b/tests/src/test_projects/signed_integers/i16_test/Forc.toml new file mode 100644 index 00000000..06eae41f --- /dev/null +++ b/tests/src/test_projects/signed_integers/i16_test/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "i16_test" + +[dependencies] +sway_libs = { path = "../../../../../sway_libs" } diff --git a/tests/src/test_projects/signed_integers/i16_test/src/main.sw b/tests/src/test_projects/signed_integers/i16_test/src/main.sw new file mode 100644 index 00000000..280b601d --- /dev/null +++ b/tests/src/test_projects/signed_integers/i16_test/src/main.sw @@ -0,0 +1,27 @@ +script; + +use std::assert::assert; +use std::i16::I16; + +fn main() -> bool { + let one = ~I16::from_uint(1u16); + let mut res = one + ~I16::from_uint(1u16); + assert(res == ~I16::from_uint(2u16)); + + res = ~I16::from_uint(10u16) - ~I16::from_uint(11u16); + assert(res == ~I16::from(32767u16)); + + res = ~I16::from_uint(10u16) * ~I16::neg_from(1u16); + assert(res == ~I16::neg_from(10u16)); + + res = ~I16::from_uint(10u16) * ~I16::from_uint(10u16); + assert(res == ~I16::from_uint(100u16)); + + res = ~I16::from_uint(10u16) / ~I16::neg_from(1u16); + assert(res == ~I16::neg_from(10u16)); + + res = ~I16::from_uint(10u16) / ~I16::from_uint(5u16); + assert(res == ~I16::from_uint(2u16)); + + true +} diff --git a/tests/src/test_projects/signed_integers/i256_test/.gitignore b/tests/src/test_projects/signed_integers/i256_test/.gitignore new file mode 100644 index 00000000..77d3844f --- /dev/null +++ b/tests/src/test_projects/signed_integers/i256_test/.gitignore @@ -0,0 +1,2 @@ +out +target diff --git a/tests/src/test_projects/signed_integers/i256_test/Forc.toml b/tests/src/test_projects/signed_integers/i256_test/Forc.toml new file mode 100644 index 00000000..57489f19 --- /dev/null +++ b/tests/src/test_projects/signed_integers/i256_test/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "i256_test" + +[dependencies] +sway_libs = { path = "../../../../../sway_libs" } diff --git a/tests/src/test_projects/signed_integers/i256_test/src/main.sw b/tests/src/test_projects/signed_integers/i256_test/src/main.sw new file mode 100644 index 00000000..0ece77d2 --- /dev/null +++ b/tests/src/test_projects/signed_integers/i256_test/src/main.sw @@ -0,0 +1,81 @@ +script; + +use std::assert::assert; +use sway_libs::i256::I256; +use std::u256::U256; +use core::num::*; + +fn main() -> bool { + let u128_one = U256 { + a: 0, + b: 0, + c: 0, + d: 1, + }; + let u128_two = U256 { + a: 0, + b: 0, + c: 0, + d: 2, + }; + let one = ~I256::from_uint(u128_one); + let mut res = one + ~I256::from_uint(u128_one); + assert(res == ~I256::from_uint(u128_two)); + + let u128_10 = U256 { + a: 0, + b: 0, + c: 0, + d: 10, + }; + let u128_11 = U256 { + a: 0, + b: 0, + c: 0, + d: 11, + }; + res = ~I256::from_uint(u128_10) - ~I256::from_uint(u128_11); + assert(res.underlying.c == ~u64::max()); + assert(res.underlying.d == ~u64::max()); + + res = ~I256::from_uint(u128_10) * ~I256::neg_from(u128_one); + assert(res == ~I256::neg_from(u128_10)); + + res = ~I256::from_uint(u128_10) * ~I256::from_uint(u128_10); + let u128_100 = U256 { + a: 0, + b: 0, + c: 0, + d: 100, + }; + assert(res == ~I256::from_uint(u128_100)); + + let u128_lower_max_u64 = U256 { + a: 0, + b: 0, + c: 0, + d: ~u64::max(), + }; + + res = ~I256::from_uint(u128_10) / ~I256::from(u128_lower_max_u64); + assert(res == ~I256::neg_from(u128_10)); + + let u128_5 = U256 { + a: 0, + b: 0, + c: 0, + d: 5, + }; + + let u128_2 = U256 { + a: 0, + b: 0, + c: 0, + d: 2, + }; + + res = ~I256::from_uint(u128_10) / ~I256::from_uint(u128_5); + assert(res == ~I256::from_uint(u128_2)); + + true +} diff --git a/tests/src/test_projects/signed_integers/i32_test/.gitignore b/tests/src/test_projects/signed_integers/i32_test/.gitignore new file mode 100644 index 00000000..77d3844f --- /dev/null +++ b/tests/src/test_projects/signed_integers/i32_test/.gitignore @@ -0,0 +1,2 @@ +out +target diff --git a/tests/src/test_projects/signed_integers/i32_test/Forc.toml b/tests/src/test_projects/signed_integers/i32_test/Forc.toml new file mode 100644 index 00000000..78b60362 --- /dev/null +++ b/tests/src/test_projects/signed_integers/i32_test/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "i32_test" + +[dependencies] +sway_libs = { path = "../../../../../sway_libs" } diff --git a/tests/src/test_projects/signed_integers/i32_test/src/main.sw b/tests/src/test_projects/signed_integers/i32_test/src/main.sw new file mode 100644 index 00000000..4d3d4efa --- /dev/null +++ b/tests/src/test_projects/signed_integers/i32_test/src/main.sw @@ -0,0 +1,27 @@ +script; + +use std::assert::assert; +use sway_libs::i32::I32; + +fn main() -> bool { + let one = ~I32::from_uint(1u32); + let mut res = one + ~I32::from_uint(1u32); + assert(res == ~I32::from_uint(2u32)); + + res = ~I32::from_uint(10u32) - ~I32::from_uint(11u32); + assert(res == ~I32::from(2147483647u32)); + + res = ~I32::from_uint(10u32) * ~I32::neg_from(1u32); + assert(res == ~I32::neg_from(10u32)); + + res = ~I32::from_uint(10u32) * ~I32::from_uint(10u32); + assert(res == ~I32::from_uint(100u32)); + + res = ~I32::from_uint(10u32) / ~I32::neg_from(1u32); + assert(res == ~I32::neg_from(10u32)); + + res = ~I32::from_uint(10u32) / ~I32::from_uint(5u32); + assert(res == ~I32::from_uint(2u32)); + + true +} diff --git a/tests/src/test_projects/signed_integers/i64_test/.gitignore b/tests/src/test_projects/signed_integers/i64_test/.gitignore new file mode 100644 index 00000000..77d3844f --- /dev/null +++ b/tests/src/test_projects/signed_integers/i64_test/.gitignore @@ -0,0 +1,2 @@ +out +target diff --git a/tests/src/test_projects/signed_integers/i64_test/Forc.toml b/tests/src/test_projects/signed_integers/i64_test/Forc.toml new file mode 100644 index 00000000..fc62ab1b --- /dev/null +++ b/tests/src/test_projects/signed_integers/i64_test/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "i64_test" + +[dependencies] +sway_libs = { path = "../../../../../sway_libs" } diff --git a/tests/src/test_projects/signed_integers/i64_test/src/main.sw b/tests/src/test_projects/signed_integers/i64_test/src/main.sw new file mode 100644 index 00000000..a4df2988 --- /dev/null +++ b/tests/src/test_projects/signed_integers/i64_test/src/main.sw @@ -0,0 +1,27 @@ +script; + +use std::assert::assert; +use sway_libs::i64::I64; + +fn main() -> bool { + let one = ~I64::from_uint(1u64); + let mut res = one + ~I64::from_uint(1u64); + assert(res == ~I64::from_uint(2u64)); + + res = ~I64::from_uint(10u64) - ~I64::from_uint(11u64); + assert(res == ~I64::from(9223372036854775807u64)); + + res = ~I64::from_uint(10u64) * ~I64::neg_from(1); + assert(res == ~I64::neg_from(10)); + + res = ~I64::from_uint(10u64) * ~I64::from_uint(10u64); + assert(res == ~I64::from_uint(100u64)); + + res = ~I64::from_uint(10u64) / ~I64::from(9223372036854775807u64); + assert(res == ~I64::neg_from(10u64)); + + res = ~I64::from_uint(10u64) / ~I64::from_uint(5u64); + assert(res == ~I64::from_uint(2u64)); + + true +} diff --git a/tests/src/test_projects/signed_integers/i8_test/.gitignore b/tests/src/test_projects/signed_integers/i8_test/.gitignore new file mode 100644 index 00000000..77d3844f --- /dev/null +++ b/tests/src/test_projects/signed_integers/i8_test/.gitignore @@ -0,0 +1,2 @@ +out +target diff --git a/tests/src/test_projects/signed_integers/i8_test/Forc.toml b/tests/src/test_projects/signed_integers/i8_test/Forc.toml new file mode 100644 index 00000000..f4b83f1e --- /dev/null +++ b/tests/src/test_projects/signed_integers/i8_test/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "i8_test" + +[dependencies] +sway_libs = { path = "../../../../../sway_libs" } diff --git a/tests/src/test_projects/signed_integers/i8_test/src/main.sw b/tests/src/test_projects/signed_integers/i8_test/src/main.sw new file mode 100644 index 00000000..b1f42009 --- /dev/null +++ b/tests/src/test_projects/signed_integers/i8_test/src/main.sw @@ -0,0 +1,27 @@ +script; + +use std::assert::assert; +use sway_libs::i8::I8; + +fn main() -> bool { + let one = ~I8::from_uint(1u8); + let mut res = one + ~I8::from_uint(1u8); + assert(res == ~I8::from_uint(2u8)); + + res = ~I8::from_uint(10u8) - ~I8::from_uint(11u8); + assert(res == ~I8::from(127u8)); + + res = ~I8::from_uint(10u8) * ~I8::from(127u8); + assert(res == ~I8::from(118u8)); + + res = ~I8::from_uint(10u8) * ~I8::from_uint(10u8); + assert(res == ~I8::from_uint(100u8)); + + res = ~I8::from_uint(10u8) / ~I8::from(127u8); + assert(res == ~I8::from(118u8)); + + res = ~I8::from_uint(10u8) / ~I8::from_uint(5u8); + assert(res == ~I8::from_uint(2u8)); + + true +} diff --git a/tests/src/test_projects/signed_integers/twos_complement_test/.gitignore b/tests/src/test_projects/signed_integers/twos_complement_test/.gitignore new file mode 100644 index 00000000..77d3844f --- /dev/null +++ b/tests/src/test_projects/signed_integers/twos_complement_test/.gitignore @@ -0,0 +1,2 @@ +out +target diff --git a/tests/src/test_projects/signed_integers/twos_complement_test/Forc.toml b/tests/src/test_projects/signed_integers/twos_complement_test/Forc.toml new file mode 100644 index 00000000..8dc1ea82 --- /dev/null +++ b/tests/src/test_projects/signed_integers/twos_complement_test/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "twos_complement_test" + +[dependencies] +sway_libs = { path = "../../../../../sway_libs" } diff --git a/tests/src/test_projects/signed_integers/twos_complement_test/src/main.sw b/tests/src/test_projects/signed_integers/twos_complement_test/src/main.sw new file mode 100644 index 00000000..d0133b20 --- /dev/null +++ b/tests/src/test_projects/signed_integers/twos_complement_test/src/main.sw @@ -0,0 +1,60 @@ +script; + +use std::assert::assert; +use sway_libs::i8::I8; +use std::i16::I16; +use sway_libs::i32::I32; +use sway_libs::i64::I64; +use sway_libs::i128::I128; +use std::u128::U128; +use sway_libs::i256::I256; +use std::u256::U256; +use core::num::*; + +fn main() -> bool { + let one_i8 = ~I8::from_uint(1u8); + let mut res_i8 = one.twos_complement(); + assert(res_i8 == ~I8::from_uint(2u8)); + + let one = ~I16::from_uint(1u16); + let mut res_i16 = one.twos_complement(); + assert(res_i16 == ~I16::from_uint(2u16)); + + let one = ~I32::from_uint(1u32); + let mut res_i32 = one.twos_complement(); + assert(res_i32 == ~I32::from_uint(2u32)); + + let one = ~I64::from_uint(1u64); + let mut res_i64 = one.twos_complement(); + assert(res_i64 == ~I64::from_uint(2u64)); + + let u128_one = U128 { + upper: 0, + lower: 1, + }; + let u128_two = U128 { + upper: 0, + lower: 2, + }; + let one = ~I128::from_uint(u128_one); + let mut res_i128 = one.twos_complement(); + assert(res_i128 == ~I128::from_uint(u128_two)); + + let u256_one = U256 { + a: 0, + b: 0, + c: 0, + d: 1, + }; + let u256_two = U256 { + a: 0, + b: 0, + c: 0, + d: 2, + }; + let one = ~I256::from_uint(u128_one); + let mut res_i256 = one.twos_complement(); + assert(res_i256 == ~I256::from_uint(u128_two)); + + true +}