gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-taler-ios] branch master updated: finish implementing, testing, a


From: gnunet
Subject: [taler-taler-ios] branch master updated: finish implementing, testing, and documenting amounts
Date: Tue, 10 Aug 2021 03:23:15 +0200

This is an automated email from the git hooks/post-receive script.

jonathan-buchanan pushed a commit to branch master
in repository taler-ios.

The following commit(s) were added to refs/heads/master by this push:
     new c98d8fb  finish implementing, testing, and documenting amounts
c98d8fb is described below

commit c98d8fbcbdb1767d9ae2caae3d58d97f06d278d1
Author: Jonathan Buchanan <jonathan.russ.buchanan@gmail.com>
AuthorDate: Mon Aug 9 21:22:52 2021 -0400

    finish implementing, testing, and documenting amounts
---
 Taler/Amount.swift           | 216 +++++++++++++++++++++++++++++++++++++++++++
 TalerTests/AmountTests.swift |   5 +
 2 files changed, 221 insertions(+)

diff --git a/Taler/Amount.swift b/Taler/Amount.swift
index 83445b4..98bb1b9 100644
--- a/Taler/Amount.swift
+++ b/Taler/Amount.swift
@@ -16,20 +16,73 @@
 
 import Foundation
 
+/**
+    Errors for `Amount`.
+ */
 enum AmountError: Error {
+    /**
+        The string cannot be parsed to create an `Amount`.
+     */
     case invalidStringRepresentation
+    
+    /**
+        Could not compare or operate on two `Amount`s of different currencies.
+     */
     case incompatibleCurrency
+    
+    /**
+        The amount is invalid. The value is either greater than the maximum, 
or the currency is the empty string.
+     */
     case invalidAmount
+    
+    /**
+        The result of the operation would yield a negative amount.
+     */
     case negativeAmount
+    
+    /**
+        The operation was division by zero.
+     */
+    case divideByZero
 }
 
+/**
+    A value of a currency.
+ */
 class Amount: Codable, CustomStringConvertible {
+    /**
+        The largest possible value that can be represented.
+     */
     private static let maxValue: UInt64 = 1 << 52
+    
+    /**
+        The size of `value` in relation to `fraction`.
+     */
     private static let fractionalBase: UInt32 = 100000000
+    
+    /**
+        The greatest number of decimal digits that can be represented.
+     */
     private static let fractionalBaseDigits: UInt = 8
+    
+    /**
+        The currency of the amount.
+     */
     var currency: String
+    
+    /**
+        The value of the amount (number to the left of the decimal point).
+     */
     var value: UInt64
+    
+    /**
+        The fractional value of the amount (number to the right of the decimal 
point).
+     */
     var fraction: UInt32
+    
+    /**
+        The string representation of the amount, formatted as 
"`currency`:`value`.`fraction`".
+     */
     var description: String {
         if fraction == 0 {
             return "\(currency):\(value)"
@@ -43,10 +96,24 @@ class Amount: Codable, CustomStringConvertible {
             return "\(currency):\(value).\(fracStr)"
         }
     }
+    
+    /**
+        Whether the value is valid. An amount is valid if and only if the 
currency is not empty and the value is less than the maximum allowed value.
+     */
     var valid: Bool {
         return (value <= Amount.maxValue && currency != "")
     }
     
+    /**
+        Initializes an amount by parsing a string representing the amount. The 
string should be formatted as "`currency`:`value`.`fraction`".
+     
+        - Parameters:
+            - fromString: The string to parse.
+     
+        - Throws:
+            - `AmountError.invalidStringRepresentation` if the string cannot 
be parsed.
+            - `AmountError.invalidAmount` if the string can be parsed, but the 
resulting amount is not valid.
+     */
     init(fromString string: String) throws {
         guard let separatorIndex = string.firstIndex(of: ":") else { throw 
AmountError.invalidStringRepresentation }
         self.currency = String(string[..<separatorIndex])
@@ -71,12 +138,30 @@ class Amount: Codable, CustomStringConvertible {
         guard self.valid else { throw AmountError.invalidAmount }
     }
     
+    /**
+        Initializes an amount with the specified currency, value, and fraction.
+     
+        - Parameters:
+            - currency: The currency of the amount.
+            - value: The value of the amount (number to the left of the 
decimal point).
+            - fraction: The fractional value of the amount (number to the 
right of the decimal point).
+     */
     init(currency: String, value: UInt64, fraction: UInt32) {
         self.currency = currency
         self.value = value
         self.fraction = fraction
     }
     
+    /**
+        Initializes an amount from a decoder.
+     
+        - Parameters:
+            - fromDecoder: The decoder to extract the amount from.
+     
+        - Throws:
+            - `AmountError.invalidStringRepresentation` if the string cannot 
be parsed.
+            - `AmountError.invalidAmount` if the string can be parsed, but the 
resulting amount is not valid.
+     */
     init(fromDecoder decoder: Decoder) throws {
         let container = try decoder.singleValueContainer()
         let string = try container.decode(String.self)
@@ -104,21 +189,43 @@ class Amount: Codable, CustomStringConvertible {
         guard self.valid else { throw AmountError.invalidAmount }
     }
     
+    /**
+        Copies an amount.
+     
+        - Returns: A copy of the amount.
+     */
     func copy() -> Amount {
         return Amount(currency: self.currency, value: self.value, fraction: 
self.fraction)
     }
     
+    /**
+        Creates a normalized copy of an amount.
+     
+        - Returns: A copy of the amount that has been normalized
+     */
     func normalizedCopy() throws -> Amount {
         let amount = self.copy()
         try amount.normalize()
         return amount
     }
     
+    /**
+        Encodes an amount.
+     
+        - Parameters:
+            - to: The encoder to encode the amount with.
+     */
     func encode(to encoder: Encoder) throws {
         var container = encoder.singleValueContainer()
         try container.encode(self.description)
     }
     
+    /**
+        Normalizes an amount by reducing `fraction` until it is less than 
`Amount.fractionalBase`, increasing `value` appropriately.
+     
+        - Throws:
+            - `AmountError.invalidAmount` if the amount is invalid either 
before or after normalization.
+     */
     func normalize() throws {
         if !valid {
             throw AmountError.invalidAmount
@@ -130,6 +237,18 @@ class Amount: Codable, CustomStringConvertible {
         }
     }
     
+    /**
+        Adds two amounts together.
+     
+        - Parameters:
+            - left: The amount on the left.
+            - right: The amount on the right.
+     
+        - Throws:
+            - `AmountError.incompatibleCurrency` if `left` and `right` do not 
share the same currency.
+     
+        - Returns: The sum of `left` and `right`, normalized.
+     */
     static func + (left: Amount, right: Amount) throws -> Amount {
         if left.currency != right.currency {
             throw AmountError.incompatibleCurrency
@@ -143,6 +262,18 @@ class Amount: Codable, CustomStringConvertible {
         return result
     }
     
+    /**
+        Subtracts one amount from another.
+     
+        - Parameters:
+            - left: The amount on the left.
+            - right: The amount on the right.
+     
+        - Throws:
+            - `AmountError.incompatibleCurrency` if `left` and `right` do not 
share the same currency.
+     
+        - Returns: The difference of `left` and `right`, normalized.
+     */
     static func - (left: Amount, right: Amount) throws -> Amount {
         if left.currency != right.currency {
             throw AmountError.incompatibleCurrency
@@ -162,6 +293,59 @@ class Amount: Codable, CustomStringConvertible {
         return diff
     }
     
+    /**
+        Divides an amount by a scalar, possibly introducing rounding error.
+     
+        - Parameters:
+            - dividend: The amount to divide.
+            - divisor: The scalar dividing `dividend`.
+     
+        - Returns: The quotient of `dividend` and `divisor`, normalized.
+     */
+    static func / (dividend: Amount, divisor: UInt32) throws -> Amount {
+        guard divisor != 0 else { throw AmountError.divideByZero }
+        let result = try dividend.normalizedCopy()
+        if (divisor == 1) {
+            return result
+        }
+        var remainder = result.value % UInt64(divisor)
+        result.value = result.value / UInt64(divisor)
+        remainder = (remainder * UInt64(Amount.fractionalBase)) + 
UInt64(result.fraction)
+        result.fraction = UInt32(remainder) / divisor
+        try result.normalize()
+        return result
+    }
+    
+    /**
+        Multiply an amount by a scalar.
+     
+        - Parameters:
+            - amount: The amount to multiply.
+            - factor: The scalar multiplying `amount`.
+     
+        - Returns: The product of `amount` and `factor`, normalized.
+     */
+    static func * (amount: Amount, factor: UInt32) throws -> Amount {
+        let result = try amount.normalizedCopy()
+        result.value = result.value * UInt64(factor)
+        let fraction_tmp = UInt64(result.fraction) * UInt64(factor)
+        result.value += fraction_tmp / UInt64(Amount.fractionalBase)
+        result.fraction = UInt32(fraction_tmp % UInt64(Amount.fractionalBase))
+        return result
+    }
+    
+    /**
+        Compares two amounts.
+     
+        - Parameters:
+            - left: The first amount.
+            - right: The second amount.
+     
+        - Throws:
+            - `AmountError.incompatibleCurrency` if `left` and `right` do not 
share the same currency.
+     
+        - Returns: `true` if and only if the amounts have the same `value` and 
`fraction` after normalization, `false` otherwise.
+     */
     static func == (left: Amount, right: Amount) throws -> Bool {
         if left.currency != right.currency {
             throw AmountError.incompatibleCurrency
@@ -171,6 +355,18 @@ class Amount: Codable, CustomStringConvertible {
         return (leftNormalized.value == rightNormalized.value && 
leftNormalized.fraction == rightNormalized.fraction)
     }
     
+    /**
+        Compares two amounts.
+     
+        - Parameters:
+            - left: The amount on the left.
+            - right: The amount on the right.
+     
+        - Throws:
+            - `AmountError.incompatibleCurrency` if `left` and `right` do not 
share the same currency.
+     
+        - Returns: `true` if and only if `left` is smaller than `right` after 
normalization, `false` otherwise.
+     */
     static func < (left: Amount, right: Amount) throws -> Bool {
         if left.currency != right.currency {
             throw AmountError.incompatibleCurrency
@@ -184,10 +380,30 @@ class Amount: Codable, CustomStringConvertible {
         }
     }
     
+    /**
+        Compares two amounts.
+     
+        - Parameters:
+            - left: The amount on the left.
+            - right: The amount on the right.
+     
+        - Throws:
+            - `AmountError.incompatibleCurrency` if `left` and `right` do not 
share the same currency.
+     
+        - Returns: `true` if and only if `left` is bigger than `right` after 
normalization, `false` otherwise.
+     */
     static func > (left: Amount, right: Amount) throws -> Bool {
         return try right < left
     }
     
+    /**
+        Creates the amount representing zero in a given currency.
+     
+        - Parameters:
+            - currency: The currency to use.
+     
+        - Returns: The zero amount for `currency`.
+     */
     static func zero(currency: String) -> Amount {
         return Amount(currency: currency, value: 0, fraction: 0)
     }
diff --git a/TalerTests/AmountTests.swift b/TalerTests/AmountTests.swift
index b7dd28d..6cbbf77 100644
--- a/TalerTests/AmountTests.swift
+++ b/TalerTests/AmountTests.swift
@@ -57,6 +57,11 @@ class AmountTests: XCTestCase {
         XCTAssertThrowsError(try amount > amount3)
         XCTAssertThrowsError(try amount + amount3)
         XCTAssertThrowsError(try amount - amount3)
+        
+        XCTAssertThrowsError(try amount3 / 0)
+        XCTAssert(try (amount3 / 1) == amount3)
+        XCTAssert(try (amount3 / 3) == Amount(fromString: "USD:4.11333333"))
+        XCTAssert(try (amount3 * 5) == Amount(fromString: "USD:61.7"))
     }
 
 }

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]