1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
use std::char::from_digit;
use std::cmp::Ordering;
use std::error::Error;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::marker::PhantomData;
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
use std::str::FromStr;

///
/// fixed-unsigned - A crate for fixed-point unsigned big integers
///
/// This was written to behave like bignumber.js
///
/// Not all traits you would expect for a number are implemented. Some things are implemented
/// just to work with Nimiq.
///

use num_bigint::BigUint;
use num_traits::identities::{One, Zero};
use num_traits::ToPrimitive;

pub mod types;


/// Maximum number of digits a decimal number can have in a `u64`
const U64_MAX_DIGITS: u64 = 19u64;
/// Maximum decimal number that can be represented with an `u64`
/// `U64_MAX_DECIMAL` = 10<sup>`U64_MAX_DIGITS`</sup>
/// NOTE: If we go with 15 decimal places, this can safely fit a Javascript Integer
const U64_MAX_DECIMAL: u64 = 10_000_000_000_000_000_000u64;

/// Trait for a fixed scale. It only has one associated constant that must be implemented:
/// `SCALE`, which defines the place of the decimal point.
pub trait FixedScale {
    const SCALE: u64;
}

/// A trait for rounding when scaling down
pub trait RoundingMode {
    /// Scale on `int_value` where `carrier` is the last digit that was already dropped.
    fn round(int_value: BigUint, carrier: u8) -> BigUint;
}

/// Round half up - i.e. 0.4 -> 0 and 0.5 -> 1
pub struct RoundHalfUp {}
impl RoundingMode for RoundHalfUp{
    #[inline]
    fn round(int_value: BigUint, carrier: u8) -> BigUint {
        int_value + if carrier >= 5u8 { 1u64 } else { 0u64 }
    }
}

/// Round down - i.e. truncate
pub struct RoundDown {}
impl RoundingMode for RoundDown {
    #[inline]
    fn round(int_value: BigUint, _: u8) -> BigUint {
        int_value
    }
}



/// Error returned when a string representation can't be parse into a FixedUnsigned.
/// TODO: Attach string to it for error message
#[derive(Debug, PartialEq, Eq)]
pub struct ParseError(String);

impl fmt::Display for ParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}: {}", self.description(), self.0)
    }
}

impl Error for ParseError {
    fn description(&self) -> &str {
        "Failed to parse fixed point decimal:"
    }

    fn cause(&self) -> Option<&dyn Error> {
        None
    }
}

/// A fixed point unsigned integer
///
/// This is a `num_bigint::BigUint` with a fixed scale.
///
/// The fixed scale is determined by the generic `S` which implements `FixedScale` and
/// provides the constant `FixedScale::SCALE`.
#[derive(Clone)]
pub struct FixedUnsigned<S>
    where S: FixedScale
{
    int_value: BigUint,
    scale: PhantomData<S>
}

impl<S> FixedUnsigned<S>
    where S: FixedScale
{
    fn new(int_value: BigUint) -> Self {
        Self { int_value, scale: PhantomData }
    }

    /// Scales up a `BigUint` by `scale`
    fn scale_up(mut int_value: BigUint, mut scale: u64) -> BigUint {
        while scale >= U64_MAX_DIGITS {
            int_value *= U64_MAX_DECIMAL;
            scale -= U64_MAX_DIGITS;
        }
        while scale > 0u64 {
            int_value *= 10u64;
            scale -= 1;
        }
        int_value
    }

    /// Scales down a `BigUint` by `scale`
    fn scale_down<R: RoundingMode>(mut int_value: BigUint, mut scale: u64) -> BigUint {
        // scale down by 10<sup>19</sup> as long as possible
        while scale >= U64_MAX_DIGITS {
            int_value /= U64_MAX_DECIMAL;
            scale -= U64_MAX_DIGITS;
        }
        // scale down by 10 until we have to potentially round
        while scale > 1u64 {
            int_value /= 10u64;
            scale -= 1;
        }
        // round
        if scale > 0u64 {
            // unwrap is safe, since `(int_value % 10u64)` < 10
            let carrier = (&int_value % 10u64).to_u8().unwrap();
            int_value /= 10u64;
            int_value = R::round(int_value, carrier);
        }
        int_value
    }

    /// Returns the integer part as `BigUint` (i.e. the part before the decimal point)
    pub fn int_part(&self) -> BigUint {
        Self::scale_down::<RoundDown>(self.int_value.clone(), S::SCALE)
    }

    pub fn frac_part(&self) -> BigUint {
        unimplemented!();
    }

    /// Returns the scale of the `FixedUnsigned` as u64.
    ///
    /// Note that the scale is fixed by type, so for a `FixedUnsigned<S>` you can also get it as
    /// constant by `S::Scale`. This function is only for convenience.
    pub fn scale(&self) -> u64 {
        S::SCALE
    }

    pub fn from_bytes_be(bytes: &[u8]) -> Self {
        Self::new(BigUint::from_bytes_be(bytes))
    }

    pub fn from_bytes_le(bytes: &[u8]) -> Self {
        Self::new(BigUint::from_bytes_be(bytes))
    }

    pub fn to_bytes_be(&self) -> Vec<u8> {
        self.int_value.to_bytes_be()
    }

    pub fn to_bytes_le(&self) -> Vec<u8> {
        self.int_value.to_bytes_le()
    }

    /// Converts the `FixedUnsigned` to a string representation in base `radix`.
    ///
    /// # Panics
    ///
    /// This function will panic if the radix is 0 or greater than 36.
    pub fn to_radix_string(&self, radix: u8, uppercase: bool) -> String {
        if radix == 0 || radix > 36 {
            panic!("Radix too large: {}", radix);
        }
        let digits = self.int_value.to_radix_be(u32::from(radix));
        let mut string: String = String::new();
        let decimal_place = digits.len().checked_sub(S::SCALE as usize);
        if let Some(0) = decimal_place {
            string.push('0');
        }
        for (i, d) in digits.iter().enumerate() {
            match decimal_place {
                Some(dp) if dp == i => string.push('.'),
                _ => ()
            }
            // This unwrap is safe, because we to_radix_be only gives us digits in the right radix
            let c = from_digit(u32::from(*d), u32::from(radix)).unwrap();
            string.push(if uppercase { c.to_ascii_uppercase() } else { c }); // NOTE: `form_digit` returns lower-case characters
        }
        string
    }

    /// Converts a string representation to a `FixedUnsigned` with base `radix`.
    ///
    /// NOTE: This function always rounds down.
    ///
    /// # Panics
    ///
    /// This function will panic if the radix is 0 or greater than 36.
    pub fn from_radix_string(string: &str, radix: u8) -> Result<Self, ParseError> {
        if radix == 0 || radix > 36 {
            panic!("Radix too large: {}", radix);
        }
        let mut digits: Vec<u8> = Vec::new();
        let mut decimal_place = None;
        for (i, c) in string.chars().enumerate() {
            if c == '.' {
                if decimal_place.is_some() {
                    return Err(ParseError(String::from(string)))
                }
                decimal_place = Some(i)
            }
            else {
                digits.push(c.to_digit(u32::from(radix)).unwrap() as u8)
            }
        }
        if digits.is_empty() {
            return Err(ParseError(String::from(string)));
        }
        // unscaled `int_value`
        let int_value = BigUint::from_radix_be(digits.as_slice(), u32::from(radix))
            .ok_or_else(|| ParseError(String::from(string)))?;
        // the scale of the string representation
        // NOTE: `string.len() - 1` is the number of digits. One is being subtracted for the decimal point
        let scale = decimal_place.map(|p| string.len() - p - 1).unwrap_or(0) as u64;
        // scale the unscaled `int_value` to the correct scale
        let int_value = if scale < S::SCALE {
            Self::scale_up(int_value, S::SCALE - scale)
        }
        else if scale > S::SCALE {
            Self::scale_down::<RoundDown>(int_value, scale - S::SCALE)
        }
        else {
            int_value
        };
        Ok(Self::new(int_value))
    }

    /// Converts from a BigUint to FixedScale. This scales the value appropriately, thus the
    /// result will have 0 for decimal places.
    fn from_biguint(int_value: BigUint) -> Self {
        Self::new(Self::scale_up(int_value, S::SCALE))
    }

    /// Converts to a BigUint losing the decimal places
    ///
    /// NOTE: This is not implemented as a `Into`/`From` trait to make the loss of precision implicit
    pub fn into_biguint(self) -> BigUint {
        Self::scale_down::<RoundDown>(self.int_value, S::SCALE)
    }

    pub fn into_biguint_without_scale(self) -> BigUint {
        self.int_value
    }

    pub fn bits(&self) -> usize {
        self.int_value.bits()
    }

    pub fn bytes(&self) -> usize {
        let bits = self.bits();
        bits / 8 + if bits % 8 == 0 {0} else {1}
    }

    /// Adds two `BigUint`s interpreted as `FixedUnsigned<S>` and returns the result.
    #[inline]
    fn add(a: &BigUint, b: &BigUint) -> BigUint {
        a + b
    }

    /// Subtracts two `BigUint`s interpreted as `FixedUnsigned<S>` and returns the result.
    #[inline]
    fn sub(a: &BigUint, b: &BigUint) -> BigUint {
        a - b
    }

    /// Multiplies two `BigUint`s interpreted as `FixedUnsigned<S>` and returns the result.
    #[inline]
    fn mul(a: &BigUint, b: &BigUint) -> BigUint {
        Self::scale_down::<RoundHalfUp>((a * b).clone(), S::SCALE)
    }

    /// Divides two `BigUint`s interpreted as `FixedUnsigned<S>` and returns the result.
    #[inline]
    fn div(a: &BigUint, b: &BigUint) -> BigUint {
        // scale up 1 digit more - to keep the carrier, then divide and scale down 1 digit. The scale down of 1 will round appropriately
        Self::scale_down::<RoundHalfUp>(Self::scale_up(a.clone(), S::SCALE + 1u64) / b, 1u64)
    }

    /// Convert from scale `S` to scale `T`.
    pub fn into_scale<T: FixedScale, R: RoundingMode>(self) -> FixedUnsigned<T> {
        FixedUnsigned::<T>::new(if S::SCALE < T::SCALE {
            Self::scale_up(self.int_value,T::SCALE - S::SCALE)
        }
        else {
            Self::scale_down::<R>(self.int_value, S::SCALE - T::SCALE)
        })
    }
}

impl<S> Add for FixedUnsigned<S>
    where S: FixedScale
{
    type Output = Self;

    fn add(self, rhs: FixedUnsigned<S>) -> Self::Output {
        Self::new(Self::add(&(self.int_value), &(rhs.int_value)))
    }
}

impl<'a, 'b, S> Add<&'b FixedUnsigned<S>> for &'a FixedUnsigned<S>
    where S: FixedScale
{
    type Output = FixedUnsigned<S>;

    fn add(self, rhs: &'b FixedUnsigned<S>) -> FixedUnsigned<S> {
        FixedUnsigned::new(FixedUnsigned::<S>::add(&(self.int_value), &(rhs.int_value)))
    }
}

impl<S> AddAssign for FixedUnsigned<S>
    where S: FixedScale
{
    fn add_assign(&mut self, rhs: Self) {
        self.int_value = FixedUnsigned::<S>::add(&(self.int_value), &(rhs.int_value))
    }
}

impl<S> Sub for FixedUnsigned<S>
    where S: FixedScale
{
    type Output = Self;

    fn sub(self, rhs: FixedUnsigned<S>) -> Self::Output {
        Self::new(Self::sub(&(self.int_value), &(rhs.int_value)))
    }
}

impl<'a, 'b, S> Sub<&'b FixedUnsigned<S>> for &'a FixedUnsigned<S>
    where S: FixedScale
{
    type Output = FixedUnsigned<S>;

    fn sub(self, rhs: &'b FixedUnsigned<S>) -> FixedUnsigned<S>  {
        FixedUnsigned::new(FixedUnsigned::<S>::sub(&(self.int_value), &(rhs.int_value)))
    }
}

impl<S> SubAssign for FixedUnsigned<S>
    where S: FixedScale
{
    fn sub_assign(&mut self, rhs: Self) {
        self.int_value = FixedUnsigned::<S>::sub(&(self.int_value), &(rhs.int_value))
    }
}

impl<S> Mul for FixedUnsigned<S>
    where S: FixedScale
{
    type Output = Self;

    fn mul(self, rhs: FixedUnsigned<S>) -> Self::Output {
        Self::new(Self::mul(&(self.int_value), &(rhs.int_value)))
    }
}

impl<'a, 'b, S> Mul<&'b FixedUnsigned<S>> for &'a FixedUnsigned<S>
    where S: FixedScale
{
    type Output = FixedUnsigned<S>;

    fn mul(self, rhs: &'b FixedUnsigned<S>) -> FixedUnsigned<S>  {
        FixedUnsigned::new(FixedUnsigned::<S>::mul(&(self.int_value), &(rhs.int_value)))
    }
}

impl<S> MulAssign for FixedUnsigned<S>
    where S: FixedScale
{
    fn mul_assign(&mut self, rhs: Self) {
        self.int_value = FixedUnsigned::<S>::mul(&(self.int_value), &(rhs.int_value))
    }
}

impl<S> Div for FixedUnsigned<S>
    where S: FixedScale
{
    type Output = Self;

    fn div(self, rhs: FixedUnsigned<S>) -> Self::Output {
        Self::new(Self::div(&(self.int_value), &(rhs.int_value)))
    }
}

impl<'a, 'b, S> Div<&'b FixedUnsigned<S>> for &'a FixedUnsigned<S>
    where S: FixedScale
{
    type Output = FixedUnsigned<S>;

    fn div(self, rhs: &'b FixedUnsigned<S>) -> FixedUnsigned<S>  {
        FixedUnsigned::new(FixedUnsigned::<S>::div(&(self.int_value), &(rhs.int_value)))
    }
}

impl<S> DivAssign for FixedUnsigned<S>
    where S: FixedScale
{
    fn div_assign(&mut self, rhs: Self) {
        self.int_value = FixedUnsigned::<S>::div(&(self.int_value), &(rhs.int_value))
    }
}

impl<S> PartialEq for FixedUnsigned<S>
    where S: FixedScale
{
    fn eq(&self, other: &Self) -> bool {
        self.int_value.eq(&other.int_value)
    }
}

impl<S> Hash for FixedUnsigned<S>
    where S: FixedScale
{
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.int_value.hash(state)
    }
}

impl<S> Eq for FixedUnsigned<S>
    where S: FixedScale
{

}

impl<S> PartialOrd for FixedUnsigned<S>
    where S: FixedScale
{
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.int_value.partial_cmp(&other.int_value)
    }
}

impl<S> Ord for FixedUnsigned<S>
    where S: FixedScale
{
    fn cmp(&self, other: &Self) -> Ordering {
        self.int_value.cmp(&other.int_value)
    }
}

/*
NOTE: Conflicts with implementation from crate `alloc`, because we implemented `Display`

impl<S> ToString for FixedUnsigned<S>
    where S: FixedScale
{
    fn to_string(&self) -> String {
        self.to_radix_string(10, false)
    }
}
*/

impl<S> FromStr for FixedUnsigned<S>
    where S: FixedScale
{
    type Err = ParseError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Self::from_radix_string(s, 10)
    }
}

impl<S> fmt::Debug for FixedUnsigned<S>
    where S: FixedScale
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "FixedUnsigned({}, scale={})", self.to_radix_string(10, false), S::SCALE)
    }
}

impl<S> fmt::Display for FixedUnsigned<S>
    where S: FixedScale
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.to_radix_string(10, false))
    }
}

impl<S> From<BigUint> for FixedUnsigned<S>
    where S: FixedScale
{
    fn from(int_value: BigUint) -> Self {
        Self::from_biguint(int_value)
    }
}

/*
    XXX While this is a nice thing to have, it causes a lot of conflicts

impl<S, T> From<T> for FixedUnsigned<S>
    where S: FixedScale, BigUint: From<T>, T:
{
    fn from(x: T) -> Self {
        Self::from_biguint(BigUint::from(x))
    }
}
*/

impl<S: FixedScale> From<u64> for FixedUnsigned<S> {
    fn from(x: u64) -> Self {
        Self::from_biguint(BigUint::from(x))
    }
}

impl<S: FixedScale> From<u32> for FixedUnsigned<S> {
    fn from(x: u32) -> Self {
        Self::from_biguint(BigUint::from(x))
    }
}

impl<S: FixedScale> From<u16> for FixedUnsigned<S> {
    fn from(x: u16) -> Self {
        Self::from_biguint(BigUint::from(x))
    }
}

impl<S: FixedScale> From<u8> for FixedUnsigned<S> {
    fn from(x: u8) -> Self {
        Self::from_biguint(BigUint::from(x))
    }
}

impl<S> Zero for FixedUnsigned<S>
    where S: FixedScale
{
    fn zero() -> Self {
        Self::new(BigUint::zero())
    }

    fn is_zero(&self) -> bool {
        self.int_value.is_zero()
    }
}

impl<S> One for FixedUnsigned<S>
    where S: FixedScale
{
    fn one() -> Self {
        Self::from(1u64)
    }
}

impl<S> Default for FixedUnsigned<S>
    where S: FixedScale
{
    fn default() -> Self {
        Self::zero()
    }
}

/// Converts a `f64` to a `FixedUnsigned`
impl<S: FixedScale> From<f64> for FixedUnsigned<S> {
    fn from(x: f64) -> Self {
        // `bignumber.js` takes the `toString` of a `Number` to convert to `BigNumber`
        // NOTE: JS and Rust seem both to use 16 decimal places
        Self::from_str(&format!("{:.16}", x)).unwrap()
    }
}