-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmap.go
102 lines (87 loc) · 2.54 KB
/
map.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
package valis
import (
"github.com/soranoba/valis/code"
"reflect"
)
type (
eachKeyRule struct {
rules []Rule
}
eachValueRule struct {
rules []Rule
}
keyRule struct {
key interface{}
rules []Rule
}
)
// Key returns a new rule that verifies the value of the key meets the rules and all common rules.
func Key(key interface{}, rules ...Rule) Rule {
if !reflect.ValueOf(key).IsValid() {
panic("key is an invalid value")
}
return &keyRule{key: key, rules: rules}
}
func (rule *keyRule) Validate(validator *Validator, value interface{}) {
val := reflect.ValueOf(value)
for val.Kind() == reflect.Ptr {
val = val.Elem()
}
if val.Kind() != reflect.Map {
validator.ErrorCollector().Add(validator.Location(), NewError(code.NotMap, value))
return
}
keyVal := reflect.ValueOf(rule.key)
if !keyVal.Type().AssignableTo(val.Type().Key()) {
validator.ErrorCollector().Add(validator.Location(), NewError(code.NotAssignable, value, keyVal.Type().String()))
return
}
mapValue := val.MapIndex(keyVal)
if mapValue.IsValid() && mapValue.CanInterface() {
validator.DiveMapKey(rule.key, func(v *Validator) {
And(rule.rules...).Validate(v, mapValue.Interface())
})
} else {
validator.ErrorCollector().Add(validator.Location(), NewError(code.NoKey, value, rule.key))
}
}
// EachKeys returns a new rule that verifies all keys of the map meet the rules and all common rules.
func EachKeys(rules ...Rule) Rule {
return &eachKeyRule{rules: rules}
}
func (rule *eachKeyRule) Validate(validator *Validator, value interface{}) {
val := reflect.ValueOf(value)
for val.Kind() == reflect.Ptr {
val = val.Elem()
}
if val.Kind() != reflect.Map {
validator.ErrorCollector().Add(validator.Location(), NewError(code.NotMap, value))
return
}
for _, keyVal := range val.MapKeys() {
k := keyVal.Interface()
validator.DiveMapKey(k, func(v *Validator) {
And(rule.rules...).Validate(v, k)
})
}
}
// EachValues returns a new rule that verifies all values of the map meet the rules and all common rules.
func EachValues(rules ...Rule) Rule {
return &eachValueRule{rules: rules}
}
func (rule *eachValueRule) Validate(validator *Validator, value interface{}) {
val := reflect.ValueOf(value)
for val.Kind() == reflect.Ptr {
val = val.Elem()
}
if val.Kind() != reflect.Map {
validator.ErrorCollector().Add(validator.Location(), NewError(code.NotMap, value))
return
}
iter := val.MapRange()
for iter.Next() {
validator.DiveMapValue(iter.Key().Interface(), func(v *Validator) {
And(rule.rules...).Validate(v, iter.Value().Interface())
})
}
}