extern crate num;
extern crate serde;
extern crate serde_json;
#[macro_use] extern crate lazy_static;
#[macro_use]
#[cfg(feature = "postgres")]
extern crate postgres as pg_crate;
#[cfg(feature = "postgres")]
mod postgres;
mod serde_types;
use std::ops::{Add, Div, Mul, Rem, Sub};
use std::str::FromStr;
use std::iter::repeat;
use std::cmp::*;
use std::cmp::Ordering::Equal;
use num::{BigInt, BigUint, FromPrimitive, Integer, One, ToPrimitive, Zero};
use num::bigint::Sign::{Minus, Plus};
#[allow(overflowing_literals)]
const SIGN_MASK: i32 = 0x80000000;
const SCALE_MASK: i32 = 0x00FF0000;
const U8_MASK: i32 = 0x000000FF;
const I32_MASK: i64 = 0xFFFFFFFF;
const SCALE_SHIFT: i32 = 16;
const MAX_PRECISION: u32 = 28;
const MAX_BYTES: usize = 12;
const MAX_BITS: usize = 96;
lazy_static! {
static ref MIN: Decimal = Decimal { flags: -2147483648, lo: -1, mid: -1, hi: -1 };
static ref MAX: Decimal = Decimal { flags: 0, lo: -1, mid: -1, hi: -1 };
}
static POWERS_10: &'static [u32; 10] = &[1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000];
static BIG_POWERS_10: &'static [u64; 10] = &[10000000000,
100000000000,
1000000000000,
10000000000000,
100000000000000,
1000000000000000,
10000000000000000,
100000000000000000,
1000000000000000000,
10000000000000000000];
#[derive(Clone, Debug, Copy)]
pub struct Decimal {
flags: i32,
hi: i32,
lo: i32,
mid: i32
}
#[allow(dead_code)]
impl Decimal {
pub fn new(num: i64, scale: u32) -> Decimal {
if scale > MAX_PRECISION {
panic!("Scale exceeds the maximum precision allowed");
}
let flags: i32 = (scale as i32) << SCALE_SHIFT;
if num < 0 {
return Decimal {
flags: flags & SIGN_MASK,
hi: 0,
lo: (num & I32_MASK) as i32,
mid: ((num.abs() >> 32) & I32_MASK) as i32
};
}
Decimal {
flags: flags,
hi: 0,
lo: (num & I32_MASK) as i32,
mid: ((num >> 32) & I32_MASK) as i32
}
}
pub fn scale(&self) -> u32 {
((self.flags & SCALE_MASK) >> SCALE_SHIFT) as u32
}
pub fn set_sign(&mut self, positive: bool) {
if positive {
if self.is_negative() {
self.flags ^= SIGN_MASK;
}
} else {
self.flags |= SIGN_MASK;
}
}
pub fn unsigned_bytes_le(&self) -> Vec<u8> {
return vec![(self.lo & U8_MASK) as u8,
((self.lo >> 8) & U8_MASK) as u8,
((self.lo >> 16) & U8_MASK) as u8,
((self.lo >> 24) & U8_MASK) as u8,
(self.mid & U8_MASK) as u8,
((self.mid >> 8) & U8_MASK) as u8,
((self.mid >> 16) & U8_MASK) as u8,
((self.mid >> 24) & U8_MASK) as u8,
(self.hi & U8_MASK) as u8,
((self.hi >> 8) & U8_MASK) as u8,
((self.hi >> 16) & U8_MASK) as u8,
((self.hi >> 24) & U8_MASK) as u8];
}
pub fn serialize(&self) -> [u8; 16] {
[(self.flags & U8_MASK) as u8,
((self.flags >> 8) & U8_MASK) as u8,
((self.flags >> 16) & U8_MASK) as u8,
((self.flags >> 24) & U8_MASK) as u8,
(self.lo & U8_MASK) as u8,
((self.lo >> 8) & U8_MASK) as u8,
((self.lo >> 16) & U8_MASK) as u8,
((self.lo >> 24) & U8_MASK) as u8,
(self.mid & U8_MASK) as u8,
((self.mid >> 8) & U8_MASK) as u8,
((self.mid >> 16) & U8_MASK) as u8,
((self.mid >> 24) & U8_MASK) as u8,
(self.hi & U8_MASK) as u8,
((self.hi >> 8) & U8_MASK) as u8,
((self.hi >> 16) & U8_MASK) as u8,
((self.hi >> 24) & U8_MASK) as u8]
}
pub fn deserialize(bytes: [u8; 16]) -> Decimal {
Decimal {
flags: (bytes[0] as i32) | (bytes[1] as i32) << 8 | (bytes[2] as i32) << 16 | (bytes[3] as i32) << 24,
lo: (bytes[4] as i32) | (bytes[5] as i32) << 8 | (bytes[6] as i32) << 16 | (bytes[7] as i32) << 24,
mid: (bytes[8] as i32) | (bytes[9] as i32) << 8 | (bytes[10] as i32) << 16 | (bytes[11] as i32) << 24,
hi: (bytes[12] as i32) | (bytes[13] as i32) << 8 | (bytes[14] as i32) << 16 | (bytes[15] as i32) << 24
}
}
pub fn is_negative(&self) -> bool {
self.flags < 0
}
pub fn is_positive(&self) -> bool {
self.flags >= 0
}
pub fn min_value() -> Decimal {
*MIN
}
pub fn max_value() -> Decimal {
*MAX
}
pub fn round(&self) -> Decimal {
self.round_dp(0)
}
pub fn round_dp(&self, dp: u32) -> Decimal {
let old_scale = self.scale();
if dp < old_scale && dp < 20 { if self.is_zero() {
return self.rescale(dp);
}
let index = dp as usize;
let power10 = if dp < 10 {
Decimal::from_u32(POWERS_10[index]).unwrap()
} else {
Decimal::from_u64(BIG_POWERS_10[index - 10]).unwrap()
};
let mut value = self.mul(power10);
let raw = self.to_biguint();
let offset = self.rescale(dp).rescale(old_scale).to_biguint();
let decimal_portion = raw - offset;
value = value.rescale(0u32);
let mut cap = BigUint::from_u32(5u32).unwrap();
for _ in 0..(old_scale - dp - 1) {
cap = cap.mul(BigUint::from_u32(10u32).unwrap());
}
if decimal_portion == cap {
let even_or_odd = value.rem(Decimal::from_u32(2u32).unwrap());
if !even_or_odd.is_zero() {
value = value.add(Decimal::one());
}
} else if decimal_portion > cap {
if self.is_negative() {
value = value.sub(Decimal::one());
} else {
value = value.add(Decimal::one());
}
}
value.div(power10)
} else {
*self
}
}
fn rescale(&self, exp: u32) -> Decimal {
if exp > MAX_PRECISION {
panic!("Cannot have an exponent greater than {}", MAX_PRECISION);
}
let diff = exp as i32 - self.scale() as i32;
if diff == 0 {
return *self;
}
let unsigned = self.to_biguint();
let result: BigUint;
let index = diff.abs() as usize;
if diff > 0 {
if index < 10 {
result = unsigned * BigUint::from_u32(POWERS_10[index]).unwrap();
} else if index < 20 {
result = unsigned * BigUint::from_u64(BIG_POWERS_10[index - 10]).unwrap();
} else {
let u32_index = index - 19; let exponent = BigUint::from_u64(BIG_POWERS_10[9]).unwrap() *
BigUint::from_u32(POWERS_10[u32_index]).unwrap();
result = unsigned * exponent;
}
} else {
if index < 10 {
result = unsigned / BigUint::from_u32(POWERS_10[index]).unwrap();
} else if index < 20 {
result = unsigned / BigUint::from_u64(BIG_POWERS_10[index - 10]).unwrap();
} else {
let u32_index = index - 19; let exponent = BigUint::from_u64(BIG_POWERS_10[9]).unwrap() *
BigUint::from_u32(POWERS_10[u32_index]).unwrap();
result = unsigned / exponent;
}
}
let bytes = result.to_bytes_le();
Decimal::from_bytes_le(bytes, exp, self.is_negative())
}
fn to_biguint(&self) -> BigUint {
let bytes = self.unsigned_bytes_le();
BigUint::from_bytes_le(&bytes[..])
}
fn to_bigint(&self) -> BigInt {
let bytes = self.unsigned_bytes_le();
let sign = if self.is_negative() {
Minus
} else {
Plus
};
BigInt::from_bytes_le(sign, &bytes[..])
}
fn from_biguint(res: BigUint, scale: u32, negative: bool) -> Result<Decimal, &'static str> {
let bytes = res.to_bytes_le();
if bytes.len() > MAX_BYTES {
return Err("Decimal Overflow");
}
if scale > MAX_PRECISION {
return Err("Scale exceeds maximum precision");
}
Ok(Decimal::from_bytes_le(bytes, scale, negative))
}
fn from_bytes_le(bytes: Vec<u8>, scale: u32, negative: bool) -> Decimal {
let mut flags = 0i32;
let mut lo = 0i32;
let mut mid = 0i32;
let mut hi = 0i32;
if scale > 0 {
flags = (scale as i32) << SCALE_SHIFT;
}
if negative {
flags |= SIGN_MASK;
}
if bytes.len() > MAX_BYTES {
panic!("Decimal Overflow");
}
let mut pos = 0;
for b in bytes {
if pos < 4 {
lo |= (b as i32) << (pos * 8);
} else if pos < 8 {
mid |= (b as i32) << ((pos - 4) * 8);
} else {
hi |= (b as i32) << ((pos - 8) * 8);
}
pos += 1;
}
Decimal {
flags: flags,
hi: hi,
lo: lo,
mid: mid
}
}
}
pub trait ToDecimal {
fn to_decimal(&self) -> Option<Decimal>;
}
macro_rules! impl_to_decimal {
($T:ty, $from_ty:path) => {
impl ToDecimal for $T {
#[inline]
fn to_decimal(&self) -> Option<Decimal> {
$from_ty(*self)
}
}
}
}
impl_to_decimal!(isize, FromPrimitive::from_isize);
impl_to_decimal!(i8, FromPrimitive::from_i8);
impl_to_decimal!(i16, FromPrimitive::from_i16);
impl_to_decimal!(i32, FromPrimitive::from_i32);
impl_to_decimal!(i64, FromPrimitive::from_i64);
impl_to_decimal!(usize, FromPrimitive::from_usize);
impl_to_decimal!(u8, FromPrimitive::from_u8);
impl_to_decimal!(u16, FromPrimitive::from_u16);
impl_to_decimal!(u32, FromPrimitive::from_u32);
impl_to_decimal!(u64, FromPrimitive::from_u64);
macro_rules! forward_val_val_binop {
(impl $imp:ident for $res:ty, $method:ident) => {
impl $imp<$res> for $res {
type Output = $res;
#[inline]
fn $method(self, other: $res) -> $res {
(&self).$method(&other)
}
}
}
}
macro_rules! forward_ref_val_binop {
(impl $imp:ident for $res:ty, $method:ident) => {
impl<'a> $imp<$res> for &'a $res {
type Output = $res;
#[inline]
fn $method(self, other: $res) -> $res {
self.$method(&other)
}
}
}
}
macro_rules! forward_val_ref_binop {
(impl $imp:ident for $res:ty, $method:ident) => {
impl<'a> $imp<&'a $res> for $res {
type Output = $res;
#[inline]
fn $method(self, other: &$res) -> $res {
(&self).$method(other)
}
}
}
}
macro_rules! forward_all_binop {
(impl $imp:ident for $res:ty, $method:ident) => {
forward_val_val_binop!(impl $imp for $res, $method);
forward_ref_val_binop!(impl $imp for $res, $method);
forward_val_ref_binop!(impl $imp for $res, $method);
};
}
impl Zero for Decimal {
fn is_zero(&self) -> bool {
self.lo.is_zero() && self.mid.is_zero() && self.hi.is_zero()
}
fn zero() -> Decimal {
Decimal {
flags: 0,
hi: 0,
lo: 0,
mid: 0
}
}
}
impl One for Decimal {
fn one() -> Decimal {
Decimal {
flags: 0,
hi: 0,
lo: 1,
mid: 0
}
}
}
impl FromStr for Decimal {
type Err = &'static str;
fn from_str(value: &str) -> Result<Decimal, &'static str> {
let mut offset = 0;
let mut len = value.len();
let chars: Vec<char> = value.chars().collect();
let mut negative = false;
if chars[offset] == '-' {
negative = true; offset += 1;
len -= 1;
} else if chars[offset] == '+' {
offset += 1;
len -= 1;
}
let mut dot_offset: i32 = -1; let cfirst = offset; let mut coeff = String::new();
while len > 0 {
let c = chars[offset];
if c.is_digit(10) {
coeff.push(c);
offset += 1;
len -= 1;
continue;
}
if c == '.' {
if dot_offset >= 0 {
return Err("Invalid decimal: two decimal points");
}
dot_offset = offset as i32;
offset += 1;
len -= 1;
continue;
}
return Err("Invalid decimal: unknown character");
}
if coeff.is_empty() {
return Err("Invalid decimal: no digits found");
}
let mut scale = 0u32;
if dot_offset >= 0 {
scale = (coeff.len() as u32) - (dot_offset as u32 - cfirst as u32);
}
let res = BigUint::from_str(&coeff[..]);
if res.is_err() {
return Err("Failed to parse string");
}
Decimal::from_biguint(res.unwrap(), scale, negative)
}
}
impl ToString for Decimal {
fn to_string(&self) -> String {
let scale = self.scale();
let uint = self.to_biguint();
let mut rep = uint.to_string();
let len = rep.len();
if scale > 0 {
if scale > len as u32 {
let mut new_rep = String::new();
let zeros = repeat("0").take(scale as usize - len).collect::<String>();
new_rep.push_str("0.");
new_rep.push_str(&zeros[..]);
new_rep.push_str(&rep[..]);
rep = new_rep;
} else if scale == len as u32 {
rep.insert(0, '.');
rep.insert(0, '0');
} else {
rep.insert(len - scale as usize, '.');
}
}
if self.is_negative() {
rep.insert(0, '-');
}
rep
}
}
impl FromPrimitive for Decimal {
fn from_i32(n: i32) -> Option<Decimal> {
let flags: i32;
let value_copy: i32;
if n >= 0 {
flags = 0;
value_copy = n;
} else {
flags = SIGN_MASK;
value_copy = -n;
}
Some(Decimal {
flags: flags,
lo: value_copy,
mid: 0,
hi: 0
})
}
fn from_i64(n: i64) -> Option<Decimal> {
let flags: i32;
let value_copy: i64;
if n >= 0 {
flags = 0;
value_copy = n;
} else {
flags = SIGN_MASK;
value_copy = -n;
}
Some(Decimal {
flags: flags,
lo: value_copy as i32,
mid: (value_copy >> 32) as i32,
hi: 0
})
}
fn from_u32(n: u32) -> Option<Decimal> {
Some(Decimal {
flags: 0,
lo: n as i32,
mid: 0,
hi: 0
})
}
fn from_u64(n: u64) -> Option<Decimal> {
Some(Decimal {
flags: 0,
lo: n as i32,
mid: (n >> 32) as i32,
hi: 0
})
}
}
impl ToPrimitive for Decimal {
fn to_i64(&self) -> Option<i64> {
let d = self.rescale(0);
let bytes = d.unsigned_bytes_le();
let sign;
if self.is_negative() {
sign = Minus;
} else {
sign = Plus;
}
BigInt::from_bytes_le(sign, &bytes[..]).to_i64()
}
fn to_u64(&self) -> Option<u64> {
if self.is_negative() {
return None;
}
let d = self.rescale(0);
if d.hi != 0 {
return None;
}
let bytes = d.unsigned_bytes_le();
BigUint::from_bytes_le(&bytes[..]).to_u64()
}
}
fn scaled_biguints(me: &Decimal, other: &Decimal) -> (BigUint, BigUint, u32) {
let s_scale = me.scale();
let o_scale = other.scale();
if s_scale > o_scale {
(me.to_biguint(),
other.rescale(s_scale).to_biguint(),
s_scale)
} else if o_scale > s_scale {
(me.rescale(o_scale).to_biguint(),
other.to_biguint(),
o_scale)
} else {
(me.to_biguint(), other.to_biguint(), s_scale)
}
}
fn scaled_bigints(me: &Decimal, other: &Decimal) -> (BigInt, BigInt, u32) {
let s_scale = me.scale();
let o_scale = other.scale();
if s_scale > o_scale {
(me.to_bigint(), other.rescale(s_scale).to_bigint(), s_scale)
} else if o_scale > s_scale {
(me.rescale(o_scale).to_bigint(), other.to_bigint(), o_scale)
} else {
(me.to_bigint(), other.to_bigint(), s_scale)
}
}
forward_all_binop!(impl Add for Decimal, add);
impl<'a, 'b> Add<&'b Decimal> for &'a Decimal {
type Output = Decimal;
#[inline]
fn add(self, other: &Decimal) -> Decimal {
let (left, right, scale) = scaled_biguints(self, other);
let l_negative = self.is_negative();
let r_negative = other.is_negative();
let result;
let is_negative;
if l_negative && r_negative {
result = left + right;
is_negative = true;
} else if !l_negative && !r_negative {
result = left + right;
is_negative = false;
} else {
if r_negative {
if left < right {
result = right - left;
is_negative = true;
} else if left > right {
result = left - right;
is_negative = false;
} else {
result = BigUint::zero();
is_negative = false;
}
} else {
if left < right {
result = right - left;
is_negative = false;
} else if left > right {
result = left - right;
is_negative = true;
} else {
result = BigUint::zero();
is_negative = false;
}
}
}
let bytes = result.to_bytes_le();
Decimal::from_bytes_le(bytes, scale, is_negative)
}
}
forward_all_binop!(impl Sub for Decimal, sub);
impl<'a, 'b> Sub<&'b Decimal> for &'a Decimal {
type Output = Decimal;
#[inline]
fn sub(self, other: &Decimal) -> Decimal {
let (left, right, scale) = scaled_biguints(self, other);
let l_negative = self.is_negative();
let r_negative = other.is_negative();
let result: BigUint;
let is_negative: bool;
if l_negative ^ r_negative {
result = left + right;
is_negative = l_negative;
} else {
if left > right {
result = left - right;
is_negative = l_negative && r_negative;
} else {
result = right - left;
is_negative = !l_negative && !r_negative;
}
}
let bytes = result.to_bytes_le();
Decimal::from_bytes_le(bytes, scale, is_negative && !result.is_zero())
}
}
forward_all_binop!(impl Mul for Decimal, mul);
impl<'a, 'b> Mul<&'b Decimal> for &'a Decimal {
type Output = Decimal;
#[inline]
fn mul(self, other: &Decimal) -> Decimal {
let left = self.to_biguint();
let right = other.to_biguint();
let mut result = left * right; let mut scale = self.scale() + other.scale();
if result.bits() > MAX_BITS {
let ten = BigUint::from_i32(10).unwrap();
while scale > 0 && result.bits() > 96 {
result = result / &ten;
scale -= 1;
}
}
if result.bits() > MAX_BITS {
panic!("Decimal overflow from multiplication");
}
if scale > MAX_PRECISION {
panic!("Scale overflow; cannot represent exp {}", scale);
}
let bytes = result.to_bytes_le();
Decimal::from_bytes_le(bytes, scale, self.is_negative() ^ other.is_negative())
}
}
forward_all_binop!(impl Div for Decimal, div);
impl<'a, 'b> Div<&'b Decimal> for &'a Decimal {
type Output = Decimal;
#[inline]
fn div(self, other: &Decimal) -> Decimal {
if other.is_zero() {
panic!("Division by zero");
}
if self.is_zero() {
return Decimal::zero();
}
let mut rem: BigUint;
let ten = BigUint::from_i32(10).unwrap();
let mut fractional: Vec<u8> = Vec::new();
let (left, right, _) = scaled_biguints(self, other);
let (i, r) = left.div_rem(&right);
let mut integral = i;
let length = if integral.is_zero() { 0usize } else { integral.to_string().len() };
rem = r;
while !rem.is_zero() && fractional.len() + length < MAX_PRECISION as usize {
let rem_carried = &ten * rem;
let (frac, r) = rem_carried.div_rem(&right);
fractional.push(frac.to_u8().unwrap());
rem = r;
}
let scale = fractional.len();
for f in fractional {
integral = integral * &ten + BigUint::from_u8(f).unwrap();
}
let bytes = integral.to_bytes_le();
Decimal::from_bytes_le(bytes,
scale as u32,
self.is_negative() ^ other.is_negative())
}
}
forward_all_binop!(impl Rem for Decimal, rem);
impl<'a, 'b> Rem<&'b Decimal> for &'a Decimal {
type Output = Decimal;
#[inline]
fn rem(self, other: &Decimal) -> Decimal {
if other.is_zero() {
panic!("Division by zero");
}
if self.is_zero() {
return Decimal::zero();
}
let (left, right, scale) = scaled_bigints(self, other);
let (_, remainder) = left.div_rem(&right);
let (sign, bytes) = remainder.to_bytes_le();
Decimal::from_bytes_le(bytes, scale, sign == Minus)
}
}
impl PartialEq for Decimal {
#[inline]
fn eq(&self, other: &Decimal) -> bool {
self.cmp(other) == Equal
}
}
impl Eq for Decimal {}
impl PartialOrd for Decimal {
#[inline]
fn partial_cmp(&self, other: &Decimal) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Decimal {
fn cmp(&self, other: &Decimal) -> Ordering {
let s = self.scale() as u32;
let o = other.scale() as u32;
if s > o {
let d = other.rescale(s);
return self.cmp(&d);
} else if s < o {
let d = self.rescale(o);
return (&d).cmp(other);
}
let si = self.to_biguint();
let oi = other.to_biguint();
si.cmp(&oi)
}
}
#[test]
fn it_rescales_integer_up_1() {
let a = Decimal::from_str("1").unwrap().rescale(8);
assert_eq!("1.00000000", a.to_string());
}
#[test]
fn it_rescales_integer_up_2() {
let a = Decimal::from_str("1").unwrap().rescale(16);
assert_eq!("1.0000000000000000", a.to_string());
}
#[test]
fn it_rescales_integer_up_3() {
let a = Decimal::from_str("1").unwrap().rescale(24);
assert_eq!("1.000000000000000000000000", a.to_string());
}
#[test]
fn it_rescales_integer_down_1() {
let a = Decimal::from_str("1.00000000").unwrap().rescale(2);
assert_eq!("1.00", a.to_string());
}
#[test]
fn it_rescales_integer_down_2() {
let a = Decimal::from_str("1.0000000000000000").unwrap().rescale(2);
assert_eq!("1.00", a.to_string());
}
#[test]
fn it_rescales_integer_down_3() {
let a = Decimal::from_str("1.000000000000000000000000").unwrap().rescale(2);
assert_eq!("1.00", a.to_string());
}
#[test]
fn it_rescales_float_up_1() {
let a = Decimal::from_str("0.1").unwrap().rescale(8);
assert_eq!("0.10000000", a.to_string());
}
#[test]
fn it_rescales_float_up_2() {
let a = Decimal::from_str("0.1").unwrap().rescale(16);
assert_eq!("0.1000000000000000", a.to_string());
}
#[test]
fn it_rescales_float_up_3() {
let a = Decimal::from_str("0.1").unwrap().rescale(24);
assert_eq!("0.100000000000000000000000", a.to_string());
}
#[test]
fn it_rescales_float_down_1() {
let a = Decimal::from_str("1.00000001").unwrap().rescale(2);
assert_eq!("1.00", a.to_string());
}
#[test]
fn it_rescales_float_down_2() {
let a = Decimal::from_str("1.0000000000000001").unwrap().rescale(2);
assert_eq!("1.00", a.to_string());
}
#[test]
fn it_rescales_float_down_3() {
let a = Decimal::from_str("1.000000000000000000000001").unwrap().rescale(2);
assert_eq!("1.00", a.to_string());
}
#[test]
fn it_can_round_complex_numbers() {
let a = Decimal { flags: 1572864, hi: 107459117, lo: -2075830955, mid: 849254895 };
let b = a.round_dp(2u32);
assert_eq!("1982.27", b.to_string());
}