Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,7 @@ tokio = { version = "1.12.0", features = ["full"] } # for our async runtime
tokio-test = "*"
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
bech32 = "0.9.0"

regex = "1" # regular expressions support
lazy_static = "1.4.0"
num-bigint = "0.4.3"
[dev-dependencies]
3 changes: 2 additions & 1 deletion src/core/auth/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
pub mod strings;
pub mod strings;
pub mod numeric;
192 changes: 192 additions & 0 deletions src/core/auth/numeric.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
use std::ops::{ Add, Sub, Mul, Div };
use std::fmt;
use regex::*;
use lazy_static::lazy_static;
use crate::core::errors::SecretError;

/*
The goal of this is to be able to use the Dec type with normal operators.
TODO: Figure out how to do that, what do the rust operators call
*/

const DEC_NUM_DIGITS: i128 = 18;
const DEC_ONE: i128 = 10_i128.pow(18_u32);

pub enum Number {
Str(&'static str),
Int(i32),
Float(f32),
}

pub fn convert_to_dec_bignum(arg: Number) -> Result<i128, SecretError> {
// TODO: Better Error messages
match arg {
Number::Str(str) => {
return match from_str(str) {
Some(BigInt) => Ok(BigInt),
None => Err(SecretError::Error("Error: Invalid String Input".to_string()))
}
},
Number::Float(float) => {
let float_string = float.to_string();
return match from_str(&float_string) {
Some(BigInt) => Ok(BigInt),
None => Err(SecretError::Error("Error: Invalid Float Input".to_string()))
}
}
Number::Int(int) => { return Ok(int as i128 * DEC_ONE) }
}

fn from_str(arg: &str) -> Option<i128> {
lazy_static! {
static ref RE: Regex = Regex::new(r"^(\-)?(\d+)(\.(\d+))?\Z").unwrap();
}
let parts = RE.captures(arg)?;
let mut result: i128 = parts.get(2)?
.as_str()
.trim()
.parse::<i128>()
.expect("Invalid String: NAN") * DEC_ONE;
if let Some(_) = parts.get(3) {
let fraction: i128 = parts.get(4)?
.as_str()
.trim() // TODO: slice
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be a string slice according to the python library, but I can't figure out a way to index an &str. See if you can figure it out

.parse::<i128>()
.expect("Invalid String: NAN");
result += fraction;
}
if let Some(_) = parts.get(1) {
result *= -1;
}
return Some(result as i128);
}
}

fn chop_precision_and_round(d: i128) -> i128 {
if d < 0 {
return -1 * chop_precision_and_round(d * -1);
}

let quo: i128 = d / DEC_ONE;
let rem: i128 = d % DEC_ONE;

if rem == 0 {
return quo;
}

if rem < DEC_ONE / 2 {
return quo;
} else if rem > DEC_ONE / 2 {
return quo + 1;
} else {
if quo % 2 == 0 {
return quo;
}
return quo;
}
}


#[derive(Default)]
pub struct Dec {
i: i128,
}

impl Dec {

pub fn from(arg: Number) -> Result<Dec, SecretError> {
Ok(Dec { i: convert_to_dec_bignum(arg)?, })
}

pub fn zero() -> Result<Dec, SecretError> { Dec::from(Number::Int(0)) }

pub fn one() -> Result<Dec, SecretError> { Dec::from(Number::Int(1)) }

pub fn whole(&self) -> String {
format!("{}", self.i.abs() / DEC_ONE)
}

pub fn frac(&self) -> String {
format!("{}", self.i.abs() % DEC_ONE).trim().to_string()
}

pub fn parity(&self) -> i32 {
if self.i < 0 { -1 } else { 1 }
}

pub fn add_dec(&self, addend: Dec) -> i128 {
self.i + addend.i
}

pub fn sub_dec(&self, subtrahend: Dec) -> i128 {
self.i - subtrahend.i
}

pub fn mul_dec(&self, multiplier: Dec) -> i128 {
let x = self.i;
let y = multiplier.i;
chop_precision_and_round(x * y)
}

pub fn div_dec(&self, divisor: Dec) -> i128 {
if divisor.i == 0 {
panic!("Error: Tried to divide by 0 for {} / {}", self.i, divisor.i);
} else {
chop_precision_and_round((self.i * DEC_ONE * DEC_ONE) / divisor.i)
}
}


// traits to implement: Add, Sub, Mul, Div
}

impl fmt::Display for Dec {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.i == 0 {
write!(f, "{}", "0.".to_owned() + &"0".repeat(DEC_NUM_DIGITS as usize));
}
let parity = if self.i > 0 { "-" } else { "" };
write!(f, "{}{}.{}", parity, self.whole(), self.frac())
}

}

impl Add for Dec {
type Output = Self;

fn add(self, addend: Self) -> Self {
Self {
i: self.add_dec(addend),
}
}
}

impl Sub for Dec {
type Output = Self;

fn sub(self, addend: Self) -> Self {
Self {
i: self.sub_dec(addend),
}
}
}

impl Mul for Dec {
type Output = Self;

fn mul(self, multiplier: Self) -> Self {
Self {
i: self.mul_dec(multiplier),
}
}
}

impl Div for Dec {
type Output = Self;

fn div(self, multiplier: Self) -> Self {
Self {
i: self.div_dec(multiplier),
}
}
}
3 changes: 2 additions & 1 deletion src/core/errors.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#[derive(Debug)]
pub enum SecretError {
Bech32Error(String),
Error(String),
}
}