From 1f4a2629d2e568b65bffa3c860be34edd41be494 Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Mon, 31 Jul 2023 19:24:26 -0700 Subject: [PATCH] Zero reflect.Value between uses. Closes #145. --- decoder.go | 8 +++--- reader_test.go | 61 ++++++++++++++++++++++++++++++++++++++++++++++ set_zero_120.go | 10 ++++++++ set_zero_pre120.go | 10 ++++++++ 4 files changed, 86 insertions(+), 3 deletions(-) create mode 100644 set_zero_120.go create mode 100644 set_zero_pre120.go diff --git a/decoder.go b/decoder.go index 0b8708d..dd0f9ba 100644 --- a/decoder.go +++ b/decoder.go @@ -596,18 +596,20 @@ func (d *decoder) decodeMap( mapType := result.Type() keyValue := reflect.New(mapType.Key()).Elem() elemType := mapType.Elem() - elemKind := elemType.Kind() var elemValue reflect.Value for i := uint(0); i < size; i++ { var key []byte var err error key, offset, err = d.decodeKey(offset) - if err != nil { return 0, err } - if !elemValue.IsValid() || elemKind == reflect.Interface { + if elemValue.IsValid() { + // After 1.20 is the minimum supported version, this can just be + // elemValue.SetZero() + reflectSetZero(elemValue) + } else { elemValue = reflect.New(elemType).Elem() } diff --git a/reader_test.go b/reader_test.go index 2ce1ab3..f40541e 100644 --- a/reader_test.go +++ b/reader_test.go @@ -454,6 +454,67 @@ func TestComplexStructWithNestingAndPointer(t *testing.T) { assert.NoError(t, reader.Close()) } +// See GitHub #115. +func TestNestedMapDecode(t *testing.T) { + db, err := Open(testFile("GeoIP2-Country-Test.mmdb")) + require.NoError(t, err) + + var r map[string]map[string]any + + require.NoError(t, db.Lookup(net.ParseIP("89.160.20.128"), &r)) + + assert.Equal( + t, + map[string]map[string]any{ + "continent": { + "code": "EU", + "geoname_id": uint64(6255148), + "names": map[string]any{ + "de": "Europa", + "en": "Europe", + "es": "Europa", + "fr": "Europe", + "ja": "ヨーロッパ", + "pt-BR": "Europa", + "ru": "Европа", + "zh-CN": "欧洲", + }, + }, + "country": { + "geoname_id": uint64(2661886), + "is_in_european_union": true, + "iso_code": "SE", + "names": map[string]any{ + "de": "Schweden", + "en": "Sweden", + "es": "Suecia", + "fr": "Suède", + "ja": "スウェーデン王国", + "pt-BR": "Suécia", + "ru": "Швеция", + "zh-CN": "瑞典", + }, + }, + "registered_country": { + "geoname_id": uint64(2921044), + "is_in_european_union": true, + "iso_code": "DE", + "names": map[string]any{ + "de": "Deutschland", + "en": "Germany", + "es": "Alemania", + "fr": "Allemagne", + "ja": "ドイツ連邦共和国", + "pt-BR": "Alemanha", + "ru": "Германия", + "zh-CN": "德国", + }, + }, + }, + r, + ) +} + func TestNestedOffsetDecode(t *testing.T) { db, err := Open(testFile("GeoIP2-City-Test.mmdb")) require.NoError(t, err) diff --git a/set_zero_120.go b/set_zero_120.go new file mode 100644 index 0000000..33b9dff --- /dev/null +++ b/set_zero_120.go @@ -0,0 +1,10 @@ +//go:build go1.20 +// +build go1.20 + +package maxminddb + +import "reflect" + +func reflectSetZero(v reflect.Value) { + v.SetZero() +} diff --git a/set_zero_pre120.go b/set_zero_pre120.go new file mode 100644 index 0000000..6639de7 --- /dev/null +++ b/set_zero_pre120.go @@ -0,0 +1,10 @@ +//go:build !go1.20 +// +build !go1.20 + +package maxminddb + +import "reflect" + +func reflectSetZero(v reflect.Value) { + v.Set(reflect.Zero(v.Type())) +}