Skip to content

Commit 2af0544

Browse files
committed
Fix panic with embedded struct. GitHub #28
1 parent 481716c commit 2af0544

File tree

2 files changed

+37
-8
lines changed

2 files changed

+37
-8
lines changed

decoder.go

+19-8
Original file line numberDiff line numberDiff line change
@@ -139,19 +139,30 @@ func (d *decoder) unmarshalBool(size uint, offset uint, result reflect.Value) (u
139139
return newOffset, newUnmarshalTypeError(value, result.Type())
140140
}
141141

142-
// follow pointers and create values as necessary
142+
// indirect follows pointers and create values as necessary. This is
143+
// heavily based on encoding/json as my original version had a subtle
144+
// bug. This method should be considered to be licensed under
145+
// https://golang.org/LICENSE
143146
func (d *decoder) indirect(result reflect.Value) reflect.Value {
144147
for {
145-
if result.Kind() == reflect.Ptr {
146-
if result.IsNil() {
147-
result.Set(reflect.New(result.Type().Elem()))
148+
// Load value from interface, but only if the result will be
149+
// usefully addressable.
150+
if result.Kind() == reflect.Interface && !result.IsNil() {
151+
e := result.Elem()
152+
if e.Kind() == reflect.Ptr && !e.IsNil() {
153+
result = e
154+
continue
148155
}
149-
result = result.Elem()
150-
} else if result.Kind() == reflect.Interface && !result.IsNil() {
151-
result = result.Elem()
152-
} else {
156+
}
157+
158+
if result.Kind() != reflect.Ptr {
153159
break
154160
}
161+
162+
if result.IsNil() {
163+
result.Set(reflect.New(result.Type().Elem()))
164+
}
165+
result = result.Elem()
155166
}
156167
return result
157168
}

reader_test.go

+18
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,24 @@ func TestNonEmptyNilInterface(t *testing.T) {
173173
assert.Equal(t, err.Error(), "maxminddb: cannot unmarshal map into type maxminddb.TestInterface")
174174
}
175175

176+
type CityTraits struct {
177+
AutonomousSystemNumber uint `json:"autonomous_system_number,omitempty" maxminddb:"autonomous_system_number"`
178+
}
179+
180+
type City struct {
181+
Traits CityTraits `maxminddb:"traits"`
182+
}
183+
184+
func TestEmbeddedStructAsInterface(t *testing.T) {
185+
var city City
186+
var result interface{} = city.Traits
187+
188+
db, err := Open("test-data/test-data/GeoIP2-ISP-Test.mmdb")
189+
require.Nil(t, err)
190+
191+
assert.Nil(t, db.Lookup(net.ParseIP("1.128.0.0"), &result))
192+
}
193+
176194
type BoolInterface interface {
177195
true() bool
178196
}

0 commit comments

Comments
 (0)