Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit acf7938

Browse files
committedJun 21, 2025
Add separate Decoder type for manual decoding
This is largely based on #91.
1 parent bee2d4a commit acf7938

File tree

9 files changed

+846
-426
lines changed

9 files changed

+846
-426
lines changed
 

‎deserializer_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ func (d *testDeserializer) Uint32(v uint32) error {
6969
}
7070

7171
func (d *testDeserializer) Int32(v int32) error {
72-
return d.add(int(v))
72+
return d.add(v)
7373
}
7474

7575
func (d *testDeserializer) Uint64(v uint64) error {

‎internal/decoder/data_decoder.go

Lines changed: 511 additions & 0 deletions
Large diffs are not rendered by default.

‎internal/decoder/decoder.go

Lines changed: 287 additions & 384 deletions
Large diffs are not rendered by default.

‎internal/decoder/reflection.go

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,19 @@ import (
1111
"github.com/oschwald/maxminddb-golang/v2/internal/mmdberrors"
1212
)
1313

14-
// Decoder is a decoder for the MMDB data section.
15-
type Decoder struct {
14+
// ReflectionDecoder is a decoder for the MMDB data section.
15+
type ReflectionDecoder struct {
1616
DataDecoder
1717
}
1818

19-
// New creates a [Decoder].
20-
func New(buffer []byte) Decoder {
21-
return Decoder{DataDecoder: NewDataDecoder(buffer)}
19+
// New creates a [ReflectionDecoder].
20+
func New(buffer []byte) ReflectionDecoder {
21+
return ReflectionDecoder{DataDecoder: NewDataDecoder(buffer)}
2222
}
2323

2424
// Decode decodes the data value at offset and stores it in the value
2525
// pointed at by v.
26-
func (d *Decoder) Decode(offset uint, v any) error {
26+
func (d *ReflectionDecoder) Decode(offset uint, v any) error {
2727
rv := reflect.ValueOf(v)
2828
if rv.Kind() != reflect.Ptr || rv.IsNil() {
2929
return errors.New("result param must be a pointer")
@@ -38,7 +38,7 @@ func (d *Decoder) Decode(offset uint, v any) error {
3838
return err
3939
}
4040

41-
func (d *Decoder) decode(offset uint, result reflect.Value, depth int) (uint, error) {
41+
func (d *ReflectionDecoder) decode(offset uint, result reflect.Value, depth int) (uint, error) {
4242
if depth > maximumDataStructureDepth {
4343
return 0, mmdberrors.NewInvalidDatabaseError(
4444
"exceeded maximum data structure depth; database is likely corrupt",
@@ -58,7 +58,7 @@ func (d *Decoder) decode(offset uint, result reflect.Value, depth int) (uint, er
5858

5959
// DecodePath decodes the data value at offset and stores the value assocated
6060
// with the path in the value pointed at by v.
61-
func (d *Decoder) DecodePath(
61+
func (d *ReflectionDecoder) DecodePath(
6262
offset uint,
6363
path []any,
6464
v any,
@@ -147,7 +147,7 @@ PATH:
147147
return err
148148
}
149149

150-
func (d *Decoder) decodeFromType(
150+
func (d *ReflectionDecoder) decodeFromType(
151151
dtype Type,
152152
size uint,
153153
offset uint,
@@ -242,7 +242,7 @@ func indirect(result reflect.Value) reflect.Value {
242242

243243
var sliceType = reflect.TypeOf([]byte{})
244244

245-
func (d *Decoder) unmarshalBytes(size, offset uint, result reflect.Value) (uint, error) {
245+
func (d *ReflectionDecoder) unmarshalBytes(size, offset uint, result reflect.Value) (uint, error) {
246246
value, newOffset, err := d.decodeBytes(size, offset)
247247
if err != nil {
248248
return 0, err
@@ -263,7 +263,9 @@ func (d *Decoder) unmarshalBytes(size, offset uint, result reflect.Value) (uint,
263263
return newOffset, mmdberrors.NewUnmarshalTypeError(value, result.Type())
264264
}
265265

266-
func (d *Decoder) unmarshalFloat32(size, offset uint, result reflect.Value) (uint, error) {
266+
func (d *ReflectionDecoder) unmarshalFloat32(
267+
size, offset uint, result reflect.Value,
268+
) (uint, error) {
267269
if size != 4 {
268270
return 0, mmdberrors.NewInvalidDatabaseError(
269271
"the MaxMind DB file's data section contains bad data (float32 size of %v)",
@@ -288,7 +290,9 @@ func (d *Decoder) unmarshalFloat32(size, offset uint, result reflect.Value) (uin
288290
return newOffset, mmdberrors.NewUnmarshalTypeError(value, result.Type())
289291
}
290292

291-
func (d *Decoder) unmarshalFloat64(size, offset uint, result reflect.Value) (uint, error) {
293+
func (d *ReflectionDecoder) unmarshalFloat64(
294+
size, offset uint, result reflect.Value,
295+
) (uint, error) {
292296
if size != 8 {
293297
return 0, mmdberrors.NewInvalidDatabaseError(
294298
"the MaxMind DB file's data section contains bad data (float 64 size of %v)",
@@ -316,15 +320,15 @@ func (d *Decoder) unmarshalFloat64(size, offset uint, result reflect.Value) (uin
316320
return newOffset, mmdberrors.NewUnmarshalTypeError(value, result.Type())
317321
}
318322

319-
func (d *Decoder) unmarshalInt32(size, offset uint, result reflect.Value) (uint, error) {
323+
func (d *ReflectionDecoder) unmarshalInt32(size, offset uint, result reflect.Value) (uint, error) {
320324
if size > 4 {
321325
return 0, mmdberrors.NewInvalidDatabaseError(
322326
"the MaxMind DB file's data section contains bad data (int32 size of %v)",
323327
size,
324328
)
325329
}
326330

327-
value, newOffset, err := d.decodeInt(size, offset)
331+
value, newOffset, err := d.decodeInt32(size, offset)
328332
if err != nil {
329333
return 0, err
330334
}
@@ -356,7 +360,7 @@ func (d *Decoder) unmarshalInt32(size, offset uint, result reflect.Value) (uint,
356360
return newOffset, mmdberrors.NewUnmarshalTypeError(value, result.Type())
357361
}
358362

359-
func (d *Decoder) unmarshalMap(
363+
func (d *ReflectionDecoder) unmarshalMap(
360364
size uint,
361365
offset uint,
362366
result reflect.Value,
@@ -381,7 +385,7 @@ func (d *Decoder) unmarshalMap(
381385
}
382386
}
383387

384-
func (d *Decoder) unmarshalPointer(
388+
func (d *ReflectionDecoder) unmarshalPointer(
385389
size, offset uint,
386390
result reflect.Value,
387391
depth int,
@@ -394,7 +398,7 @@ func (d *Decoder) unmarshalPointer(
394398
return newOffset, err
395399
}
396400

397-
func (d *Decoder) unmarshalSlice(
401+
func (d *ReflectionDecoder) unmarshalSlice(
398402
size uint,
399403
offset uint,
400404
result reflect.Value,
@@ -415,7 +419,7 @@ func (d *Decoder) unmarshalSlice(
415419
return 0, mmdberrors.NewUnmarshalTypeStrError("array", result.Type())
416420
}
417421

418-
func (d *Decoder) unmarshalString(size, offset uint, result reflect.Value) (uint, error) {
422+
func (d *ReflectionDecoder) unmarshalString(size, offset uint, result reflect.Value) (uint, error) {
419423
value, newOffset, err := d.decodeString(size, offset)
420424
if err != nil {
421425
return 0, err
@@ -434,7 +438,7 @@ func (d *Decoder) unmarshalString(size, offset uint, result reflect.Value) (uint
434438
return newOffset, mmdberrors.NewUnmarshalTypeError(value, result.Type())
435439
}
436440

437-
func (d *Decoder) unmarshalUint(
441+
func (d *ReflectionDecoder) unmarshalUint(
438442
size, offset uint,
439443
result reflect.Value,
440444
uintType uint,
@@ -447,7 +451,7 @@ func (d *Decoder) unmarshalUint(
447451
)
448452
}
449453

450-
value, newOffset, err := d.decodeUint(size, offset)
454+
value, newOffset, err := d.decodeUint64(size, offset)
451455
if err != nil {
452456
return 0, err
453457
}
@@ -480,7 +484,9 @@ func (d *Decoder) unmarshalUint(
480484

481485
var bigIntType = reflect.TypeOf(big.Int{})
482486

483-
func (d *Decoder) unmarshalUint128(size, offset uint, result reflect.Value) (uint, error) {
487+
func (d *ReflectionDecoder) unmarshalUint128(
488+
size, offset uint, result reflect.Value,
489+
) (uint, error) {
484490
if size > 16 {
485491
return 0, mmdberrors.NewInvalidDatabaseError(
486492
"the MaxMind DB file's data section contains bad data (uint128 size of %v)",
@@ -508,7 +514,7 @@ func (d *Decoder) unmarshalUint128(size, offset uint, result reflect.Value) (uin
508514
return newOffset, mmdberrors.NewUnmarshalTypeError(value, result.Type())
509515
}
510516

511-
func (d *Decoder) decodeMap(
517+
func (d *ReflectionDecoder) decodeMap(
512518
size uint,
513519
offset uint,
514520
result reflect.Value,
@@ -547,7 +553,7 @@ func (d *Decoder) decodeMap(
547553
return offset, nil
548554
}
549555

550-
func (d *Decoder) decodeSlice(
556+
func (d *ReflectionDecoder) decodeSlice(
551557
size uint,
552558
offset uint,
553559
result reflect.Value,
@@ -564,7 +570,7 @@ func (d *Decoder) decodeSlice(
564570
return offset, nil
565571
}
566572

567-
func (d *Decoder) decodeStruct(
573+
func (d *ReflectionDecoder) decodeStruct(
568574
size uint,
569575
offset uint,
570576
result reflect.Value,

‎internal/decoder/decoder_test.go renamed to ‎internal/decoder/reflection_test.go

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -52,18 +52,18 @@ func TestFloat(t *testing.T) {
5252

5353
func TestInt32(t *testing.T) {
5454
int32s := map[string]any{
55-
"0001": 0,
56-
"0401ffffffff": -1,
57-
"0101ff": 255,
58-
"0401ffffff01": -255,
59-
"020101f4": 500,
60-
"0401fffffe0c": -500,
61-
"0201ffff": 65535,
62-
"0401ffff0001": -65535,
63-
"0301ffffff": 16777215,
64-
"0401ff000001": -16777215,
65-
"04017fffffff": 2147483647,
66-
"040180000001": -2147483647,
55+
"0001": int32(0),
56+
"0401ffffffff": int32(-1),
57+
"0101ff": int32(255),
58+
"0401ffffff01": int32(-255),
59+
"020101f4": int32(500),
60+
"0401fffffe0c": int32(-500),
61+
"0201ffff": int32(65535),
62+
"0401ffff0001": int32(-65535),
63+
"0301ffffff": int32(16777215),
64+
"0401ff000001": int32(-16777215),
65+
"04017fffffff": int32(2147483647),
66+
"040180000001": int32(-2147483647),
6767
}
6868
validateDecoding(t, int32s)
6969
}

‎internal/decoder/verifier.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import (
88

99
// VerifyDataSection verifies the data section against the provided
1010
// offsets from the tree.
11-
func (d *Decoder) VerifyDataSection(offsets map[uint]bool) error {
11+
func (d *ReflectionDecoder) VerifyDataSection(offsets map[uint]bool) error {
1212
pointerCount := len(offsets)
1313

1414
var offset uint

‎reader.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ var metadataStartMarker = []byte("\xAB\xCD\xEFMaxMind.com")
2626
type Reader struct {
2727
nodeReader nodeReader
2828
buffer []byte
29-
decoder decoder.Decoder
29+
decoder decoder.ReflectionDecoder
3030
Metadata Metadata
3131
ipv4Start uint
3232
ipv4StartBitDepth int

‎reader_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ func TestLookupNetwork(t *testing.T) {
8383
},
8484
"double": 42.123456,
8585
"float": float32(1.1),
86-
"int32": -268435456,
86+
"int32": int32(-268435456),
8787
"map": map[string]any{
8888
"mapX": map[string]any{
8989
"arrayX": []any{
@@ -234,7 +234,7 @@ func checkDecodingToInterface(t *testing.T, recordInterface any) {
234234
assert.Equal(t, []byte{0x00, 0x00, 0x00, 0x2a}, record["bytes"])
235235
assert.InEpsilon(t, 42.123456, record["double"], 1e-10)
236236
assert.InEpsilon(t, float32(1.1), record["float"], 1e-5)
237-
assert.Equal(t, -268435456, record["int32"])
237+
assert.Equal(t, int32(-268435456), record["int32"])
238238
assert.Equal(t,
239239
map[string]any{
240240
"mapX": map[string]any{

‎result.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ const notFound uint = math.MaxUint
1313
type Result struct {
1414
ip netip.Addr
1515
err error
16-
decoder decoder.Decoder
16+
decoder decoder.ReflectionDecoder
1717
offset uint
1818
prefixLen uint8
1919
}

0 commit comments

Comments
 (0)
Please sign in to comment.