u256 math module example

This commit is contained in:
vms 2021-06-01 20:54:28 +03:00
parent f5e6c88270
commit 8dd889b333
4 changed files with 145 additions and 78 deletions

View File

@ -15,5 +15,7 @@ path = "src/main.rs"
fluence = "0.6.9"
ethnum = "1.0.3"
thiserror = "1.0.25"
[dev-dependencies]
fluence-test = "0.1.9"

28
math/src/errors.rs Normal file
View File

@ -0,0 +1,28 @@
/*
* Copyright 2021 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use thiserror::Error as ThisError;
use std::num::ParseIntError;
#[derive(ThisError, Debug)]
pub enum U256Error {
#[error("an overflow is occured")]
U256Overflow,
#[error("{0}")]
ParseError(#[from] ParseIntError),
}

View File

@ -16,7 +16,24 @@
* limitations under the License.
*/
use ethnum::*;
#![warn(rust_2018_idioms)]
#![deny(
dead_code,
nonstandard_style,
unused_imports,
unused_mut,
unused_variables,
unused_unsafe,
unreachable_patterns
)]
mod errors;
mod result;
use errors::U256Error;
use result::U256Result;
use ethnum::u256;
use fluence::marine;
use fluence::module_manifest;
@ -24,104 +41,69 @@ module_manifest!();
pub fn main() {}
/// Result<u256, MathError: ToPrimitive + FromPrimitive> like
#[marine]
pub struct MathResult {
/// u256 string representation
pub u256: String,
pub ret_code: u8,
/// error string representation
pub err_msg: String,
}
mod math_result {
use ethnum::u256;
use crate::MathResult;
pub fn ok(ok: u256) -> MathResult {
MathResult {
u256: ok.to_string(),
ret_code: 0,
err_msg: Default::default(),
}
}
pub fn err(err: &str) -> MathResult {
MathResult {
u256: Default::default(),
ret_code: 1,
err_msg: err.to_string(),
}
}
}
use math_result::{err, ok};
use std::convert::identity;
use U256Error::U256Overflow;
/// adds 2 256 bits integers (ETH compatible)
/// return number or error (failed to parse input or overflow of output)
#[marine]
pub fn add_u256(number_1: String, number_2: String) -> MathResult {
let number_1 = number_1.parse::<u256>();
let number_2 = number_2.parse::<u256>();
if let (Ok(number_1), Ok(number_2)) = (number_1, number_2) {
let number = number_1.checked_add(number_2);
if let Some(number) = number {
return ok(number);
}
pub fn add_u256(lhs: String, rhs: String) -> U256Result {
add_u256_impl(lhs, rhs)
.map_err(Into::into)
.unwrap_or_else(identity)
}
return err("Overflow");
}
pub fn add_u256_impl(lhs: String, rhs: String) -> Result<U256Result, U256Error> {
let lhs = lhs.parse::<u256>()?;
let rhs = rhs.parse::<u256>()?;
let result = lhs.checked_add(rhs).ok_or_else(|| U256Overflow)?;
err("InputNonAU256Number")
Ok(U256Result::from_u256(result))
}
#[marine]
pub fn sub_u256(number_1: String, number_2: String) -> MathResult {
let number_1 = number_1.parse::<u256>();
let number_2 = number_2.parse::<u256>();
if let (Ok(number_1), Ok(number_2)) = (number_1, number_2) {
let number = number_1.checked_sub(number_2);
if let Some(number) = number {
return ok(number);
}
pub fn sub_u256(lhs: String, rhs: String) -> U256Result {
sub_u256_impl(lhs, rhs)
.map_err(Into::into)
.unwrap_or_else(identity)
}
return err("Underflow");
}
pub fn sub_u256_impl(lhs: String, rhs: String) -> Result<U256Result, U256Error> {
let lhs = lhs.parse::<u256>()?;
let rhs = rhs.parse::<u256>()?;
let result = lhs.checked_sub(rhs).ok_or_else(|| U256Overflow)?;
err("InputNonAU256Number")
Ok(U256Result::from_u256(result))
}
#[marine]
pub fn mul_u256(number_1: String, number_2: String) -> MathResult {
let number_1 = number_1.parse::<u256>();
let number_2 = number_2.parse::<u256>();
if let (Ok(number_1), Ok(number_2)) = (number_1, number_2) {
let number = number_1.checked_mul(number_2);
if let Some(number) = number {
return ok(number);
}
pub fn mul_u256(lhs: String, rhs: String) -> U256Result {
mul_u256_impl(lhs, rhs)
.map_err(Into::into)
.unwrap_or_else(identity)
}
return err("Overflow");
}
pub fn mul_u256_impl(lhs: String, rhs: String) -> Result<U256Result, U256Error> {
let lhs = lhs.parse::<u256>()?;
let rhs = rhs.parse::<u256>()?;
let result = lhs.checked_mul(rhs).ok_or_else(|| U256Overflow)?;
err("InputNonAU256Number")
Ok(U256Result::from_u256(result))
}
#[marine]
pub fn div_u256(number_1: String, number_2: String) -> MathResult {
let number_1 = number_1.parse::<u256>();
let number_2 = number_2.parse::<u256>();
if let (Ok(number_1), Ok(number_2)) = (number_1, number_2) {
let number = number_1.checked_div(number_2);
if let Some(number) = number {
return ok(number);
}
pub fn div_u256(lhs: String, rhs: String) -> U256Result {
div_u256_impl(lhs, rhs)
.map_err(Into::into)
.unwrap_or_else(identity)
}
return err("DivisionByZero");
}
pub fn div_u256_impl(lhs: String, rhs: String) -> Result<U256Result, U256Error> {
let lhs = lhs.parse::<u256>()?;
let rhs = rhs.parse::<u256>()?;
let result = lhs.checked_div(rhs).ok_or_else(|| U256Overflow)?;
err("InputNonAU256Number")
Ok(U256Result::from_u256(result))
}
#[cfg(test)]

55
math/src/result.rs Normal file
View File

@ -0,0 +1,55 @@
/*
* Copyright 2021 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use crate::errors::U256Error;
use ethnum::u256;
use fluence::marine;
#[marine]
#[derive(Default, Debug)]
pub struct U256Result {
/// u256 string representation
pub value: String,
pub ret_code: u8,
/// contains error as a string
pub err_msg: String,
}
impl U256Result {
pub(crate) fn from_u256(value: u256) -> Self {
Self {
value: value.to_string(),
ret_code: 0, // 0 means success
err_msg: <_>::default(),
}
}
}
impl From<U256Error> for U256Result {
fn from(e: U256Error) -> Self {
let ret_code = match e {
U256Error::ParseError(_) => 1,
U256Error::U256Overflow => 2,
};
Self {
ret_code,
err_msg: e.to_string(),
..<_>::default()
}
}
}