-
Notifications
You must be signed in to change notification settings - Fork 0
/
calculator.go
119 lines (97 loc) · 2.66 KB
/
calculator.go
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
package value
import (
"fmt"
"sort"
"strings"
)
var (
calculators = make(map[string]Calculator)
)
// Calculator performs a calculation to generate a Value.
// It takes a time.Time to represent when this calculation represents
type Calculator func(Time, ...Value) (Value, error)
// As returns a Calculator which will attempt to transform the returned
// value from the wrapped Calculator to the required Unit
func (c Calculator) As(to *Unit) Calculator {
return func(t Time, args ...Value) (Value, error) {
v, err := c(t, args...)
if err == nil {
v, err = v.As(to)
}
return v, err
}
}
// NewCalculator registers a named Calculator
func NewCalculator(id string, calc Calculator) {
id = strings.ToLower(id)
mutex.Lock()
defer mutex.Unlock()
if _, exists := calculators[id]; exists {
panic(fmt.Errorf("calculator %q already defined", id))
}
calculators[id] = calc
}
// GetCalculator returns a named Calculator
func GetCalculator(id string) (Calculator, error) {
id = strings.ToLower(id)
mutex.Lock()
defer mutex.Unlock()
calc, exists := calculators[id]
if exists {
return calc, nil
}
return nil, fmt.Errorf("calculator %q not defined", id)
}
func CalculatorExists(id string) bool {
id = strings.ToLower(id)
mutex.Lock()
defer mutex.Unlock()
_, exists := calculators[id]
return exists
}
// GetCalculatorIDs return's the ID's of all registered Calculator's
func GetCalculatorIDs() []string {
var r []string
mutex.Lock()
defer mutex.Unlock()
for k, _ := range calculators {
r = append(r, k)
}
sort.SliceStable(r, func(i, j int) bool { return r[i] < r[j] })
return r
}
// Calculator2arg utility to convert a function that takes two Value's into a Calculator
func Calculator2arg(f func(_, _ Value) (Value, error)) Calculator {
return func(_ Time, args ...Value) (Value, error) {
return f(args[0], args[1])
}
}
// Calculator3arg utility to convert a function that takes three Value's into a Calculator
func Calculator3arg(f func(_, _, _ Value) (Value, error)) Calculator {
return func(_ Time, args ...Value) (Value, error) {
return f(args[0], args[1], args[2])
}
}
func Basic1ArgCalculator(f func(float64) float64) Calculator {
return func(_ Time, value ...Value) (Value, error) {
if len(value) != 1 {
return Value{}, invalidValue
}
u1 := value[0]
return u1.Unit().Value(f(u1.Float())), nil
}
}
func Basic2ArgCalculator(f func(float64, float64) float64) Calculator {
return func(_ Time, value ...Value) (Value, error) {
if len(value) != 2 {
return Value{}, invalidValue
}
v1 := value[0]
u1 := v1.Unit()
v2, err := value[1].As(u1)
if err != nil {
return Value{}, err
}
return u1.Value(f(v1.Float(), v2.Float())), nil
}
}