diff options
-rw-r--r-- | borrowed_misc.go | 20 | ||||
-rw-r--r-- | compat/json/compat_test.go | 4 | ||||
-rw-r--r-- | decode.go | 11 | ||||
-rw-r--r-- | encode.go | 4 | ||||
-rw-r--r-- | internal/jsonstruct/borrowed_misc.go | 30 | ||||
-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.go | 7 |
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 @@ -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 { @@ -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 |