aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/mitchellh/hashstructure
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/mitchellh/hashstructure')
-rw-r--r--vendor/github.com/mitchellh/hashstructure/README.md56
-rw-r--r--vendor/github.com/mitchellh/hashstructure/go.mod1
-rw-r--r--vendor/github.com/mitchellh/hashstructure/hashstructure.go63
3 files changed, 80 insertions, 40 deletions
diff --git a/vendor/github.com/mitchellh/hashstructure/README.md b/vendor/github.com/mitchellh/hashstructure/README.md
index 7d0de5b..28ce45a 100644
--- a/vendor/github.com/mitchellh/hashstructure/README.md
+++ b/vendor/github.com/mitchellh/hashstructure/README.md
@@ -1,4 +1,4 @@
1# hashstructure 1# hashstructure [![GoDoc](https://godoc.org/github.com/mitchellh/hashstructure?status.svg)](https://godoc.org/github.com/mitchellh/hashstructure)
2 2
3hashstructure is a Go library for creating a unique hash value 3hashstructure is a Go library for creating a unique hash value
4for arbitrary values in Go. 4for arbitrary values in Go.
@@ -19,6 +19,9 @@ sending data across the network, caching values locally (de-dup), and so on.
19 19
20 * Optionally specify a custom hash function to optimize for speed, collision 20 * Optionally specify a custom hash function to optimize for speed, collision
21 avoidance for your data set, etc. 21 avoidance for your data set, etc.
22
23 * Optionally hash the output of `.String()` on structs that implement fmt.Stringer,
24 allowing effective hashing of time.Time
22 25
23## Installation 26## Installation
24 27
@@ -34,28 +37,29 @@ For usage and examples see the [Godoc](http://godoc.org/github.com/mitchellh/has
34 37
35A quick code example is shown below: 38A quick code example is shown below:
36 39
37 40```go
38 type ComplexStruct struct { 41type ComplexStruct struct {
39 Name string 42 Name string
40 Age uint 43 Age uint
41 Metadata map[string]interface{} 44 Metadata map[string]interface{}
42 } 45}
43 46
44 v := ComplexStruct{ 47v := ComplexStruct{
45 Name: "mitchellh", 48 Name: "mitchellh",
46 Age: 64, 49 Age: 64,
47 Metadata: map[string]interface{}{ 50 Metadata: map[string]interface{}{
48 "car": true, 51 "car": true,
49 "location": "California", 52 "location": "California",
50 "siblings": []string{"Bob", "John"}, 53 "siblings": []string{"Bob", "John"},
51 }, 54 },
52 } 55}
53 56
54 hash, err := hashstructure.Hash(v, nil) 57hash, err := hashstructure.Hash(v, nil)
55 if err != nil { 58if err != nil {
56 panic(err) 59 panic(err)
57 } 60}
58 61
59 fmt.Printf("%d", hash) 62fmt.Printf("%d", hash)
60 // Output: 63// Output:
61 // 2307517237273902113 64// 2307517237273902113
65```
diff --git a/vendor/github.com/mitchellh/hashstructure/go.mod b/vendor/github.com/mitchellh/hashstructure/go.mod
new file mode 100644
index 0000000..966582a
--- /dev/null
+++ b/vendor/github.com/mitchellh/hashstructure/go.mod
@@ -0,0 +1 @@
module github.com/mitchellh/hashstructure
diff --git a/vendor/github.com/mitchellh/hashstructure/hashstructure.go b/vendor/github.com/mitchellh/hashstructure/hashstructure.go
index 6f586fa..ea13a15 100644
--- a/vendor/github.com/mitchellh/hashstructure/hashstructure.go
+++ b/vendor/github.com/mitchellh/hashstructure/hashstructure.go
@@ -8,6 +8,16 @@ import (
8 "reflect" 8 "reflect"
9) 9)
10 10
11// ErrNotStringer is returned when there's an error with hash:"string"
12type ErrNotStringer struct {
13 Field string
14}
15
16// Error implements error for ErrNotStringer
17func (ens *ErrNotStringer) Error() string {
18 return fmt.Sprintf("hashstructure: %s has hash:\"string\" set, but does not implement fmt.Stringer", ens.Field)
19}
20
11// HashOptions are options that are available for hashing. 21// HashOptions are options that are available for hashing.
12type HashOptions struct { 22type HashOptions struct {
13 // Hasher is the hash function to use. If this isn't set, it will 23 // Hasher is the hash function to use. If this isn't set, it will
@@ -17,12 +27,18 @@ type HashOptions struct {
17 // TagName is the struct tag to look at when hashing the structure. 27 // TagName is the struct tag to look at when hashing the structure.
18 // By default this is "hash". 28 // By default this is "hash".
19 TagName string 29 TagName string
30
31 // ZeroNil is flag determining if nil pointer should be treated equal
32 // to a zero value of pointed type. By default this is false.
33 ZeroNil bool
20} 34}
21 35
22// Hash returns the hash value of an arbitrary value. 36// Hash returns the hash value of an arbitrary value.
23// 37//
24// If opts is nil, then default options will be used. See HashOptions 38// If opts is nil, then default options will be used. See HashOptions
25// for the default values. 39// for the default values. The same *HashOptions value cannot be used
40// concurrently. None of the values within a *HashOptions struct are
41// safe to read/write while hashing is being done.
26// 42//
27// Notes on the value: 43// Notes on the value:
28// 44//
@@ -41,11 +57,14 @@ type HashOptions struct {
41// 57//
42// The available tag values are: 58// The available tag values are:
43// 59//
44// * "ignore" - The field will be ignored and not affect the hash code. 60// * "ignore" or "-" - The field will be ignored and not affect the hash code.
45// 61//
46// * "set" - The field will be treated as a set, where ordering doesn't 62// * "set" - The field will be treated as a set, where ordering doesn't
47// affect the hash code. This only works for slices. 63// affect the hash code. This only works for slices.
48// 64//
65// * "string" - The field will be hashed as a string, only works when the
66// field implements fmt.Stringer
67//
49func Hash(v interface{}, opts *HashOptions) (uint64, error) { 68func Hash(v interface{}, opts *HashOptions) (uint64, error) {
50 // Create default options 69 // Create default options
51 if opts == nil { 70 if opts == nil {
@@ -63,15 +82,17 @@ func Hash(v interface{}, opts *HashOptions) (uint64, error) {
63 82
64 // Create our walker and walk the structure 83 // Create our walker and walk the structure
65 w := &walker{ 84 w := &walker{
66 h: opts.Hasher, 85 h: opts.Hasher,
67 tag: opts.TagName, 86 tag: opts.TagName,
87 zeronil: opts.ZeroNil,
68 } 88 }
69 return w.visit(reflect.ValueOf(v), nil) 89 return w.visit(reflect.ValueOf(v), nil)
70} 90}
71 91
72type walker struct { 92type walker struct {
73 h hash.Hash64 93 h hash.Hash64
74 tag string 94 tag string
95 zeronil bool
75} 96}
76 97
77type visitOpts struct { 98type visitOpts struct {
@@ -84,6 +105,8 @@ type visitOpts struct {
84} 105}
85 106
86func (w *walker) visit(v reflect.Value, opts *visitOpts) (uint64, error) { 107func (w *walker) visit(v reflect.Value, opts *visitOpts) (uint64, error) {
108 t := reflect.TypeOf(0)
109
87 // Loop since these can be wrapped in multiple layers of pointers 110 // Loop since these can be wrapped in multiple layers of pointers
88 // and interfaces. 111 // and interfaces.
89 for { 112 for {
@@ -96,6 +119,9 @@ func (w *walker) visit(v reflect.Value, opts *visitOpts) (uint64, error) {
96 } 119 }
97 120
98 if v.Kind() == reflect.Ptr { 121 if v.Kind() == reflect.Ptr {
122 if w.zeronil {
123 t = v.Type().Elem()
124 }
99 v = reflect.Indirect(v) 125 v = reflect.Indirect(v)
100 continue 126 continue
101 } 127 }
@@ -105,8 +131,7 @@ func (w *walker) visit(v reflect.Value, opts *visitOpts) (uint64, error) {
105 131
106 // If it is nil, treat it like a zero. 132 // If it is nil, treat it like a zero.
107 if !v.IsValid() { 133 if !v.IsValid() {
108 var tmp int8 134 v = reflect.Zero(t)
109 v = reflect.ValueOf(tmp)
110 } 135 }
111 136
112 // Binary writing can use raw ints, we have to convert to 137 // Binary writing can use raw ints, we have to convert to
@@ -189,8 +214,8 @@ func (w *walker) visit(v reflect.Value, opts *visitOpts) (uint64, error) {
189 return h, nil 214 return h, nil
190 215
191 case reflect.Struct: 216 case reflect.Struct:
192 var include Includable
193 parent := v.Interface() 217 parent := v.Interface()
218 var include Includable
194 if impl, ok := parent.(Includable); ok { 219 if impl, ok := parent.(Includable); ok {
195 include = impl 220 include = impl
196 } 221 }
@@ -203,7 +228,7 @@ func (w *walker) visit(v reflect.Value, opts *visitOpts) (uint64, error) {
203 228
204 l := v.NumField() 229 l := v.NumField()
205 for i := 0; i < l; i++ { 230 for i := 0; i < l; i++ {
206 if v := v.Field(i); v.CanSet() || t.Field(i).Name != "_" { 231 if innerV := v.Field(i); v.CanSet() || t.Field(i).Name != "_" {
207 var f visitFlag 232 var f visitFlag
208 fieldType := t.Field(i) 233 fieldType := t.Field(i)
209 if fieldType.PkgPath != "" { 234 if fieldType.PkgPath != "" {
@@ -212,14 +237,25 @@ func (w *walker) visit(v reflect.Value, opts *visitOpts) (uint64, error) {
212 } 237 }
213 238
214 tag := fieldType.Tag.Get(w.tag) 239 tag := fieldType.Tag.Get(w.tag)
215 if tag == "ignore" { 240 if tag == "ignore" || tag == "-" {
216 // Ignore this field 241 // Ignore this field
217 continue 242 continue
218 } 243 }
219 244
245 // if string is set, use the string value
246 if tag == "string" {
247 if impl, ok := innerV.Interface().(fmt.Stringer); ok {
248 innerV = reflect.ValueOf(impl.String())
249 } else {
250 return 0, &ErrNotStringer{
251 Field: v.Type().Field(i).Name,
252 }
253 }
254 }
255
220 // Check if we implement includable and check it 256 // Check if we implement includable and check it
221 if include != nil { 257 if include != nil {
222 incl, err := include.HashInclude(fieldType.Name, v) 258 incl, err := include.HashInclude(fieldType.Name, innerV)
223 if err != nil { 259 if err != nil {
224 return 0, err 260 return 0, err
225 } 261 }
@@ -238,7 +274,7 @@ func (w *walker) visit(v reflect.Value, opts *visitOpts) (uint64, error) {
238 return 0, err 274 return 0, err
239 } 275 }
240 276
241 vh, err := w.visit(v, &visitOpts{ 277 vh, err := w.visit(innerV, &visitOpts{
242 Flags: f, 278 Flags: f,
243 Struct: parent, 279 Struct: parent,
244 StructField: fieldType.Name, 280 StructField: fieldType.Name,
@@ -289,7 +325,6 @@ func (w *walker) visit(v reflect.Value, opts *visitOpts) (uint64, error) {
289 return 0, fmt.Errorf("unknown kind to hash: %s", k) 325 return 0, fmt.Errorf("unknown kind to hash: %s", k)
290 } 326 }
291 327
292 return 0, nil
293} 328}
294 329
295func hashUpdateOrdered(h hash.Hash64, a, b uint64) uint64 { 330func hashUpdateOrdered(h hash.Hash64, a, b uint64) uint64 {