Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v2 #144

Merged
merged 16 commits into from
Aug 18, 2024
Merged

v2 #144

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ jobs:
name: Build
strategy:
matrix:
go-version: [1.21.x, 1.22.x]
go-version: [1.23.0-rc.1]
platform: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.platform }}
steps:
Expand Down
1 change: 1 addition & 0 deletions .golangci.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ disable = [
"forcetypeassert",
"funlen",
"gochecknoglobals",
"gocognit",
"godox",
"gomnd",
"inamedparam",
Expand Down
80 changes: 78 additions & 2 deletions decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ const (
_Slice
// We don't use the next two. They are placeholders. See the spec
// for more details.
_Container //nolint: deadcode, varcheck // above
_Marker //nolint: deadcode, varcheck // above
_Container //nolint:deadcode,varcheck // above
_Marker //nolint:deadcode,varcheck // above
_Bool
_Float32
)
Expand Down Expand Up @@ -89,6 +89,82 @@ func (d *decoder) decodeToDeserializer(
return d.decodeFromTypeToDeserializer(typeNum, size, newOffset, dser, depth+1)
}

func (d *decoder) decodePath(
offset uint,
path []any,
result reflect.Value,
) error {
PATH:
for i, v := range path {
var (
typeNum dataType
size uint
err error
)
typeNum, size, offset, err = d.decodeCtrlData(offset)
if err != nil {
return err
}

if typeNum == _Pointer {
pointer, _, err := d.decodePointer(size, offset)
if err != nil {
return err
}

typeNum, size, offset, err = d.decodeCtrlData(pointer)
if err != nil {
return err
}
}

switch v := v.(type) {
case string:
// We are expecting a map
if typeNum != _Map {
// XXX - use type names in errors.
return fmt.Errorf("expected a map for %s but found %d", v, typeNum)
}
for i := uint(0); i < size; i++ {
var key []byte
key, offset, err = d.decodeKey(offset)
if err != nil {
return err
}
if string(key) == v {
continue PATH
}
offset, err = d.nextValueOffset(offset, 1)
if err != nil {
return err
}
}
// Not found. Maybe return a boolean?
return nil
case int:
// We are expecting an array
if typeNum != _Slice {
// XXX - use type names in errors.
return fmt.Errorf("expected a slice for %d but found %d", v, typeNum)
}
if size < uint(v) {
// Slice is smaller than index, not found
return nil
}
// TODO: support negative indexes? Seems useful for subdivisions in
// particular.
offset, err = d.nextValueOffset(offset, uint(v))
if err != nil {
return err
}
default:
return fmt.Errorf("unexpected type for %d value in path, %v: %T", i, v, v)
}
}
_, err := d.decode(offset, result, len(path))
return err
}

func (d *decoder) decodeCtrlData(offset uint) (dataType, uint, uint, error) {
newOffset := offset + 1
if offset >= uint(len(d.buffer)) {
Expand Down
4 changes: 2 additions & 2 deletions decoder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ func validateDecoding(t *testing.T, tests map[string]any) {
for inputStr, expected := range tests {
inputBytes, err := hex.DecodeString(inputStr)
require.NoError(t, err)
d := decoder{inputBytes}
d := decoder{buffer: inputBytes}

var result any
_, err = d.decode(0, reflect.ValueOf(&result), 0)
Expand All @@ -223,7 +223,7 @@ func validateDecoding(t *testing.T, tests map[string]any) {
func TestPointers(t *testing.T) {
bytes, err := os.ReadFile(testFile("maps-with-pointers.raw"))
require.NoError(t, err)
d := decoder{bytes}
d := decoder{buffer: bytes}

expected := map[uint]map[string]string{
0: {"long_key": "long_value1"},
Expand Down
4 changes: 2 additions & 2 deletions deserializer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package maxminddb

import (
"math/big"
"net"
"net/netip"
"testing"

"github.com/stretchr/testify/require"
Expand All @@ -13,7 +13,7 @@ func TestDecodingToDeserializer(t *testing.T) {
require.NoError(t, err, "unexpected error while opening database: %v", err)

dser := testDeserializer{}
err = reader.Lookup(net.ParseIP("::1.1.1.0"), &dser)
err = reader.Lookup(netip.MustParseAddr("::1.1.1.0")).Decode(&dser)
require.NoError(t, err, "unexpected error while doing lookup: %v", err)

checkDecodingToInterface(t, dser.rv)
Expand Down
35 changes: 13 additions & 22 deletions example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ package maxminddb_test
import (
"fmt"
"log"
"net"
"net/netip"

"github.com/oschwald/maxminddb-golang"
"github.com/oschwald/maxminddb-golang/v2"
)

// This example shows how to decode to a struct.
Expand All @@ -16,15 +16,15 @@ func ExampleReader_Lookup_struct() {
}
defer db.Close()

ip := net.ParseIP("81.2.69.142")
addr := netip.MustParseAddr("81.2.69.142")

var record struct {
Country struct {
ISOCode string `maxminddb:"iso_code"`
} `maxminddb:"country"`
} // Or any appropriate struct

err = db.Lookup(ip, &record)
err = db.Lookup(addr).Decode(&record)
if err != nil {
log.Panic(err)
}
Expand All @@ -41,10 +41,10 @@ func ExampleReader_Lookup_interface() {
}
defer db.Close()

ip := net.ParseIP("81.2.69.142")
addr := netip.MustParseAddr("81.2.69.142")

var record any
err = db.Lookup(ip, &record)
err = db.Lookup(addr).Decode(&record)
if err != nil {
log.Panic(err)
}
Expand All @@ -63,20 +63,16 @@ func ExampleReader_Networks() {
}
defer db.Close()

networks := db.Networks(maxminddb.SkipAliasedNetworks)
for networks.Next() {
for result := range db.Networks() {
record := struct {
Domain string `maxminddb:"connection_type"`
}{}

subnet, err := networks.Network(&record)
err := result.Decode(&record)
if err != nil {
log.Panic(err)
}
fmt.Printf("%s: %s\n", subnet.String(), record.Domain)
}
if networks.Err() != nil {
log.Panic(networks.Err())
fmt.Printf("%s: %s\n", result.Prefix(), record.Domain)
}
// Output:
// 1.0.0.0/24: Cable/DSL
Expand Down Expand Up @@ -114,25 +110,20 @@ func ExampleReader_NetworksWithin() {
}
defer db.Close()

_, network, err := net.ParseCIDR("1.0.0.0/8")
prefix, err := netip.ParsePrefix("1.0.0.0/8")
if err != nil {
log.Panic(err)
}

networks := db.NetworksWithin(network, maxminddb.SkipAliasedNetworks)
for networks.Next() {
for result := range db.NetworksWithin(prefix) {
record := struct {
Domain string `maxminddb:"connection_type"`
}{}

subnet, err := networks.Network(&record)
err := result.Decode(&record)
if err != nil {
log.Panic(err)
}
fmt.Printf("%s: %s\n", subnet.String(), record.Domain)
}
if networks.Err() != nil {
log.Panic(networks.Err())
fmt.Printf("%s: %s\n", result.Prefix(), record.Domain)
}

// Output:
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/oschwald/maxminddb-golang
module github.com/oschwald/maxminddb-golang/v2

go 1.21
go 1.23

require (
github.com/stretchr/testify v1.9.0
Expand Down
Loading
Loading