-
-
Notifications
You must be signed in to change notification settings - Fork 357
/
range.go
89 lines (73 loc) · 2.03 KB
/
range.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
package app
import (
"reflect"
"sort"
"github.com/maxence-charriere/go-app/v6/pkg/log"
)
// RangeLoop represents a control structure that iterates within a slice, an
// array or a map.
type RangeLoop interface {
Node
nodes() []UI
// Slice sets the loop content by repeating the given function for the
// number of elements in the source.
//
// It panics if the range source is not a slice or an array.
Slice(f func(int) UI) RangeLoop
// Map sets the loop content by repeating the given function for the number
// of elements in the source. Elements are ordered by keys.
//
// It panics if the range source is not a map or if map keys are not strings.
Map(f func(string) UI) RangeLoop
}
// Range returns a range loop that iterates within the given source. Source must
// be a slice, an array or a map with strings as keys.
func Range(src interface{}) RangeLoop {
return rangeCondition{source: src}
}
type rangeCondition struct {
source interface{}
body []UI
}
func (c rangeCondition) nodeType() reflect.Type {
return reflect.TypeOf(c)
}
func (c rangeCondition) nodes() []UI {
return c.body
}
func (c rangeCondition) Slice(f func(int) UI) RangeLoop {
v := reflect.ValueOf(c.source)
if v.Kind() != reflect.Slice && v.Kind() != reflect.Array {
log.Error("range source is not a slice or array").
T("source-type", v.Type()).
Panic()
}
c.body = nil
for i := 0; i < v.Len(); i++ {
c.body = append(c.body, indirect(f(i))...)
}
return c
}
func (c rangeCondition) Map(f func(string) UI) RangeLoop {
v := reflect.ValueOf(c.source)
if v.Kind() != reflect.Map {
log.Error("range source is not a map").
T("source-type", v.Type()).
Panic()
}
if keyType := v.Type().Key(); keyType.Kind() != reflect.String {
log.Error("range source keys are not strings").
T("key-type", keyType).
Panic()
}
c.body = nil
keys := make([]string, 0, v.Len())
for _, k := range v.MapKeys() {
keys = append(keys, k.String())
}
sort.Strings(keys)
for _, k := range keys {
c.body = append(c.body, indirect(f(k))...)
}
return c
}