diff options
Diffstat (limited to 'vendor/github.com/mitchellh/hashstructure')
-rw-r--r-- | vendor/github.com/mitchellh/hashstructure/README.md | 56 | ||||
-rw-r--r-- | vendor/github.com/mitchellh/hashstructure/go.mod | 1 | ||||
-rw-r--r-- | vendor/github.com/mitchellh/hashstructure/hashstructure.go | 63 |
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 | ||
3 | hashstructure is a Go library for creating a unique hash value | 3 | hashstructure is a Go library for creating a unique hash value |
4 | for arbitrary values in Go. | 4 | for 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 | ||
35 | A quick code example is shown below: | 38 | A quick code example is shown below: |
36 | 39 | ||
37 | 40 | ```go | |
38 | type ComplexStruct struct { | 41 | type 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{ | 47 | v := 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) | 57 | hash, err := hashstructure.Hash(v, nil) |
55 | if err != nil { | 58 | if err != nil { |
56 | panic(err) | 59 | panic(err) |
57 | } | 60 | } |
58 | 61 | ||
59 | fmt.Printf("%d", hash) | 62 | fmt.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" | ||
12 | type ErrNotStringer struct { | ||
13 | Field string | ||
14 | } | ||
15 | |||
16 | // Error implements error for ErrNotStringer | ||
17 | func (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. |
12 | type HashOptions struct { | 22 | type 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 | // | ||
49 | func Hash(v interface{}, opts *HashOptions) (uint64, error) { | 68 | func 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 | ||
72 | type walker struct { | 92 | type walker struct { |
73 | h hash.Hash64 | 93 | h hash.Hash64 |
74 | tag string | 94 | tag string |
95 | zeronil bool | ||
75 | } | 96 | } |
76 | 97 | ||
77 | type visitOpts struct { | 98 | type visitOpts struct { |
@@ -84,6 +105,8 @@ type visitOpts struct { | |||
84 | } | 105 | } |
85 | 106 | ||
86 | func (w *walker) visit(v reflect.Value, opts *visitOpts) (uint64, error) { | 107 | func (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 | ||
295 | func hashUpdateOrdered(h hash.Hash64, a, b uint64) uint64 { | 330 | func hashUpdateOrdered(h hash.Hash64, a, b uint64) uint64 { |