-
Notifications
You must be signed in to change notification settings - Fork 225
/
from.go
193 lines (164 loc) · 4.04 KB
/
from.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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
package linq
import "reflect"
// Iterator is an alias for function to iterate over data.
type Iterator func() (item interface{}, ok bool)
// Query is the type returned from query functions. It can be iterated manually
// as shown in the example.
type Query struct {
Iterate func() Iterator
}
// KeyValue is a type that is used to iterate over a map (if query is created
// from a map). This type is also used by ToMap() method to output result of a
// query into a map.
type KeyValue struct {
Key interface{}
Value interface{}
}
// Iterable is an interface that has to be implemented by a custom collection in
// order to work with linq.
type Iterable interface {
Iterate() Iterator
}
// From initializes a linq query with passed slice, array or map as the source.
// String, channel or struct implementing Iterable interface can be used as an
// input. In this case From delegates it to FromString, FromChannel and
// FromIterable internally.
func From(source interface{}) Query {
src := reflect.ValueOf(source)
switch src.Kind() {
case reflect.Slice, reflect.Array:
len := src.Len()
return Query{
Iterate: func() Iterator {
index := 0
return func() (item interface{}, ok bool) {
ok = index < len
if ok {
item = src.Index(index).Interface()
index++
}
return
}
},
}
case reflect.Map:
len := src.Len()
return Query{
Iterate: func() Iterator {
index := 0
keys := src.MapKeys()
return func() (item interface{}, ok bool) {
ok = index < len
if ok {
key := keys[index]
item = KeyValue{
Key: key.Interface(),
Value: src.MapIndex(key).Interface(),
}
index++
}
return
}
},
}
case reflect.String:
return FromString(source.(string))
case reflect.Chan:
if _, ok := source.(chan interface{}); ok {
return FromChannel(source.(chan interface{}))
} else {
return FromChannelT(source)
}
default:
return FromIterable(source.(Iterable))
}
}
// FromChannel initializes a linq query with passed channel, linq iterates over
// channel until it is closed.
func FromChannel(source <-chan interface{}) Query {
return Query{
Iterate: func() Iterator {
return func() (item interface{}, ok bool) {
item, ok = <-source
return
}
},
}
}
// FromChannelT is the typed version of FromChannel.
//
// - source is of type "chan TSource"
//
// NOTE: FromChannel has better performance than FromChannelT.
func FromChannelT(source interface{}) Query {
src := reflect.ValueOf(source)
return Query{
Iterate: func() Iterator {
return func() (interface{}, bool) {
value, ok := src.Recv()
return value.Interface(), ok
}
},
}
}
// FromString initializes a linq query with passed string, linq iterates over
// runes of string.
func FromString(source string) Query {
runes := []rune(source)
len := len(runes)
return Query{
Iterate: func() Iterator {
index := 0
return func() (item interface{}, ok bool) {
ok = index < len
if ok {
item = runes[index]
index++
}
return
}
},
}
}
// FromIterable initializes a linq query with custom collection passed. This
// collection has to implement Iterable interface, linq iterates over items,
// that has to implement Comparable interface or be basic types.
func FromIterable(source Iterable) Query {
return Query{
Iterate: source.Iterate,
}
}
// Range generates a sequence of integral numbers within a specified range.
func Range(start, count int) Query {
return Query{
Iterate: func() Iterator {
index := 0
current := start
return func() (item interface{}, ok bool) {
if index >= count {
return nil, false
}
item, ok = current, true
index++
current++
return
}
},
}
}
// Repeat generates a sequence that contains one repeated value.
func Repeat(value interface{}, count int) Query {
return Query{
Iterate: func() Iterator {
index := 0
return func() (item interface{}, ok bool) {
if index >= count {
return nil, false
}
item, ok = value, true
index++
return
}
},
}
}