Skip to content
This repository has been archived by the owner on Jul 22, 2024. It is now read-only.

Commit

Permalink
Browse files Browse the repository at this point in the history
…into LarsFronius-master
  • Loading branch information
mitchellh committed Nov 22, 2020
2 parents 7791672 + 1610f71 commit 5f56cab
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 10 deletions.
34 changes: 24 additions & 10 deletions hashstructure.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ type HashOptions struct {
// to a zero value of pointed type. By default this is false.
ZeroNil bool

// IgnoreZeroValue is determining if zero value fields should be
// ignored for hash calculation.
IgnoreZeroValue bool

// SlicesAsSets assumes that a `set` tag is always present for slices.
// Default is false (in which case the tag is used instead)
SlicesAsSets bool
Expand Down Expand Up @@ -93,21 +97,23 @@ func Hash(v interface{}, opts *HashOptions) (uint64, error) {

// Create our walker and walk the structure
w := &walker{
h: opts.Hasher,
tag: opts.TagName,
zeronil: opts.ZeroNil,
sets: opts.SlicesAsSets,
stringer: opts.UseStringer,
h: opts.Hasher,
tag: opts.TagName,
zeronil: opts.ZeroNil,
ignorezerovalue: opts.IgnoreZeroValue,
sets: opts.SlicesAsSets,
stringer: opts.UseStringer,
}
return w.visit(reflect.ValueOf(v), nil)
}

type walker struct {
h hash.Hash64
tag string
zeronil bool
sets bool
stringer bool
h hash.Hash64
tag string
zeronil bool
ignorezerovalue bool
sets bool
stringer bool
}

type visitOpts struct {
Expand Down Expand Up @@ -248,6 +254,7 @@ func (w *walker) visit(v reflect.Value, opts *visitOpts) (uint64, error) {
l := v.NumField()
for i := 0; i < l; i++ {
if innerV := v.Field(i); v.CanSet() || t.Field(i).Name != "_" {

var f visitFlag
fieldType := t.Field(i)
if fieldType.PkgPath != "" {
Expand All @@ -261,6 +268,13 @@ func (w *walker) visit(v reflect.Value, opts *visitOpts) (uint64, error) {
continue
}

if w.ignorezerovalue {
zeroVal := reflect.Zero(reflect.TypeOf(innerV.Interface())).Interface()
if innerV.Interface() == zeroVal {
continue
}
}

// if string is set, use the string value
if tag == "string" || w.stringer {
if impl, ok := innerV.Interface().(fmt.Stringer); ok {
Expand Down
42 changes: 42 additions & 0 deletions hashstructure_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,48 @@ func TestHash_includable(t *testing.T) {
}
}

func TestHash_ignoreZeroValue(t *testing.T) {
cases := []struct {
IgnoreZeroValue bool
}{
{
IgnoreZeroValue: true,
},
{
IgnoreZeroValue: false,
},
}
structA := struct {
Foo string
Bar string
}{
Foo: "foo",
Bar: "bar",
}
structB := struct {
Foo string
Bar string
Baz string
}{
Foo: "foo",
Bar: "bar",
}

for _, tc := range cases {
hashA, err := Hash(structA, &HashOptions{IgnoreZeroValue: tc.IgnoreZeroValue})
if err != nil {
t.Fatalf("Failed to hash %#v: %s", structA, err)
}
hashB, err := Hash(structB, &HashOptions{IgnoreZeroValue: tc.IgnoreZeroValue})
if err != nil {
t.Fatalf("Failed to hash %#v: %s", structB, err)
}
if (hashA == hashB) != tc.IgnoreZeroValue {
t.Fatalf("bad, expected: %#v\n\n%d\n\n%d", tc.IgnoreZeroValue, hashA, hashB)
}
}
}

func TestHash_includableMap(t *testing.T) {
cases := []struct {
One, Two interface{}
Expand Down

0 comments on commit 5f56cab

Please sign in to comment.