-
Notifications
You must be signed in to change notification settings - Fork 225
Expand file tree
/
Copy pathfrom.go
More file actions
202 lines (184 loc) · 4.32 KB
/
from.go
File metadata and controls
202 lines (184 loc) · 4.32 KB
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
194
195
196
197
198
199
200
201
202
package linq
import (
"context"
"fmt"
"iter"
"reflect"
)
// Query is the type returned from query functions. It can be iterated manually
// as shown in the example.
type Query struct {
Iterate iter.Seq[any]
}
// KeyValue is a type used to iterate over a map. This type is also used by ToMap()
// method to output the result of a query into a map.
type KeyValue struct {
Key any
Value any
}
// Iterable is an interface that has to be implemented by a custom collection
// to work with linq.
type Iterable interface {
Iterate() iter.Seq[any]
}
// FromSlice initializes a linq query with a passed slice.
func FromSlice[S ~[]T, T any](source S) Query {
return Query{
Iterate: func(yield func(any) bool) {
for _, item := range source {
if !yield(item) {
return
}
}
},
}
}
// FromMap initializes a linq query with a passed map.
func FromMap[M ~map[K]V, K comparable, V any](source M) Query {
return Query{
Iterate: func(yield func(any) bool) {
for k, v := range source {
if !yield(KeyValue{
Key: k,
Value: v,
}) {
return
}
}
},
}
}
// FromChannel initializes a linq query with a passed channel, linq iterates over
// the channel until it is closed.
func FromChannel[T any](source <-chan T) Query {
return Query{
Iterate: func(yield func(any) bool) {
for item := range source {
if !yield(item) {
return
}
}
},
}
}
// FromChannelWithContext initializes a linq query with a passed channel
// and stops iterating either when the channel is closed or when the context is canceled.
func FromChannelWithContext[T any](ctx context.Context, source <-chan T) Query {
return Query{
Iterate: func(yield func(any) bool) {
for {
select {
case <-ctx.Done():
// Context canceled or deadline exceeded
return
case item, ok := <-source:
if !ok || !yield(item) {
// Channel closed or Consumer stopped early
return
}
}
}
},
}
}
// FromString initializes a query from a string, iterating over its runes.
func FromString[S ~string](source S) Query {
return Query{
Iterate: func(yield func(any) bool) {
for _, ch := range string(source) {
if !yield(ch) {
return
}
}
},
}
}
// FromIterable initializes a linq query with a custom collection passed. This
// collection has to implement Iterable.
func FromIterable(source Iterable) Query {
return Query{
Iterate: source.Iterate(),
}
}
// From initializes a Query from a supported data source by inspecting its
// type at runtime. It panics if the source type is not supported.
//
// NOTE: It is recommended to call the specific From* function directly
// (e.g., FromSlice, FromMap, etc.). This unified function is less efficient
// because it relies on runtime reflection.
func From(source any) Query {
if source == nil {
return Query{
Iterate: func(yield func(any) bool) {},
}
}
switch s := source.(type) {
case string:
return FromString(s)
case Iterable:
return FromIterable(s)
}
sourceValue := reflect.ValueOf(source)
switch sourceValue.Kind() {
case reflect.Slice, reflect.Array:
return Query{
Iterate: func(yield func(any) bool) {
length := sourceValue.Len()
for i := 0; i < length; i++ {
if !yield(sourceValue.Index(i).Interface()) {
return
}
}
},
}
case reflect.Map:
return Query{
Iterate: func(yield func(any) bool) {
for _, key := range sourceValue.MapKeys() {
value := sourceValue.MapIndex(key)
if !yield(KeyValue{Key: key.Interface(), Value: value.Interface()}) {
return
}
}
},
}
case reflect.Chan:
return Query{
Iterate: func(yield func(any) bool) {
for {
value, ok := sourceValue.Recv()
if !ok || !yield(value.Interface()) {
return
}
}
},
}
default:
panic(fmt.Sprintf("unsupported type for From: %T", source))
}
}
// Range generates a sequence of integral numbers within a specified range.
func Range(start, count int) Query {
return Query{
Iterate: func(yield func(any) bool) {
end := start + count
for i := start; i < end; i++ {
if !yield(i) {
return
}
}
},
}
}
// Repeat generates a sequence that contains one repeated value.
func Repeat[T any](value T, count int) Query {
return Query{
Iterate: func(yield func(any) bool) {
for i := 0; i < count; i++ {
if !yield(value) {
return
}
}
},
}
}