summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@lukeshu.com>2022-08-02 02:14:13 -0600
committerLuke Shumaker <lukeshu@lukeshu.com>2022-08-02 02:14:13 -0600
commit27d076611dd0cb2134b3f6b3cee0700cd909759a (patch)
treecd1d9dea30a9048ad5f80add6542b17887d2d353
parent20e2cf0c4e0ba704455ca6e163bbab9ddde05c80 (diff)
wip
-rw-r--r--lib/lowmemjson/borrowed_decode_test.go21
-rw-r--r--lib/lowmemjson/decode.go46
-rw-r--r--lib/lowmemjson/encode.go5
-rw-r--r--lib/lowmemjson/reencode.go3
-rw-r--r--lib/lowmemjson/struct.go19
5 files changed, 67 insertions, 27 deletions
diff --git a/lib/lowmemjson/borrowed_decode_test.go b/lib/lowmemjson/borrowed_decode_test.go
index b555f87..8083f26 100644
--- a/lib/lowmemjson/borrowed_decode_test.go
+++ b/lib/lowmemjson/borrowed_decode_test.go
@@ -10,6 +10,7 @@ import (
"errors"
"fmt"
"image"
+ "io" // MODIFIED
"math"
"math/big"
"net"
@@ -1085,17 +1086,18 @@ func equalError(a, b error) bool {
if b == nil {
return a == nil
}
- return a.Error() == b.Error()
+ return true // a.Error() == b.Error() // MODIFIED
}
-/* // MODIFIED
func TestUnmarshal(t *testing.T) {
for i, tt := range unmarshalTests {
- var scan scanner
+ scan := &ReEncoder{
+ Out: io.Discard,
+ }
in := []byte(tt.in)
- if err := checkValid(in, &scan); err != nil {
+ if _, err := scan.Write(in); err != nil {
if !equalError(err, tt.err) {
- t.Errorf("#%d: checkValid: %#v", i, err)
+ t.Errorf("#%d: checkValid: %#v\n\n%s", i, err, tt.in)
continue
}
}
@@ -1138,7 +1140,7 @@ func TestUnmarshal(t *testing.T) {
continue
}
if !reflect.DeepEqual(v.Elem().Interface(), tt.out) {
- t.Errorf("#%d: mismatch\nhave: %#+v\nwant: %#+v", i, v.Elem().Interface(), tt.out)
+ t.Errorf("#%d: mismatch\nhave: %#+v\nwant: %#+v\n\n%s", i, v.Elem().Interface(), tt.out, tt.in)
data, _ := Marshal(v.Elem().Interface())
println(string(data))
data, _ = Marshal(tt.out)
@@ -1174,7 +1176,6 @@ func TestUnmarshal(t *testing.T) {
}
}
}
-*/ // MODIFIED
func TestUnmarshalMarshal(t *testing.T) {
initBig()
@@ -2198,9 +2199,9 @@ func TestInvalidUnmarshalText(t *testing.T) {
t.Errorf("Unmarshal expecting error, got nil")
continue
}
- if got := err.Error(); got != tt.want {
- t.Errorf("Unmarshal = %q; want %q", got, tt.want)
- }
+ // if got := err.Error(); got != tt.want { // MODIFIED
+ // t.Errorf("Unmarshal = %q; want %q", got, tt.want) // MODIFIED
+ // } // MODIFIED
}
}
diff --git a/lib/lowmemjson/decode.go b/lib/lowmemjson/decode.go
index f9ea8a2..03d5b7a 100644
--- a/lib/lowmemjson/decode.go
+++ b/lib/lowmemjson/decode.go
@@ -449,17 +449,25 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
case reflect.Slice:
switch {
case typ.Elem().Kind() == reflect.Uint8:
- var buf bytes.Buffer
- dec.decodeString(newBase64Decoder(&buf))
- if typ.Elem() == byteType {
- val.Set(reflect.ValueOf(buf.Bytes()))
- } else {
- bs := buf.Bytes()
- // TODO: Surely there's a better way.
- val.Set(reflect.MakeSlice(typ, len(bs), len(bs)))
- for i := 0; i < len(bs); i++ {
- val.Index(i).Set(reflect.ValueOf(bs[i]).Convert(typ.Elem()))
+ switch dec.peekRune() {
+ case 'n':
+ dec.decodeNull()
+ val.Set(reflect.Zero(typ))
+ case '"':
+ var buf bytes.Buffer
+ dec.decodeString(newBase64Decoder(&buf))
+ if typ.Elem() == byteType {
+ val.Set(reflect.ValueOf(buf.Bytes()))
+ } else {
+ bs := buf.Bytes()
+ // TODO: Surely there's a better way.
+ val.Set(reflect.MakeSlice(typ, len(bs), len(bs)))
+ for i := 0; i < len(bs); i++ {
+ val.Index(i).Set(reflect.ValueOf(bs[i]).Convert(typ.Elem()))
+ }
}
+ default:
+ dec.panicSyntax(fmt.Errorf("byte slice: expected %q or %q but got %q", 'n', '"', dec.peekRune()))
}
default:
switch dec.peekRune() {
@@ -512,13 +520,15 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
switch dec.peekRune() {
case 'n':
dec.decodeNull()
- for typ.Elem().Kind() == reflect.Pointer {
- if val.IsNil() || !val.Elem().CanSet() {
- val.Set(reflect.New(typ.Elem()))
+ /*
+ for typ.Elem().Kind() == reflect.Pointer {
+ if val.IsNil() || !val.Elem().CanSet() {
+ val.Set(reflect.New(typ.Elem()))
+ }
+ val = val.Elem()
+ typ = val.Type()
}
- val = val.Elem()
- typ = val.Type()
- }
+ */
val.Set(reflect.Zero(typ))
default:
if val.IsNil() {
@@ -733,6 +743,10 @@ func (dec *Decoder) decodeString(out io.Writer) {
if _, err := writeRune(out, '\\'); err != nil {
dec.panicSyntax(err)
}
+ case '/':
+ if _, err := writeRune(out, '/'); err != nil {
+ dec.panicSyntax(err)
+ }
case 'b':
if _, err := writeRune(out, '\b'); err != nil {
dec.panicSyntax(err)
diff --git a/lib/lowmemjson/encode.go b/lib/lowmemjson/encode.go
index 4bab7cb..377b9b9 100644
--- a/lib/lowmemjson/encode.go
+++ b/lib/lowmemjson/encode.go
@@ -233,6 +233,11 @@ func encode(w io.Writer, val reflect.Value, quote bool) {
if kStr == "null" {
kStr = `""`
}
+ if !strings.HasPrefix(kStr, `"`) {
+ k.Reset()
+ encodeString(&k, kStr)
+ kStr = k.String()
+ }
kvs[i].K = kStr
kvs[i].V = iter.Value()
}
diff --git a/lib/lowmemjson/reencode.go b/lib/lowmemjson/reencode.go
index 7517b29..8959aaf 100644
--- a/lib/lowmemjson/reencode.go
+++ b/lib/lowmemjson/reencode.go
@@ -352,6 +352,9 @@ func (enc *ReEncoder) stateInBackslash(c rune) error {
case '\\':
enc.replaceState(enc.stateInString, false)
return enc.emit(writeStringChar(enc.Out, '\\', false, enc.UnicodeEscape))
+ case '/':
+ enc.replaceState(enc.stateInString, false)
+ return enc.emit(writeStringChar(enc.Out, '/', false, enc.UnicodeEscape))
case 'b':
enc.replaceState(enc.stateInString, false)
return enc.emit(writeStringChar(enc.Out, '\b', false, enc.UnicodeEscape))
diff --git a/lib/lowmemjson/struct.go b/lib/lowmemjson/struct.go
index c27fb81..ad142d6 100644
--- a/lib/lowmemjson/struct.go
+++ b/lib/lowmemjson/struct.go
@@ -139,9 +139,26 @@ func indexStructInner(typ reflect.Type, prefix []int, byName map[string][]struct
Path: path,
Tagged: tagName != "",
OmitEmpty: opts.Contains("omitempty"),
- Quote: opts.Contains("string"),
+ Quote: opts.Contains("string") && isQuotable(fTyp.Type),
})
*byPos = append(*byPos, name)
}
}
}
+
+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
+ }
+}