Repository navigation
Expand file tree
/
Copy pathcollection.go
More file actions
67 lines (57 loc) · 1.47 KB
/
Copy pathcollection.go
File metadata and controls
67 lines (57 loc) · 1.47 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
package validator
import (
"reflect"
)
func init() { registerRules(&uniqueRule{}) }
var (
_ Rule = (*uniqueRule)(nil)
_ leafCompiler = (*uniqueRule)(nil)
)
// uniqueRule: a slice/array has no duplicate elements (a map no duplicate
// values). Elements compare by canonical string plus dynamic type, so 1 and "1"
// stay distinct. Non-collection non-empty values fail closed.
type uniqueRule struct{}
func (r *uniqueRule) Signature() string { return "unique" }
func (r *uniqueRule) Passes(f *Field) bool {
rv := f.Reflect()
if isEmptyV(rv) {
return true
}
switch rv.Kind() {
case reflect.Slice, reflect.Array:
n := rv.Len()
seen := make(map[uniqueKey]struct{}, n)
for i := range n {
k := elemKey(unwrapValue(rv.Index(i)))
if _, dup := seen[k]; dup {
return false
}
seen[k] = struct{}{}
}
return true
case reflect.Map:
seen := make(map[uniqueKey]struct{}, rv.Len())
for it := rv.MapRange(); it.Next(); {
k := elemKey(unwrapValue(it.Value()))
if _, dup := seen[k]; dup {
return false
}
seen[k] = struct{}{}
}
return true
default:
return false
}
}
func (r *uniqueRule) Message() string { return "The {field} field has duplicate values." }
func (r *uniqueRule) compilePasses([]string) func(*Field) bool { return r.Passes }
type uniqueKey struct {
repr string
typ reflect.Type
}
func elemKey(rv reflect.Value) uniqueKey {
if !rv.IsValid() {
return uniqueKey{}
}
return uniqueKey{repr: cmpString(rv), typ: rv.Type()}
}