commit 95f0f59f1e462cf543cd3acf335f08630dd84a1d
parent 8ae9aa1ed13e122e2f9ddf13120add39c246a424
Author: Martin Schanzenbach <schanzen@gnunet.org>
Date: Mon, 18 Jul 2022 22:24:12 +0200
go fmt
Diffstat:
| M | pkg/util/amount.go | | | 183 | +++++++++++++++++++++++++++++++++++++++---------------------------------------- |
1 file changed, 91 insertions(+), 92 deletions(-)
diff --git a/pkg/util/amount.go b/pkg/util/amount.go
@@ -16,29 +16,28 @@
//
// SPDX-License-Identifier: AGPL3.0-or-later
-
package util
-import(
- "errors"
- "regexp"
- "strconv"
- "fmt"
- "math"
- "strings"
+import (
+ "errors"
+ "fmt"
+ "math"
+ "regexp"
+ "strconv"
+ "strings"
)
// The GNU Taler Amount object
type Amount struct {
- // The type of currency, e.g. EUR
- Currency string
+ // The type of currency, e.g. EUR
+ Currency string
- // The value (before the ".")
- Value uint64
+ // The value (before the ".")
+ Value uint64
- // The fraction (after the ".", optional)
- Fraction uint64
+ // The fraction (after the ".", optional)
+ Fraction uint64
}
// The maximim length of a fraction (in digits)
@@ -52,103 +51,103 @@ var MaxAmountValue = uint64(math.Pow(2, 52))
// Create a new amount from value and fraction in a currency
func NewAmount(currency string, value uint64, fraction uint64) Amount {
- return Amount{
- Currency: currency,
- Value: value,
- Fraction: fraction,
- }
+ return Amount{
+ Currency: currency,
+ Value: value,
+ Fraction: fraction,
+ }
}
// Subtract the amount b from a and return the result.
// a and b must be of the same currency and a >= b
-func (a *Amount) Sub(b Amount) (*Amount,error) {
- if a.Currency != b.Currency {
- return nil, errors.New("Currency mismatch!")
- }
- v := a.Value
- f := a.Fraction
- if a.Fraction < b.Fraction {
- v -= 1
- f += FractionalBase
- }
- f -= b.Fraction
- if v < b.Value {
- return nil, errors.New("Amount Overflow!")
- }
- v -= b.Value
- r := Amount{
- Currency: a.Currency,
- Value: v,
- Fraction: f,
- }
- return &r, nil
+func (a *Amount) Sub(b Amount) (*Amount, error) {
+ if a.Currency != b.Currency {
+ return nil, errors.New("Currency mismatch!")
+ }
+ v := a.Value
+ f := a.Fraction
+ if a.Fraction < b.Fraction {
+ v -= 1
+ f += FractionalBase
+ }
+ f -= b.Fraction
+ if v < b.Value {
+ return nil, errors.New("Amount Overflow!")
+ }
+ v -= b.Value
+ r := Amount{
+ Currency: a.Currency,
+ Value: v,
+ Fraction: f,
+ }
+ return &r, nil
}
// Add b to a and return the result.
// Returns an error if the currencies do not match or the addition would
// cause an overflow of the value
-func (a *Amount) Add(b Amount) (*Amount,error) {
- if a.Currency != b.Currency {
- return nil, errors.New("Currency mismatch!")
- }
- v := a.Value +
- b.Value +
- uint64(math.Floor((float64(a.Fraction) + float64(b.Fraction)) / FractionalBase))
-
- if v >= MaxAmountValue {
- return nil, errors.New(fmt.Sprintf("Amount Overflow (%d > %d)!", v, MaxAmountValue))
- }
- f := uint64((a.Fraction + b.Fraction) % FractionalBase)
- r := Amount{
- Currency: a.Currency,
- Value: v,
- Fraction: f,
- }
- return &r, nil
+func (a *Amount) Add(b Amount) (*Amount, error) {
+ if a.Currency != b.Currency {
+ return nil, errors.New("Currency mismatch!")
+ }
+ v := a.Value +
+ b.Value +
+ uint64(math.Floor((float64(a.Fraction)+float64(b.Fraction))/FractionalBase))
+
+ if v >= MaxAmountValue {
+ return nil, errors.New(fmt.Sprintf("Amount Overflow (%d > %d)!", v, MaxAmountValue))
+ }
+ f := uint64((a.Fraction + b.Fraction) % FractionalBase)
+ r := Amount{
+ Currency: a.Currency,
+ Value: v,
+ Fraction: f,
+ }
+ return &r, nil
}
// Parses an amount string in the format <currency>:<value>[.<fraction>]
-func ParseAmount(s string) (*Amount,error) {
- re, err := regexp.Compile(`^\s*([-_*A-Za-z0-9]+):([0-9]+)\.?([0-9]+)?\s*$`)
- parsed := re.FindStringSubmatch(s)
-
- if nil != err {
- return nil, errors.New(fmt.Sprintf("invalid amount: %s", s))
- }
- tail := "0.0"
- if len(parsed) >= 4 {
- tail = "0." + parsed[3]
- }
- if len(tail) > FractionalLength + 1 {
- return nil, errors.New("fraction too long")
- }
- value, err := strconv.ParseUint(parsed[2], 10, 64)
- if nil != err {
- return nil, errors.New(fmt.Sprintf("Unable to parse value %s", parsed[2]))
- }
- fractionF, err := strconv.ParseFloat(tail, 64)
- if nil != err {
- return nil, errors.New(fmt.Sprintf("Unable to parse fraction %s", tail))
- }
- fraction := uint64(math.Round(fractionF * FractionalBase))
- currency := parsed[1]
- a := NewAmount(currency, value, fraction)
- return &a, nil
+func ParseAmount(s string) (*Amount, error) {
+ re, err := regexp.Compile(`^\s*([-_*A-Za-z0-9]+):([0-9]+)\.?([0-9]+)?\s*$`)
+ parsed := re.FindStringSubmatch(s)
+
+ if nil != err {
+ return nil, errors.New(fmt.Sprintf("invalid amount: %s", s))
+ }
+ tail := "0.0"
+ if len(parsed) >= 4 {
+ tail = "0." + parsed[3]
+ }
+ if len(tail) > FractionalLength+1 {
+ return nil, errors.New("fraction too long")
+ }
+ value, err := strconv.ParseUint(parsed[2], 10, 64)
+ if nil != err {
+ return nil, errors.New(fmt.Sprintf("Unable to parse value %s", parsed[2]))
+ }
+ fractionF, err := strconv.ParseFloat(tail, 64)
+ if nil != err {
+ return nil, errors.New(fmt.Sprintf("Unable to parse fraction %s", tail))
+ }
+ fraction := uint64(math.Round(fractionF * FractionalBase))
+ currency := parsed[1]
+ a := NewAmount(currency, value, fraction)
+ return &a, nil
}
// Check if this amount is zero
func (a *Amount) IsZero() bool {
- return (a.Value == 0) && (a.Fraction == 0)
+ return (a.Value == 0) && (a.Fraction == 0)
}
// Returns the string representation of the amount: <currency>:<value>[.<fraction>]
// Omits trailing zeroes.
func (a *Amount) String() string {
- v := strconv.FormatUint(a.Value, 10)
- if a.Fraction != 0 {
- f := strconv.FormatUint(a.Fraction, 10)
- f = strings.TrimRight(f, "0")
- v = fmt.Sprintf("%s.%s", v, f)
- }
- return fmt.Sprintf("%s:%s", a.Currency, v)
+ v := strconv.FormatUint(a.Value, 10)
+ if a.Fraction != 0 {
+ f := strconv.FormatUint(a.Fraction, 10)
+ f = strings.TrimRight(f, "0")
+ v = fmt.Sprintf("%s.%s", v, f)
+ }
+ return fmt.Sprintf("%s:%s", a.Currency, v)
}