mirror of
https://github.com/hanzo-fi/stack.git
synced 2026-10-30 20:34:43 +00:00
95 lines
2.2 KiB
Go
95 lines
2.2 KiB
Go
package machine
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"math/big"
|
|
"regexp"
|
|
)
|
|
|
|
type Portion struct {
|
|
Remaining bool `json:"remaining"`
|
|
Specific *big.Rat `json:"specific"`
|
|
}
|
|
|
|
func (Portion) GetType() Type { return TypePortion }
|
|
|
|
func NewPortionRemaining() Portion {
|
|
return Portion{
|
|
Remaining: true,
|
|
Specific: nil,
|
|
}
|
|
}
|
|
|
|
func NewPortionSpecific(r big.Rat) (*Portion, error) {
|
|
if r.Cmp(big.NewRat(0, 1)) == -1 || r.Cmp(big.NewRat(1, 1)) == 1 {
|
|
return nil, errors.New("portion must be between 0% and 100% inclusive")
|
|
}
|
|
return &Portion{
|
|
Remaining: false,
|
|
Specific: &r,
|
|
}, nil
|
|
}
|
|
|
|
func ValidatePortionSpecific(p Portion) error {
|
|
if p.Remaining {
|
|
return errors.New("remaining should not be true for a specific portion")
|
|
}
|
|
if p.Specific == nil {
|
|
return errors.New("specific portion should not be nil")
|
|
}
|
|
if p.Specific.Cmp(big.NewRat(0, 1)) == -1 || p.Specific.Cmp(big.NewRat(1, 1)) == 1 {
|
|
return errors.New("specific portion must be between 0% and 100% inclusive")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (lhs Portion) Equals(rhs Portion) bool {
|
|
if lhs.Remaining != rhs.Remaining {
|
|
return false
|
|
}
|
|
if !lhs.Remaining && lhs.Specific.Cmp(rhs.Specific) != 0 {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
func ParsePortionSpecific(input string) (*Portion, error) {
|
|
var res *big.Rat
|
|
var ok bool
|
|
|
|
re := regexp.MustCompile(`^([0-9]+)(?:[.]([0-9]+))?[%]$`)
|
|
percentMatch := re.FindStringSubmatch(input)
|
|
if len(percentMatch) != 0 {
|
|
integral := percentMatch[1]
|
|
fractional := percentMatch[2]
|
|
res, ok = new(big.Rat).SetString(integral + "." + fractional)
|
|
if !ok {
|
|
return nil, errors.New("invalid percent format")
|
|
}
|
|
res.Mul(res, big.NewRat(1, 100))
|
|
} else {
|
|
re = regexp.MustCompile(`^([0-9]+)\s?[/]\s?([0-9]+)$`)
|
|
fractionMatch := re.FindStringSubmatch(input)
|
|
if len(fractionMatch) != 0 {
|
|
numerator := fractionMatch[1]
|
|
denominator := fractionMatch[2]
|
|
res, ok = new(big.Rat).SetString(numerator + "/" + denominator)
|
|
if !ok {
|
|
return nil, errors.New("invalid fractional format")
|
|
}
|
|
}
|
|
}
|
|
if res == nil {
|
|
return nil, errors.New("invalid format")
|
|
}
|
|
return NewPortionSpecific(*res)
|
|
}
|
|
|
|
func (p Portion) String() string {
|
|
if p.Remaining {
|
|
return "remaining"
|
|
}
|
|
return fmt.Sprintf("%v", p.Specific)
|
|
}
|