diff --git a/proptools/filter.go b/proptools/filter.go index e6b3336..54a20d5 100644 --- a/proptools/filter.go +++ b/proptools/filter.go @@ -173,7 +173,13 @@ func filterPropertyStruct(prop reflect.Type, prefix string, maxNameSize int, return nil, true } - if !filtered { + // If the predicate selected all fields in the structure then it is generally better to reuse the + // original type as it avoids the footprint of creating another type. Also, if the original type + // is a named type then it will reduce the size of any structs the caller may create that include + // fields of this type. However, the original type should only be reused if it does not exceed + // maxNameSize. That is, of course, more likely for an anonymous type than a named one but this + // treats them the same. + if !filtered && (maxNameSize < 0 || len(prop.String()) < maxNameSize) { if ptr { return []reflect.Type{reflect.PtrTo(prop)}, false } diff --git a/proptools/filter_test.go b/proptools/filter_test.go index 0ea04bb..1c27cb2 100644 --- a/proptools/filter_test.go +++ b/proptools/filter_test.go @@ -240,6 +240,12 @@ func TestFilterPropertyStruct(t *testing.T) { } func TestFilterPropertyStructSharded(t *testing.T) { + type KeepAllWithAReallyLongNameThatExceedsTheMaxNameSize struct { + A *string `keep:"true"` + B *string `keep:"true"` + C *string `keep:"true"` + } + tests := []struct { name string maxNameSize int @@ -266,6 +272,44 @@ func TestFilterPropertyStructSharded(t *testing.T) { }, filtered: true, }, + { + name: "anonymous where all match but still needs sharding", + maxNameSize: 20, + in: &struct { + A *string `keep:"true"` + B *string `keep:"true"` + C *string `keep:"true"` + }{}, + out: []interface{}{ + &struct { + A *string + }{}, + &struct { + B *string + }{}, + &struct { + C *string + }{}, + }, + filtered: true, + }, + { + name: "named where all match but still needs sharding", + maxNameSize: 20, + in: &KeepAllWithAReallyLongNameThatExceedsTheMaxNameSize{}, + out: []interface{}{ + &struct { + A *string + }{}, + &struct { + B *string + }{}, + &struct { + C *string + }{}, + }, + filtered: true, + }, } for _, test := range tests {