summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@lukeshu.com>2023-02-07 12:45:46 -0700
committerLuke Shumaker <lukeshu@lukeshu.com>2023-02-07 14:05:37 -0700
commit643cbc4d6e37d07619bec05039da1abb411d28d4 (patch)
tree68f771d5103d0243ed49b21ff896f01e49a81a72
parent2b9473f5e8816eeea76b2fdada184532be00d3a2 (diff)
Move struct-handling to internal/jsonstruct
-rw-r--r--borrowed_misc.go20
-rw-r--r--compat/json/compat_test.go4
-rw-r--r--decode.go11
-rw-r--r--encode.go4
-rw-r--r--internal/jsonstruct/borrowed_misc.go30
-rw-r--r--internal/jsonstruct/borrowed_tags.go (renamed from internal/jsontags/borrowed_tags.go)2
-rw-r--r--internal/jsonstruct/struct.go (renamed from struct.go)48
-rw-r--r--internal/jsontags/tags.go7
8 files changed, 66 insertions, 60 deletions
diff --git a/borrowed_misc.go b/borrowed_misc.go
index b84158b..59c49aa 100644
--- a/borrowed_misc.go
+++ b/borrowed_misc.go
@@ -8,8 +8,6 @@ package lowmemjson
import (
"reflect"
- "strings"
- "unicode"
)
// isEmptyValue is borrowed from encode.go.
@@ -30,21 +28,3 @@ func isEmptyValue(v reflect.Value) bool {
}
return false
}
-
-// isValidTag is borrowed from encode.go.
-func isValidTag(s string) bool {
- if s == "" {
- return false
- }
- for _, c := range s {
- switch {
- case strings.ContainsRune("!#$%&()*+-./:;<=>?@[]^_{|}~ ", c):
- // Backslash and quote chars are reserved, but
- // otherwise any punctuation chars are allowed
- // in a tag name.
- case !unicode.IsLetter(c) && !unicode.IsDigit(c):
- return false
- }
- }
- return true
-}
diff --git a/compat/json/compat_test.go b/compat/json/compat_test.go
index 4b167d1..2969107 100644
--- a/compat/json/compat_test.go
+++ b/compat/json/compat_test.go
@@ -10,11 +10,11 @@ import (
"git.lukeshu.com/go/lowmemjson"
"git.lukeshu.com/go/lowmemjson/internal/jsonparse"
- "git.lukeshu.com/go/lowmemjson/internal/jsontags"
+ "git.lukeshu.com/go/lowmemjson/internal/jsonstruct"
"git.lukeshu.com/go/lowmemjson/internal/jsontest"
)
-var parseTag = jsontags.ParseTag
+var parseTag = jsonstruct.ParseTag
type scanner = lowmemjson.ReEncoderConfig
diff --git a/decode.go b/decode.go
index 3a9a4b1..487bce4 100644
--- a/decode.go
+++ b/decode.go
@@ -26,6 +26,7 @@ import (
"git.lukeshu.com/go/lowmemjson/internal/base64dec"
"git.lukeshu.com/go/lowmemjson/internal/fastio"
"git.lukeshu.com/go/lowmemjson/internal/jsonparse"
+ "git.lukeshu.com/go/lowmemjson/internal/jsonstruct"
)
// Decodable is the interface implemented by types that can decode a
@@ -532,7 +533,7 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
dec.decodeNull()
return
}
- index := indexStruct(typ)
+ index := jsonstruct.IndexStruct(typ)
var nameBuf strings.Builder
dec.decodeObject(typ, func() {
dec.posStackPush()
@@ -545,10 +546,10 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
name := nameBuf.String()
dec.structStackPush(typ, name)
defer dec.structStackPop()
- idx, ok := index.byName[name]
+ idx, ok := index.ByName[name]
if !ok {
- for oidx := range index.byPos {
- if strings.EqualFold(name, index.byPos[oidx].Name) {
+ for oidx := range index.ByPos {
+ if strings.EqualFold(name, index.ByPos[oidx].Name) {
idx = oidx
ok = true
break
@@ -562,7 +563,7 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
dec.scan(fastio.Discard)
return
}
- field := index.byPos[idx]
+ field := index.ByPos[idx]
fVal := val
for _, idx := range field.Path {
if fVal.Kind() == reflect.Pointer {
diff --git a/encode.go b/encode.go
index ca4e060..fa558b9 100644
--- a/encode.go
+++ b/encode.go
@@ -16,6 +16,8 @@ import (
"strconv"
"strings"
"unsafe"
+
+ "git.lukeshu.com/go/lowmemjson/internal/jsonstruct"
)
// Encodable is the interface implemented by types that can encode
@@ -299,7 +301,7 @@ func encode(w *ReEncoder, val reflect.Value, escaper BackslashEscaper, quote boo
return err
}
empty := true
- for _, field := range indexStruct(val.Type()).byPos {
+ for _, field := range jsonstruct.IndexStruct(val.Type()).ByPos {
fVal, err := val.FieldByIndexErr(field.Path)
if err != nil {
continue
diff --git a/internal/jsonstruct/borrowed_misc.go b/internal/jsonstruct/borrowed_misc.go
new file mode 100644
index 0000000..3b4181e
--- /dev/null
+++ b/internal/jsonstruct/borrowed_misc.go
@@ -0,0 +1,30 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+//
+// SPDX-License-Identifier: BSD-3-Clause
+
+package jsonstruct
+
+import (
+ "strings"
+ "unicode"
+)
+
+// isValidTag is borrowed from encode.go.
+func isValidTag(s string) bool {
+ if s == "" {
+ return false
+ }
+ for _, c := range s {
+ switch {
+ case strings.ContainsRune("!#$%&()*+-./:;<=>?@[]^_{|}~ ", c):
+ // Backslash and quote chars are reserved, but
+ // otherwise any punctuation chars are allowed
+ // in a tag name.
+ case !unicode.IsLetter(c) && !unicode.IsDigit(c):
+ return false
+ }
+ }
+ return true
+}
diff --git a/internal/jsontags/borrowed_tags.go b/internal/jsonstruct/borrowed_tags.go
index aa94b9b..f2ef71c 100644
--- a/internal/jsontags/borrowed_tags.go
+++ b/internal/jsonstruct/borrowed_tags.go
@@ -4,7 +4,7 @@
//
// SPDX-License-Identifier: BSD-3-Clause
-package jsontags // MODIFIED: changed package name
+package jsonstruct // MODIFIED: changed package name
import (
"strings"
diff --git a/struct.go b/internal/jsonstruct/struct.go
index 5ccb62f..830dc80 100644
--- a/struct.go
+++ b/internal/jsonstruct/struct.go
@@ -2,17 +2,17 @@
//
// SPDX-License-Identifier: GPL-2.0-or-later
-package lowmemjson
+package jsonstruct
import (
"reflect"
"git.lukeshu.com/go/typedsync"
-
- "git.lukeshu.com/go/lowmemjson/internal/jsontags"
)
-type structField struct {
+var ParseTag = parseTag
+
+type StructField struct {
Name string
Path []int
Tagged bool
@@ -20,33 +20,33 @@ type structField struct {
Quote bool
}
-// A structIndex is used by Decoder.Decode() and Encoder.Encode() when
+// A StructIndex is used by Decoder.Decode() and Encoder.Encode() when
// decoding-to or encoding-from a struct.
-type structIndex struct {
- byPos []structField
- byName map[string]int
+type StructIndex struct {
+ ByPos []StructField
+ ByName map[string]int
}
-var structIndexCache typedsync.CacheMap[reflect.Type, structIndex]
+var structIndexCache typedsync.CacheMap[reflect.Type, StructIndex]
-// indexStruct takes a struct Type, and indexes its fields for use by
+// IndexStruct takes a struct Type, and indexes its fields for use by
// Decoder.Decode() and Encoder.Encode(). indexStruct caches its
// results.
-func indexStruct(typ reflect.Type) structIndex {
+func IndexStruct(typ reflect.Type) StructIndex {
ret, _ := structIndexCache.LoadOrCompute(typ, indexStructReal)
return ret
}
// indexStructReal is like indexStruct, but is the real indexer,
// bypassing the cache.
-func indexStructReal(typ reflect.Type) structIndex {
- var byPos []structField
+func indexStructReal(typ reflect.Type) StructIndex {
+ var byPos []StructField
byName := make(map[string][]int)
indexStructInner(typ, &byPos, byName, nil, map[reflect.Type]struct{}{})
- ret := structIndex{
- byName: make(map[string]int),
+ ret := StructIndex{
+ ByName: make(map[string]int),
}
for curPos, _field := range byPos {
@@ -56,8 +56,8 @@ func indexStructReal(typ reflect.Type) structIndex {
case 0:
// do nothing
case 1:
- ret.byName[name] = len(ret.byPos)
- ret.byPos = append(ret.byPos, _field)
+ ret.ByName[name] = len(ret.ByPos)
+ ret.ByPos = append(ret.ByPos, _field)
default:
// To quote the encoding/json docs (version 1.18.4):
//
@@ -106,14 +106,14 @@ func indexStructReal(typ reflect.Type) structIndex {
// do nothing
case 1:
if curPos == untaggedPos {
- ret.byName[name] = len(ret.byPos)
- ret.byPos = append(ret.byPos, byPos[curPos])
+ ret.ByName[name] = len(ret.ByPos)
+ ret.ByPos = append(ret.ByPos, byPos[curPos])
}
}
case 1:
if curPos == taggedPos {
- ret.byName[name] = len(ret.byPos)
- ret.byPos = append(ret.byPos, byPos[curPos])
+ ret.ByName[name] = len(ret.ByPos)
+ ret.ByPos = append(ret.ByPos, byPos[curPos])
}
}
}
@@ -128,7 +128,7 @@ func indexStructReal(typ reflect.Type) structIndex {
// call itself; keeping track of stack information with `stackPath`
// (which identifies where we are in the parent struct) and
// `stackSeen` (which is used for detecting loops).
-func indexStructInner(typ reflect.Type, byPos *[]structField, byName map[string][]int, stackPath []int, stackSeen map[reflect.Type]struct{}) {
+func indexStructInner(typ reflect.Type, byPos *[]StructField, byName map[string][]int, stackPath []int, stackSeen map[reflect.Type]struct{}) {
if _, ok := stackSeen[typ]; ok {
return
}
@@ -157,7 +157,7 @@ func indexStructInner(typ reflect.Type, byPos *[]structField, byName map[string]
if tag == "-" {
continue
}
- tagName, opts := jsontags.ParseTag(tag)
+ tagName, opts := parseTag(tag)
name := tagName
if !isValidTag(name) {
name = ""
@@ -174,7 +174,7 @@ func indexStructInner(typ reflect.Type, byPos *[]structField, byName map[string]
indexStructInner(t, byPos, byName, stackPath, stackSeen)
} else {
byName[name] = append(byName[name], len(*byPos))
- *byPos = append(*byPos, structField{
+ *byPos = append(*byPos, StructField{
Name: name,
Path: append([]int(nil), stackPath...),
Tagged: tagName != "",
diff --git a/internal/jsontags/tags.go b/internal/jsontags/tags.go
deleted file mode 100644
index 386824d..0000000
--- a/internal/jsontags/tags.go
+++ /dev/null
@@ -1,7 +0,0 @@
-// Copyright (C) 2022-2023 Luke Shumaker <lukeshu@lukeshu.com>
-//
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-package jsontags
-
-var ParseTag = parseTag