diff options
Diffstat (limited to 'internal')
33 files changed, 295 insertions, 17 deletions
diff --git a/internal/base64.go b/internal/base64dec/base64.go index 291a229..dcb4b1c 100644 --- a/internal/base64.go +++ b/internal/base64dec/base64.go @@ -2,12 +2,14 @@ // // SPDX-License-Identifier: GPL-2.0-or-later -package internal +package base64dec import ( "encoding/base64" "io" "strings" + + "git.lukeshu.com/go/lowmemjson/internal/fastio" ) type base64Decoder struct { @@ -21,7 +23,7 @@ type base64Decoder struct { func NewBase64Decoder(w io.Writer) interface { io.WriteCloser - RuneWriter + fastio.RuneWriter } { return &base64Decoder{ dst: w, @@ -116,7 +118,7 @@ func (dec *base64Decoder) Write(dat []byte) (int, error) { } func (dec *base64Decoder) WriteRune(r rune) (int, error) { - return WriteRune(dec, r) + return fastio.WriteRune(dec, r) } func (dec *base64Decoder) Close() error { diff --git a/internal/base64_test.go b/internal/base64dec/base64_test.go index f18bcd7..cb3063d 100644 --- a/internal/base64_test.go +++ b/internal/base64dec/base64_test.go @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: GPL-2.0-or-later -package internal +package base64dec import ( "bytes" diff --git a/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/06e2c9db80a08b67fad7f1a4606dc7419750995a57828aa25ea57fe7099d5c03 b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/06e2c9db80a08b67fad7f1a4606dc7419750995a57828aa25ea57fe7099d5c03 new file mode 100644 index 0000000..c3774e7 --- /dev/null +++ b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/06e2c9db80a08b67fad7f1a4606dc7419750995a57828aa25ea57fe7099d5c03 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000000") diff --git a/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/24f53a36f8832fec65cac0aa0f3b43ec1c904414fa6d38f6fc288b0bbd69588a b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/24f53a36f8832fec65cac0aa0f3b43ec1c904414fa6d38f6fc288b0bbd69588a new file mode 100644 index 0000000..4c861db --- /dev/null +++ b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/24f53a36f8832fec65cac0aa0f3b43ec1c904414fa6d38f6fc288b0bbd69588a @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000000000000000000000000") diff --git a/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/2d49311ef22319f70a3590a86b406b9f2565987a4a3b6d7660ddc308b5b2fae2 b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/2d49311ef22319f70a3590a86b406b9f2565987a4a3b6d7660ddc308b5b2fae2 new file mode 100644 index 0000000..3d32e14 --- /dev/null +++ b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/2d49311ef22319f70a3590a86b406b9f2565987a4a3b6d7660ddc308b5b2fae2 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000000000000") diff --git a/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/356e28f5914a0f16f3cef81330f1d92060be4d694a93dedd654bf48743a7d2bd b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/356e28f5914a0f16f3cef81330f1d92060be4d694a93dedd654bf48743a7d2bd new file mode 100644 index 0000000..d08ef92 --- /dev/null +++ b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/356e28f5914a0f16f3cef81330f1d92060be4d694a93dedd654bf48743a7d2bd @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000000000000000000000000000") diff --git a/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 new file mode 100644 index 0000000..a96f559 --- /dev/null +++ b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0") diff --git a/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/60c81ee499a7f1e151b66b08f0a4ff81edd7cb53d00dce8ee0eaf31683996026 b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/60c81ee499a7f1e151b66b08f0a4ff81edd7cb53d00dce8ee0eaf31683996026 new file mode 100644 index 0000000..87c024d --- /dev/null +++ b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/60c81ee499a7f1e151b66b08f0a4ff81edd7cb53d00dce8ee0eaf31683996026 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000000000000000000000000000000000000000000000000000") diff --git a/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/66498f377f38b53eebe1ceaa4a53e4de01a04efc02ac9cfda60f9815f80e9b9d b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/66498f377f38b53eebe1ceaa4a53e4de01a04efc02ac9cfda60f9815f80e9b9d new file mode 100644 index 0000000..959401e --- /dev/null +++ b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/66498f377f38b53eebe1ceaa4a53e4de01a04efc02ac9cfda60f9815f80e9b9d @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000") diff --git a/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/731951fe84fa6f3a7f6ee8adaa585d4f6a01f359a04737e51ffc70f16f480b9b b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/731951fe84fa6f3a7f6ee8adaa585d4f6a01f359a04737e51ffc70f16f480b9b new file mode 100644 index 0000000..bd1ae59 --- /dev/null +++ b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/731951fe84fa6f3a7f6ee8adaa585d4f6a01f359a04737e51ffc70f16f480b9b @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000000000000000000000000000000000000000") diff --git a/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/7d6367ba84cd18550920b5202cd1269174416ce32769c7f59376e76b7dd3129c b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/7d6367ba84cd18550920b5202cd1269174416ce32769c7f59376e76b7dd3129c new file mode 100644 index 0000000..09e0ad2 --- /dev/null +++ b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/7d6367ba84cd18550920b5202cd1269174416ce32769c7f59376e76b7dd3129c @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") diff --git a/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/8727b16d337d7b8187433233f3a90099024e580a6ba319ea2bf539880c50bd7c b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/8727b16d337d7b8187433233f3a90099024e580a6ba319ea2bf539880c50bd7c new file mode 100644 index 0000000..e8000f3 --- /dev/null +++ b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/8727b16d337d7b8187433233f3a90099024e580a6ba319ea2bf539880c50bd7c @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00") diff --git a/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/9201a772731543760326638b8915f80863feab0ba0108183b3093934bdc0420c b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/9201a772731543760326638b8915f80863feab0ba0108183b3093934bdc0420c new file mode 100644 index 0000000..aac6b7d --- /dev/null +++ b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/9201a772731543760326638b8915f80863feab0ba0108183b3093934bdc0420c @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000000000") diff --git a/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/92f75f690317ace34aeaae3fe39f5f2ff9830777253ff371c5ef6f403a0f8f0f b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/92f75f690317ace34aeaae3fe39f5f2ff9830777253ff371c5ef6f403a0f8f0f new file mode 100644 index 0000000..f3bf6d9 --- /dev/null +++ b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/92f75f690317ace34aeaae3fe39f5f2ff9830777253ff371c5ef6f403a0f8f0f @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000000") diff --git a/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/93d6f7bc0d93f998c7b7fe654ff46010d6fa76f0a142c3523c42454f8ad10b07 b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/93d6f7bc0d93f998c7b7fe654ff46010d6fa76f0a142c3523c42454f8ad10b07 new file mode 100644 index 0000000..2e7f462 --- /dev/null +++ b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/93d6f7bc0d93f998c7b7fe654ff46010d6fa76f0a142c3523c42454f8ad10b07 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000") diff --git a/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/a7450fd77fc7c53cc5bd136874415dddfff5c586e662f21420caa7a94131a56a b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/a7450fd77fc7c53cc5bd136874415dddfff5c586e662f21420caa7a94131a56a new file mode 100644 index 0000000..c541f52 --- /dev/null +++ b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/a7450fd77fc7c53cc5bd136874415dddfff5c586e662f21420caa7a94131a56a @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000000000000000000000000000000000000000000") diff --git a/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/a95d2a0f87501a643d54218d2ad8112204672cc1fb30be297853616788208a5c b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/a95d2a0f87501a643d54218d2ad8112204672cc1fb30be297853616788208a5c new file mode 100644 index 0000000..5d56f29 --- /dev/null +++ b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/a95d2a0f87501a643d54218d2ad8112204672cc1fb30be297853616788208a5c @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") diff --git a/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/beed435aa2fee4819eab217543561dfd8001d4a44f53ceb664aaba86cebfaf21 b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/beed435aa2fee4819eab217543561dfd8001d4a44f53ceb664aaba86cebfaf21 new file mode 100644 index 0000000..4b4d59f --- /dev/null +++ b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/beed435aa2fee4819eab217543561dfd8001d4a44f53ceb664aaba86cebfaf21 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") diff --git a/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/c2501043394e49f2477408be5ef9389790e33ed1886073dec445d4cf05bcd4b4 b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/c2501043394e49f2477408be5ef9389790e33ed1886073dec445d4cf05bcd4b4 new file mode 100644 index 0000000..ef9f9d4 --- /dev/null +++ b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/c2501043394e49f2477408be5ef9389790e33ed1886073dec445d4cf05bcd4b4 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000") diff --git a/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/caf81e9797b19c76c1fc4dbf537d4d81f389524539f402d13aa01f93a65ac7e9 b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/caf81e9797b19c76c1fc4dbf537d4d81f389524539f402d13aa01f93a65ac7e9 new file mode 100644 index 0000000..67322c7 --- /dev/null +++ b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/caf81e9797b19c76c1fc4dbf537d4d81f389524539f402d13aa01f93a65ac7e9 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("") diff --git a/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/cc90a4a40ae9b3beac70baf6d7821a5a6f3a90cabb033575790be91723593680 b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/cc90a4a40ae9b3beac70baf6d7821a5a6f3a90cabb033575790be91723593680 new file mode 100644 index 0000000..f195330 --- /dev/null +++ b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/cc90a4a40ae9b3beac70baf6d7821a5a6f3a90cabb033575790be91723593680 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\x04000000000000\r00000000000000000000") diff --git a/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/ec72f669d648d8d9b9f75a3b303897c59b11e4bfb7622f25ff251a92f182bc2a b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/ec72f669d648d8d9b9f75a3b303897c59b11e4bfb7622f25ff251a92f182bc2a new file mode 100644 index 0000000..5b0d392 --- /dev/null +++ b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/ec72f669d648d8d9b9f75a3b303897c59b11e4bfb7622f25ff251a92f182bc2a @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000000000000000000000000000000000000000") diff --git a/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/f34630c44c11bb13d27531927c5c1e65d159b70f39cd161da0dba348c1221ab3 b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/f34630c44c11bb13d27531927c5c1e65d159b70f39cd161da0dba348c1221ab3 new file mode 100644 index 0000000..a389d3c --- /dev/null +++ b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/f34630c44c11bb13d27531927c5c1e65d159b70f39cd161da0dba348c1221ab3 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000") diff --git a/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/fd67efb09d433a1351a201281dbf6568628b4135c35c811dd9bce97620a75d43 b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/fd67efb09d433a1351a201281dbf6568628b4135c35c811dd9bce97620a75d43 new file mode 100644 index 0000000..17d10b2 --- /dev/null +++ b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/fd67efb09d433a1351a201281dbf6568628b4135c35c811dd9bce97620a75d43 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000") diff --git a/internal/allwriter.go b/internal/fastio/allwriter.go index 187aa8e..9de8fdc 100644 --- a/internal/allwriter.go +++ b/internal/fastio/allwriter.go @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: GPL-2.0-or-later -package internal +package fastio import ( "io" diff --git a/internal/hex.go b/internal/jsonparse/hex.go index 62a818f..3ed5f01 100644 --- a/internal/hex.go +++ b/internal/jsonparse/hex.go @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: GPL-2.0-or-later -package internal +package jsonparse const Hex = "0123456789abcdef" diff --git a/internal/parse.go b/internal/jsonparse/parse.go index 36db4a9..7d97be0 100644 --- a/internal/parse.go +++ b/internal/jsonparse/parse.go @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: GPL-2.0-or-later -package internal +package jsonparse import ( "errors" diff --git a/internal/parse_test.go b/internal/jsonparse/parse_test.go index 34977fb..e531daf 100644 --- a/internal/parse_test.go +++ b/internal/jsonparse/parse_test.go @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: GPL-2.0-or-later -package internal +package jsonparse import ( "testing" 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/borrowed_tags.go b/internal/jsonstruct/borrowed_tags.go index 6eaf5da..f2ef71c 100644 --- a/internal/borrowed_tags.go +++ b/internal/jsonstruct/borrowed_tags.go @@ -4,7 +4,7 @@ // // SPDX-License-Identifier: BSD-3-Clause -package internal // MODIFIED: changed package name +package jsonstruct // MODIFIED: changed package name import ( "strings" diff --git a/internal/jsonstruct/struct.go b/internal/jsonstruct/struct.go new file mode 100644 index 0000000..16c45de --- /dev/null +++ b/internal/jsonstruct/struct.go @@ -0,0 +1,209 @@ +// Copyright (C) 2022-2023 Luke Shumaker <lukeshu@lukeshu.com> +// +// SPDX-License-Identifier: GPL-2.0-or-later + +package jsonstruct + +import ( + "reflect" + + "git.lukeshu.com/go/typedsync" +) + +var ParseTag = parseTag + +type StructField struct { + Name string + Path []int + Tagged bool + OmitEmpty bool + Quote bool +} + +// 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 +} + +var structIndexCache typedsync.CacheMap[reflect.Type, StructIndex] + +// 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 { + ret, _ := structIndexCache.LoadOrCompute(typ, indexStructReal) + return ret +} + +func ClearCache() { + structIndexCache = typedsync.CacheMap[reflect.Type, StructIndex]{} +} + +// indexStructReal is like indexStruct, but is the real indexer, +// bypassing the cache. +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), + } + + for curPos, _field := range byPos { + name := _field.Name + fieldPoss := byName[name] + switch len(fieldPoss) { + case 0: + // do nothing + case 1: + ret.ByName[name] = len(ret.ByPos) + ret.ByPos = append(ret.ByPos, _field) + default: + // To quote the encoding/json docs (version 1.18.4): + // + // If there are multiple fields at the same level, and that level is the + // least nested (and would therefore be the nesting level selected by the + // usual Go rules), the following extra rules apply: + // + // 1) Of those fields, if any are JSON-tagged, only tagged fields are + // considered, even if there are multiple untagged fields that would + // otherwise conflict. + // + // 2) If there is exactly one field (tagged or not according to the first + // rule), that is selected. + // + // 3) Otherwise there are multiple fields, and all are ignored; no error + // occurs. + leastLevel := len(byPos[fieldPoss[0]].Path) + for _, fieldPos := range fieldPoss[1:] { + field := byPos[fieldPos] + if len(field.Path) < leastLevel { + leastLevel = len(field.Path) + } + } + var numUntagged, numTagged int + var untaggedPos, taggedPos int + for _, fieldPos := range fieldPoss { + field := byPos[fieldPos] + if len(field.Path) != leastLevel { + continue + } + if field.Tagged { + numTagged++ + taggedPos = fieldPos + if numTagged > 1 { + break // optimization + } + } else { + numUntagged++ + untaggedPos = fieldPos + } + } + switch numTagged { + case 0: + switch numUntagged { + case 0: + // do nothing + case 1: + if curPos == untaggedPos { + 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]) + } + } + } + } + + return ret +} + +// indexStructInner crawls the struct `typ`, storing information on +// all struct fields found in to `byPos` and `byName`. If `typ` +// contains other structs as fields, indexStructInner will recurse and +// 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{}) { + if _, ok := stackSeen[typ]; ok { + return + } + stackSeen[typ] = struct{}{} + defer delete(stackSeen, typ) + + n := typ.NumField() + for i := 0; i < n; i++ { + stackPath := append(stackPath, i) + + fTyp := typ.Field(i) + var embed bool + if fTyp.Anonymous { + t := fTyp.Type + if t.Kind() == reflect.Pointer { + t = t.Elem() + } + if !fTyp.IsExported() && t.Kind() != reflect.Struct { + continue + } + embed = t.Kind() == reflect.Struct + } else if !fTyp.IsExported() { + continue + } + tag := fTyp.Tag.Get("json") + if tag == "-" { + continue + } + tagName, opts := parseTag(tag) + name := tagName + if !isValidTag(name) { + name = "" + } + if name == "" { + name = fTyp.Name + } + + if embed && tagName == "" { + t := fTyp.Type + if t.Kind() == reflect.Pointer { + t = t.Elem() + } + indexStructInner(t, byPos, byName, stackPath, stackSeen) + } else { + byName[name] = append(byName[name], len(*byPos)) + *byPos = append(*byPos, StructField{ + Name: name, + Path: append([]int(nil), stackPath...), + Tagged: tagName != "", + OmitEmpty: opts.Contains("omitempty"), + Quote: opts.Contains("string") && isQuotable(fTyp.Type), + }) + } + } +} + +// isQuotable returns whether a type is eligible for `json:,string` +// quoting. +func isQuotable(typ reflect.Type) bool { + for typ.Kind() == reflect.Pointer { + typ = typ.Elem() + } + switch typ.Kind() { + case reflect.Bool, + reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, + reflect.Uintptr, + reflect.Float32, reflect.Float64, + reflect.String: + return true + default: + return false + } +} diff --git a/internal/encode.go b/internal/jsontest/jsontest.go index 8aae673..fbc775d 100644 --- a/internal/encode.go +++ b/internal/jsontest/jsontest.go @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: GPL-2.0-or-later -package internal +package jsontest import ( "io" diff --git a/internal/tags.go b/internal/tags.go deleted file mode 100644 index bdf1f72..0000000 --- a/internal/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 internal - -var ParseTag = parseTag |