-
Notifications
You must be signed in to change notification settings - Fork 1
/
aox.go
142 lines (122 loc) · 3.42 KB
/
aox.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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package maybe
import (
"errors"
"fmt"
"reflect"
)
// AoX implements the Maybe monad for a slice of empty interfaces. An AoX is
// considered 'valid' or 'invalid' depending on whether it contains a slice of
// empty interfaces or an error value. A zero-value AoX is invalid and
// Unbox() will return an error to that effect.
type AoX struct {
just []interface{}
err error
}
// NewAoX constructs an AoX from a given slice of empty interfaces or error.
// If e is not nil, returns ErrAoX(e), otherwise returns JustAoX(x).
func NewAoX(x []interface{}, e error) AoX {
if e != nil {
return ErrAoX(e)
}
return JustAoX(x)
}
var errAoXNotSlice = errors.New("NewAoXFromSlice called with non-slice")
// NewAoXFromSlice constructs an AoX from a given slice of arbitrary values or
// error. If e is not nil, returns ErrAoX(e), otherwise, the slice of values
// is converted to a slice of empty interface and returned as JustAoX(x). If
// the provided value is not a slice, ErrAoX is returned.
func NewAoXFromSlice(x interface{}, e error) AoX {
if e != nil {
return ErrAoX(e)
}
if x == nil {
return ErrAoX(errAoXNotSlice)
}
switch reflect.TypeOf(x).Kind() {
case reflect.Slice:
s := reflect.ValueOf(x)
xs := make([]interface{}, s.Len())
for i := 0; i < s.Len(); i++ {
xs[i] = s.Index(i).Interface()
}
return JustAoX(xs)
default:
return ErrAoX(errAoXNotSlice)
}
}
// JustAoX constructs a valid AoX from a given slice of empty interfaces.
func JustAoX(x []interface{}) AoX {
return AoX{just: x}
}
// ErrAoX constructs an invalid AoX from a given error.
func ErrAoX(e error) AoX {
return AoX{err: e}
}
// IsErr returns true for an invalid AoX.
func (m AoX) IsErr() bool {
return m.just == nil || m.err != nil
}
// Bind applies a function that takes a slice of empty interfaces and returns
// an AoX.
func (m AoX) Bind(f func(x []interface{}) AoX) AoX {
if m.IsErr() {
return m
}
return f(m.just)
}
// Join applies a function that takes a slice of empty interfaces and returns
// an I.
func (m AoX) Join(f func(x []interface{}) X) X {
if m.IsErr() {
return ErrX(m.err)
}
return f(m.just)
}
// Split applies a splitting function to each element of a valid AoX,
// resulting in a higher-dimension structure. If the AoX is invalid or if any
// function returns an invalid AoX, Split returns an invalid AoAoX.
func (m AoX) Split(f func(x interface{}) AoX) AoAoX {
if m.IsErr() {
return ErrAoAoX(m.err)
}
xss := make([][]interface{}, len(m.just))
for i, v := range m.just {
xs, err := f(v).Unbox()
if err != nil {
return ErrAoAoX(err)
}
xss[i] = xs
}
return JustAoAoX(xss)
}
// Map applies a function to each element of a valid AoX and returns a new
// AoX. If the AoX is invalid or if any function returns an invalid I, Map
// returns an invalid AoX.
func (m AoX) Map(f func(x interface{}) X) AoX {
if m.IsErr() {
return m
}
xss := make([]interface{}, len(m.just))
for i, v := range m.just {
x, err := f(v).Unbox()
if err != nil {
return ErrAoX(err)
}
xss[i] = x
}
return JustAoX(xss)
}
// String returns a string representation, mostly useful for debugging.
func (m AoX) String() string {
if m.IsErr() {
return fmt.Sprintf("Err %v", m.err)
}
return fmt.Sprintf("Just %v", m.just)
}
// Unbox returns the underlying slice of empty interfaces or error.
func (m AoX) Unbox() ([]interface{}, error) {
if m.just == nil && m.err == nil {
return nil, errors.New("zero-value AoX")
}
return m.just, m.err
}