mirror of https://github.com/k3s-io/k3s
Merge pull request #15534 from wojtek-t/update_goetcd_and_ugorji
Update github.com/coreos/go-etcd and github.com/ugorji/go/codec dependenciespull/6/head
commit
9b45ed8897
|
@ -108,8 +108,8 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/coreos/go-etcd/etcd",
|
"ImportPath": "github.com/coreos/go-etcd/etcd",
|
||||||
"Comment": "v2.0.0-13-g4cceaf7",
|
"Comment": "v2.0.0-34-gde3514f",
|
||||||
"Rev": "4cceaf7283b76f27c4a732b20730dcdb61053bf5"
|
"Rev": "de3514f25635bbfb024fdaf2a8d5f67378492675"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/coreos/go-oidc/http",
|
"ImportPath": "github.com/coreos/go-oidc/http",
|
||||||
|
@ -559,7 +559,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/ugorji/go/codec",
|
"ImportPath": "github.com/ugorji/go/codec",
|
||||||
"Rev": "821cda7e48749cacf7cad2c6ed01e96457ca7e9d"
|
"Rev": "2f4b94206aae781e63846a9bf02ad83c387d5296"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/vaughan0/go-ini",
|
"ImportPath": "github.com/vaughan0/go-ini",
|
||||||
|
|
|
@ -192,7 +192,7 @@ func (c *Client) Close() {
|
||||||
// initHTTPClient initializes a HTTP client for etcd client
|
// initHTTPClient initializes a HTTP client for etcd client
|
||||||
func (c *Client) initHTTPClient() {
|
func (c *Client) initHTTPClient() {
|
||||||
c.transport = &http.Transport{
|
c.transport = &http.Transport{
|
||||||
Dial: c.dial,
|
Dial: c.DefaultDial,
|
||||||
TLSClientConfig: &tls.Config{
|
TLSClientConfig: &tls.Config{
|
||||||
InsecureSkipVerify: true,
|
InsecureSkipVerify: true,
|
||||||
},
|
},
|
||||||
|
@ -216,12 +216,12 @@ func (c *Client) initHTTPSClient(cert, key string) error {
|
||||||
InsecureSkipVerify: true,
|
InsecureSkipVerify: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
tr := &http.Transport{
|
c.transport = &http.Transport{
|
||||||
TLSClientConfig: tlsConfig,
|
TLSClientConfig: tlsConfig,
|
||||||
Dial: c.dial,
|
Dial: c.DefaultDial,
|
||||||
}
|
}
|
||||||
|
|
||||||
c.httpClient = &http.Client{Transport: tr}
|
c.httpClient = &http.Client{Transport: c.transport}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -391,29 +391,15 @@ func (c *Client) createHttpPath(serverName string, _path string) string {
|
||||||
return u.String()
|
return u.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
// dial attempts to open a TCP connection to the provided address, explicitly
|
// DefaultDial attempts to open a TCP connection to the provided address, explicitly
|
||||||
// enabling keep-alives with a one-second interval.
|
// enabling keep-alives with a one-second interval.
|
||||||
func (c *Client) dial(network, addr string) (net.Conn, error) {
|
func (c *Client) DefaultDial(network, addr string) (net.Conn, error) {
|
||||||
conn, err := net.DialTimeout(network, addr, c.config.DialTimeout)
|
dialer := net.Dialer{
|
||||||
if err != nil {
|
Timeout: c.config.DialTimeout,
|
||||||
return nil, err
|
KeepAlive: time.Second,
|
||||||
}
|
}
|
||||||
|
|
||||||
tcpConn, ok := conn.(*net.TCPConn)
|
return dialer.Dial(network, addr)
|
||||||
if !ok {
|
|
||||||
return nil, errors.New("Failed type-assertion of net.Conn as *net.TCPConn")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Keep TCP alive to check whether or not the remote machine is down
|
|
||||||
if err = tcpConn.SetKeepAlive(true); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = tcpConn.SetKeepAlivePeriod(time.Second); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return tcpConn, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) OpenCURL() {
|
func (c *Client) OpenCURL() {
|
||||||
|
|
|
@ -3,12 +3,14 @@ package etcd
|
||||||
import (
|
import (
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Cluster struct {
|
type Cluster struct {
|
||||||
Leader string `json:"leader"`
|
Leader string `json:"leader"`
|
||||||
Machines []string `json:"machines"`
|
Machines []string `json:"machines"`
|
||||||
picked int
|
picked int
|
||||||
|
mu sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCluster(machines []string) *Cluster {
|
func NewCluster(machines []string) *Cluster {
|
||||||
|
@ -17,6 +19,8 @@ func NewCluster(machines []string) *Cluster {
|
||||||
machines = []string{"http://127.0.0.1:4001"}
|
machines = []string{"http://127.0.0.1:4001"}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
machines = shuffleStringSlice(machines)
|
||||||
|
logger.Debug("Shuffle cluster machines", machines)
|
||||||
// default leader and machines
|
// default leader and machines
|
||||||
return &Cluster{
|
return &Cluster{
|
||||||
Leader: "",
|
Leader: "",
|
||||||
|
@ -25,13 +29,26 @@ func NewCluster(machines []string) *Cluster {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cl *Cluster) failure() { cl.picked = rand.Intn(len(cl.Machines)) }
|
func (cl *Cluster) failure() {
|
||||||
func (cl *Cluster) pick() string { return cl.Machines[cl.picked] }
|
cl.mu.Lock()
|
||||||
|
defer cl.mu.Unlock()
|
||||||
|
cl.picked = (cl.picked + 1) % len(cl.Machines)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cl *Cluster) pick() string {
|
||||||
|
cl.mu.Lock()
|
||||||
|
defer cl.mu.Unlock()
|
||||||
|
return cl.Machines[cl.picked]
|
||||||
|
}
|
||||||
|
|
||||||
func (cl *Cluster) updateFromStr(machines string) {
|
func (cl *Cluster) updateFromStr(machines string) {
|
||||||
|
cl.mu.Lock()
|
||||||
|
defer cl.mu.Unlock()
|
||||||
|
|
||||||
cl.Machines = strings.Split(machines, ",")
|
cl.Machines = strings.Split(machines, ",")
|
||||||
for i := range cl.Machines {
|
for i := range cl.Machines {
|
||||||
cl.Machines[i] = strings.TrimSpace(cl.Machines[i])
|
cl.Machines[i] = strings.TrimSpace(cl.Machines[i])
|
||||||
}
|
}
|
||||||
|
cl.Machines = shuffleStringSlice(cl.Machines)
|
||||||
cl.picked = rand.Intn(len(cl.Machines))
|
cl.picked = rand.Intn(len(cl.Machines))
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,19 @@
|
||||||
|
package etcd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/rand"
|
||||||
|
)
|
||||||
|
|
||||||
|
func shuffleStringSlice(cards []string) []string {
|
||||||
|
size := len(cards)
|
||||||
|
//Do not need to copy if nothing changed
|
||||||
|
if size <= 1 {
|
||||||
|
return cards
|
||||||
|
}
|
||||||
|
shuffled := make([]string, size)
|
||||||
|
index := rand.Perm(size)
|
||||||
|
for i := range cards {
|
||||||
|
shuffled[index[i]] = cards[i]
|
||||||
|
}
|
||||||
|
return shuffled
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style license found in the LICENSE file.
|
// Use of this source code is governed by a MIT license found in the LICENSE file.
|
||||||
|
|
||||||
/*
|
/*
|
||||||
High Performance, Feature-Rich Idiomatic Go codec/encoding library for
|
High Performance, Feature-Rich Idiomatic Go codec/encoding library for
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style license found in the LICENSE file.
|
// Use of this source code is governed by a MIT license found in the LICENSE file.
|
||||||
|
|
||||||
package codec
|
package codec
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math"
|
"math"
|
||||||
|
"reflect"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -69,7 +70,15 @@ func (e *bincEncDriver) IsBuiltinType(rt uintptr) bool {
|
||||||
|
|
||||||
func (e *bincEncDriver) EncodeBuiltin(rt uintptr, v interface{}) {
|
func (e *bincEncDriver) EncodeBuiltin(rt uintptr, v interface{}) {
|
||||||
if rt == timeTypId {
|
if rt == timeTypId {
|
||||||
bs := encodeTime(v.(time.Time))
|
var bs []byte
|
||||||
|
switch x := v.(type) {
|
||||||
|
case time.Time:
|
||||||
|
bs = encodeTime(x)
|
||||||
|
case *time.Time:
|
||||||
|
bs = encodeTime(*x)
|
||||||
|
default:
|
||||||
|
e.e.errorf("binc error encoding builtin: expect time.Time, received %T", v)
|
||||||
|
}
|
||||||
e.w.writen1(bincVdTimestamp<<4 | uint8(len(bs)))
|
e.w.writen1(bincVdTimestamp<<4 | uint8(len(bs)))
|
||||||
e.w.writeb(bs)
|
e.w.writeb(bs)
|
||||||
}
|
}
|
||||||
|
@ -897,5 +906,9 @@ func (h *BincHandle) newDecDriver(d *Decoder) decDriver {
|
||||||
return &bincDecDriver{d: d, r: d.r, h: h, br: d.bytes}
|
return &bincDecDriver{d: d, r: d.r, h: h, br: d.bytes}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *BincHandle) SetBytesExt(rt reflect.Type, tag uint64, ext BytesExt) (err error) {
|
||||||
|
return h.SetExt(rt, tag, &setExtWrapper{b: ext})
|
||||||
|
}
|
||||||
|
|
||||||
var _ decDriver = (*bincDecDriver)(nil)
|
var _ decDriver = (*bincDecDriver)(nil)
|
||||||
var _ encDriver = (*bincEncDriver)(nil)
|
var _ encDriver = (*bincEncDriver)(nil)
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style license found in the LICENSE file.
|
// Use of this source code is governed by a MIT license found in the LICENSE file.
|
||||||
|
|
||||||
package codec
|
package codec
|
||||||
|
|
||||||
import "math"
|
import (
|
||||||
|
"math"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
cborMajorUint byte = iota
|
cborMajorUint byte = iota
|
||||||
|
@ -98,7 +101,7 @@ func (e *cborEncDriver) encUint(v uint64, bd byte) {
|
||||||
} else if v <= math.MaxUint32 {
|
} else if v <= math.MaxUint32 {
|
||||||
e.w.writen1(bd + 0x1a)
|
e.w.writen1(bd + 0x1a)
|
||||||
bigenHelper{e.x[:4], e.w}.writeUint32(uint32(v))
|
bigenHelper{e.x[:4], e.w}.writeUint32(uint32(v))
|
||||||
} else if v <= math.MaxUint64 {
|
} else { // if v <= math.MaxUint64 {
|
||||||
e.w.writen1(bd + 0x1b)
|
e.w.writen1(bd + 0x1b)
|
||||||
bigenHelper{e.x[:8], e.w}.writeUint64(v)
|
bigenHelper{e.x[:8], e.w}.writeUint64(v)
|
||||||
}
|
}
|
||||||
|
@ -158,7 +161,11 @@ func (e *cborEncDriver) EncodeSymbol(v string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *cborEncDriver) EncodeStringBytes(c charEncoding, v []byte) {
|
func (e *cborEncDriver) EncodeStringBytes(c charEncoding, v []byte) {
|
||||||
|
if c == c_RAW {
|
||||||
e.encLen(cborBaseBytes, len(v))
|
e.encLen(cborBaseBytes, len(v))
|
||||||
|
} else {
|
||||||
|
e.encLen(cborBaseString, len(v))
|
||||||
|
}
|
||||||
e.w.writeb(v)
|
e.w.writeb(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -562,5 +569,9 @@ func (h *CborHandle) newDecDriver(d *Decoder) decDriver {
|
||||||
return &cborDecDriver{d: d, r: d.r, h: h, br: d.bytes}
|
return &cborDecDriver{d: d, r: d.r, h: h, br: d.bytes}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *CborHandle) SetInterfaceExt(rt reflect.Type, tag uint64, ext InterfaceExt) (err error) {
|
||||||
|
return h.SetExt(rt, tag, &setExtWrapper{i: ext})
|
||||||
|
}
|
||||||
|
|
||||||
var _ decDriver = (*cborDecDriver)(nil)
|
var _ decDriver = (*cborDecDriver)(nil)
|
||||||
var _ encDriver = (*cborEncDriver)(nil)
|
var _ encDriver = (*cborEncDriver)(nil)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style license found in the LICENSE file.
|
// Use of this source code is governed by a MIT license found in the LICENSE file.
|
||||||
|
|
||||||
package codec
|
package codec
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style license found in the LICENSE file.
|
// Use of this source code is governed by a MIT license found in the LICENSE file.
|
||||||
|
|
||||||
package codec
|
package codec
|
||||||
|
|
||||||
|
@ -860,6 +860,60 @@ func testCodecRpcOne(t *testing.T, rr Rpc, h Handle, doRequest bool, exitSleepMs
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func doTestMapEncodeForCanonical(t *testing.T, name string, h Handle) {
|
||||||
|
v1 := map[string]interface{}{
|
||||||
|
"a": 1,
|
||||||
|
"b": "hello",
|
||||||
|
"c": map[string]interface{}{
|
||||||
|
"c/a": 1,
|
||||||
|
"c/b": "world",
|
||||||
|
"c/c": []int{1, 2, 3, 4},
|
||||||
|
"c/d": map[string]interface{}{
|
||||||
|
"c/d/a": "fdisajfoidsajfopdjsaopfjdsapofda",
|
||||||
|
"c/d/b": "fdsafjdposakfodpsakfopdsakfpodsakfpodksaopfkdsopafkdopsa",
|
||||||
|
"c/d/c": "poir02 ir30qif4p03qir0pogjfpoaerfgjp ofke[padfk[ewapf kdp[afep[aw",
|
||||||
|
"c/d/d": "fdsopafkd[sa f-32qor-=4qeof -afo-erfo r-eafo 4e- o r4-qwo ag",
|
||||||
|
"c/d/e": "kfep[a sfkr0[paf[a foe-[wq ewpfao-q ro3-q ro-4qof4-qor 3-e orfkropzjbvoisdb",
|
||||||
|
"c/d/f": "",
|
||||||
|
},
|
||||||
|
"c/e": map[int]string{
|
||||||
|
1: "1",
|
||||||
|
22: "22",
|
||||||
|
333: "333",
|
||||||
|
4444: "4444",
|
||||||
|
55555: "55555",
|
||||||
|
},
|
||||||
|
"c/f": map[string]int{
|
||||||
|
"1": 1,
|
||||||
|
"22": 22,
|
||||||
|
"333": 333,
|
||||||
|
"4444": 4444,
|
||||||
|
"55555": 55555,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
var v2 map[string]interface{}
|
||||||
|
var b1, b2 []byte
|
||||||
|
|
||||||
|
// encode v1 into b1, decode b1 into v2, encode v2 into b2, compare b1 and b2
|
||||||
|
|
||||||
|
bh := h.getBasicHandle()
|
||||||
|
canonical0 := bh.Canonical
|
||||||
|
bh.Canonical = true
|
||||||
|
defer func() { bh.Canonical = canonical0 }()
|
||||||
|
|
||||||
|
e1 := NewEncoderBytes(&b1, h)
|
||||||
|
e1.MustEncode(v1)
|
||||||
|
d1 := NewDecoderBytes(b1, h)
|
||||||
|
d1.MustDecode(&v2)
|
||||||
|
e2 := NewEncoderBytes(&b2, h)
|
||||||
|
e2.MustEncode(v2)
|
||||||
|
if !bytes.Equal(b1, b2) {
|
||||||
|
logT(t, "Unequal bytes: %v VS %v", b1, b2)
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Comprehensive testing that generates data encoded from python handle (cbor, msgpack),
|
// Comprehensive testing that generates data encoded from python handle (cbor, msgpack),
|
||||||
// and validates that our code can read and write it out accordingly.
|
// and validates that our code can read and write it out accordingly.
|
||||||
// We keep this unexported here, and put actual test in ext_dep_test.go.
|
// We keep this unexported here, and put actual test in ext_dep_test.go.
|
||||||
|
@ -1048,6 +1102,10 @@ func TestCborCodecsEmbeddedPointer(t *testing.T) {
|
||||||
testCodecEmbeddedPointer(t, testCborH)
|
testCodecEmbeddedPointer(t, testCborH)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCborMapEncodeForCanonical(t *testing.T) {
|
||||||
|
doTestMapEncodeForCanonical(t, "cbor", testCborH)
|
||||||
|
}
|
||||||
|
|
||||||
func TestJsonCodecsTable(t *testing.T) {
|
func TestJsonCodecsTable(t *testing.T) {
|
||||||
testCodecTableOne(t, testJsonH)
|
testCodecTableOne(t, testJsonH)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style license found in the LICENSE file.
|
// Use of this source code is governed by a MIT license found in the LICENSE file.
|
||||||
|
|
||||||
// codecgen generates codec.Selfer implementations for a set of types.
|
// codecgen generates codec.Selfer implementations for a set of types.
|
||||||
package main
|
package main
|
||||||
|
@ -14,6 +14,7 @@ import (
|
||||||
"go/build"
|
"go/build"
|
||||||
"go/parser"
|
"go/parser"
|
||||||
"go/token"
|
"go/token"
|
||||||
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -23,6 +24,8 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const genCodecPkg = "codec1978" // keep this in sync with codec.genCodecPkg
|
||||||
|
|
||||||
const genFrunMainTmpl = `//+build ignore
|
const genFrunMainTmpl = `//+build ignore
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
@ -45,6 +48,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"strings"
|
||||||
"go/format"
|
"go/format"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -69,7 +73,7 @@ func CodecGenTempWrite{{ .RandString }}() {
|
||||||
var t{{ $index }} {{ . }}
|
var t{{ $index }} {{ . }}
|
||||||
typs = append(typs, reflect.TypeOf(t{{ $index }}))
|
typs = append(typs, reflect.TypeOf(t{{ $index }}))
|
||||||
{{ end }}
|
{{ end }}
|
||||||
{{ if not .CodecPkgFiles }}{{ .CodecPkgName }}.{{ end }}Gen(&out, "{{ .BuildTag }}", "{{ .PackageName }}", {{ .UseUnsafe }}, typs...)
|
{{ if not .CodecPkgFiles }}{{ .CodecPkgName }}.{{ end }}Gen(&out, "{{ .BuildTag }}", "{{ .PackageName }}", "{{ .RandString }}", {{ .UseUnsafe }}, {{ if not .CodecPkgFiles }}{{ .CodecPkgName }}.{{ end }}NewTypeInfos(strings.Split("{{ .StructTags }}", ",")), typs...)
|
||||||
bout, err := format.Source(out.Bytes())
|
bout, err := format.Source(out.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fout.Write(out.Bytes())
|
fout.Write(out.Bytes())
|
||||||
|
@ -89,8 +93,8 @@ func CodecGenTempWrite{{ .RandString }}() {
|
||||||
// Tool then executes: "go run __frun__" which creates fout.
|
// Tool then executes: "go run __frun__" which creates fout.
|
||||||
// fout contains Codec(En|De)codeSelf implementations for every type T.
|
// fout contains Codec(En|De)codeSelf implementations for every type T.
|
||||||
//
|
//
|
||||||
func Generate(outfile, buildTag, codecPkgPath string, useUnsafe bool, goRunTag string,
|
func Generate(outfile, buildTag, codecPkgPath string, uid int64, useUnsafe bool, goRunTag string,
|
||||||
regexName *regexp.Regexp, deleteTempFile bool, infiles ...string) (err error) {
|
st string, regexName *regexp.Regexp, deleteTempFile bool, infiles ...string) (err error) {
|
||||||
// For each file, grab AST, find each type, and write a call to it.
|
// For each file, grab AST, find each type, and write a call to it.
|
||||||
if len(infiles) == 0 {
|
if len(infiles) == 0 {
|
||||||
return
|
return
|
||||||
|
@ -99,6 +103,13 @@ func Generate(outfile, buildTag, codecPkgPath string, useUnsafe bool, goRunTag s
|
||||||
err = errors.New("outfile and codec package path cannot be blank")
|
err = errors.New("outfile and codec package path cannot be blank")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if uid < 0 {
|
||||||
|
uid = -uid
|
||||||
|
}
|
||||||
|
if uid == 0 {
|
||||||
|
rr := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||||
|
uid = 101 + rr.Int63n(9777)
|
||||||
|
}
|
||||||
// We have to parse dir for package, before opening the temp file for writing (else ImportDir fails).
|
// We have to parse dir for package, before opening the temp file for writing (else ImportDir fails).
|
||||||
// Also, ImportDir(...) must take an absolute path.
|
// Also, ImportDir(...) must take an absolute path.
|
||||||
lastdir := filepath.Dir(outfile)
|
lastdir := filepath.Dir(outfile)
|
||||||
|
@ -118,17 +129,19 @@ func Generate(outfile, buildTag, codecPkgPath string, useUnsafe bool, goRunTag s
|
||||||
PackageName string
|
PackageName string
|
||||||
RandString string
|
RandString string
|
||||||
BuildTag string
|
BuildTag string
|
||||||
|
StructTags string
|
||||||
Types []string
|
Types []string
|
||||||
CodecPkgFiles bool
|
CodecPkgFiles bool
|
||||||
UseUnsafe bool
|
UseUnsafe bool
|
||||||
}
|
}
|
||||||
tv := tmplT{
|
tv := tmplT{
|
||||||
CodecPkgName: "codec1978",
|
CodecPkgName: genCodecPkg,
|
||||||
OutFile: outfile,
|
OutFile: outfile,
|
||||||
CodecImportPath: codecPkgPath,
|
CodecImportPath: codecPkgPath,
|
||||||
BuildTag: buildTag,
|
BuildTag: buildTag,
|
||||||
UseUnsafe: useUnsafe,
|
UseUnsafe: useUnsafe,
|
||||||
RandString: strconv.FormatInt(time.Now().UnixNano(), 10),
|
RandString: strconv.FormatInt(uid, 10),
|
||||||
|
StructTags: st,
|
||||||
}
|
}
|
||||||
tv.ImportPath = pkg.ImportPath
|
tv.ImportPath = pkg.ImportPath
|
||||||
if tv.ImportPath == tv.CodecImportPath {
|
if tv.ImportPath == tv.CodecImportPath {
|
||||||
|
@ -259,11 +272,12 @@ func main() {
|
||||||
t := flag.String("t", "", "build tag to put in file")
|
t := flag.String("t", "", "build tag to put in file")
|
||||||
r := flag.String("r", ".*", "regex for type name to match")
|
r := flag.String("r", ".*", "regex for type name to match")
|
||||||
rt := flag.String("rt", "", "tags for go run")
|
rt := flag.String("rt", "", "tags for go run")
|
||||||
|
st := flag.String("st", "codec,json", "struct tag keys to introspect")
|
||||||
x := flag.Bool("x", false, "keep temp file")
|
x := flag.Bool("x", false, "keep temp file")
|
||||||
u := flag.Bool("u", false, "Use unsafe, e.g. to avoid unnecessary allocation on []byte->string")
|
u := flag.Bool("u", false, "Use unsafe, e.g. to avoid unnecessary allocation on []byte->string")
|
||||||
|
d := flag.Int64("d", 0, "random identifier for use in generated code")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
if err := Generate(*o, *t, *c, *u, *rt,
|
if err := Generate(*o, *t, *c, *d, *u, *rt, *st,
|
||||||
regexp.MustCompile(*r), !*x, flag.Args()...); err != nil {
|
regexp.MustCompile(*r), !*x, flag.Args()...); err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "codecgen error: %v\n", err)
|
fmt.Fprintf(os.Stderr, "codecgen error: %v\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCodecgenJson1(t *testing.T) {
|
func TestCodecgenJson1(t *testing.T) {
|
||||||
|
// This is just a simplistic test for codecgen.
|
||||||
const callCodecgenDirect bool = true
|
const callCodecgenDirect bool = true
|
||||||
v := newTestStruc(2, false, !testSkipIntf, false)
|
v := newTestStruc(2, false, !testSkipIntf, false)
|
||||||
var bs []byte
|
var bs []byte
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,12 +1,11 @@
|
||||||
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style license found in the LICENSE file.
|
// Use of this source code is governed by a MIT license found in the LICENSE file.
|
||||||
|
|
||||||
package codec
|
package codec
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding"
|
"encoding"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
@ -63,12 +62,8 @@ type encDriver interface {
|
||||||
EncodeRawExt(re *RawExt, e *Encoder)
|
EncodeRawExt(re *RawExt, e *Encoder)
|
||||||
EncodeExt(v interface{}, xtag uint64, ext Ext, e *Encoder)
|
EncodeExt(v interface{}, xtag uint64, ext Ext, e *Encoder)
|
||||||
EncodeArrayStart(length int)
|
EncodeArrayStart(length int)
|
||||||
EncodeArrayEnd()
|
|
||||||
EncodeArrayEntrySeparator()
|
|
||||||
EncodeMapStart(length int)
|
EncodeMapStart(length int)
|
||||||
EncodeMapEnd()
|
EncodeEnd()
|
||||||
EncodeMapEntrySeparator()
|
|
||||||
EncodeMapKVSeparator()
|
|
||||||
EncodeString(c charEncoding, v string)
|
EncodeString(c charEncoding, v string)
|
||||||
EncodeSymbol(v string)
|
EncodeSymbol(v string)
|
||||||
EncodeStringBytes(c charEncoding, v []byte)
|
EncodeStringBytes(c charEncoding, v []byte)
|
||||||
|
@ -77,13 +72,13 @@ type encDriver interface {
|
||||||
//encStringRunes(c charEncoding, v []rune)
|
//encStringRunes(c charEncoding, v []rune)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type encDriverAsis interface {
|
||||||
|
EncodeAsis(v []byte)
|
||||||
|
}
|
||||||
|
|
||||||
type encNoSeparator struct{}
|
type encNoSeparator struct{}
|
||||||
|
|
||||||
func (_ encNoSeparator) EncodeMapEnd() {}
|
func (_ encNoSeparator) EncodeEnd() {}
|
||||||
func (_ encNoSeparator) EncodeArrayEnd() {}
|
|
||||||
func (_ encNoSeparator) EncodeArrayEntrySeparator() {}
|
|
||||||
func (_ encNoSeparator) EncodeMapEntrySeparator() {}
|
|
||||||
func (_ encNoSeparator) EncodeMapKVSeparator() {}
|
|
||||||
|
|
||||||
type encStructFieldBytesV struct {
|
type encStructFieldBytesV struct {
|
||||||
b []byte
|
b []byte
|
||||||
|
@ -113,8 +108,9 @@ type EncodeOptions struct {
|
||||||
// Canonical representation means that encoding a value will always result in the same
|
// Canonical representation means that encoding a value will always result in the same
|
||||||
// sequence of bytes.
|
// sequence of bytes.
|
||||||
//
|
//
|
||||||
// This mostly will apply to maps. In this case, codec will do more work to encode the
|
// This only affects maps, as the iteration order for maps is random.
|
||||||
// map keys out of band, and then sort them, before writing out the map to the stream.
|
// In this case, the map keys will first be encoded into []byte, and then sorted,
|
||||||
|
// before writing the sorted keys and the corresponding map values to the stream.
|
||||||
Canonical bool
|
Canonical bool
|
||||||
|
|
||||||
// AsSymbols defines what should be encoded as symbols.
|
// AsSymbols defines what should be encoded as symbols.
|
||||||
|
@ -249,10 +245,10 @@ func (z *bytesEncWriter) grow(n int) (oldcursor int) {
|
||||||
z.c = oldcursor + n
|
z.c = oldcursor + n
|
||||||
if z.c > len(z.b) {
|
if z.c > len(z.b) {
|
||||||
if z.c > cap(z.b) {
|
if z.c > cap(z.b) {
|
||||||
// Tried using appendslice logic: (if cap < 1024, *2, else *1.25).
|
// appendslice logic (if cap < 1024, *2, else *1.25): more expensive. many copy calls.
|
||||||
// However, it was too expensive, causing too many iterations of copy.
|
// bytes.Buffer model (2*cap + n): much better
|
||||||
// Using bytes.Buffer model was much better (2*cap + n)
|
// bs := make([]byte, 2*cap(z.b)+n)
|
||||||
bs := make([]byte, 2*cap(z.b)+n)
|
bs := make([]byte, growCap(cap(z.b), 1, n))
|
||||||
copy(bs, z.b[:oldcursor])
|
copy(bs, z.b[:oldcursor])
|
||||||
z.b = bs
|
z.b = bs
|
||||||
} else {
|
} else {
|
||||||
|
@ -264,7 +260,7 @@ func (z *bytesEncWriter) grow(n int) (oldcursor int) {
|
||||||
|
|
||||||
// ---------------------------------------------
|
// ---------------------------------------------
|
||||||
|
|
||||||
type encFnInfoX struct {
|
type encFnInfo struct {
|
||||||
e *Encoder
|
e *Encoder
|
||||||
ti *typeInfo
|
ti *typeInfo
|
||||||
xfFn Ext
|
xfFn Ext
|
||||||
|
@ -272,25 +268,13 @@ type encFnInfoX struct {
|
||||||
seq seqType
|
seq seqType
|
||||||
}
|
}
|
||||||
|
|
||||||
type encFnInfo struct {
|
func (f *encFnInfo) builtin(rv reflect.Value) {
|
||||||
// use encFnInfo as a value receiver.
|
f.e.e.EncodeBuiltin(f.ti.rtid, rv.Interface())
|
||||||
// keep most of it less-used variables accessible via a pointer (*encFnInfoX).
|
|
||||||
// As sweet spot for value-receiver is 3 words, keep everything except
|
|
||||||
// encDriver (which everyone needs) directly accessible.
|
|
||||||
// ensure encFnInfoX is set for everyone who needs it i.e.
|
|
||||||
// rawExt, ext, builtin, (selfer|binary|text)Marshal, kSlice, kStruct, kMap, kInterface, fastpath
|
|
||||||
|
|
||||||
ee encDriver
|
|
||||||
*encFnInfoX
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f encFnInfo) builtin(rv reflect.Value) {
|
func (f *encFnInfo) rawExt(rv reflect.Value) {
|
||||||
f.ee.EncodeBuiltin(f.ti.rtid, rv.Interface())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f encFnInfo) rawExt(rv reflect.Value) {
|
|
||||||
// rev := rv.Interface().(RawExt)
|
// rev := rv.Interface().(RawExt)
|
||||||
// f.ee.EncodeRawExt(&rev, f.e)
|
// f.e.e.EncodeRawExt(&rev, f.e)
|
||||||
var re *RawExt
|
var re *RawExt
|
||||||
if rv.CanAddr() {
|
if rv.CanAddr() {
|
||||||
re = rv.Addr().Interface().(*RawExt)
|
re = rv.Addr().Interface().(*RawExt)
|
||||||
|
@ -298,26 +282,35 @@ func (f encFnInfo) rawExt(rv reflect.Value) {
|
||||||
rev := rv.Interface().(RawExt)
|
rev := rv.Interface().(RawExt)
|
||||||
re = &rev
|
re = &rev
|
||||||
}
|
}
|
||||||
f.ee.EncodeRawExt(re, f.e)
|
f.e.e.EncodeRawExt(re, f.e)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f encFnInfo) ext(rv reflect.Value) {
|
func (f *encFnInfo) ext(rv reflect.Value) {
|
||||||
// if this is a struct and it was addressable, then pass the address directly (not the value)
|
// if this is a struct|array and it was addressable, then pass the address directly (not the value)
|
||||||
if rv.CanAddr() && rv.Kind() == reflect.Struct {
|
if k := rv.Kind(); (k == reflect.Struct || k == reflect.Array) && rv.CanAddr() {
|
||||||
rv = rv.Addr()
|
rv = rv.Addr()
|
||||||
}
|
}
|
||||||
f.ee.EncodeExt(rv.Interface(), f.xfTag, f.xfFn, f.e)
|
f.e.e.EncodeExt(rv.Interface(), f.xfTag, f.xfFn, f.e)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f encFnInfo) getValueForMarshalInterface(rv reflect.Value, indir int8) (v interface{}, proceed bool) {
|
func (f *encFnInfo) getValueForMarshalInterface(rv reflect.Value, indir int8) (v interface{}, proceed bool) {
|
||||||
if indir == 0 {
|
if indir == 0 {
|
||||||
v = rv.Interface()
|
v = rv.Interface()
|
||||||
} else if indir == -1 {
|
} else if indir == -1 {
|
||||||
|
// If a non-pointer was passed to Encode(), then that value is not addressable.
|
||||||
|
// Take addr if addresable, else copy value to an addressable value.
|
||||||
|
if rv.CanAddr() {
|
||||||
v = rv.Addr().Interface()
|
v = rv.Addr().Interface()
|
||||||
|
} else {
|
||||||
|
rv2 := reflect.New(rv.Type())
|
||||||
|
rv2.Elem().Set(rv)
|
||||||
|
v = rv2.Interface()
|
||||||
|
// fmt.Printf("rv.Type: %v, rv2.Type: %v, v: %v\n", rv.Type(), rv2.Type(), v)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
for j := int8(0); j < indir; j++ {
|
for j := int8(0); j < indir; j++ {
|
||||||
if rv.IsNil() {
|
if rv.IsNil() {
|
||||||
f.ee.EncodeNil()
|
f.e.e.EncodeNil()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
rv = rv.Elem()
|
rv = rv.Elem()
|
||||||
|
@ -327,74 +320,67 @@ func (f encFnInfo) getValueForMarshalInterface(rv reflect.Value, indir int8) (v
|
||||||
return v, true
|
return v, true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f encFnInfo) selferMarshal(rv reflect.Value) {
|
func (f *encFnInfo) selferMarshal(rv reflect.Value) {
|
||||||
if v, proceed := f.getValueForMarshalInterface(rv, f.ti.csIndir); proceed {
|
if v, proceed := f.getValueForMarshalInterface(rv, f.ti.csIndir); proceed {
|
||||||
v.(Selfer).CodecEncodeSelf(f.e)
|
v.(Selfer).CodecEncodeSelf(f.e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f encFnInfo) binaryMarshal(rv reflect.Value) {
|
func (f *encFnInfo) binaryMarshal(rv reflect.Value) {
|
||||||
if v, proceed := f.getValueForMarshalInterface(rv, f.ti.bmIndir); proceed {
|
if v, proceed := f.getValueForMarshalInterface(rv, f.ti.bmIndir); proceed {
|
||||||
bs, fnerr := v.(encoding.BinaryMarshaler).MarshalBinary()
|
bs, fnerr := v.(encoding.BinaryMarshaler).MarshalBinary()
|
||||||
if fnerr != nil {
|
f.e.marshal(bs, fnerr, false, c_RAW)
|
||||||
panic(fnerr)
|
|
||||||
}
|
|
||||||
if bs == nil {
|
|
||||||
f.ee.EncodeNil()
|
|
||||||
} else {
|
|
||||||
f.ee.EncodeStringBytes(c_RAW, bs)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f encFnInfo) textMarshal(rv reflect.Value) {
|
func (f *encFnInfo) textMarshal(rv reflect.Value) {
|
||||||
if v, proceed := f.getValueForMarshalInterface(rv, f.ti.tmIndir); proceed {
|
if v, proceed := f.getValueForMarshalInterface(rv, f.ti.tmIndir); proceed {
|
||||||
// debugf(">>>> encoding.TextMarshaler: %T", rv.Interface())
|
// debugf(">>>> encoding.TextMarshaler: %T", rv.Interface())
|
||||||
bs, fnerr := v.(encoding.TextMarshaler).MarshalText()
|
bs, fnerr := v.(encoding.TextMarshaler).MarshalText()
|
||||||
if fnerr != nil {
|
f.e.marshal(bs, fnerr, false, c_UTF8)
|
||||||
panic(fnerr)
|
|
||||||
}
|
|
||||||
if bs == nil {
|
|
||||||
f.ee.EncodeNil()
|
|
||||||
} else {
|
|
||||||
f.ee.EncodeStringBytes(c_UTF8, bs)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f encFnInfo) kBool(rv reflect.Value) {
|
func (f *encFnInfo) jsonMarshal(rv reflect.Value) {
|
||||||
f.ee.EncodeBool(rv.Bool())
|
if v, proceed := f.getValueForMarshalInterface(rv, f.ti.jmIndir); proceed {
|
||||||
|
bs, fnerr := v.(jsonMarshaler).MarshalJSON()
|
||||||
|
f.e.marshal(bs, fnerr, true, c_UTF8)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f encFnInfo) kString(rv reflect.Value) {
|
func (f *encFnInfo) kBool(rv reflect.Value) {
|
||||||
f.ee.EncodeString(c_UTF8, rv.String())
|
f.e.e.EncodeBool(rv.Bool())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f encFnInfo) kFloat64(rv reflect.Value) {
|
func (f *encFnInfo) kString(rv reflect.Value) {
|
||||||
f.ee.EncodeFloat64(rv.Float())
|
f.e.e.EncodeString(c_UTF8, rv.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f encFnInfo) kFloat32(rv reflect.Value) {
|
func (f *encFnInfo) kFloat64(rv reflect.Value) {
|
||||||
f.ee.EncodeFloat32(float32(rv.Float()))
|
f.e.e.EncodeFloat64(rv.Float())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f encFnInfo) kInt(rv reflect.Value) {
|
func (f *encFnInfo) kFloat32(rv reflect.Value) {
|
||||||
f.ee.EncodeInt(rv.Int())
|
f.e.e.EncodeFloat32(float32(rv.Float()))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f encFnInfo) kUint(rv reflect.Value) {
|
func (f *encFnInfo) kInt(rv reflect.Value) {
|
||||||
f.ee.EncodeUint(rv.Uint())
|
f.e.e.EncodeInt(rv.Int())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f encFnInfo) kInvalid(rv reflect.Value) {
|
func (f *encFnInfo) kUint(rv reflect.Value) {
|
||||||
f.ee.EncodeNil()
|
f.e.e.EncodeUint(rv.Uint())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f encFnInfo) kErr(rv reflect.Value) {
|
func (f *encFnInfo) kInvalid(rv reflect.Value) {
|
||||||
|
f.e.e.EncodeNil()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *encFnInfo) kErr(rv reflect.Value) {
|
||||||
f.e.errorf("unsupported kind %s, for %#v", rv.Kind(), rv)
|
f.e.errorf("unsupported kind %s, for %#v", rv.Kind(), rv)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f encFnInfo) kSlice(rv reflect.Value) {
|
func (f *encFnInfo) kSlice(rv reflect.Value) {
|
||||||
ti := f.ti
|
ti := f.ti
|
||||||
// array may be non-addressable, so we have to manage with care
|
// array may be non-addressable, so we have to manage with care
|
||||||
// (don't call rv.Bytes, rv.Slice, etc).
|
// (don't call rv.Bytes, rv.Slice, etc).
|
||||||
|
@ -402,13 +388,13 @@ func (f encFnInfo) kSlice(rv reflect.Value) {
|
||||||
// Encode(S{}) will bomb on "panic: slice of unaddressable array".
|
// Encode(S{}) will bomb on "panic: slice of unaddressable array".
|
||||||
if f.seq != seqTypeArray {
|
if f.seq != seqTypeArray {
|
||||||
if rv.IsNil() {
|
if rv.IsNil() {
|
||||||
f.ee.EncodeNil()
|
f.e.e.EncodeNil()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// If in this method, then there was no extension function defined.
|
// If in this method, then there was no extension function defined.
|
||||||
// So it's okay to treat as []byte.
|
// So it's okay to treat as []byte.
|
||||||
if ti.rtid == uint8SliceTypId {
|
if ti.rtid == uint8SliceTypId {
|
||||||
f.ee.EncodeStringBytes(c_RAW, rv.Bytes())
|
f.e.e.EncodeStringBytes(c_RAW, rv.Bytes())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -417,9 +403,9 @@ func (f encFnInfo) kSlice(rv reflect.Value) {
|
||||||
if rtelem.Kind() == reflect.Uint8 {
|
if rtelem.Kind() == reflect.Uint8 {
|
||||||
switch f.seq {
|
switch f.seq {
|
||||||
case seqTypeArray:
|
case seqTypeArray:
|
||||||
// if l == 0 { f.ee.encodeStringBytes(c_RAW, nil) } else
|
// if l == 0 { f.e.e.encodeStringBytes(c_RAW, nil) } else
|
||||||
if rv.CanAddr() {
|
if rv.CanAddr() {
|
||||||
f.ee.EncodeStringBytes(c_RAW, rv.Slice(0, l).Bytes())
|
f.e.e.EncodeStringBytes(c_RAW, rv.Slice(0, l).Bytes())
|
||||||
} else {
|
} else {
|
||||||
var bs []byte
|
var bs []byte
|
||||||
if l <= cap(f.e.b) {
|
if l <= cap(f.e.b) {
|
||||||
|
@ -432,10 +418,10 @@ func (f encFnInfo) kSlice(rv reflect.Value) {
|
||||||
// for i := 0; i < l; i++ {
|
// for i := 0; i < l; i++ {
|
||||||
// bs[i] = byte(rv.Index(i).Uint())
|
// bs[i] = byte(rv.Index(i).Uint())
|
||||||
// }
|
// }
|
||||||
f.ee.EncodeStringBytes(c_RAW, bs)
|
f.e.e.EncodeStringBytes(c_RAW, bs)
|
||||||
}
|
}
|
||||||
case seqTypeSlice:
|
case seqTypeSlice:
|
||||||
f.ee.EncodeStringBytes(c_RAW, rv.Bytes())
|
f.e.e.EncodeStringBytes(c_RAW, rv.Bytes())
|
||||||
case seqTypeChan:
|
case seqTypeChan:
|
||||||
bs := f.e.b[:0]
|
bs := f.e.b[:0]
|
||||||
// do not use range, so that the number of elements encoded
|
// do not use range, so that the number of elements encoded
|
||||||
|
@ -447,7 +433,7 @@ func (f encFnInfo) kSlice(rv reflect.Value) {
|
||||||
for i := 0; i < l; i++ {
|
for i := 0; i < l; i++ {
|
||||||
bs = append(bs, <-ch)
|
bs = append(bs, <-ch)
|
||||||
}
|
}
|
||||||
f.ee.EncodeStringBytes(c_RAW, bs)
|
f.e.e.EncodeStringBytes(c_RAW, bs)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -457,13 +443,12 @@ func (f encFnInfo) kSlice(rv reflect.Value) {
|
||||||
f.e.errorf("mapBySlice requires even slice length, but got %v", l)
|
f.e.errorf("mapBySlice requires even slice length, but got %v", l)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
f.ee.EncodeMapStart(l / 2)
|
f.e.e.EncodeMapStart(l / 2)
|
||||||
} else {
|
} else {
|
||||||
f.ee.EncodeArrayStart(l)
|
f.e.e.EncodeArrayStart(l)
|
||||||
}
|
}
|
||||||
|
|
||||||
e := f.e
|
e := f.e
|
||||||
sep := !e.be
|
|
||||||
if l > 0 {
|
if l > 0 {
|
||||||
for rtelem.Kind() == reflect.Ptr {
|
for rtelem.Kind() == reflect.Ptr {
|
||||||
rtelem = rtelem.Elem()
|
rtelem = rtelem.Elem()
|
||||||
|
@ -471,34 +456,12 @@ func (f encFnInfo) kSlice(rv reflect.Value) {
|
||||||
// if kind is reflect.Interface, do not pre-determine the
|
// if kind is reflect.Interface, do not pre-determine the
|
||||||
// encoding type, because preEncodeValue may break it down to
|
// encoding type, because preEncodeValue may break it down to
|
||||||
// a concrete type and kInterface will bomb.
|
// a concrete type and kInterface will bomb.
|
||||||
var fn encFn
|
var fn *encFn
|
||||||
if rtelem.Kind() != reflect.Interface {
|
if rtelem.Kind() != reflect.Interface {
|
||||||
rtelemid := reflect.ValueOf(rtelem).Pointer()
|
rtelemid := reflect.ValueOf(rtelem).Pointer()
|
||||||
fn = e.getEncFn(rtelemid, rtelem, true, true)
|
fn = e.getEncFn(rtelemid, rtelem, true, true)
|
||||||
}
|
}
|
||||||
// TODO: Consider perf implication of encoding odd index values as symbols if type is string
|
// TODO: Consider perf implication of encoding odd index values as symbols if type is string
|
||||||
if sep {
|
|
||||||
for j := 0; j < l; j++ {
|
|
||||||
if j > 0 {
|
|
||||||
if ti.mbs {
|
|
||||||
if j%2 == 0 {
|
|
||||||
f.ee.EncodeMapEntrySeparator()
|
|
||||||
} else {
|
|
||||||
f.ee.EncodeMapKVSeparator()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
f.ee.EncodeArrayEntrySeparator()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if f.seq == seqTypeChan {
|
|
||||||
if rv2, ok2 := rv.Recv(); ok2 {
|
|
||||||
e.encodeValue(rv2, fn)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
e.encodeValue(rv.Index(j), fn)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for j := 0; j < l; j++ {
|
for j := 0; j < l; j++ {
|
||||||
if f.seq == seqTypeChan {
|
if f.seq == seqTypeChan {
|
||||||
if rv2, ok2 := rv.Recv(); ok2 {
|
if rv2, ok2 := rv.Recv(); ok2 {
|
||||||
|
@ -508,51 +471,23 @@ func (f encFnInfo) kSlice(rv reflect.Value) {
|
||||||
e.encodeValue(rv.Index(j), fn)
|
e.encodeValue(rv.Index(j), fn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if sep {
|
f.e.e.EncodeEnd()
|
||||||
if ti.mbs {
|
|
||||||
f.ee.EncodeMapEnd()
|
|
||||||
} else {
|
|
||||||
f.ee.EncodeArrayEnd()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f encFnInfo) kStruct(rv reflect.Value) {
|
func (f *encFnInfo) kStruct(rv reflect.Value) {
|
||||||
fti := f.ti
|
fti := f.ti
|
||||||
e := f.e
|
e := f.e
|
||||||
tisfi := fti.sfip
|
tisfi := fti.sfip
|
||||||
toMap := !(fti.toArray || e.h.StructToArray)
|
toMap := !(fti.toArray || e.h.StructToArray)
|
||||||
newlen := len(fti.sfi)
|
newlen := len(fti.sfi)
|
||||||
|
|
||||||
// Use sync.Pool to reduce allocating slices unnecessarily.
|
// Use sync.Pool to reduce allocating slices unnecessarily.
|
||||||
// The cost of the occasional locking is less than the cost of locking.
|
// The cost of the occasional locking is less than the cost of locking.
|
||||||
|
pool, poolv, fkvs := encStructPoolGet(newlen)
|
||||||
|
|
||||||
var fkvs []encStructFieldKV
|
|
||||||
var pool *sync.Pool
|
|
||||||
var poolv interface{}
|
|
||||||
idxpool := newlen / 8
|
|
||||||
if encStructPoolLen != 4 {
|
|
||||||
panic(errors.New("encStructPoolLen must be equal to 4")) // defensive, in case it is changed
|
|
||||||
}
|
|
||||||
if idxpool < encStructPoolLen {
|
|
||||||
pool = &encStructPool[idxpool]
|
|
||||||
poolv = pool.Get()
|
|
||||||
switch vv := poolv.(type) {
|
|
||||||
case *[8]encStructFieldKV:
|
|
||||||
fkvs = vv[:newlen]
|
|
||||||
case *[16]encStructFieldKV:
|
|
||||||
fkvs = vv[:newlen]
|
|
||||||
case *[32]encStructFieldKV:
|
|
||||||
fkvs = vv[:newlen]
|
|
||||||
case *[64]encStructFieldKV:
|
|
||||||
fkvs = vv[:newlen]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if fkvs == nil {
|
|
||||||
fkvs = make([]encStructFieldKV, newlen)
|
|
||||||
}
|
|
||||||
// if toMap, use the sorted array. If toArray, use unsorted array (to match sequence in struct)
|
// if toMap, use the sorted array. If toArray, use unsorted array (to match sequence in struct)
|
||||||
if toMap {
|
if toMap {
|
||||||
tisfi = fti.sfi
|
tisfi = fti.sfi
|
||||||
|
@ -587,39 +522,9 @@ func (f encFnInfo) kStruct(rv reflect.Value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// debugf(">>>> kStruct: newlen: %v", newlen)
|
// debugf(">>>> kStruct: newlen: %v", newlen)
|
||||||
sep := !e.be
|
// sep := !e.be
|
||||||
ee := f.ee //don't dereference everytime
|
ee := f.e.e //don't dereference everytime
|
||||||
if sep {
|
|
||||||
if toMap {
|
|
||||||
ee.EncodeMapStart(newlen)
|
|
||||||
// asSymbols := e.h.AsSymbols&AsSymbolStructFieldNameFlag != 0
|
|
||||||
asSymbols := e.h.AsSymbols == AsSymbolDefault || e.h.AsSymbols&AsSymbolStructFieldNameFlag != 0
|
|
||||||
for j := 0; j < newlen; j++ {
|
|
||||||
kv = fkvs[j]
|
|
||||||
if j > 0 {
|
|
||||||
ee.EncodeMapEntrySeparator()
|
|
||||||
}
|
|
||||||
if asSymbols {
|
|
||||||
ee.EncodeSymbol(kv.k)
|
|
||||||
} else {
|
|
||||||
ee.EncodeString(c_UTF8, kv.k)
|
|
||||||
}
|
|
||||||
ee.EncodeMapKVSeparator()
|
|
||||||
e.encodeValue(kv.v, encFn{})
|
|
||||||
}
|
|
||||||
ee.EncodeMapEnd()
|
|
||||||
} else {
|
|
||||||
ee.EncodeArrayStart(newlen)
|
|
||||||
for j := 0; j < newlen; j++ {
|
|
||||||
kv = fkvs[j]
|
|
||||||
if j > 0 {
|
|
||||||
ee.EncodeArrayEntrySeparator()
|
|
||||||
}
|
|
||||||
e.encodeValue(kv.v, encFn{})
|
|
||||||
}
|
|
||||||
ee.EncodeArrayEnd()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if toMap {
|
if toMap {
|
||||||
ee.EncodeMapStart(newlen)
|
ee.EncodeMapStart(newlen)
|
||||||
// asSymbols := e.h.AsSymbols&AsSymbolStructFieldNameFlag != 0
|
// asSymbols := e.h.AsSymbols&AsSymbolStructFieldNameFlag != 0
|
||||||
|
@ -631,16 +536,16 @@ func (f encFnInfo) kStruct(rv reflect.Value) {
|
||||||
} else {
|
} else {
|
||||||
ee.EncodeString(c_UTF8, kv.k)
|
ee.EncodeString(c_UTF8, kv.k)
|
||||||
}
|
}
|
||||||
e.encodeValue(kv.v, encFn{})
|
e.encodeValue(kv.v, nil)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ee.EncodeArrayStart(newlen)
|
ee.EncodeArrayStart(newlen)
|
||||||
for j := 0; j < newlen; j++ {
|
for j := 0; j < newlen; j++ {
|
||||||
kv = fkvs[j]
|
kv = fkvs[j]
|
||||||
e.encodeValue(kv.v, encFn{})
|
e.encodeValue(kv.v, nil)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ee.EncodeEnd()
|
||||||
|
|
||||||
// do not use defer. Instead, use explicit pool return at end of function.
|
// do not use defer. Instead, use explicit pool return at end of function.
|
||||||
// defer has a cost we are trying to avoid.
|
// defer has a cost we are trying to avoid.
|
||||||
|
@ -650,37 +555,35 @@ func (f encFnInfo) kStruct(rv reflect.Value) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// func (f encFnInfo) kPtr(rv reflect.Value) {
|
// func (f *encFnInfo) kPtr(rv reflect.Value) {
|
||||||
// debugf(">>>>>>> ??? encode kPtr called - shouldn't get called")
|
// debugf(">>>>>>> ??? encode kPtr called - shouldn't get called")
|
||||||
// if rv.IsNil() {
|
// if rv.IsNil() {
|
||||||
// f.ee.encodeNil()
|
// f.e.e.encodeNil()
|
||||||
// return
|
// return
|
||||||
// }
|
// }
|
||||||
// f.e.encodeValue(rv.Elem())
|
// f.e.encodeValue(rv.Elem())
|
||||||
// }
|
// }
|
||||||
|
|
||||||
func (f encFnInfo) kInterface(rv reflect.Value) {
|
func (f *encFnInfo) kInterface(rv reflect.Value) {
|
||||||
if rv.IsNil() {
|
if rv.IsNil() {
|
||||||
f.ee.EncodeNil()
|
f.e.e.EncodeNil()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
f.e.encodeValue(rv.Elem(), encFn{})
|
f.e.encodeValue(rv.Elem(), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f encFnInfo) kMap(rv reflect.Value) {
|
func (f *encFnInfo) kMap(rv reflect.Value) {
|
||||||
|
ee := f.e.e
|
||||||
if rv.IsNil() {
|
if rv.IsNil() {
|
||||||
f.ee.EncodeNil()
|
ee.EncodeNil()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
l := rv.Len()
|
l := rv.Len()
|
||||||
f.ee.EncodeMapStart(l)
|
ee.EncodeMapStart(l)
|
||||||
e := f.e
|
e := f.e
|
||||||
sep := !e.be
|
|
||||||
if l == 0 {
|
if l == 0 {
|
||||||
if sep {
|
ee.EncodeEnd()
|
||||||
f.ee.EncodeMapEnd()
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var asSymbols bool
|
var asSymbols bool
|
||||||
|
@ -691,7 +594,7 @@ func (f encFnInfo) kMap(rv reflect.Value) {
|
||||||
// However, if kind is reflect.Interface, do not pre-determine the
|
// However, if kind is reflect.Interface, do not pre-determine the
|
||||||
// encoding type, because preEncodeValue may break it down to
|
// encoding type, because preEncodeValue may break it down to
|
||||||
// a concrete type and kInterface will bomb.
|
// a concrete type and kInterface will bomb.
|
||||||
var keyFn, valFn encFn
|
var keyFn, valFn *encFn
|
||||||
ti := f.ti
|
ti := f.ti
|
||||||
rtkey := ti.rt.Key()
|
rtkey := ti.rt.Key()
|
||||||
rtval := ti.rt.Elem()
|
rtval := ti.rt.Elem()
|
||||||
|
@ -718,11 +621,10 @@ func (f encFnInfo) kMap(rv reflect.Value) {
|
||||||
}
|
}
|
||||||
mks := rv.MapKeys()
|
mks := rv.MapKeys()
|
||||||
// for j, lmks := 0, len(mks); j < lmks; j++ {
|
// for j, lmks := 0, len(mks); j < lmks; j++ {
|
||||||
ee := f.ee //don't dereference everytime
|
|
||||||
if e.h.Canonical {
|
if e.h.Canonical {
|
||||||
// first encode each key to a []byte first, then sort them, then record
|
// first encode each key to a []byte first, then sort them, then record
|
||||||
// println(">>>>>>>> CANONICAL <<<<<<<<")
|
// println(">>>>>>>> CANONICAL <<<<<<<<")
|
||||||
var mksv []byte // temporary byte slice for the encoding
|
var mksv []byte = make([]byte, 0, len(mks)*16) // temporary byte slice for the encoding
|
||||||
e2 := NewEncoderBytes(&mksv, e.hh)
|
e2 := NewEncoderBytes(&mksv, e.hh)
|
||||||
mksbv := make([]encStructFieldBytesV, len(mks))
|
mksbv := make([]encStructFieldBytesV, len(mks))
|
||||||
for i, k := range mks {
|
for i, k := range mks {
|
||||||
|
@ -730,35 +632,13 @@ func (f encFnInfo) kMap(rv reflect.Value) {
|
||||||
e2.MustEncode(k)
|
e2.MustEncode(k)
|
||||||
mksbv[i].v = k
|
mksbv[i].v = k
|
||||||
mksbv[i].b = mksv[l:]
|
mksbv[i].b = mksv[l:]
|
||||||
|
// fmt.Printf(">>>>> %s\n", mksv[l:])
|
||||||
}
|
}
|
||||||
sort.Sort(encStructFieldBytesVslice(mksbv))
|
sort.Sort(encStructFieldBytesVslice(mksbv))
|
||||||
for j := range mksbv {
|
for j := range mksbv {
|
||||||
if j > 0 {
|
e.asis(mksbv[j].b)
|
||||||
ee.EncodeMapEntrySeparator()
|
|
||||||
}
|
|
||||||
e.w.writeb(mksbv[j].b)
|
|
||||||
ee.EncodeMapKVSeparator()
|
|
||||||
e.encodeValue(rv.MapIndex(mksbv[j].v), valFn)
|
e.encodeValue(rv.MapIndex(mksbv[j].v), valFn)
|
||||||
}
|
}
|
||||||
ee.EncodeMapEnd()
|
|
||||||
} else if sep {
|
|
||||||
for j := range mks {
|
|
||||||
if j > 0 {
|
|
||||||
ee.EncodeMapEntrySeparator()
|
|
||||||
}
|
|
||||||
if keyTypeIsString {
|
|
||||||
if asSymbols {
|
|
||||||
ee.EncodeSymbol(mks[j].String())
|
|
||||||
} else {
|
|
||||||
ee.EncodeString(c_UTF8, mks[j].String())
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
e.encodeValue(mks[j], keyFn)
|
|
||||||
}
|
|
||||||
ee.EncodeMapKVSeparator()
|
|
||||||
e.encodeValue(rv.MapIndex(mks[j]), valFn)
|
|
||||||
}
|
|
||||||
ee.EncodeMapEnd()
|
|
||||||
} else {
|
} else {
|
||||||
for j := range mks {
|
for j := range mks {
|
||||||
if keyTypeIsString {
|
if keyTypeIsString {
|
||||||
|
@ -773,6 +653,7 @@ func (f encFnInfo) kMap(rv reflect.Value) {
|
||||||
e.encodeValue(rv.MapIndex(mks[j]), valFn)
|
e.encodeValue(rv.MapIndex(mks[j]), valFn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ee.EncodeEnd()
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------
|
// --------------------------------------------------
|
||||||
|
@ -783,12 +664,12 @@ func (f encFnInfo) kMap(rv reflect.Value) {
|
||||||
// instead of executing the checks every time.
|
// instead of executing the checks every time.
|
||||||
type encFn struct {
|
type encFn struct {
|
||||||
i encFnInfo
|
i encFnInfo
|
||||||
f func(encFnInfo, reflect.Value)
|
f func(*encFnInfo, reflect.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------
|
// --------------------------------------------------
|
||||||
|
|
||||||
type rtidEncFn struct {
|
type encRtidFn struct {
|
||||||
rtid uintptr
|
rtid uintptr
|
||||||
fn encFn
|
fn encFn
|
||||||
}
|
}
|
||||||
|
@ -797,16 +678,20 @@ type rtidEncFn struct {
|
||||||
type Encoder struct {
|
type Encoder struct {
|
||||||
// hopefully, reduce derefencing cost by laying the encWriter inside the Encoder
|
// hopefully, reduce derefencing cost by laying the encWriter inside the Encoder
|
||||||
e encDriver
|
e encDriver
|
||||||
|
// NOTE: Encoder shouldn't call it's write methods,
|
||||||
|
// as the handler MAY need to do some coordination.
|
||||||
w encWriter
|
w encWriter
|
||||||
s []rtidEncFn
|
s []encRtidFn
|
||||||
be bool // is binary encoding
|
be bool // is binary encoding
|
||||||
|
js bool // is json handle
|
||||||
|
|
||||||
wi ioEncWriter
|
wi ioEncWriter
|
||||||
wb bytesEncWriter
|
wb bytesEncWriter
|
||||||
h *BasicHandle
|
h *BasicHandle
|
||||||
|
|
||||||
|
as encDriverAsis
|
||||||
hh Handle
|
hh Handle
|
||||||
f map[uintptr]encFn
|
f map[uintptr]*encFn
|
||||||
b [scratchByteArrayLen]byte
|
b [scratchByteArrayLen]byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -826,7 +711,9 @@ func NewEncoder(w io.Writer, h Handle) *Encoder {
|
||||||
}
|
}
|
||||||
e.wi.w = ww
|
e.wi.w = ww
|
||||||
e.w = &e.wi
|
e.w = &e.wi
|
||||||
|
_, e.js = h.(*JsonHandle)
|
||||||
e.e = h.newEncDriver(e)
|
e.e = h.newEncDriver(e)
|
||||||
|
e.as, _ = e.e.(encDriverAsis)
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -843,7 +730,9 @@ func NewEncoderBytes(out *[]byte, h Handle) *Encoder {
|
||||||
}
|
}
|
||||||
e.wb.b, e.wb.out = in, out
|
e.wb.b, e.wb.out = in, out
|
||||||
e.w = &e.wb
|
e.w = &e.wb
|
||||||
|
_, e.js = h.(*JsonHandle)
|
||||||
e.e = h.newEncDriver(e)
|
e.e = h.newEncDriver(e)
|
||||||
|
e.as, _ = e.e.(encDriverAsis)
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -873,8 +762,9 @@ func NewEncoderBytes(out *[]byte, h Handle) *Encoder {
|
||||||
// The empty values (for omitempty option) are false, 0, any nil pointer
|
// The empty values (for omitempty option) are false, 0, any nil pointer
|
||||||
// or interface value, and any array, slice, map, or string of length zero.
|
// or interface value, and any array, slice, map, or string of length zero.
|
||||||
//
|
//
|
||||||
// Anonymous fields are encoded inline if no struct tag is present.
|
// Anonymous fields are encoded inline except:
|
||||||
// Else they are encoded as regular fields.
|
// - the struct tag specifies a replacement name (first value)
|
||||||
|
// - the field is of an interface type
|
||||||
//
|
//
|
||||||
// Examples:
|
// Examples:
|
||||||
//
|
//
|
||||||
|
@ -885,6 +775,9 @@ func NewEncoderBytes(out *[]byte, h Handle) *Encoder {
|
||||||
// Field2 int `codec:"myName"` //Use key "myName" in encode stream
|
// Field2 int `codec:"myName"` //Use key "myName" in encode stream
|
||||||
// Field3 int32 `codec:",omitempty"` //use key "Field3". Omit if empty.
|
// Field3 int32 `codec:",omitempty"` //use key "Field3". Omit if empty.
|
||||||
// Field4 bool `codec:"f4,omitempty"` //use key "f4". Omit if empty.
|
// Field4 bool `codec:"f4,omitempty"` //use key "f4". Omit if empty.
|
||||||
|
// io.Reader //use key "Reader".
|
||||||
|
// MyStruct `codec:"my1" //use key "my1".
|
||||||
|
// MyStruct //inline it
|
||||||
// ...
|
// ...
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
|
@ -894,8 +787,9 @@ func NewEncoderBytes(out *[]byte, h Handle) *Encoder {
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// The mode of encoding is based on the type of the value. When a value is seen:
|
// The mode of encoding is based on the type of the value. When a value is seen:
|
||||||
|
// - If a Selfer, call its CodecEncodeSelf method
|
||||||
// - If an extension is registered for it, call that extension function
|
// - If an extension is registered for it, call that extension function
|
||||||
// - If it implements BinaryMarshaler, call its MarshalBinary() (data []byte, err error)
|
// - If it implements encoding.(Binary|Text|JSON)Marshaler, call its Marshal(Binary|Text|JSON) method
|
||||||
// - Else encode it based on its reflect.Kind
|
// - Else encode it based on its reflect.Kind
|
||||||
//
|
//
|
||||||
// Note that struct field names and keys in map[string]XXX will be treated as symbols.
|
// Note that struct field names and keys in map[string]XXX will be treated as symbols.
|
||||||
|
@ -942,7 +836,7 @@ func (e *Encoder) encode(iv interface{}) {
|
||||||
v.CodecEncodeSelf(e)
|
v.CodecEncodeSelf(e)
|
||||||
|
|
||||||
case reflect.Value:
|
case reflect.Value:
|
||||||
e.encodeValue(v, encFn{})
|
e.encodeValue(v, nil)
|
||||||
|
|
||||||
case string:
|
case string:
|
||||||
e.e.EncodeString(c_UTF8, v)
|
e.e.EncodeString(c_UTF8, v)
|
||||||
|
@ -1010,12 +904,15 @@ func (e *Encoder) encode(iv interface{}) {
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// canonical mode is not supported for fastpath of maps (but is fine for slices)
|
// canonical mode is not supported for fastpath of maps (but is fine for slices)
|
||||||
|
const checkCodecSelfer1 = true // in case T is passed, where *T is a Selfer, still checkCodecSelfer
|
||||||
if e.h.Canonical {
|
if e.h.Canonical {
|
||||||
if !fastpathEncodeTypeSwitchSlice(iv, e) {
|
if !fastpathEncodeTypeSwitchSlice(iv, e) {
|
||||||
e.encodeI(iv, false, false)
|
e.encodeI(iv, false, checkCodecSelfer1)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if !fastpathEncodeTypeSwitch(iv, e) {
|
||||||
|
e.encodeI(iv, false, checkCodecSelfer1)
|
||||||
}
|
}
|
||||||
} else if !fastpathEncodeTypeSwitch(iv, e) {
|
|
||||||
e.encodeI(iv, false, false)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1025,7 +922,7 @@ func (e *Encoder) encodeI(iv interface{}, checkFastpath, checkCodecSelfer bool)
|
||||||
rt := rv.Type()
|
rt := rv.Type()
|
||||||
rtid := reflect.ValueOf(rt).Pointer()
|
rtid := reflect.ValueOf(rt).Pointer()
|
||||||
fn := e.getEncFn(rtid, rt, checkFastpath, checkCodecSelfer)
|
fn := e.getEncFn(rtid, rt, checkFastpath, checkCodecSelfer)
|
||||||
fn.f(fn.i, rv)
|
fn.f(&fn.i, rv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1055,27 +952,28 @@ LOOP:
|
||||||
return rv, true
|
return rv, true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Encoder) encodeValue(rv reflect.Value, fn encFn) {
|
func (e *Encoder) encodeValue(rv reflect.Value, fn *encFn) {
|
||||||
// if a valid fn is passed, it MUST BE for the dereferenced type of rv
|
// if a valid fn is passed, it MUST BE for the dereferenced type of rv
|
||||||
if rv, proceed := e.preEncodeValue(rv); proceed {
|
if rv, proceed := e.preEncodeValue(rv); proceed {
|
||||||
if fn.f == nil {
|
if fn == nil {
|
||||||
rt := rv.Type()
|
rt := rv.Type()
|
||||||
rtid := reflect.ValueOf(rt).Pointer()
|
rtid := reflect.ValueOf(rt).Pointer()
|
||||||
fn = e.getEncFn(rtid, rt, true, true)
|
fn = e.getEncFn(rtid, rt, true, true)
|
||||||
}
|
}
|
||||||
fn.f(fn.i, rv)
|
fn.f(&fn.i, rv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Encoder) getEncFn(rtid uintptr, rt reflect.Type, checkFastpath, checkCodecSelfer bool) (fn encFn) {
|
func (e *Encoder) getEncFn(rtid uintptr, rt reflect.Type, checkFastpath, checkCodecSelfer bool) (fn *encFn) {
|
||||||
// rtid := reflect.ValueOf(rt).Pointer()
|
// rtid := reflect.ValueOf(rt).Pointer()
|
||||||
var ok bool
|
var ok bool
|
||||||
if useMapForCodecCache {
|
if useMapForCodecCache {
|
||||||
fn, ok = e.f[rtid]
|
fn, ok = e.f[rtid]
|
||||||
} else {
|
} else {
|
||||||
for _, v := range e.s {
|
for i := range e.s {
|
||||||
|
v := &(e.s[i])
|
||||||
if v.rtid == rtid {
|
if v.rtid == rtid {
|
||||||
fn, ok = v.fn, true
|
fn, ok = &(v.fn), true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1083,37 +981,48 @@ func (e *Encoder) getEncFn(rtid uintptr, rt reflect.Type, checkFastpath, checkCo
|
||||||
if ok {
|
if ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// fi.encFnInfoX = new(encFnInfoX)
|
|
||||||
ti := getTypeInfo(rtid, rt)
|
if useMapForCodecCache {
|
||||||
var fi encFnInfo
|
if e.f == nil {
|
||||||
fi.ee = e.e
|
e.f = make(map[uintptr]*encFn, initCollectionCap)
|
||||||
|
}
|
||||||
|
fn = new(encFn)
|
||||||
|
e.f[rtid] = fn
|
||||||
|
} else {
|
||||||
|
if e.s == nil {
|
||||||
|
e.s = make([]encRtidFn, 0, initCollectionCap)
|
||||||
|
}
|
||||||
|
e.s = append(e.s, encRtidFn{rtid: rtid})
|
||||||
|
fn = &(e.s[len(e.s)-1]).fn
|
||||||
|
}
|
||||||
|
|
||||||
|
ti := e.h.getTypeInfo(rtid, rt)
|
||||||
|
fi := &(fn.i)
|
||||||
|
fi.e = e
|
||||||
|
fi.ti = ti
|
||||||
|
|
||||||
if checkCodecSelfer && ti.cs {
|
if checkCodecSelfer && ti.cs {
|
||||||
fi.encFnInfoX = &encFnInfoX{e: e, ti: ti}
|
fn.f = (*encFnInfo).selferMarshal
|
||||||
fn.f = (encFnInfo).selferMarshal
|
|
||||||
} else if rtid == rawExtTypId {
|
} else if rtid == rawExtTypId {
|
||||||
fi.encFnInfoX = &encFnInfoX{e: e, ti: ti}
|
fn.f = (*encFnInfo).rawExt
|
||||||
fn.f = (encFnInfo).rawExt
|
|
||||||
} else if e.e.IsBuiltinType(rtid) {
|
} else if e.e.IsBuiltinType(rtid) {
|
||||||
fi.encFnInfoX = &encFnInfoX{e: e, ti: ti}
|
fn.f = (*encFnInfo).builtin
|
||||||
fn.f = (encFnInfo).builtin
|
|
||||||
} else if xfFn := e.h.getExt(rtid); xfFn != nil {
|
} else if xfFn := e.h.getExt(rtid); xfFn != nil {
|
||||||
// fi.encFnInfoX = new(encFnInfoX)
|
|
||||||
fi.encFnInfoX = &encFnInfoX{e: e, ti: ti}
|
|
||||||
fi.xfTag, fi.xfFn = xfFn.tag, xfFn.ext
|
fi.xfTag, fi.xfFn = xfFn.tag, xfFn.ext
|
||||||
fn.f = (encFnInfo).ext
|
fn.f = (*encFnInfo).ext
|
||||||
} else if supportMarshalInterfaces && e.be && ti.bm {
|
} else if supportMarshalInterfaces && e.be && ti.bm {
|
||||||
fi.encFnInfoX = &encFnInfoX{e: e, ti: ti}
|
fn.f = (*encFnInfo).binaryMarshal
|
||||||
fn.f = (encFnInfo).binaryMarshal
|
} else if supportMarshalInterfaces && !e.be && e.js && ti.jm {
|
||||||
|
//If JSON, we should check JSONMarshal before textMarshal
|
||||||
|
fn.f = (*encFnInfo).jsonMarshal
|
||||||
} else if supportMarshalInterfaces && !e.be && ti.tm {
|
} else if supportMarshalInterfaces && !e.be && ti.tm {
|
||||||
fi.encFnInfoX = &encFnInfoX{e: e, ti: ti}
|
fn.f = (*encFnInfo).textMarshal
|
||||||
fn.f = (encFnInfo).textMarshal
|
|
||||||
} else {
|
} else {
|
||||||
rk := rt.Kind()
|
rk := rt.Kind()
|
||||||
if fastpathEnabled && checkFastpath && (rk == reflect.Map || rk == reflect.Slice) {
|
// if fastpathEnabled && checkFastpath && (rk == reflect.Map || rk == reflect.Slice) {
|
||||||
|
if fastpathEnabled && checkFastpath && (rk == reflect.Slice || (rk == reflect.Map && !e.h.Canonical)) {
|
||||||
if rt.PkgPath() == "" {
|
if rt.PkgPath() == "" {
|
||||||
if idx := fastpathAV.index(rtid); idx != -1 {
|
if idx := fastpathAV.index(rtid); idx != -1 {
|
||||||
fi.encFnInfoX = &encFnInfoX{e: e, ti: ti}
|
|
||||||
fn.f = fastpathAV[idx].encfn
|
fn.f = fastpathAV[idx].encfn
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -1129,8 +1038,7 @@ func (e *Encoder) getEncFn(rtid uintptr, rt reflect.Type, checkFastpath, checkCo
|
||||||
if idx := fastpathAV.index(rtuid); idx != -1 {
|
if idx := fastpathAV.index(rtuid); idx != -1 {
|
||||||
xfnf := fastpathAV[idx].encfn
|
xfnf := fastpathAV[idx].encfn
|
||||||
xrt := fastpathAV[idx].rt
|
xrt := fastpathAV[idx].rt
|
||||||
fi.encFnInfoX = &encFnInfoX{e: e, ti: ti}
|
fn.f = func(xf *encFnInfo, xrv reflect.Value) {
|
||||||
fn.f = func(xf encFnInfo, xrv reflect.Value) {
|
|
||||||
xfnf(xf, xrv.Convert(xrt))
|
xfnf(xf, xrv.Convert(xrt))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1139,60 +1047,66 @@ func (e *Encoder) getEncFn(rtid uintptr, rt reflect.Type, checkFastpath, checkCo
|
||||||
if fn.f == nil {
|
if fn.f == nil {
|
||||||
switch rk {
|
switch rk {
|
||||||
case reflect.Bool:
|
case reflect.Bool:
|
||||||
fn.f = (encFnInfo).kBool
|
fn.f = (*encFnInfo).kBool
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
fn.f = (encFnInfo).kString
|
fn.f = (*encFnInfo).kString
|
||||||
case reflect.Float64:
|
case reflect.Float64:
|
||||||
fn.f = (encFnInfo).kFloat64
|
fn.f = (*encFnInfo).kFloat64
|
||||||
case reflect.Float32:
|
case reflect.Float32:
|
||||||
fn.f = (encFnInfo).kFloat32
|
fn.f = (*encFnInfo).kFloat32
|
||||||
case reflect.Int, reflect.Int8, reflect.Int64, reflect.Int32, reflect.Int16:
|
case reflect.Int, reflect.Int8, reflect.Int64, reflect.Int32, reflect.Int16:
|
||||||
fn.f = (encFnInfo).kInt
|
fn.f = (*encFnInfo).kInt
|
||||||
case reflect.Uint8, reflect.Uint64, reflect.Uint, reflect.Uint32, reflect.Uint16:
|
case reflect.Uint8, reflect.Uint64, reflect.Uint, reflect.Uint32, reflect.Uint16, reflect.Uintptr:
|
||||||
fn.f = (encFnInfo).kUint
|
fn.f = (*encFnInfo).kUint
|
||||||
case reflect.Invalid:
|
case reflect.Invalid:
|
||||||
fn.f = (encFnInfo).kInvalid
|
fn.f = (*encFnInfo).kInvalid
|
||||||
case reflect.Chan:
|
case reflect.Chan:
|
||||||
fi.encFnInfoX = &encFnInfoX{e: e, ti: ti, seq: seqTypeChan}
|
fi.seq = seqTypeChan
|
||||||
fn.f = (encFnInfo).kSlice
|
fn.f = (*encFnInfo).kSlice
|
||||||
case reflect.Slice:
|
case reflect.Slice:
|
||||||
fi.encFnInfoX = &encFnInfoX{e: e, ti: ti, seq: seqTypeSlice}
|
fi.seq = seqTypeSlice
|
||||||
fn.f = (encFnInfo).kSlice
|
fn.f = (*encFnInfo).kSlice
|
||||||
case reflect.Array:
|
case reflect.Array:
|
||||||
fi.encFnInfoX = &encFnInfoX{e: e, ti: ti, seq: seqTypeArray}
|
fi.seq = seqTypeArray
|
||||||
fn.f = (encFnInfo).kSlice
|
fn.f = (*encFnInfo).kSlice
|
||||||
case reflect.Struct:
|
case reflect.Struct:
|
||||||
fi.encFnInfoX = &encFnInfoX{e: e, ti: ti}
|
fn.f = (*encFnInfo).kStruct
|
||||||
fn.f = (encFnInfo).kStruct
|
|
||||||
// case reflect.Ptr:
|
// case reflect.Ptr:
|
||||||
// fn.f = (encFnInfo).kPtr
|
// fn.f = (*encFnInfo).kPtr
|
||||||
case reflect.Interface:
|
case reflect.Interface:
|
||||||
fi.encFnInfoX = &encFnInfoX{e: e, ti: ti}
|
fn.f = (*encFnInfo).kInterface
|
||||||
fn.f = (encFnInfo).kInterface
|
|
||||||
case reflect.Map:
|
case reflect.Map:
|
||||||
fi.encFnInfoX = &encFnInfoX{e: e, ti: ti}
|
fn.f = (*encFnInfo).kMap
|
||||||
fn.f = (encFnInfo).kMap
|
|
||||||
default:
|
default:
|
||||||
fn.f = (encFnInfo).kErr
|
fn.f = (*encFnInfo).kErr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn.i = fi
|
|
||||||
|
|
||||||
if useMapForCodecCache {
|
|
||||||
if e.f == nil {
|
|
||||||
e.f = make(map[uintptr]encFn, 32)
|
|
||||||
}
|
|
||||||
e.f[rtid] = fn
|
|
||||||
} else {
|
|
||||||
if e.s == nil {
|
|
||||||
e.s = make([]rtidEncFn, 0, 32)
|
|
||||||
}
|
|
||||||
e.s = append(e.s, rtidEncFn{rtid, fn})
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) marshal(bs []byte, fnerr error, asis bool, c charEncoding) {
|
||||||
|
if fnerr != nil {
|
||||||
|
panic(fnerr)
|
||||||
|
}
|
||||||
|
if bs == nil {
|
||||||
|
e.e.EncodeNil()
|
||||||
|
} else if asis {
|
||||||
|
e.asis(bs)
|
||||||
|
} else {
|
||||||
|
e.e.EncodeStringBytes(c, bs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) asis(v []byte) {
|
||||||
|
if e.as == nil {
|
||||||
|
e.w.writeb(v)
|
||||||
|
} else {
|
||||||
|
e.as.EncodeAsis(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (e *Encoder) errorf(format string, params ...interface{}) {
|
func (e *Encoder) errorf(format string, params ...interface{}) {
|
||||||
err := fmt.Errorf(format, params...)
|
err := fmt.Errorf(format, params...)
|
||||||
panic(err)
|
panic(err)
|
||||||
|
@ -1205,7 +1119,7 @@ type encStructFieldKV struct {
|
||||||
v reflect.Value
|
v reflect.Value
|
||||||
}
|
}
|
||||||
|
|
||||||
const encStructPoolLen = 4
|
const encStructPoolLen = 5
|
||||||
|
|
||||||
// encStructPool is an array of sync.Pool.
|
// encStructPool is an array of sync.Pool.
|
||||||
// Each element of the array pools one of encStructPool(8|16|32|64).
|
// Each element of the array pools one of encStructPool(8|16|32|64).
|
||||||
|
@ -1223,6 +1137,57 @@ func init() {
|
||||||
encStructPool[1].New = func() interface{} { return new([16]encStructFieldKV) }
|
encStructPool[1].New = func() interface{} { return new([16]encStructFieldKV) }
|
||||||
encStructPool[2].New = func() interface{} { return new([32]encStructFieldKV) }
|
encStructPool[2].New = func() interface{} { return new([32]encStructFieldKV) }
|
||||||
encStructPool[3].New = func() interface{} { return new([64]encStructFieldKV) }
|
encStructPool[3].New = func() interface{} { return new([64]encStructFieldKV) }
|
||||||
|
encStructPool[4].New = func() interface{} { return new([128]encStructFieldKV) }
|
||||||
|
}
|
||||||
|
|
||||||
|
func encStructPoolGet(newlen int) (p *sync.Pool, v interface{}, s []encStructFieldKV) {
|
||||||
|
// if encStructPoolLen != 5 { // constant chec, so removed at build time.
|
||||||
|
// panic(errors.New("encStructPoolLen must be equal to 4")) // defensive, in case it is changed
|
||||||
|
// }
|
||||||
|
// idxpool := newlen / 8
|
||||||
|
|
||||||
|
// if pool == nil {
|
||||||
|
// fkvs = make([]encStructFieldKV, newlen)
|
||||||
|
// } else {
|
||||||
|
// poolv = pool.Get()
|
||||||
|
// switch vv := poolv.(type) {
|
||||||
|
// case *[8]encStructFieldKV:
|
||||||
|
// fkvs = vv[:newlen]
|
||||||
|
// case *[16]encStructFieldKV:
|
||||||
|
// fkvs = vv[:newlen]
|
||||||
|
// case *[32]encStructFieldKV:
|
||||||
|
// fkvs = vv[:newlen]
|
||||||
|
// case *[64]encStructFieldKV:
|
||||||
|
// fkvs = vv[:newlen]
|
||||||
|
// case *[128]encStructFieldKV:
|
||||||
|
// fkvs = vv[:newlen]
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
if newlen <= 8 {
|
||||||
|
p = &encStructPool[0]
|
||||||
|
v = p.Get()
|
||||||
|
s = v.(*[8]encStructFieldKV)[:newlen]
|
||||||
|
} else if newlen <= 16 {
|
||||||
|
p = &encStructPool[1]
|
||||||
|
v = p.Get()
|
||||||
|
s = v.(*[16]encStructFieldKV)[:newlen]
|
||||||
|
} else if newlen <= 32 {
|
||||||
|
p = &encStructPool[2]
|
||||||
|
v = p.Get()
|
||||||
|
s = v.(*[32]encStructFieldKV)[:newlen]
|
||||||
|
} else if newlen <= 64 {
|
||||||
|
p = &encStructPool[3]
|
||||||
|
v = p.Get()
|
||||||
|
s = v.(*[64]encStructFieldKV)[:newlen]
|
||||||
|
} else if newlen <= 128 {
|
||||||
|
p = &encStructPool[4]
|
||||||
|
v = p.Get()
|
||||||
|
s = v.(*[128]encStructFieldKV)[:newlen]
|
||||||
|
} else {
|
||||||
|
s = make([]encStructFieldKV, newlen)
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,7 +1,7 @@
|
||||||
// //+build ignore
|
// //+build ignore
|
||||||
|
|
||||||
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style license found in the LICENSE file.
|
// Use of this source code is governed by a MIT license found in the LICENSE file.
|
||||||
|
|
||||||
// ************************************************************
|
// ************************************************************
|
||||||
// DO NOT EDIT.
|
// DO NOT EDIT.
|
||||||
|
@ -48,8 +48,8 @@ var fastpathTV fastpathT
|
||||||
type fastpathE struct {
|
type fastpathE struct {
|
||||||
rtid uintptr
|
rtid uintptr
|
||||||
rt reflect.Type
|
rt reflect.Type
|
||||||
encfn func(encFnInfo, reflect.Value)
|
encfn func(*encFnInfo, reflect.Value)
|
||||||
decfn func(decFnInfo, reflect.Value)
|
decfn func(*decFnInfo, reflect.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
type fastpathA [{{ .FastpathLen }}]fastpathE
|
type fastpathA [{{ .FastpathLen }}]fastpathE
|
||||||
|
@ -85,7 +85,7 @@ func init() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
i := 0
|
i := 0
|
||||||
fn := func(v interface{}, fe func(encFnInfo, reflect.Value), fd func(decFnInfo, reflect.Value)) (f fastpathE) {
|
fn := func(v interface{}, fe func(*encFnInfo, reflect.Value), fd func(*decFnInfo, reflect.Value)) (f fastpathE) {
|
||||||
xrt := reflect.TypeOf(v)
|
xrt := reflect.TypeOf(v)
|
||||||
xptr := reflect.ValueOf(xrt).Pointer()
|
xptr := reflect.ValueOf(xrt).Pointer()
|
||||||
fastpathAV[i] = fastpathE{xptr, xrt, fe, fd}
|
fastpathAV[i] = fastpathE{xptr, xrt, fe, fd}
|
||||||
|
@ -93,11 +93,11 @@ func init() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
{{range .Values}}{{if not .Primitive}}{{if .Slice }}
|
{{range .Values}}{{if not .Primitive}}{{if not .MapKey }}
|
||||||
fn([]{{ .Elem }}(nil), (encFnInfo).{{ .MethodNamePfx "fastpathEnc" false }}R, (decFnInfo).{{ .MethodNamePfx "fastpathDec" false }}R){{end}}{{end}}{{end}}
|
fn([]{{ .Elem }}(nil), (*encFnInfo).{{ .MethodNamePfx "fastpathEnc" false }}R, (*decFnInfo).{{ .MethodNamePfx "fastpathDec" false }}R){{end}}{{end}}{{end}}
|
||||||
|
|
||||||
{{range .Values}}{{if not .Primitive}}{{if not .Slice }}
|
{{range .Values}}{{if not .Primitive}}{{if .MapKey }}
|
||||||
fn(map[{{ .MapKey }}]{{ .Elem }}(nil), (encFnInfo).{{ .MethodNamePfx "fastpathEnc" false }}R, (decFnInfo).{{ .MethodNamePfx "fastpathDec" false }}R){{end}}{{end}}{{end}}
|
fn(map[{{ .MapKey }}]{{ .Elem }}(nil), (*encFnInfo).{{ .MethodNamePfx "fastpathEnc" false }}R, (*decFnInfo).{{ .MethodNamePfx "fastpathDec" false }}R){{end}}{{end}}{{end}}
|
||||||
|
|
||||||
sort.Sort(fastpathAslice(fastpathAV[:]))
|
sort.Sort(fastpathAslice(fastpathAV[:]))
|
||||||
}
|
}
|
||||||
|
@ -107,10 +107,10 @@ func init() {
|
||||||
// -- -- fast path type switch
|
// -- -- fast path type switch
|
||||||
func fastpathEncodeTypeSwitch(iv interface{}, e *Encoder) bool {
|
func fastpathEncodeTypeSwitch(iv interface{}, e *Encoder) bool {
|
||||||
switch v := iv.(type) {
|
switch v := iv.(type) {
|
||||||
{{range .Values}}{{if not .Primitive}}{{if .Slice }}
|
{{range .Values}}{{if not .Primitive}}{{if not .MapKey }}
|
||||||
case []{{ .Elem }}:{{else}}
|
case []{{ .Elem }}:{{else}}
|
||||||
case map[{{ .MapKey }}]{{ .Elem }}:{{end}}
|
case map[{{ .MapKey }}]{{ .Elem }}:{{end}}
|
||||||
fastpathTV.{{ .MethodNamePfx "Enc" false }}V(v, fastpathCheckNilTrue, e){{if .Slice }}
|
fastpathTV.{{ .MethodNamePfx "Enc" false }}V(v, fastpathCheckNilTrue, e){{if not .MapKey }}
|
||||||
case *[]{{ .Elem }}:{{else}}
|
case *[]{{ .Elem }}:{{else}}
|
||||||
case *map[{{ .MapKey }}]{{ .Elem }}:{{end}}
|
case *map[{{ .MapKey }}]{{ .Elem }}:{{end}}
|
||||||
fastpathTV.{{ .MethodNamePfx "Enc" false }}V(*v, fastpathCheckNilTrue, e)
|
fastpathTV.{{ .MethodNamePfx "Enc" false }}V(*v, fastpathCheckNilTrue, e)
|
||||||
|
@ -123,7 +123,7 @@ func fastpathEncodeTypeSwitch(iv interface{}, e *Encoder) bool {
|
||||||
|
|
||||||
func fastpathEncodeTypeSwitchSlice(iv interface{}, e *Encoder) bool {
|
func fastpathEncodeTypeSwitchSlice(iv interface{}, e *Encoder) bool {
|
||||||
switch v := iv.(type) {
|
switch v := iv.(type) {
|
||||||
{{range .Values}}{{if not .Primitive}}{{if .Slice }}
|
{{range .Values}}{{if not .Primitive}}{{if not .MapKey }}
|
||||||
case []{{ .Elem }}:
|
case []{{ .Elem }}:
|
||||||
fastpathTV.{{ .MethodNamePfx "Enc" false }}V(v, fastpathCheckNilTrue, e)
|
fastpathTV.{{ .MethodNamePfx "Enc" false }}V(v, fastpathCheckNilTrue, e)
|
||||||
case *[]{{ .Elem }}:
|
case *[]{{ .Elem }}:
|
||||||
|
@ -137,7 +137,7 @@ func fastpathEncodeTypeSwitchSlice(iv interface{}, e *Encoder) bool {
|
||||||
|
|
||||||
func fastpathEncodeTypeSwitchMap(iv interface{}, e *Encoder) bool {
|
func fastpathEncodeTypeSwitchMap(iv interface{}, e *Encoder) bool {
|
||||||
switch v := iv.(type) {
|
switch v := iv.(type) {
|
||||||
{{range .Values}}{{if not .Primitive}}{{if not .Slice }}
|
{{range .Values}}{{if not .Primitive}}{{if .MapKey }}
|
||||||
case map[{{ .MapKey }}]{{ .Elem }}:
|
case map[{{ .MapKey }}]{{ .Elem }}:
|
||||||
fastpathTV.{{ .MethodNamePfx "Enc" false }}V(v, fastpathCheckNilTrue, e)
|
fastpathTV.{{ .MethodNamePfx "Enc" false }}V(v, fastpathCheckNilTrue, e)
|
||||||
case *map[{{ .MapKey }}]{{ .Elem }}:
|
case *map[{{ .MapKey }}]{{ .Elem }}:
|
||||||
|
@ -150,9 +150,9 @@ func fastpathEncodeTypeSwitchMap(iv interface{}, e *Encoder) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// -- -- fast path functions
|
// -- -- fast path functions
|
||||||
{{range .Values}}{{if not .Primitive}}{{if .Slice }}
|
{{range .Values}}{{if not .Primitive}}{{if not .MapKey }}
|
||||||
|
|
||||||
func (f encFnInfo) {{ .MethodNamePfx "fastpathEnc" false }}R(rv reflect.Value) {
|
func (f *encFnInfo) {{ .MethodNamePfx "fastpathEnc" false }}R(rv reflect.Value) {
|
||||||
fastpathTV.{{ .MethodNamePfx "Enc" false }}V(rv.Interface().([]{{ .Elem }}), fastpathCheckNilFalse, f.e)
|
fastpathTV.{{ .MethodNamePfx "Enc" false }}V(rv.Interface().([]{{ .Elem }}), fastpathCheckNilFalse, f.e)
|
||||||
}
|
}
|
||||||
func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v []{{ .Elem }}, checkNil bool, e *Encoder) {
|
func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v []{{ .Elem }}, checkNil bool, e *Encoder) {
|
||||||
|
@ -162,26 +162,17 @@ func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v []{{ .Elem }}, checkNil b
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ee.EncodeArrayStart(len(v))
|
ee.EncodeArrayStart(len(v))
|
||||||
if e.be {
|
|
||||||
for _, v2 := range v {
|
for _, v2 := range v {
|
||||||
{{ encmd .Elem "v2"}}
|
{{ encmd .Elem "v2"}}
|
||||||
}
|
}
|
||||||
} else {
|
ee.EncodeEnd()
|
||||||
for j, v2 := range v {
|
|
||||||
if j > 0 {
|
|
||||||
ee.EncodeArrayEntrySeparator()
|
|
||||||
}
|
|
||||||
{{ encmd .Elem "v2"}}
|
|
||||||
}
|
|
||||||
ee.EncodeArrayEnd()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{{end}}{{end}}{{end}}
|
{{end}}{{end}}{{end}}
|
||||||
|
|
||||||
{{range .Values}}{{if not .Primitive}}{{if not .Slice }}
|
{{range .Values}}{{if not .Primitive}}{{if .MapKey }}
|
||||||
|
|
||||||
func (f encFnInfo) {{ .MethodNamePfx "fastpathEnc" false }}R(rv reflect.Value) {
|
func (f *encFnInfo) {{ .MethodNamePfx "fastpathEnc" false }}R(rv reflect.Value) {
|
||||||
fastpathTV.{{ .MethodNamePfx "Enc" false }}V(rv.Interface().(map[{{ .MapKey }}]{{ .Elem }}), fastpathCheckNilFalse, f.e)
|
fastpathTV.{{ .MethodNamePfx "Enc" false }}V(rv.Interface().(map[{{ .MapKey }}]{{ .Elem }}), fastpathCheckNilFalse, f.e)
|
||||||
}
|
}
|
||||||
func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v map[{{ .MapKey }}]{{ .Elem }}, checkNil bool, e *Encoder) {
|
func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v map[{{ .MapKey }}]{{ .Elem }}, checkNil bool, e *Encoder) {
|
||||||
|
@ -192,7 +183,6 @@ func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v map[{{ .MapKey }}]{{ .Ele
|
||||||
}
|
}
|
||||||
ee.EncodeMapStart(len(v))
|
ee.EncodeMapStart(len(v))
|
||||||
{{if eq .MapKey "string"}}asSymbols := e.h.AsSymbols&AsSymbolMapStringKeysFlag != 0{{end}}
|
{{if eq .MapKey "string"}}asSymbols := e.h.AsSymbols&AsSymbolMapStringKeysFlag != 0{{end}}
|
||||||
if e.be {
|
|
||||||
for k2, v2 := range v {
|
for k2, v2 := range v {
|
||||||
{{if eq .MapKey "string"}}if asSymbols {
|
{{if eq .MapKey "string"}}if asSymbols {
|
||||||
ee.EncodeSymbol(k2)
|
ee.EncodeSymbol(k2)
|
||||||
|
@ -201,23 +191,7 @@ func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v map[{{ .MapKey }}]{{ .Ele
|
||||||
}{{else}}{{ encmd .MapKey "k2"}}{{end}}
|
}{{else}}{{ encmd .MapKey "k2"}}{{end}}
|
||||||
{{ encmd .Elem "v2"}}
|
{{ encmd .Elem "v2"}}
|
||||||
}
|
}
|
||||||
} else {
|
ee.EncodeEnd()
|
||||||
j := 0
|
|
||||||
for k2, v2 := range v {
|
|
||||||
if j > 0 {
|
|
||||||
ee.EncodeMapEntrySeparator()
|
|
||||||
}
|
|
||||||
{{if eq .MapKey "string"}}if asSymbols {
|
|
||||||
ee.EncodeSymbol(k2)
|
|
||||||
} else {
|
|
||||||
ee.EncodeString(c_UTF8, k2)
|
|
||||||
}{{else}}{{ encmd .MapKey "k2"}}{{end}}
|
|
||||||
ee.EncodeMapKVSeparator()
|
|
||||||
{{ encmd .Elem "v2"}}
|
|
||||||
j++
|
|
||||||
}
|
|
||||||
ee.EncodeMapEnd()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{{end}}{{end}}{{end}}
|
{{end}}{{end}}{{end}}
|
||||||
|
@ -227,10 +201,10 @@ func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v map[{{ .MapKey }}]{{ .Ele
|
||||||
// -- -- fast path type switch
|
// -- -- fast path type switch
|
||||||
func fastpathDecodeTypeSwitch(iv interface{}, d *Decoder) bool {
|
func fastpathDecodeTypeSwitch(iv interface{}, d *Decoder) bool {
|
||||||
switch v := iv.(type) {
|
switch v := iv.(type) {
|
||||||
{{range .Values}}{{if not .Primitive}}{{if .Slice }}
|
{{range .Values}}{{if not .Primitive}}{{if not .MapKey }}
|
||||||
case []{{ .Elem }}:{{else}}
|
case []{{ .Elem }}:{{else}}
|
||||||
case map[{{ .MapKey }}]{{ .Elem }}:{{end}}
|
case map[{{ .MapKey }}]{{ .Elem }}:{{end}}
|
||||||
fastpathTV.{{ .MethodNamePfx "Dec" false }}V(v, fastpathCheckNilFalse, false, d){{if .Slice }}
|
fastpathTV.{{ .MethodNamePfx "Dec" false }}V(v, fastpathCheckNilFalse, false, d){{if not .MapKey }}
|
||||||
case *[]{{ .Elem }}:{{else}}
|
case *[]{{ .Elem }}:{{else}}
|
||||||
case *map[{{ .MapKey }}]{{ .Elem }}:{{end}}
|
case *map[{{ .MapKey }}]{{ .Elem }}:{{end}}
|
||||||
v2, changed2 := fastpathTV.{{ .MethodNamePfx "Dec" false }}V(*v, fastpathCheckNilFalse, true, d)
|
v2, changed2 := fastpathTV.{{ .MethodNamePfx "Dec" false }}V(*v, fastpathCheckNilFalse, true, d)
|
||||||
|
@ -245,16 +219,16 @@ func fastpathDecodeTypeSwitch(iv interface{}, d *Decoder) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// -- -- fast path functions
|
// -- -- fast path functions
|
||||||
{{range .Values}}{{if not .Primitive}}{{if .Slice }}
|
{{range .Values}}{{if not .Primitive}}{{if not .MapKey }}
|
||||||
{{/*
|
{{/*
|
||||||
Slices can change if they
|
Slices can change if they
|
||||||
- did not come from an array
|
- did not come from an array
|
||||||
- are addressable (from a ptr)
|
- are addressable (from a ptr)
|
||||||
- are settable (e.g. contained in an interface{})
|
- are settable (e.g. contained in an interface{})
|
||||||
*/}}
|
*/}}
|
||||||
func (f decFnInfo) {{ .MethodNamePfx "fastpathDec" false }}R(rv reflect.Value) {
|
func (f *decFnInfo) {{ .MethodNamePfx "fastpathDec" false }}R(rv reflect.Value) {
|
||||||
array := f.seq == seqTypeArray
|
array := f.seq == seqTypeArray
|
||||||
if !array && rv.CanAddr() { // CanSet => CanAddr + Exported
|
if !array && rv.CanAddr() { {{/* // CanSet => CanAddr + Exported */}}
|
||||||
vp := rv.Addr().Interface().(*[]{{ .Elem }})
|
vp := rv.Addr().Interface().(*[]{{ .Elem }})
|
||||||
v, changed := fastpathTV.{{ .MethodNamePfx "Dec" false }}V(*vp, fastpathCheckNilFalse, !array, f.d)
|
v, changed := fastpathTV.{{ .MethodNamePfx "Dec" false }}V(*vp, fastpathCheckNilFalse, !array, f.d)
|
||||||
if changed {
|
if changed {
|
||||||
|
@ -275,7 +249,7 @@ func (f fastpathT) {{ .MethodNamePfx "Dec" false }}X(vp *[]{{ .Elem }}, checkNil
|
||||||
func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v []{{ .Elem }}, checkNil bool, canChange bool,
|
func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v []{{ .Elem }}, checkNil bool, canChange bool,
|
||||||
d *Decoder) (_ []{{ .Elem }}, changed bool) {
|
d *Decoder) (_ []{{ .Elem }}, changed bool) {
|
||||||
dd := d.d
|
dd := d.d
|
||||||
// if dd.isContainerType(valueTypeNil) { dd.TryDecodeAsNil()
|
{{/* // if dd.isContainerType(valueTypeNil) { dd.TryDecodeAsNil() */}}
|
||||||
if checkNil && dd.TryDecodeAsNil() {
|
if checkNil && dd.TryDecodeAsNil() {
|
||||||
if v != nil {
|
if v != nil {
|
||||||
changed = true
|
changed = true
|
||||||
|
@ -284,12 +258,14 @@ func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v []{{ .Elem }}, checkNil b
|
||||||
}
|
}
|
||||||
|
|
||||||
slh, containerLenS := d.decSliceHelperStart()
|
slh, containerLenS := d.decSliceHelperStart()
|
||||||
|
x2read := containerLenS
|
||||||
|
var xtrunc bool
|
||||||
if canChange && v == nil {
|
if canChange && v == nil {
|
||||||
if containerLenS <= 0 {
|
var xlen int
|
||||||
v = []{{ .Elem }}{}
|
if xlen, xtrunc = decInferLen(containerLenS, d.h.MaxInitLen, {{ .Size }}); xtrunc {
|
||||||
} else {
|
x2read = xlen
|
||||||
v = make([]{{ .Elem }}, containerLenS, containerLenS)
|
|
||||||
}
|
}
|
||||||
|
v = make([]{{ .Elem }}, xlen)
|
||||||
changed = true
|
changed = true
|
||||||
}
|
}
|
||||||
if containerLenS == 0 {
|
if containerLenS == 0 {
|
||||||
|
@ -302,29 +278,39 @@ func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v []{{ .Elem }}, checkNil b
|
||||||
return v, changed
|
return v, changed
|
||||||
}
|
}
|
||||||
|
|
||||||
// for j := 0; j < containerLenS; j++ {
|
{{/* // for j := 0; j < containerLenS; j++ { */}}
|
||||||
if containerLenS > 0 {
|
if containerLenS > 0 {
|
||||||
decLen := containerLenS
|
|
||||||
if containerLenS > cap(v) {
|
if containerLenS > cap(v) {
|
||||||
if canChange {
|
if canChange { {{/*
|
||||||
s := make([]{{ .Elem }}, containerLenS, containerLenS)
|
// fast-path is for "basic" immutable types, so no need to copy them over
|
||||||
|
// s := make([]{{ .Elem }}, decInferLen(containerLenS, d.h.MaxInitLen))
|
||||||
// copy(s, v[:cap(v)])
|
// copy(s, v[:cap(v)])
|
||||||
v = s
|
// v = s */}}
|
||||||
|
var xlen int
|
||||||
|
if xlen, xtrunc = decInferLen(containerLenS, d.h.MaxInitLen, {{ .Size }}); xtrunc {
|
||||||
|
x2read = xlen
|
||||||
|
}
|
||||||
|
v = make([]{{ .Elem }}, xlen)
|
||||||
changed = true
|
changed = true
|
||||||
} else {
|
} else {
|
||||||
d.arrayCannotExpand(len(v), containerLenS)
|
d.arrayCannotExpand(len(v), containerLenS)
|
||||||
decLen = len(v)
|
x2read = len(v)
|
||||||
}
|
}
|
||||||
} else if containerLenS != len(v) {
|
} else if containerLenS != len(v) {
|
||||||
v = v[:containerLenS]
|
v = v[:containerLenS]
|
||||||
changed = true
|
changed = true
|
||||||
}
|
}
|
||||||
// all checks done. cannot go past len.
|
{{/* // all checks done. cannot go past len. */}}
|
||||||
j := 0
|
j := 0
|
||||||
for ; j < decLen; j++ {
|
for ; j < x2read; j++ {
|
||||||
{{ if eq .Elem "interface{}" }}d.decode(&v[j]){{ else }}v[j] = {{ decmd .Elem }}{{ end }}
|
{{ if eq .Elem "interface{}" }}d.decode(&v[j]){{ else }}v[j] = {{ decmd .Elem }}{{ end }}
|
||||||
}
|
}
|
||||||
if !canChange {
|
if xtrunc { {{/* // means canChange=true, changed=true already. */}}
|
||||||
|
for ; j < containerLenS; j++ {
|
||||||
|
v = append(v, {{ zerocmd .Elem }})
|
||||||
|
{{ if eq .Elem "interface{}" }}d.decode(&v[j]){{ else }}v[j] = {{ decmd .Elem }}{{ end }}
|
||||||
|
}
|
||||||
|
} else if !canChange {
|
||||||
for ; j < containerLenS; j++ {
|
for ; j < containerLenS; j++ {
|
||||||
d.swallow()
|
d.swallow()
|
||||||
}
|
}
|
||||||
|
@ -340,10 +326,7 @@ func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v []{{ .Elem }}, checkNil b
|
||||||
d.arrayCannotExpand(len(v), j+1)
|
d.arrayCannotExpand(len(v), j+1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if j > 0 {
|
if j < len(v) { {{/* // all checks done. cannot go past len. */}}
|
||||||
slh.Sep(j)
|
|
||||||
}
|
|
||||||
if j < len(v) { // all checks done. cannot go past len.
|
|
||||||
{{ if eq .Elem "interface{}" }}d.decode(&v[j])
|
{{ if eq .Elem "interface{}" }}d.decode(&v[j])
|
||||||
{{ else }}v[j] = {{ decmd .Elem }}{{ end }}
|
{{ else }}v[j] = {{ decmd .Elem }}{{ end }}
|
||||||
} else {
|
} else {
|
||||||
|
@ -358,13 +341,13 @@ func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v []{{ .Elem }}, checkNil b
|
||||||
{{end}}{{end}}{{end}}
|
{{end}}{{end}}{{end}}
|
||||||
|
|
||||||
|
|
||||||
{{range .Values}}{{if not .Primitive}}{{if not .Slice }}
|
{{range .Values}}{{if not .Primitive}}{{if .MapKey }}
|
||||||
{{/*
|
{{/*
|
||||||
Maps can change if they are
|
Maps can change if they are
|
||||||
- addressable (from a ptr)
|
- addressable (from a ptr)
|
||||||
- settable (e.g. contained in an interface{})
|
- settable (e.g. contained in an interface{})
|
||||||
*/}}
|
*/}}
|
||||||
func (f decFnInfo) {{ .MethodNamePfx "fastpathDec" false }}R(rv reflect.Value) {
|
func (f *decFnInfo) {{ .MethodNamePfx "fastpathDec" false }}R(rv reflect.Value) {
|
||||||
if rv.CanAddr() {
|
if rv.CanAddr() {
|
||||||
vp := rv.Addr().Interface().(*map[{{ .MapKey }}]{{ .Elem }})
|
vp := rv.Addr().Interface().(*map[{{ .MapKey }}]{{ .Elem }})
|
||||||
v, changed := fastpathTV.{{ .MethodNamePfx "Dec" false }}V(*vp, fastpathCheckNilFalse, true, f.d)
|
v, changed := fastpathTV.{{ .MethodNamePfx "Dec" false }}V(*vp, fastpathCheckNilFalse, true, f.d)
|
||||||
|
@ -385,7 +368,7 @@ func (f fastpathT) {{ .MethodNamePfx "Dec" false }}X(vp *map[{{ .MapKey }}]{{ .E
|
||||||
func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v map[{{ .MapKey }}]{{ .Elem }}, checkNil bool, canChange bool,
|
func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v map[{{ .MapKey }}]{{ .Elem }}, checkNil bool, canChange bool,
|
||||||
d *Decoder) (_ map[{{ .MapKey }}]{{ .Elem }}, changed bool) {
|
d *Decoder) (_ map[{{ .MapKey }}]{{ .Elem }}, changed bool) {
|
||||||
dd := d.d
|
dd := d.d
|
||||||
// if dd.isContainerType(valueTypeNil) {dd.TryDecodeAsNil()
|
{{/* // if dd.isContainerType(valueTypeNil) {dd.TryDecodeAsNil() */}}
|
||||||
if checkNil && dd.TryDecodeAsNil() {
|
if checkNil && dd.TryDecodeAsNil() {
|
||||||
if v != nil {
|
if v != nil {
|
||||||
changed = true
|
changed = true
|
||||||
|
@ -395,11 +378,8 @@ func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v map[{{ .MapKey }}]{{ .Ele
|
||||||
|
|
||||||
containerLen := dd.ReadMapStart()
|
containerLen := dd.ReadMapStart()
|
||||||
if canChange && v == nil {
|
if canChange && v == nil {
|
||||||
if containerLen > 0 {
|
xlen, _ := decInferLen(containerLen, d.h.MaxInitLen, {{ .Size }})
|
||||||
v = make(map[{{ .MapKey }}]{{ .Elem }}, containerLen)
|
v = make(map[{{ .MapKey }}]{{ .Elem }}, xlen)
|
||||||
} else {
|
|
||||||
v = make(map[{{ .MapKey }}]{{ .Elem }}) // supports indefinite-length, etc
|
|
||||||
}
|
|
||||||
changed = true
|
changed = true
|
||||||
}
|
}
|
||||||
if containerLen > 0 {
|
if containerLen > 0 {
|
||||||
|
@ -407,7 +387,7 @@ func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v map[{{ .MapKey }}]{{ .Ele
|
||||||
{{ if eq .MapKey "interface{}" }}var mk interface{}
|
{{ if eq .MapKey "interface{}" }}var mk interface{}
|
||||||
d.decode(&mk)
|
d.decode(&mk)
|
||||||
if bv, bok := mk.([]byte); bok {
|
if bv, bok := mk.([]byte); bok {
|
||||||
mk = string(bv) // maps cannot have []byte as key. switch to string.
|
mk = string(bv) {{/* // maps cannot have []byte as key. switch to string. */}}
|
||||||
}{{ else }}mk := {{ decmd .MapKey }}{{ end }}
|
}{{ else }}mk := {{ decmd .MapKey }}{{ end }}
|
||||||
mv := v[mk]
|
mv := v[mk]
|
||||||
{{ if eq .Elem "interface{}" }}d.decode(&mv)
|
{{ if eq .Elem "interface{}" }}d.decode(&mv)
|
||||||
|
@ -418,15 +398,11 @@ func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v map[{{ .MapKey }}]{{ .Ele
|
||||||
}
|
}
|
||||||
} else if containerLen < 0 {
|
} else if containerLen < 0 {
|
||||||
for j := 0; !dd.CheckBreak(); j++ {
|
for j := 0; !dd.CheckBreak(); j++ {
|
||||||
if j > 0 {
|
|
||||||
dd.ReadMapEntrySeparator()
|
|
||||||
}
|
|
||||||
{{ if eq .MapKey "interface{}" }}var mk interface{}
|
{{ if eq .MapKey "interface{}" }}var mk interface{}
|
||||||
d.decode(&mk)
|
d.decode(&mk)
|
||||||
if bv, bok := mk.([]byte); bok {
|
if bv, bok := mk.([]byte); bok {
|
||||||
mk = string(bv) // maps cannot have []byte as key. switch to string.
|
mk = string(bv) {{/* // maps cannot have []byte as key. switch to string. */}}
|
||||||
}{{ else }}mk := {{ decmd .MapKey }}{{ end }}
|
}{{ else }}mk := {{ decmd .MapKey }}{{ end }}
|
||||||
dd.ReadMapKVSeparator()
|
|
||||||
mv := v[mk]
|
mv := v[mk]
|
||||||
{{ if eq .Elem "interface{}" }}d.decode(&mv)
|
{{ if eq .Elem "interface{}" }}d.decode(&mv)
|
||||||
{{ else }}mv = {{ decmd .Elem }}{{ end }}
|
{{ else }}mv = {{ decmd .Elem }}{{ end }}
|
||||||
|
@ -434,7 +410,7 @@ func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v map[{{ .MapKey }}]{{ .Ele
|
||||||
v[mk] = mv
|
v[mk] = mv
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dd.ReadMapEnd()
|
dd.ReadEnd()
|
||||||
}
|
}
|
||||||
return v, changed
|
return v, changed
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,17 @@
|
||||||
{{var "v"}} := *{{ .Varname }}
|
{{var "v"}} := {{ if not isArray}}*{{ end }}{{ .Varname }}
|
||||||
{{var "h"}}, {{var "l"}} := z.DecSliceHelperStart()
|
{{var "h"}}, {{var "l"}} := z.DecSliceHelperStart() {{/* // helper, containerLenS */}}
|
||||||
|
|
||||||
|
var {{var "rr"}}, {{var "rl"}} int {{/* // num2read, length of slice/array/chan */}}
|
||||||
|
var {{var "c"}}, {{var "rt"}} bool {{/* // changed, truncated */}}
|
||||||
|
_, _, _ = {{var "c"}}, {{var "rt"}}, {{var "rl"}}
|
||||||
|
{{var "rr"}} = {{var "l"}}
|
||||||
|
{{/* rl is NOT used. Only used for getting DecInferLen. len(r) used directly in code */}}
|
||||||
|
|
||||||
var {{var "c"}} bool
|
|
||||||
{{ if not isArray }}if {{var "v"}} == nil {
|
{{ if not isArray }}if {{var "v"}} == nil {
|
||||||
if {{var "l"}} <= 0 {
|
if {{var "rl"}}, {{var "rt"}} = z.DecInferLen({{var "l"}}, z.DecBasicHandle().MaxInitLen, {{ .Size }}); {{var "rt"}} {
|
||||||
{{var "v"}} = make({{ .CTyp }}, 0)
|
{{var "rr"}} = {{var "rl"}}
|
||||||
} else {
|
|
||||||
{{var "v"}} = make({{ .CTyp }}, {{var "l"}})
|
|
||||||
}
|
}
|
||||||
|
{{var "v"}} = make({{ .CTyp }}, {{var "rl"}})
|
||||||
{{var "c"}} = true
|
{{var "c"}} = true
|
||||||
}
|
}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
@ -23,41 +27,45 @@ if {{var "l"}} == 0 { {{ if isSlice }}
|
||||||
{{ $x := printf "%st%s" .TempVar .Rand }}{{ decLineVar $x }}
|
{{ $x := printf "%st%s" .TempVar .Rand }}{{ decLineVar $x }}
|
||||||
{{var "v"}} <- {{var "t"}}
|
{{var "v"}} <- {{var "t"}}
|
||||||
{{ else }}
|
{{ else }}
|
||||||
{{var "n"}} := {{var "l"}}
|
|
||||||
if {{var "l"}} > cap({{var "v"}}) {
|
if {{var "l"}} > cap({{var "v"}}) {
|
||||||
{{ if isArray }}r.ReadArrayCannotExpand(len({{var "v"}}), {{var "l"}})
|
{{ if isArray }}z.DecArrayCannotExpand(len({{var "v"}}), {{var "l"}})
|
||||||
{{var "n"}} = len({{var "v"}})
|
{{ else }}{{var "rl"}}, {{var "rt"}} = z.DecInferLen({{var "l"}}, z.DecBasicHandle().MaxInitLen, {{ .Size }})
|
||||||
{{ else }}{{ if .Immutable }}
|
{{ if .Immutable }}
|
||||||
{{var "v2"}} := {{var "v"}}
|
{{var "v2"}} := {{var "v"}}
|
||||||
{{var "v"}} = make([]{{ .Typ }}, {{var "l"}}, {{var "l"}})
|
{{var "v"}} = make([]{{ .Typ }}, {{var "rl"}})
|
||||||
if len({{var "v"}}) > 0 {
|
if len({{var "v"}}) > 0 {
|
||||||
copy({{var "v"}}, {{var "v2"}}[:cap({{var "v2"}})])
|
copy({{var "v"}}, {{var "v2"}}[:cap({{var "v2"}})])
|
||||||
}
|
}
|
||||||
{{ else }}{{var "v"}} = make([]{{ .Typ }}, {{var "l"}}, {{var "l"}})
|
{{ else }}{{var "v"}} = make([]{{ .Typ }}, {{var "rl"}})
|
||||||
{{ end }}{{var "c"}} = true
|
{{ end }}{{var "c"}} = true
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
{{var "rr"}} = len({{var "v"}})
|
||||||
} else if {{var "l"}} != len({{var "v"}}) {
|
} else if {{var "l"}} != len({{var "v"}}) {
|
||||||
{{var "v"}} = {{var "v"}}[:{{var "l"}}]
|
{{ if isSlice }}{{var "v"}} = {{var "v"}}[:{{var "l"}}]
|
||||||
{{var "c"}} = true
|
{{var "c"}} = true {{ end }}
|
||||||
}
|
}
|
||||||
{{var "j"}} := 0
|
{{var "j"}} := 0
|
||||||
for ; {{var "j"}} < {{var "n"}} ; {{var "j"}}++ {
|
for ; {{var "j"}} < {{var "rr"}} ; {{var "j"}}++ {
|
||||||
{{ $x := printf "%[1]vv%[2]v[%[1]vj%[2]v]" .TempVar .Rand }}{{ decLineVar $x }}
|
{{ $x := printf "%[1]vv%[2]v[%[1]vj%[2]v]" .TempVar .Rand }}{{ decLineVar $x }}
|
||||||
} {{ if isArray }}
|
}
|
||||||
for ; {{var "j"}} < {{var "l"}} ; {{var "j"}}++ {
|
{{ if isArray }}for ; {{var "j"}} < {{var "l"}} ; {{var "j"}}++ {
|
||||||
z.DecSwallow()
|
z.DecSwallow()
|
||||||
}{{ end }}
|
}
|
||||||
{{ end }}{{/* closing if not chan */}}
|
{{ else }}if {{var "rt"}} { {{/* means that it is mutable and slice */}}
|
||||||
|
for ; {{var "j"}} < {{var "l"}} ; {{var "j"}}++ {
|
||||||
|
{{var "v"}} = append({{var "v"}}, {{ zero}})
|
||||||
|
{{ $x := printf "%[1]vv%[2]v[%[1]vj%[2]v]" .TempVar .Rand }}{{ decLineVar $x }}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{{ end }}
|
||||||
|
{{ end }}{{/* closing 'if not chan' */}}
|
||||||
} else {
|
} else {
|
||||||
for {{var "j"}} := 0; !r.CheckBreak(); {{var "j"}}++ {
|
for {{var "j"}} := 0; !r.CheckBreak(); {{var "j"}}++ {
|
||||||
if {{var "j"}} >= len({{var "v"}}) {
|
if {{var "j"}} >= len({{var "v"}}) {
|
||||||
{{ if isArray }}r.ReadArrayCannotExpand(len({{var "v"}}), {{var "j"}}+1)
|
{{ if isArray }}z.DecArrayCannotExpand(len({{var "v"}}), {{var "j"}}+1)
|
||||||
{{ else if isSlice}}{{var "v"}} = append({{var "v"}}, {{zero}})// var {{var "z"}} {{ .Typ }}
|
{{ else if isSlice}}{{var "v"}} = append({{var "v"}}, {{zero}})// var {{var "z"}} {{ .Typ }}
|
||||||
{{var "c"}} = true {{ end }}
|
{{var "c"}} = true {{ end }}
|
||||||
}
|
}
|
||||||
if {{var "j"}} > 0 {
|
|
||||||
{{var "h"}}.Sep({{var "j"}})
|
|
||||||
}
|
|
||||||
{{ if isChan}}
|
{{ if isChan}}
|
||||||
var {{var "t"}} {{ .Typ }}
|
var {{var "t"}} {{ .Typ }}
|
||||||
{{ $x := printf "%st%s" .TempVar .Rand }}{{ decLineVar $x }}
|
{{ $x := printf "%st%s" .TempVar .Rand }}{{ decLineVar $x }}
|
||||||
|
@ -72,6 +80,7 @@ if {{var "l"}} == 0 { {{ if isSlice }}
|
||||||
}
|
}
|
||||||
{{var "h"}}.End()
|
{{var "h"}}.End()
|
||||||
}
|
}
|
||||||
if {{var "c"}} {
|
{{ if not isArray }}if {{var "c"}} {
|
||||||
*{{ .Varname }} = {{var "v"}}
|
*{{ .Varname }} = {{var "v"}}
|
||||||
}
|
}{{ end }}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
{{var "v"}} := *{{ .Varname }}
|
{{var "v"}} := *{{ .Varname }}
|
||||||
{{var "l"}} := r.ReadMapStart()
|
{{var "l"}} := r.ReadMapStart()
|
||||||
if {{var "v"}} == nil {
|
if {{var "v"}} == nil {
|
||||||
if {{var "l"}} > 0 {
|
{{var "rl"}}, _ := z.DecInferLen({{var "l"}}, z.DecBasicHandle().MaxInitLen, {{ .Size }})
|
||||||
{{var "v"}} = make(map[{{ .KTyp }}]{{ .Typ }}, {{var "l"}})
|
{{var "v"}} = make(map[{{ .KTyp }}]{{ .Typ }}, {{var "rl"}})
|
||||||
} else {
|
|
||||||
{{var "v"}} = make(map[{{ .KTyp }}]{{ .Typ }}) // supports indefinite-length, etc
|
|
||||||
}
|
|
||||||
*{{ .Varname }} = {{var "v"}}
|
*{{ .Varname }} = {{var "v"}}
|
||||||
}
|
}
|
||||||
if {{var "l"}} > 0 {
|
if {{var "l"}} > 0 {
|
||||||
|
@ -25,9 +22,6 @@ for {{var "j"}} := 0; {{var "j"}} < {{var "l"}}; {{var "j"}}++ {
|
||||||
}
|
}
|
||||||
} else if {{var "l"}} < 0 {
|
} else if {{var "l"}} < 0 {
|
||||||
for {{var "j"}} := 0; !r.CheckBreak(); {{var "j"}}++ {
|
for {{var "j"}} := 0; !r.CheckBreak(); {{var "j"}}++ {
|
||||||
if {{var "j"}} > 0 {
|
|
||||||
r.ReadMapEntrySeparator()
|
|
||||||
}
|
|
||||||
var {{var "mk"}} {{ .KTyp }}
|
var {{var "mk"}} {{ .KTyp }}
|
||||||
{{ $x := printf "%vmk%v" .TempVar .Rand }}{{ decLineVarK $x }}
|
{{ $x := printf "%vmk%v" .TempVar .Rand }}{{ decLineVarK $x }}
|
||||||
{{ if eq .KTyp "interface{}" }}// special case if a byte array.
|
{{ if eq .KTyp "interface{}" }}// special case if a byte array.
|
||||||
|
@ -35,12 +29,11 @@ for {{var "j"}} := 0; !r.CheckBreak(); {{var "j"}}++ {
|
||||||
{{var "mk"}} = string({{var "bv"}})
|
{{var "mk"}} = string({{var "bv"}})
|
||||||
}
|
}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
r.ReadMapKVSeparator()
|
|
||||||
{{var "mv"}} := {{var "v"}}[{{var "mk"}}]
|
{{var "mv"}} := {{var "v"}}[{{var "mk"}}]
|
||||||
{{ $x := printf "%vmv%v" .TempVar .Rand }}{{ decLineVar $x }}
|
{{ $x := printf "%vmv%v" .TempVar .Rand }}{{ decLineVar $x }}
|
||||||
if {{var "v"}} != nil {
|
if {{var "v"}} != nil {
|
||||||
{{var "v"}}[{{var "mk"}}] = {{var "mv"}}
|
{{var "v"}}[{{var "mk"}}] = {{var "mv"}}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
r.ReadMapEnd()
|
r.ReadEnd()
|
||||||
} // else len==0: TODO: Should we clear map entries?
|
} // else len==0: TODO: Should we clear map entries?
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// //+build ignore
|
// //+build ignore
|
||||||
|
|
||||||
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style license found in the LICENSE file.
|
// Use of this source code is governed by a MIT license found in the LICENSE file.
|
||||||
|
|
||||||
// ************************************************************
|
// ************************************************************
|
||||||
// DO NOT EDIT.
|
// DO NOT EDIT.
|
||||||
|
@ -10,6 +10,11 @@
|
||||||
|
|
||||||
package codec
|
package codec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
// This file is used to generate helper code for codecgen.
|
// This file is used to generate helper code for codecgen.
|
||||||
// The values here i.e. genHelper(En|De)coder are not to be used directly by
|
// The values here i.e. genHelper(En|De)coder are not to be used directly by
|
||||||
// library users. They WILL change continously and without notice.
|
// library users. They WILL change continously and without notice.
|
||||||
|
@ -60,6 +65,56 @@ func (f genHelperEncoder) EncFallback(iv interface{}) {
|
||||||
f.e.encodeI(iv, false, false)
|
f.e.encodeI(iv, false, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
|
||||||
|
func (f genHelperEncoder) EncTextMarshal(iv encoding.TextMarshaler) {
|
||||||
|
bs, fnerr := iv.MarshalText()
|
||||||
|
f.e.marshal(bs, fnerr, false, c_UTF8)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
|
||||||
|
func (f genHelperEncoder) EncJSONMarshal(iv jsonMarshaler) {
|
||||||
|
bs, fnerr := iv.MarshalJSON()
|
||||||
|
f.e.marshal(bs, fnerr, true, c_UTF8)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
|
||||||
|
func (f genHelperEncoder) EncBinaryMarshal(iv encoding.BinaryMarshaler) {
|
||||||
|
bs, fnerr := iv.MarshalBinary()
|
||||||
|
f.e.marshal(bs, fnerr, false, c_RAW)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
|
||||||
|
func (f genHelperEncoder) TimeRtidIfBinc() uintptr {
|
||||||
|
if _, ok := f.e.hh.(*BincHandle); ok {
|
||||||
|
return timeTypId
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
|
||||||
|
func (f genHelperEncoder) IsJSONHandle() bool {
|
||||||
|
return f.e.js
|
||||||
|
}
|
||||||
|
|
||||||
|
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
|
||||||
|
func (f genHelperEncoder) HasExtensions() bool {
|
||||||
|
return len(f.e.h.extHandle) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
|
||||||
|
func (f genHelperEncoder) EncExt(v interface{}) (r bool) {
|
||||||
|
rt := reflect.TypeOf(v)
|
||||||
|
if rt.Kind() == reflect.Ptr {
|
||||||
|
rt = rt.Elem()
|
||||||
|
}
|
||||||
|
rtid := reflect.ValueOf(rt).Pointer()
|
||||||
|
if xfFn := f.e.h.getExt(rtid); xfFn != nil {
|
||||||
|
f.e.e.EncodeExt(v, xfFn.tag, xfFn.ext, f.e)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
|
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
|
||||||
func (f genHelperDecoder) DecBasicHandle() *BasicHandle {
|
func (f genHelperDecoder) DecBasicHandle() *BasicHandle {
|
||||||
return f.d.h
|
return f.d.h
|
||||||
|
@ -100,3 +155,66 @@ func (f genHelperDecoder) DecStructFieldNotFound(index int, name string) {
|
||||||
func (f genHelperDecoder) DecArrayCannotExpand(sliceLen, streamLen int) {
|
func (f genHelperDecoder) DecArrayCannotExpand(sliceLen, streamLen int) {
|
||||||
f.d.arrayCannotExpand(sliceLen, streamLen)
|
f.d.arrayCannotExpand(sliceLen, streamLen)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
|
||||||
|
func (f genHelperDecoder) DecTextUnmarshal(tm encoding.TextUnmarshaler) {
|
||||||
|
fnerr := tm.UnmarshalText(f.d.d.DecodeBytes(f.d.b[:], true, true))
|
||||||
|
if fnerr != nil {
|
||||||
|
panic(fnerr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
|
||||||
|
func (f genHelperDecoder) DecJSONUnmarshal(tm jsonUnmarshaler) {
|
||||||
|
// bs := f.dd.DecodeBytes(f.d.b[:], true, true)
|
||||||
|
f.d.r.track()
|
||||||
|
f.d.swallow()
|
||||||
|
bs := f.d.r.stopTrack()
|
||||||
|
// fmt.Printf(">>>>>> CODECGEN JSON: %s\n", bs)
|
||||||
|
fnerr := tm.UnmarshalJSON(bs)
|
||||||
|
if fnerr != nil {
|
||||||
|
panic(fnerr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
|
||||||
|
func (f genHelperDecoder) DecBinaryUnmarshal(bm encoding.BinaryUnmarshaler) {
|
||||||
|
fnerr := bm.UnmarshalBinary(f.d.d.DecodeBytes(nil, false, true))
|
||||||
|
if fnerr != nil {
|
||||||
|
panic(fnerr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
|
||||||
|
func (f genHelperDecoder) TimeRtidIfBinc() uintptr {
|
||||||
|
if _, ok := f.d.hh.(*BincHandle); ok {
|
||||||
|
return timeTypId
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
|
||||||
|
func (f genHelperDecoder) IsJSONHandle() bool {
|
||||||
|
return f.d.js
|
||||||
|
}
|
||||||
|
|
||||||
|
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
|
||||||
|
func (f genHelperDecoder) HasExtensions() bool {
|
||||||
|
return len(f.d.h.extHandle) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
|
||||||
|
func (f genHelperDecoder) DecExt(v interface{}) (r bool) {
|
||||||
|
rt := reflect.TypeOf(v).Elem()
|
||||||
|
rtid := reflect.ValueOf(rt).Pointer()
|
||||||
|
if xfFn := f.d.h.getExt(rtid); xfFn != nil {
|
||||||
|
f.d.d.DecodeExt(v, xfFn.tag, xfFn.ext)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
|
||||||
|
func (f genHelperDecoder) DecInferLen(clen, maxlen, unit int) (rvlen int, truncated bool) {
|
||||||
|
return decInferLen(clen, maxlen, unit)
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// //+build ignore
|
// //+build ignore
|
||||||
|
|
||||||
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style license found in the LICENSE file.
|
// Use of this source code is governed by a MIT license found in the LICENSE file.
|
||||||
|
|
||||||
// ************************************************************
|
// ************************************************************
|
||||||
// DO NOT EDIT.
|
// DO NOT EDIT.
|
||||||
|
@ -10,6 +10,11 @@
|
||||||
|
|
||||||
package codec
|
package codec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
// This file is used to generate helper code for codecgen.
|
// This file is used to generate helper code for codecgen.
|
||||||
// The values here i.e. genHelper(En|De)coder are not to be used directly by
|
// The values here i.e. genHelper(En|De)coder are not to be used directly by
|
||||||
// library users. They WILL change continously and without notice.
|
// library users. They WILL change continously and without notice.
|
||||||
|
@ -48,6 +53,7 @@ type genHelperDecoder struct {
|
||||||
func (f genHelperEncoder) EncBasicHandle() *BasicHandle {
|
func (f genHelperEncoder) EncBasicHandle() *BasicHandle {
|
||||||
return f.e.h
|
return f.e.h
|
||||||
}
|
}
|
||||||
|
|
||||||
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
|
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
|
||||||
func (f genHelperEncoder) EncBinary() bool {
|
func (f genHelperEncoder) EncBinary() bool {
|
||||||
return f.e.be // f.e.hh.isBinaryEncoding()
|
return f.e.be // f.e.hh.isBinaryEncoding()
|
||||||
|
@ -57,6 +63,49 @@ func (f genHelperEncoder) EncFallback(iv interface{}) {
|
||||||
// println(">>>>>>>>> EncFallback")
|
// println(">>>>>>>>> EncFallback")
|
||||||
f.e.encodeI(iv, false, false)
|
f.e.encodeI(iv, false, false)
|
||||||
}
|
}
|
||||||
|
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
|
||||||
|
func (f genHelperEncoder) EncTextMarshal(iv encoding.TextMarshaler) {
|
||||||
|
bs, fnerr := iv.MarshalText()
|
||||||
|
f.e.marshal(bs, fnerr, false, c_UTF8)
|
||||||
|
}
|
||||||
|
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
|
||||||
|
func (f genHelperEncoder) EncJSONMarshal(iv jsonMarshaler) {
|
||||||
|
bs, fnerr := iv.MarshalJSON()
|
||||||
|
f.e.marshal(bs, fnerr, true, c_UTF8)
|
||||||
|
}
|
||||||
|
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
|
||||||
|
func (f genHelperEncoder) EncBinaryMarshal(iv encoding.BinaryMarshaler) {
|
||||||
|
bs, fnerr := iv.MarshalBinary()
|
||||||
|
f.e.marshal(bs, fnerr, false, c_RAW)
|
||||||
|
}
|
||||||
|
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
|
||||||
|
func (f genHelperEncoder) TimeRtidIfBinc() uintptr {
|
||||||
|
if _, ok := f.e.hh.(*BincHandle); ok {
|
||||||
|
return timeTypId
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
|
||||||
|
func (f genHelperEncoder) IsJSONHandle() bool {
|
||||||
|
return f.e.js
|
||||||
|
}
|
||||||
|
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
|
||||||
|
func (f genHelperEncoder) HasExtensions() bool {
|
||||||
|
return len(f.e.h.extHandle) != 0
|
||||||
|
}
|
||||||
|
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
|
||||||
|
func (f genHelperEncoder) EncExt(v interface{}) (r bool) {
|
||||||
|
rt := reflect.TypeOf(v)
|
||||||
|
if rt.Kind() == reflect.Ptr {
|
||||||
|
rt = rt.Elem()
|
||||||
|
}
|
||||||
|
rtid := reflect.ValueOf(rt).Pointer()
|
||||||
|
if xfFn := f.e.h.getExt(rtid); xfFn != nil {
|
||||||
|
f.e.e.EncodeExt(v, xfFn.tag, xfFn.ext, f.e)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
|
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
|
||||||
func (f genHelperDecoder) DecBasicHandle() *BasicHandle {
|
func (f genHelperDecoder) DecBasicHandle() *BasicHandle {
|
||||||
|
@ -91,7 +140,61 @@ func (f genHelperDecoder) DecStructFieldNotFound(index int, name string) {
|
||||||
func (f genHelperDecoder) DecArrayCannotExpand(sliceLen, streamLen int) {
|
func (f genHelperDecoder) DecArrayCannotExpand(sliceLen, streamLen int) {
|
||||||
f.d.arrayCannotExpand(sliceLen, streamLen)
|
f.d.arrayCannotExpand(sliceLen, streamLen)
|
||||||
}
|
}
|
||||||
|
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
|
||||||
|
func (f genHelperDecoder) DecTextUnmarshal(tm encoding.TextUnmarshaler) {
|
||||||
|
fnerr := tm.UnmarshalText(f.d.d.DecodeBytes(f.d.b[:], true, true))
|
||||||
|
if fnerr != nil {
|
||||||
|
panic(fnerr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
|
||||||
|
func (f genHelperDecoder) DecJSONUnmarshal(tm jsonUnmarshaler) {
|
||||||
|
// bs := f.dd.DecodeBytes(f.d.b[:], true, true)
|
||||||
|
f.d.r.track()
|
||||||
|
f.d.swallow()
|
||||||
|
bs := f.d.r.stopTrack()
|
||||||
|
// fmt.Printf(">>>>>> CODECGEN JSON: %s\n", bs)
|
||||||
|
fnerr := tm.UnmarshalJSON(bs)
|
||||||
|
if fnerr != nil {
|
||||||
|
panic(fnerr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
|
||||||
|
func (f genHelperDecoder) DecBinaryUnmarshal(bm encoding.BinaryUnmarshaler) {
|
||||||
|
fnerr := bm.UnmarshalBinary(f.d.d.DecodeBytes(nil, false, true))
|
||||||
|
if fnerr != nil {
|
||||||
|
panic(fnerr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
|
||||||
|
func (f genHelperDecoder) TimeRtidIfBinc() uintptr {
|
||||||
|
if _, ok := f.d.hh.(*BincHandle); ok {
|
||||||
|
return timeTypId
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
|
||||||
|
func (f genHelperDecoder) IsJSONHandle() bool {
|
||||||
|
return f.d.js
|
||||||
|
}
|
||||||
|
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
|
||||||
|
func (f genHelperDecoder) HasExtensions() bool {
|
||||||
|
return len(f.d.h.extHandle) != 0
|
||||||
|
}
|
||||||
|
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
|
||||||
|
func (f genHelperDecoder) DecExt(v interface{}) (r bool) {
|
||||||
|
rt := reflect.TypeOf(v).Elem()
|
||||||
|
rtid := reflect.ValueOf(rt).Pointer()
|
||||||
|
if xfFn := f.d.h.getExt(rtid); xfFn != nil {
|
||||||
|
f.d.d.DecodeExt(v, xfFn.tag, xfFn.ext)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
|
||||||
|
func (f genHelperDecoder) DecInferLen(clen, maxlen, unit int) (rvlen int, truncated bool) {
|
||||||
|
return decInferLen(clen, maxlen, unit)
|
||||||
|
}
|
||||||
|
|
||||||
{{/*
|
{{/*
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style license found in the LICENSE file.
|
// Use of this source code is governed by a MIT license found in the LICENSE file.
|
||||||
|
|
||||||
package codec
|
package codec
|
||||||
|
|
||||||
|
@ -9,11 +9,8 @@ const genDecMapTmpl = `
|
||||||
{{var "v"}} := *{{ .Varname }}
|
{{var "v"}} := *{{ .Varname }}
|
||||||
{{var "l"}} := r.ReadMapStart()
|
{{var "l"}} := r.ReadMapStart()
|
||||||
if {{var "v"}} == nil {
|
if {{var "v"}} == nil {
|
||||||
if {{var "l"}} > 0 {
|
{{var "rl"}}, _ := z.DecInferLen({{var "l"}}, z.DecBasicHandle().MaxInitLen, {{ .Size }})
|
||||||
{{var "v"}} = make(map[{{ .KTyp }}]{{ .Typ }}, {{var "l"}})
|
{{var "v"}} = make(map[{{ .KTyp }}]{{ .Typ }}, {{var "rl"}})
|
||||||
} else {
|
|
||||||
{{var "v"}} = make(map[{{ .KTyp }}]{{ .Typ }}) // supports indefinite-length, etc
|
|
||||||
}
|
|
||||||
*{{ .Varname }} = {{var "v"}}
|
*{{ .Varname }} = {{var "v"}}
|
||||||
}
|
}
|
||||||
if {{var "l"}} > 0 {
|
if {{var "l"}} > 0 {
|
||||||
|
@ -33,9 +30,6 @@ for {{var "j"}} := 0; {{var "j"}} < {{var "l"}}; {{var "j"}}++ {
|
||||||
}
|
}
|
||||||
} else if {{var "l"}} < 0 {
|
} else if {{var "l"}} < 0 {
|
||||||
for {{var "j"}} := 0; !r.CheckBreak(); {{var "j"}}++ {
|
for {{var "j"}} := 0; !r.CheckBreak(); {{var "j"}}++ {
|
||||||
if {{var "j"}} > 0 {
|
|
||||||
r.ReadMapEntrySeparator()
|
|
||||||
}
|
|
||||||
var {{var "mk"}} {{ .KTyp }}
|
var {{var "mk"}} {{ .KTyp }}
|
||||||
{{ $x := printf "%vmk%v" .TempVar .Rand }}{{ decLineVarK $x }}
|
{{ $x := printf "%vmk%v" .TempVar .Rand }}{{ decLineVarK $x }}
|
||||||
{{ if eq .KTyp "interface{}" }}// special case if a byte array.
|
{{ if eq .KTyp "interface{}" }}// special case if a byte array.
|
||||||
|
@ -43,28 +37,31 @@ for {{var "j"}} := 0; !r.CheckBreak(); {{var "j"}}++ {
|
||||||
{{var "mk"}} = string({{var "bv"}})
|
{{var "mk"}} = string({{var "bv"}})
|
||||||
}
|
}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
r.ReadMapKVSeparator()
|
|
||||||
{{var "mv"}} := {{var "v"}}[{{var "mk"}}]
|
{{var "mv"}} := {{var "v"}}[{{var "mk"}}]
|
||||||
{{ $x := printf "%vmv%v" .TempVar .Rand }}{{ decLineVar $x }}
|
{{ $x := printf "%vmv%v" .TempVar .Rand }}{{ decLineVar $x }}
|
||||||
if {{var "v"}} != nil {
|
if {{var "v"}} != nil {
|
||||||
{{var "v"}}[{{var "mk"}}] = {{var "mv"}}
|
{{var "v"}}[{{var "mk"}}] = {{var "mv"}}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
r.ReadMapEnd()
|
r.ReadEnd()
|
||||||
} // else len==0: TODO: Should we clear map entries?
|
} // else len==0: TODO: Should we clear map entries?
|
||||||
`
|
`
|
||||||
|
|
||||||
const genDecListTmpl = `
|
const genDecListTmpl = `
|
||||||
{{var "v"}} := *{{ .Varname }}
|
{{var "v"}} := {{ if not isArray}}*{{ end }}{{ .Varname }}
|
||||||
{{var "h"}}, {{var "l"}} := z.DecSliceHelperStart()
|
{{var "h"}}, {{var "l"}} := z.DecSliceHelperStart() {{/* // helper, containerLenS */}}
|
||||||
|
|
||||||
|
var {{var "rr"}}, {{var "rl"}} int {{/* // num2read, length of slice/array/chan */}}
|
||||||
|
var {{var "c"}}, {{var "rt"}} bool {{/* // changed, truncated */}}
|
||||||
|
_, _, _ = {{var "c"}}, {{var "rt"}}, {{var "rl"}}
|
||||||
|
{{var "rr"}} = {{var "l"}}
|
||||||
|
{{/* rl is NOT used. Only used for getting DecInferLen. len(r) used directly in code */}}
|
||||||
|
|
||||||
var {{var "c"}} bool
|
|
||||||
{{ if not isArray }}if {{var "v"}} == nil {
|
{{ if not isArray }}if {{var "v"}} == nil {
|
||||||
if {{var "l"}} <= 0 {
|
if {{var "rl"}}, {{var "rt"}} = z.DecInferLen({{var "l"}}, z.DecBasicHandle().MaxInitLen, {{ .Size }}); {{var "rt"}} {
|
||||||
{{var "v"}} = make({{ .CTyp }}, 0)
|
{{var "rr"}} = {{var "rl"}}
|
||||||
} else {
|
|
||||||
{{var "v"}} = make({{ .CTyp }}, {{var "l"}})
|
|
||||||
}
|
}
|
||||||
|
{{var "v"}} = make({{ .CTyp }}, {{var "rl"}})
|
||||||
{{var "c"}} = true
|
{{var "c"}} = true
|
||||||
}
|
}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
@ -80,41 +77,45 @@ if {{var "l"}} == 0 { {{ if isSlice }}
|
||||||
{{ $x := printf "%st%s" .TempVar .Rand }}{{ decLineVar $x }}
|
{{ $x := printf "%st%s" .TempVar .Rand }}{{ decLineVar $x }}
|
||||||
{{var "v"}} <- {{var "t"}}
|
{{var "v"}} <- {{var "t"}}
|
||||||
{{ else }}
|
{{ else }}
|
||||||
{{var "n"}} := {{var "l"}}
|
|
||||||
if {{var "l"}} > cap({{var "v"}}) {
|
if {{var "l"}} > cap({{var "v"}}) {
|
||||||
{{ if isArray }}r.ReadArrayCannotExpand(len({{var "v"}}), {{var "l"}})
|
{{ if isArray }}z.DecArrayCannotExpand(len({{var "v"}}), {{var "l"}})
|
||||||
{{var "n"}} = len({{var "v"}})
|
{{ else }}{{var "rl"}}, {{var "rt"}} = z.DecInferLen({{var "l"}}, z.DecBasicHandle().MaxInitLen, {{ .Size }})
|
||||||
{{ else }}{{ if .Immutable }}
|
{{ if .Immutable }}
|
||||||
{{var "v2"}} := {{var "v"}}
|
{{var "v2"}} := {{var "v"}}
|
||||||
{{var "v"}} = make([]{{ .Typ }}, {{var "l"}}, {{var "l"}})
|
{{var "v"}} = make([]{{ .Typ }}, {{var "rl"}})
|
||||||
if len({{var "v"}}) > 0 {
|
if len({{var "v"}}) > 0 {
|
||||||
copy({{var "v"}}, {{var "v2"}}[:cap({{var "v2"}})])
|
copy({{var "v"}}, {{var "v2"}}[:cap({{var "v2"}})])
|
||||||
}
|
}
|
||||||
{{ else }}{{var "v"}} = make([]{{ .Typ }}, {{var "l"}}, {{var "l"}})
|
{{ else }}{{var "v"}} = make([]{{ .Typ }}, {{var "rl"}})
|
||||||
{{ end }}{{var "c"}} = true
|
{{ end }}{{var "c"}} = true
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
{{var "rr"}} = len({{var "v"}})
|
||||||
} else if {{var "l"}} != len({{var "v"}}) {
|
} else if {{var "l"}} != len({{var "v"}}) {
|
||||||
{{var "v"}} = {{var "v"}}[:{{var "l"}}]
|
{{ if isSlice }}{{var "v"}} = {{var "v"}}[:{{var "l"}}]
|
||||||
{{var "c"}} = true
|
{{var "c"}} = true {{ end }}
|
||||||
}
|
}
|
||||||
{{var "j"}} := 0
|
{{var "j"}} := 0
|
||||||
for ; {{var "j"}} < {{var "n"}} ; {{var "j"}}++ {
|
for ; {{var "j"}} < {{var "rr"}} ; {{var "j"}}++ {
|
||||||
{{ $x := printf "%[1]vv%[2]v[%[1]vj%[2]v]" .TempVar .Rand }}{{ decLineVar $x }}
|
{{ $x := printf "%[1]vv%[2]v[%[1]vj%[2]v]" .TempVar .Rand }}{{ decLineVar $x }}
|
||||||
} {{ if isArray }}
|
}
|
||||||
for ; {{var "j"}} < {{var "l"}} ; {{var "j"}}++ {
|
{{ if isArray }}for ; {{var "j"}} < {{var "l"}} ; {{var "j"}}++ {
|
||||||
z.DecSwallow()
|
z.DecSwallow()
|
||||||
}{{ end }}
|
}
|
||||||
{{ end }}{{/* closing if not chan */}}
|
{{ else }}if {{var "rt"}} { {{/* means that it is mutable and slice */}}
|
||||||
|
for ; {{var "j"}} < {{var "l"}} ; {{var "j"}}++ {
|
||||||
|
{{var "v"}} = append({{var "v"}}, {{ zero}})
|
||||||
|
{{ $x := printf "%[1]vv%[2]v[%[1]vj%[2]v]" .TempVar .Rand }}{{ decLineVar $x }}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{{ end }}
|
||||||
|
{{ end }}{{/* closing 'if not chan' */}}
|
||||||
} else {
|
} else {
|
||||||
for {{var "j"}} := 0; !r.CheckBreak(); {{var "j"}}++ {
|
for {{var "j"}} := 0; !r.CheckBreak(); {{var "j"}}++ {
|
||||||
if {{var "j"}} >= len({{var "v"}}) {
|
if {{var "j"}} >= len({{var "v"}}) {
|
||||||
{{ if isArray }}r.ReadArrayCannotExpand(len({{var "v"}}), {{var "j"}}+1)
|
{{ if isArray }}z.DecArrayCannotExpand(len({{var "v"}}), {{var "j"}}+1)
|
||||||
{{ else if isSlice}}{{var "v"}} = append({{var "v"}}, {{zero}})// var {{var "z"}} {{ .Typ }}
|
{{ else if isSlice}}{{var "v"}} = append({{var "v"}}, {{zero}})// var {{var "z"}} {{ .Typ }}
|
||||||
{{var "c"}} = true {{ end }}
|
{{var "c"}} = true {{ end }}
|
||||||
}
|
}
|
||||||
if {{var "j"}} > 0 {
|
|
||||||
{{var "h"}}.Sep({{var "j"}})
|
|
||||||
}
|
|
||||||
{{ if isChan}}
|
{{ if isChan}}
|
||||||
var {{var "t"}} {{ .Typ }}
|
var {{var "t"}} {{ .Typ }}
|
||||||
{{ $x := printf "%st%s" .TempVar .Rand }}{{ decLineVar $x }}
|
{{ $x := printf "%st%s" .TempVar .Rand }}{{ decLineVar $x }}
|
||||||
|
@ -129,8 +130,9 @@ if {{var "l"}} == 0 { {{ if isSlice }}
|
||||||
}
|
}
|
||||||
{{var "h"}}.End()
|
{{var "h"}}.End()
|
||||||
}
|
}
|
||||||
if {{var "c"}} {
|
{{ if not isArray }}if {{var "c"}} {
|
||||||
*{{ .Varname }} = {{var "v"}}
|
*{{ .Varname }} = {{var "v"}}
|
||||||
}
|
}{{ end }}
|
||||||
|
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,5 +1,5 @@
|
||||||
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style license found in the LICENSE file.
|
// Use of this source code is governed by a MIT license found in the LICENSE file.
|
||||||
|
|
||||||
package codec
|
package codec
|
||||||
|
|
||||||
|
@ -117,6 +117,7 @@ import (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
scratchByteArrayLen = 32
|
scratchByteArrayLen = 32
|
||||||
|
initCollectionCap = 32 // 32 is defensive. 16 is preferred.
|
||||||
|
|
||||||
// Support encoding.(Binary|Text)(Unm|M)arshaler.
|
// Support encoding.(Binary|Text)(Unm|M)arshaler.
|
||||||
// This constant flag will enable or disable it.
|
// This constant flag will enable or disable it.
|
||||||
|
@ -147,6 +148,12 @@ const (
|
||||||
|
|
||||||
// if derefForIsEmptyValue, deref pointers and interfaces when checking isEmptyValue
|
// if derefForIsEmptyValue, deref pointers and interfaces when checking isEmptyValue
|
||||||
derefForIsEmptyValue = false
|
derefForIsEmptyValue = false
|
||||||
|
|
||||||
|
// if resetSliceElemToZeroValue, then on decoding a slice, reset the element to a zero value first.
|
||||||
|
// Only concern is that, if the slice already contained some garbage, we will decode into that garbage.
|
||||||
|
// The chances of this are slim, so leave this "optimization".
|
||||||
|
// TODO: should this be true, to ensure that we always decode into a "zero" "empty" value?
|
||||||
|
resetSliceElemToZeroValue bool = false
|
||||||
)
|
)
|
||||||
|
|
||||||
var oneByteArr = [1]byte{0}
|
var oneByteArr = [1]byte{0}
|
||||||
|
@ -186,6 +193,14 @@ const (
|
||||||
|
|
||||||
type seqType uint8
|
type seqType uint8
|
||||||
|
|
||||||
|
// mirror json.Marshaler and json.Unmarshaler here, so we don't import the encoding/json package
|
||||||
|
type jsonMarshaler interface {
|
||||||
|
MarshalJSON() ([]byte, error)
|
||||||
|
}
|
||||||
|
type jsonUnmarshaler interface {
|
||||||
|
UnmarshalJSON([]byte) error
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
_ seqType = iota
|
_ seqType = iota
|
||||||
seqTypeArray
|
seqTypeArray
|
||||||
|
@ -197,9 +212,6 @@ var (
|
||||||
bigen = binary.BigEndian
|
bigen = binary.BigEndian
|
||||||
structInfoFieldName = "_struct"
|
structInfoFieldName = "_struct"
|
||||||
|
|
||||||
cachedTypeInfo = make(map[uintptr]*typeInfo, 64)
|
|
||||||
cachedTypeInfoMutex sync.RWMutex
|
|
||||||
|
|
||||||
// mapStrIntfTyp = reflect.TypeOf(map[string]interface{}(nil))
|
// mapStrIntfTyp = reflect.TypeOf(map[string]interface{}(nil))
|
||||||
intfSliceTyp = reflect.TypeOf([]interface{}(nil))
|
intfSliceTyp = reflect.TypeOf([]interface{}(nil))
|
||||||
intfTyp = intfSliceTyp.Elem()
|
intfTyp = intfSliceTyp.Elem()
|
||||||
|
@ -217,6 +229,9 @@ var (
|
||||||
textMarshalerTyp = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
|
textMarshalerTyp = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
|
||||||
textUnmarshalerTyp = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
|
textUnmarshalerTyp = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
|
||||||
|
|
||||||
|
jsonMarshalerTyp = reflect.TypeOf((*jsonMarshaler)(nil)).Elem()
|
||||||
|
jsonUnmarshalerTyp = reflect.TypeOf((*jsonUnmarshaler)(nil)).Elem()
|
||||||
|
|
||||||
selferTyp = reflect.TypeOf((*Selfer)(nil)).Elem()
|
selferTyp = reflect.TypeOf((*Selfer)(nil)).Elem()
|
||||||
|
|
||||||
uint8SliceTypId = reflect.ValueOf(uint8SliceTyp).Pointer()
|
uint8SliceTypId = reflect.ValueOf(uint8SliceTyp).Pointer()
|
||||||
|
@ -238,6 +253,8 @@ var (
|
||||||
noFieldNameToStructFieldInfoErr = errors.New("no field name passed to parseStructFieldInfo")
|
noFieldNameToStructFieldInfoErr = errors.New("no field name passed to parseStructFieldInfo")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var defTypeInfos = NewTypeInfos([]string{"codec", "json"})
|
||||||
|
|
||||||
// Selfer defines methods by which a value can encode or decode itself.
|
// Selfer defines methods by which a value can encode or decode itself.
|
||||||
//
|
//
|
||||||
// Any type which implements Selfer will be able to encode or decode itself.
|
// Any type which implements Selfer will be able to encode or decode itself.
|
||||||
|
@ -263,6 +280,11 @@ type MapBySlice interface {
|
||||||
//
|
//
|
||||||
// BasicHandle encapsulates the common options and extension functions.
|
// BasicHandle encapsulates the common options and extension functions.
|
||||||
type BasicHandle struct {
|
type BasicHandle struct {
|
||||||
|
// TypeInfos is used to get the type info for any type.
|
||||||
|
//
|
||||||
|
// If not configure, the default TypeInfos is used, which uses struct tag keys: codec, json
|
||||||
|
TypeInfos *TypeInfos
|
||||||
|
|
||||||
extHandle
|
extHandle
|
||||||
EncodeOptions
|
EncodeOptions
|
||||||
DecodeOptions
|
DecodeOptions
|
||||||
|
@ -272,6 +294,13 @@ func (x *BasicHandle) getBasicHandle() *BasicHandle {
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *BasicHandle) getTypeInfo(rtid uintptr, rt reflect.Type) (pti *typeInfo) {
|
||||||
|
if x.TypeInfos != nil {
|
||||||
|
return x.TypeInfos.get(rtid, rt)
|
||||||
|
}
|
||||||
|
return defTypeInfos.get(rtid, rt)
|
||||||
|
}
|
||||||
|
|
||||||
// Handle is the interface for a specific encoding format.
|
// Handle is the interface for a specific encoding format.
|
||||||
//
|
//
|
||||||
// Typically, a Handle is pre-configured before first time use,
|
// Typically, a Handle is pre-configured before first time use,
|
||||||
|
@ -298,32 +327,41 @@ type RawExt struct {
|
||||||
Value interface{}
|
Value interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ext handles custom (de)serialization of custom types / extensions.
|
// BytesExt handles custom (de)serialization of types to/from []byte.
|
||||||
type Ext interface {
|
|
||||||
// WriteExt converts a value to a []byte.
|
|
||||||
// It is used by codecs (e.g. binc, msgpack, simple) which do custom serialization of the types.
|
// It is used by codecs (e.g. binc, msgpack, simple) which do custom serialization of the types.
|
||||||
|
type BytesExt interface {
|
||||||
|
// WriteExt converts a value to a []byte.
|
||||||
WriteExt(v interface{}) []byte
|
WriteExt(v interface{}) []byte
|
||||||
|
|
||||||
// ReadExt updates a value from a []byte.
|
// ReadExt updates a value from a []byte.
|
||||||
// It is used by codecs (e.g. binc, msgpack, simple) which do custom serialization of the types.
|
|
||||||
ReadExt(dst interface{}, src []byte)
|
ReadExt(dst interface{}, src []byte)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InterfaceExt handles custom (de)serialization of types to/from another interface{} value.
|
||||||
|
// The Encoder or Decoder will then handle the further (de)serialization of that known type.
|
||||||
|
//
|
||||||
|
// It is used by codecs (e.g. cbor, json) which use the format to do custom serialization of the types.
|
||||||
|
type InterfaceExt interface {
|
||||||
// ConvertExt converts a value into a simpler interface for easy encoding e.g. convert time.Time to int64.
|
// ConvertExt converts a value into a simpler interface for easy encoding e.g. convert time.Time to int64.
|
||||||
// It is used by codecs (e.g. cbor) which use the format to do custom serialization of the types.
|
|
||||||
ConvertExt(v interface{}) interface{}
|
ConvertExt(v interface{}) interface{}
|
||||||
|
|
||||||
// UpdateExt updates a value from a simpler interface for easy decoding e.g. convert int64 to time.Time.
|
// UpdateExt updates a value from a simpler interface for easy decoding e.g. convert int64 to time.Time.
|
||||||
// It is used by codecs (e.g. cbor) which use the format to do custom serialization of the types.
|
|
||||||
UpdateExt(dst interface{}, src interface{})
|
UpdateExt(dst interface{}, src interface{})
|
||||||
}
|
}
|
||||||
|
|
||||||
// bytesExt is a wrapper implementation to support former AddExt exported method.
|
// Ext handles custom (de)serialization of custom types / extensions.
|
||||||
type bytesExt struct {
|
type Ext interface {
|
||||||
|
BytesExt
|
||||||
|
InterfaceExt
|
||||||
|
}
|
||||||
|
|
||||||
|
// addExtWrapper is a wrapper implementation to support former AddExt exported method.
|
||||||
|
type addExtWrapper struct {
|
||||||
encFn func(reflect.Value) ([]byte, error)
|
encFn func(reflect.Value) ([]byte, error)
|
||||||
decFn func(reflect.Value, []byte) error
|
decFn func(reflect.Value, []byte) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x bytesExt) WriteExt(v interface{}) []byte {
|
func (x addExtWrapper) WriteExt(v interface{}) []byte {
|
||||||
// fmt.Printf(">>>>>>>>>> WriteExt: %T, %v\n", v, v)
|
// fmt.Printf(">>>>>>>>>> WriteExt: %T, %v\n", v, v)
|
||||||
bs, err := x.encFn(reflect.ValueOf(v))
|
bs, err := x.encFn(reflect.ValueOf(v))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -332,21 +370,57 @@ func (x bytesExt) WriteExt(v interface{}) []byte {
|
||||||
return bs
|
return bs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x bytesExt) ReadExt(v interface{}, bs []byte) {
|
func (x addExtWrapper) ReadExt(v interface{}, bs []byte) {
|
||||||
// fmt.Printf(">>>>>>>>>> ReadExt: %T, %v\n", v, v)
|
// fmt.Printf(">>>>>>>>>> ReadExt: %T, %v\n", v, v)
|
||||||
if err := x.decFn(reflect.ValueOf(v), bs); err != nil {
|
if err := x.decFn(reflect.ValueOf(v), bs); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x bytesExt) ConvertExt(v interface{}) interface{} {
|
func (x addExtWrapper) ConvertExt(v interface{}) interface{} {
|
||||||
return x.WriteExt(v)
|
return x.WriteExt(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x bytesExt) UpdateExt(dest interface{}, v interface{}) {
|
func (x addExtWrapper) UpdateExt(dest interface{}, v interface{}) {
|
||||||
x.ReadExt(dest, v.([]byte))
|
x.ReadExt(dest, v.([]byte))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type setExtWrapper struct {
|
||||||
|
b BytesExt
|
||||||
|
i InterfaceExt
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *setExtWrapper) WriteExt(v interface{}) []byte {
|
||||||
|
if x.b == nil {
|
||||||
|
panic("BytesExt.WriteExt is not supported")
|
||||||
|
}
|
||||||
|
return x.b.WriteExt(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *setExtWrapper) ReadExt(v interface{}, bs []byte) {
|
||||||
|
if x.b == nil {
|
||||||
|
panic("BytesExt.WriteExt is not supported")
|
||||||
|
|
||||||
|
}
|
||||||
|
x.b.ReadExt(v, bs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *setExtWrapper) ConvertExt(v interface{}) interface{} {
|
||||||
|
if x.i == nil {
|
||||||
|
panic("InterfaceExt.ConvertExt is not supported")
|
||||||
|
|
||||||
|
}
|
||||||
|
return x.i.ConvertExt(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *setExtWrapper) UpdateExt(dest interface{}, v interface{}) {
|
||||||
|
if x.i == nil {
|
||||||
|
panic("InterfaceExxt.UpdateExt is not supported")
|
||||||
|
|
||||||
|
}
|
||||||
|
x.i.UpdateExt(dest, v)
|
||||||
|
}
|
||||||
|
|
||||||
// type errorString string
|
// type errorString string
|
||||||
// func (x errorString) Error() string { return string(x) }
|
// func (x errorString) Error() string { return string(x) }
|
||||||
|
|
||||||
|
@ -401,7 +475,7 @@ type extTypeTagFn struct {
|
||||||
|
|
||||||
type extHandle []*extTypeTagFn
|
type extHandle []*extTypeTagFn
|
||||||
|
|
||||||
// DEPRECATED: AddExt is deprecated in favor of SetExt. It exists for compatibility only.
|
// DEPRECATED: Use SetBytesExt or SetInterfaceExt on the Handle instead.
|
||||||
//
|
//
|
||||||
// AddExt registes an encode and decode function for a reflect.Type.
|
// AddExt registes an encode and decode function for a reflect.Type.
|
||||||
// AddExt internally calls SetExt.
|
// AddExt internally calls SetExt.
|
||||||
|
@ -413,10 +487,10 @@ func (o *extHandle) AddExt(
|
||||||
if encfn == nil || decfn == nil {
|
if encfn == nil || decfn == nil {
|
||||||
return o.SetExt(rt, uint64(tag), nil)
|
return o.SetExt(rt, uint64(tag), nil)
|
||||||
}
|
}
|
||||||
return o.SetExt(rt, uint64(tag), bytesExt{encfn, decfn})
|
return o.SetExt(rt, uint64(tag), addExtWrapper{encfn, decfn})
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetExt registers a tag and Ext for a reflect.Type.
|
// DEPRECATED: Use SetBytesExt or SetInterfaceExt on the Handle instead.
|
||||||
//
|
//
|
||||||
// Note that the type must be a named type, and specifically not
|
// Note that the type must be a named type, and specifically not
|
||||||
// a pointer or Interface. An error is returned if that is not honored.
|
// a pointer or Interface. An error is returned if that is not honored.
|
||||||
|
@ -471,6 +545,10 @@ type structFieldInfo struct {
|
||||||
toArray bool // if field is _struct, is the toArray set?
|
toArray bool // if field is _struct, is the toArray set?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// func (si *structFieldInfo) isZero() bool {
|
||||||
|
// return si.encName == "" && len(si.is) == 0 && si.i == 0 && !si.omitEmpty && !si.toArray
|
||||||
|
// }
|
||||||
|
|
||||||
// rv returns the field of the struct.
|
// rv returns the field of the struct.
|
||||||
// If anonymous, it returns an Invalid
|
// If anonymous, it returns an Invalid
|
||||||
func (si *structFieldInfo) field(v reflect.Value, update bool) (rv2 reflect.Value) {
|
func (si *structFieldInfo) field(v reflect.Value, update bool) (rv2 reflect.Value) {
|
||||||
|
@ -516,9 +594,9 @@ func (si *structFieldInfo) setToZeroValue(v reflect.Value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseStructFieldInfo(fname string, stag string) *structFieldInfo {
|
func parseStructFieldInfo(fname string, stag string) *structFieldInfo {
|
||||||
if fname == "" {
|
// if fname == "" {
|
||||||
panic(noFieldNameToStructFieldInfoErr)
|
// panic(noFieldNameToStructFieldInfoErr)
|
||||||
}
|
// }
|
||||||
si := structFieldInfo{
|
si := structFieldInfo{
|
||||||
encName: fname,
|
encName: fname,
|
||||||
}
|
}
|
||||||
|
@ -589,6 +667,11 @@ type typeInfo struct {
|
||||||
tmIndir int8 // number of indirections to get to textMarshaler type
|
tmIndir int8 // number of indirections to get to textMarshaler type
|
||||||
tunmIndir int8 // number of indirections to get to textUnmarshaler type
|
tunmIndir int8 // number of indirections to get to textUnmarshaler type
|
||||||
|
|
||||||
|
jm bool // base type (T or *T) is a jsonMarshaler
|
||||||
|
junm bool // base type (T or *T) is a jsonUnmarshaler
|
||||||
|
jmIndir int8 // number of indirections to get to jsonMarshaler type
|
||||||
|
junmIndir int8 // number of indirections to get to jsonUnmarshaler type
|
||||||
|
|
||||||
cs bool // base type (T or *T) is a Selfer
|
cs bool // base type (T or *T) is a Selfer
|
||||||
csIndir int8 // number of indirections to get to Selfer type
|
csIndir int8 // number of indirections to get to Selfer type
|
||||||
|
|
||||||
|
@ -623,28 +706,48 @@ func (ti *typeInfo) indexForEncName(name string) int {
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
func getStructTag(t reflect.StructTag) (s string) {
|
// TypeInfos caches typeInfo for each type on first inspection.
|
||||||
|
//
|
||||||
|
// It is configured with a set of tag keys, which are used to get
|
||||||
|
// configuration for the type.
|
||||||
|
type TypeInfos struct {
|
||||||
|
infos map[uintptr]*typeInfo
|
||||||
|
mu sync.RWMutex
|
||||||
|
tags []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTypeInfos creates a TypeInfos given a set of struct tags keys.
|
||||||
|
//
|
||||||
|
// This allows users customize the struct tag keys which contain configuration
|
||||||
|
// of their types.
|
||||||
|
func NewTypeInfos(tags []string) *TypeInfos {
|
||||||
|
return &TypeInfos{tags: tags, infos: make(map[uintptr]*typeInfo, 64)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *TypeInfos) structTag(t reflect.StructTag) (s string) {
|
||||||
// check for tags: codec, json, in that order.
|
// check for tags: codec, json, in that order.
|
||||||
// this allows seamless support for many configured structs.
|
// this allows seamless support for many configured structs.
|
||||||
s = t.Get("codec")
|
for _, x := range x.tags {
|
||||||
if s == "" {
|
s = t.Get(x)
|
||||||
s = t.Get("json")
|
if s != "" {
|
||||||
|
return s
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTypeInfo(rtid uintptr, rt reflect.Type) (pti *typeInfo) {
|
func (x *TypeInfos) get(rtid uintptr, rt reflect.Type) (pti *typeInfo) {
|
||||||
var ok bool
|
var ok bool
|
||||||
cachedTypeInfoMutex.RLock()
|
x.mu.RLock()
|
||||||
pti, ok = cachedTypeInfo[rtid]
|
pti, ok = x.infos[rtid]
|
||||||
cachedTypeInfoMutex.RUnlock()
|
x.mu.RUnlock()
|
||||||
if ok {
|
if ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cachedTypeInfoMutex.Lock()
|
x.mu.Lock()
|
||||||
defer cachedTypeInfoMutex.Unlock()
|
defer x.mu.Unlock()
|
||||||
if pti, ok = cachedTypeInfo[rtid]; ok {
|
if pti, ok = x.infos[rtid]; ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -664,6 +767,12 @@ func getTypeInfo(rtid uintptr, rt reflect.Type) (pti *typeInfo) {
|
||||||
if ok, indir = implementsIntf(rt, textUnmarshalerTyp); ok {
|
if ok, indir = implementsIntf(rt, textUnmarshalerTyp); ok {
|
||||||
ti.tunm, ti.tunmIndir = true, indir
|
ti.tunm, ti.tunmIndir = true, indir
|
||||||
}
|
}
|
||||||
|
if ok, indir = implementsIntf(rt, jsonMarshalerTyp); ok {
|
||||||
|
ti.jm, ti.jmIndir = true, indir
|
||||||
|
}
|
||||||
|
if ok, indir = implementsIntf(rt, jsonUnmarshalerTyp); ok {
|
||||||
|
ti.junm, ti.junmIndir = true, indir
|
||||||
|
}
|
||||||
if ok, indir = implementsIntf(rt, selferTyp); ok {
|
if ok, indir = implementsIntf(rt, selferTyp); ok {
|
||||||
ti.cs, ti.csIndir = true, indir
|
ti.cs, ti.csIndir = true, indir
|
||||||
}
|
}
|
||||||
|
@ -690,11 +799,11 @@ func getTypeInfo(rtid uintptr, rt reflect.Type) (pti *typeInfo) {
|
||||||
if rt.Kind() == reflect.Struct {
|
if rt.Kind() == reflect.Struct {
|
||||||
var siInfo *structFieldInfo
|
var siInfo *structFieldInfo
|
||||||
if f, ok := rt.FieldByName(structInfoFieldName); ok {
|
if f, ok := rt.FieldByName(structInfoFieldName); ok {
|
||||||
siInfo = parseStructFieldInfo(structInfoFieldName, getStructTag(f.Tag))
|
siInfo = parseStructFieldInfo(structInfoFieldName, x.structTag(f.Tag))
|
||||||
ti.toArray = siInfo.toArray
|
ti.toArray = siInfo.toArray
|
||||||
}
|
}
|
||||||
sfip := make([]*structFieldInfo, 0, rt.NumField())
|
sfip := make([]*structFieldInfo, 0, rt.NumField())
|
||||||
rgetTypeInfo(rt, nil, make(map[string]bool, 16), &sfip, siInfo)
|
x.rget(rt, nil, make(map[string]bool, 16), &sfip, siInfo)
|
||||||
|
|
||||||
ti.sfip = make([]*structFieldInfo, len(sfip))
|
ti.sfip = make([]*structFieldInfo, len(sfip))
|
||||||
ti.sfi = make([]*structFieldInfo, len(sfip))
|
ti.sfi = make([]*structFieldInfo, len(sfip))
|
||||||
|
@ -703,11 +812,11 @@ func getTypeInfo(rtid uintptr, rt reflect.Type) (pti *typeInfo) {
|
||||||
copy(ti.sfi, sfip)
|
copy(ti.sfi, sfip)
|
||||||
}
|
}
|
||||||
// sfi = sfip
|
// sfi = sfip
|
||||||
cachedTypeInfo[rtid] = pti
|
x.infos[rtid] = pti
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func rgetTypeInfo(rt reflect.Type, indexstack []int, fnameToHastag map[string]bool,
|
func (x *TypeInfos) rget(rt reflect.Type, indexstack []int, fnameToHastag map[string]bool,
|
||||||
sfi *[]*structFieldInfo, siInfo *structFieldInfo,
|
sfi *[]*structFieldInfo, siInfo *structFieldInfo,
|
||||||
) {
|
) {
|
||||||
for j := 0; j < rt.NumField(); j++ {
|
for j := 0; j < rt.NumField(); j++ {
|
||||||
|
@ -716,15 +825,28 @@ func rgetTypeInfo(rt reflect.Type, indexstack []int, fnameToHastag map[string]bo
|
||||||
if tk := f.Type.Kind(); tk == reflect.Func {
|
if tk := f.Type.Kind(); tk == reflect.Func {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
stag := getStructTag(f.Tag)
|
stag := x.structTag(f.Tag)
|
||||||
if stag == "-" {
|
if stag == "-" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if r1, _ := utf8.DecodeRuneInString(f.Name); r1 == utf8.RuneError || !unicode.IsUpper(r1) {
|
if r1, _ := utf8.DecodeRuneInString(f.Name); r1 == utf8.RuneError || !unicode.IsUpper(r1) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// if anonymous and there is no struct tag and its a struct (or pointer to struct), inline it.
|
var si *structFieldInfo
|
||||||
if f.Anonymous && stag == "" {
|
// if anonymous and there is no struct tag (or it's blank)
|
||||||
|
// and its a struct (or pointer to struct), inline it.
|
||||||
|
var doInline bool
|
||||||
|
if f.Anonymous && f.Type.Kind() != reflect.Interface {
|
||||||
|
doInline = stag == ""
|
||||||
|
if !doInline {
|
||||||
|
si = parseStructFieldInfo("", stag)
|
||||||
|
doInline = si.encName == ""
|
||||||
|
// doInline = si.isZero()
|
||||||
|
// fmt.Printf(">>>> doInline for si.isZero: %s: %v\n", f.Name, doInline)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if doInline {
|
||||||
ft := f.Type
|
ft := f.Type
|
||||||
for ft.Kind() == reflect.Ptr {
|
for ft.Kind() == reflect.Ptr {
|
||||||
ft = ft.Elem()
|
ft = ft.Elem()
|
||||||
|
@ -734,7 +856,7 @@ func rgetTypeInfo(rt reflect.Type, indexstack []int, fnameToHastag map[string]bo
|
||||||
copy(indexstack2, indexstack)
|
copy(indexstack2, indexstack)
|
||||||
indexstack2[len(indexstack)] = j
|
indexstack2[len(indexstack)] = j
|
||||||
// indexstack2 := append(append(make([]int, 0, len(indexstack)+4), indexstack...), j)
|
// indexstack2 := append(append(make([]int, 0, len(indexstack)+4), indexstack...), j)
|
||||||
rgetTypeInfo(ft, indexstack2, fnameToHastag, sfi, siInfo)
|
x.rget(ft, indexstack2, fnameToHastag, sfi, siInfo)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -744,7 +866,14 @@ func rgetTypeInfo(rt reflect.Type, indexstack []int, fnameToHastag map[string]bo
|
||||||
if _, ok := fnameToHastag[f.Name]; ok {
|
if _, ok := fnameToHastag[f.Name]; ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
si := parseStructFieldInfo(f.Name, stag)
|
if f.Name == "" {
|
||||||
|
panic(noFieldNameToStructFieldInfoErr)
|
||||||
|
}
|
||||||
|
if si == nil {
|
||||||
|
si = parseStructFieldInfo(f.Name, stag)
|
||||||
|
} else if si.encName == "" {
|
||||||
|
si.encName = f.Name
|
||||||
|
}
|
||||||
// si.ikind = int(f.Type.Kind())
|
// si.ikind = int(f.Type.Kind())
|
||||||
if len(indexstack) == 0 {
|
if len(indexstack) == 0 {
|
||||||
si.i = int16(j)
|
si.i = int16(j)
|
||||||
|
@ -779,8 +908,9 @@ func panicToErr(err *error) {
|
||||||
// panic(fmt.Errorf("%s: "+format, params2...))
|
// panic(fmt.Errorf("%s: "+format, params2...))
|
||||||
// }
|
// }
|
||||||
|
|
||||||
func isMutableKind(k reflect.Kind) (v bool) {
|
func isImmutableKind(k reflect.Kind) (v bool) {
|
||||||
return k == reflect.Int ||
|
return false ||
|
||||||
|
k == reflect.Int ||
|
||||||
k == reflect.Int8 ||
|
k == reflect.Int8 ||
|
||||||
k == reflect.Int16 ||
|
k == reflect.Int16 ||
|
||||||
k == reflect.Int32 ||
|
k == reflect.Int32 ||
|
||||||
|
@ -790,6 +920,7 @@ func isMutableKind(k reflect.Kind) (v bool) {
|
||||||
k == reflect.Uint16 ||
|
k == reflect.Uint16 ||
|
||||||
k == reflect.Uint32 ||
|
k == reflect.Uint32 ||
|
||||||
k == reflect.Uint64 ||
|
k == reflect.Uint64 ||
|
||||||
|
k == reflect.Uintptr ||
|
||||||
k == reflect.Float32 ||
|
k == reflect.Float32 ||
|
||||||
k == reflect.Float64 ||
|
k == reflect.Float64 ||
|
||||||
k == reflect.Bool ||
|
k == reflect.Bool ||
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// Copyright (c) 2012, 2013 Ugorji Nwoke. All rights reserved.
|
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style license found in the LICENSE file.
|
// Use of this source code is governed by a MIT license found in the LICENSE file.
|
||||||
|
|
||||||
package codec
|
package codec
|
||||||
|
|
||||||
|
@ -149,3 +149,94 @@ func halfFloatToFloatBits(yy uint16) (d uint32) {
|
||||||
m = m << 13
|
m = m << 13
|
||||||
return (s << 31) | (e << 23) | m
|
return (s << 31) | (e << 23) | m
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GrowCap will return a new capacity for a slice, given the following:
|
||||||
|
// - oldCap: current capacity
|
||||||
|
// - unit: in-memory size of an element
|
||||||
|
// - num: number of elements to add
|
||||||
|
func growCap(oldCap, unit, num int) (newCap int) {
|
||||||
|
// appendslice logic (if cap < 1024, *2, else *1.25):
|
||||||
|
// leads to many copy calls, especially when copying bytes.
|
||||||
|
// bytes.Buffer model (2*cap + n): much better for bytes.
|
||||||
|
// smarter way is to take the byte-size of the appended element(type) into account
|
||||||
|
|
||||||
|
// maintain 3 thresholds:
|
||||||
|
// t1: if cap <= t1, newcap = 2x
|
||||||
|
// t2: if cap <= t2, newcap = 1.75x
|
||||||
|
// t3: if cap <= t3, newcap = 1.5x
|
||||||
|
// else newcap = 1.25x
|
||||||
|
//
|
||||||
|
// t1, t2, t3 >= 1024 always.
|
||||||
|
// i.e. if unit size >= 16, then always do 2x or 1.25x (ie t1, t2, t3 are all same)
|
||||||
|
//
|
||||||
|
// With this, appending for bytes increase by:
|
||||||
|
// 100% up to 4K
|
||||||
|
// 75% up to 8K
|
||||||
|
// 50% up to 16K
|
||||||
|
// 25% beyond that
|
||||||
|
|
||||||
|
// unit can be 0 e.g. for struct{}{}; handle that appropriately
|
||||||
|
var t1, t2, t3 int // thresholds
|
||||||
|
if unit <= 1 {
|
||||||
|
t1, t2, t3 = 4*1024, 8*1024, 16*1024
|
||||||
|
} else if unit < 16 {
|
||||||
|
t3 = 16 / unit * 1024
|
||||||
|
t1 = t3 * 1 / 4
|
||||||
|
t2 = t3 * 2 / 4
|
||||||
|
} else {
|
||||||
|
t1, t2, t3 = 1024, 1024, 1024
|
||||||
|
}
|
||||||
|
|
||||||
|
var x int // temporary variable
|
||||||
|
|
||||||
|
// x is multiplier here: one of 5, 6, 7 or 8; incr of 25%, 50%, 75% or 100% respectively
|
||||||
|
if oldCap <= t1 { // [0,t1]
|
||||||
|
x = 8
|
||||||
|
} else if oldCap > t3 { // (t3,infinity]
|
||||||
|
x = 5
|
||||||
|
} else if oldCap <= t2 { // (t1,t2]
|
||||||
|
x = 7
|
||||||
|
} else { // (t2,t3]
|
||||||
|
x = 6
|
||||||
|
}
|
||||||
|
newCap = x * oldCap / 4
|
||||||
|
|
||||||
|
if num > 0 {
|
||||||
|
newCap += num
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensure newCap is a multiple of 64 (if it is > 64) or 16.
|
||||||
|
if newCap > 64 {
|
||||||
|
if x = newCap % 64; x != 0 {
|
||||||
|
x = newCap / 64
|
||||||
|
newCap = 64 * (x + 1)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if x = newCap % 16; x != 0 {
|
||||||
|
x = newCap / 16
|
||||||
|
newCap = 16 * (x + 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func expandSliceValue(s reflect.Value, num int) reflect.Value {
|
||||||
|
if num <= 0 {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
l0 := s.Len()
|
||||||
|
l1 := l0 + num // new slice length
|
||||||
|
if l1 < l0 {
|
||||||
|
panic("ExpandSlice: slice overflow")
|
||||||
|
}
|
||||||
|
c0 := s.Cap()
|
||||||
|
if l1 <= c0 {
|
||||||
|
return s.Slice(0, l1)
|
||||||
|
}
|
||||||
|
st := s.Type()
|
||||||
|
c1 := growCap(c0, int(st.Elem().Size()), num)
|
||||||
|
s2 := reflect.MakeSlice(st, l1, c1)
|
||||||
|
// println("expandslicevalue: cap-old: ", c0, ", cap-new: ", c1, ", len-new: ", l1)
|
||||||
|
reflect.Copy(s2, s)
|
||||||
|
return s2
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//+build !unsafe
|
//+build !unsafe
|
||||||
|
|
||||||
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style license found in the LICENSE file.
|
// Use of this source code is governed by a MIT license found in the LICENSE file.
|
||||||
|
|
||||||
package codec
|
package codec
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style license found in the LICENSE file.
|
// Use of this source code is governed by a MIT license found in the LICENSE file.
|
||||||
|
|
||||||
package codec
|
package codec
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//+build unsafe
|
//+build unsafe
|
||||||
|
|
||||||
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style license found in the LICENSE file.
|
// Use of this source code is governed by a MIT license found in the LICENSE file.
|
||||||
|
|
||||||
package codec
|
package codec
|
||||||
|
|
||||||
|
@ -26,6 +26,9 @@ type unsafeBytes struct {
|
||||||
// In unsafe mode, it doesn't incur allocation and copying caused by conversion.
|
// In unsafe mode, it doesn't incur allocation and copying caused by conversion.
|
||||||
// In regular safe mode, it is an allocation and copy.
|
// In regular safe mode, it is an allocation and copy.
|
||||||
func stringView(v []byte) string {
|
func stringView(v []byte) string {
|
||||||
|
if len(v) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
x := unsafeString{uintptr(unsafe.Pointer(&v[0])), len(v)}
|
x := unsafeString{uintptr(unsafe.Pointer(&v[0])), len(v)}
|
||||||
return *(*string)(unsafe.Pointer(&x))
|
return *(*string)(unsafe.Pointer(&x))
|
||||||
}
|
}
|
||||||
|
@ -34,6 +37,9 @@ func stringView(v []byte) string {
|
||||||
// In unsafe mode, it doesn't incur allocation and copying caused by conversion.
|
// In unsafe mode, it doesn't incur allocation and copying caused by conversion.
|
||||||
// In regular safe mode, it is an allocation and copy.
|
// In regular safe mode, it is an allocation and copy.
|
||||||
func bytesView(v string) []byte {
|
func bytesView(v string) []byte {
|
||||||
|
if len(v) == 0 {
|
||||||
|
return zeroByteSlice
|
||||||
|
}
|
||||||
x := unsafeBytes{uintptr(unsafe.Pointer(&v)), len(v), len(v)}
|
x := unsafeBytes{uintptr(unsafe.Pointer(&v)), len(v), len(v)}
|
||||||
return *(*[]byte)(unsafe.Pointer(&x))
|
return *(*[]byte)(unsafe.Pointer(&x))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style license found in the LICENSE file.
|
// Use of this source code is governed by a MIT license found in the LICENSE file.
|
||||||
|
|
||||||
package codec
|
package codec
|
||||||
|
|
||||||
// This json support uses base64 encoding for bytes, because you cannot
|
// By default, this json support uses base64 encoding for bytes, because you cannot
|
||||||
// store and read any arbitrary string in json (only unicode).
|
// store and read any arbitrary string in json (only unicode).
|
||||||
|
// However, the user can configre how to encode/decode bytes.
|
||||||
//
|
//
|
||||||
// This library specifically supports UTF-8 for encoding and decoding only.
|
// This library specifically supports UTF-8 for encoding and decoding only.
|
||||||
//
|
//
|
||||||
|
@ -27,11 +28,18 @@ package codec
|
||||||
// - encode does not beautify. There is no whitespace when encoding.
|
// - encode does not beautify. There is no whitespace when encoding.
|
||||||
// - rpc calls which take single integer arguments or write single numeric arguments will need care.
|
// - rpc calls which take single integer arguments or write single numeric arguments will need care.
|
||||||
|
|
||||||
|
// Top-level methods of json(End|Dec)Driver (which are implementations of (en|de)cDriver
|
||||||
|
// MUST not call one-another.
|
||||||
|
// They all must call sep(), and sep() MUST NOT be called more than once for each read.
|
||||||
|
// If sep() is called and read is not done, you MUST call retryRead so separator wouldn't be read/written twice.
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"sync"
|
||||||
"unicode/utf16"
|
"unicode/utf16"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
)
|
)
|
||||||
|
@ -81,20 +89,122 @@ const (
|
||||||
// jsonNumDigitsUint64Largest = 19
|
// jsonNumDigitsUint64Largest = 19
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// A stack is used to keep track of where we are in the tree.
|
||||||
|
// This is necessary, as the Handle must know whether to consume or emit a separator.
|
||||||
|
|
||||||
|
type jsonStackElem struct {
|
||||||
|
st byte // top of stack (either '}' or ']' or 0 for map, array or neither).
|
||||||
|
sf bool // NOT first time in that container at top of stack
|
||||||
|
so bool // stack ctr odd
|
||||||
|
sr bool // value has NOT been read, so do not re-send separator
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *jsonStackElem) retryRead() {
|
||||||
|
if x != nil && !x.sr {
|
||||||
|
x.sr = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *jsonStackElem) sep() (c byte) {
|
||||||
|
// do not use switch, so it's a candidate for inlining.
|
||||||
|
// to inline effectively, this must not be called from within another method.
|
||||||
|
// v := j.st
|
||||||
|
if x == nil || x.st == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if x.sr {
|
||||||
|
x.sr = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// v == '}' OR ']'
|
||||||
|
if x.st == '}' {
|
||||||
|
// put , or : depending on if even or odd respectively
|
||||||
|
if x.so {
|
||||||
|
c = ':'
|
||||||
|
if !x.sf {
|
||||||
|
x.sf = true
|
||||||
|
}
|
||||||
|
} else if x.sf {
|
||||||
|
c = ','
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if x.sf {
|
||||||
|
c = ','
|
||||||
|
} else {
|
||||||
|
x.sf = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
x.so = !x.so
|
||||||
|
// Note: Anything more, and this function doesn't inline. Keep it tight.
|
||||||
|
// if x.sr {
|
||||||
|
// x.sr = false
|
||||||
|
// }
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const jsonStackPoolArrayLen = 32
|
||||||
|
|
||||||
|
// pool used to prevent constant allocation of stacks.
|
||||||
|
var jsonStackPool = sync.Pool{
|
||||||
|
New: func() interface{} {
|
||||||
|
return new([jsonStackPoolArrayLen]jsonStackElem)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// jsonStack contains the stack for tracking the state of the container (branch).
|
||||||
|
// The same data structure is used during encode and decode, as it is similar functionality.
|
||||||
|
type jsonStack struct {
|
||||||
|
s []jsonStackElem // stack for map or array end tag. map=}, array=]
|
||||||
|
sc *jsonStackElem // pointer to current (top) element on the stack.
|
||||||
|
sp *[jsonStackPoolArrayLen]jsonStackElem
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j *jsonStack) start(c byte) {
|
||||||
|
if j.s == nil {
|
||||||
|
// j.s = make([]jsonStackElem, 0, 8)
|
||||||
|
j.sp = jsonStackPool.Get().(*[jsonStackPoolArrayLen]jsonStackElem)
|
||||||
|
j.s = j.sp[:0]
|
||||||
|
}
|
||||||
|
j.s = append(j.s, jsonStackElem{st: c})
|
||||||
|
j.sc = &(j.s[len(j.s)-1])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j *jsonStack) end() {
|
||||||
|
l := len(j.s) - 1 // length of new stack after pop'ing
|
||||||
|
if l == 0 {
|
||||||
|
jsonStackPool.Put(j.sp)
|
||||||
|
j.s = nil
|
||||||
|
j.sp = nil
|
||||||
|
j.sc = nil
|
||||||
|
} else {
|
||||||
|
j.s = j.s[:l]
|
||||||
|
j.sc = &(j.s[l-1])
|
||||||
|
}
|
||||||
|
//j.sc = &(j.s[len(j.s)-1])
|
||||||
|
}
|
||||||
|
|
||||||
type jsonEncDriver struct {
|
type jsonEncDriver struct {
|
||||||
e *Encoder
|
e *Encoder
|
||||||
w encWriter
|
w encWriter
|
||||||
h *JsonHandle
|
h *JsonHandle
|
||||||
b [64]byte // scratch
|
b [64]byte // scratch
|
||||||
bs []byte // scratch
|
bs []byte // scratch
|
||||||
|
se setExtWrapper
|
||||||
|
s jsonStack
|
||||||
noBuiltInTypes
|
noBuiltInTypes
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *jsonEncDriver) EncodeNil() {
|
func (e *jsonEncDriver) EncodeNil() {
|
||||||
|
if c := e.s.sc.sep(); c != 0 {
|
||||||
|
e.w.writen1(c)
|
||||||
|
}
|
||||||
e.w.writeb(jsonLiterals[9:13]) // null
|
e.w.writeb(jsonLiterals[9:13]) // null
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *jsonEncDriver) EncodeBool(b bool) {
|
func (e *jsonEncDriver) EncodeBool(b bool) {
|
||||||
|
if c := e.s.sc.sep(); c != 0 {
|
||||||
|
e.w.writen1(c)
|
||||||
|
}
|
||||||
if b {
|
if b {
|
||||||
e.w.writeb(jsonLiterals[0:4]) // true
|
e.w.writeb(jsonLiterals[0:4]) // true
|
||||||
} else {
|
} else {
|
||||||
|
@ -103,78 +213,106 @@ func (e *jsonEncDriver) EncodeBool(b bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *jsonEncDriver) EncodeFloat32(f float32) {
|
func (e *jsonEncDriver) EncodeFloat32(f float32) {
|
||||||
|
if c := e.s.sc.sep(); c != 0 {
|
||||||
|
e.w.writen1(c)
|
||||||
|
}
|
||||||
e.w.writeb(strconv.AppendFloat(e.b[:0], float64(f), 'E', -1, 32))
|
e.w.writeb(strconv.AppendFloat(e.b[:0], float64(f), 'E', -1, 32))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *jsonEncDriver) EncodeFloat64(f float64) {
|
func (e *jsonEncDriver) EncodeFloat64(f float64) {
|
||||||
|
if c := e.s.sc.sep(); c != 0 {
|
||||||
|
e.w.writen1(c)
|
||||||
|
}
|
||||||
// e.w.writestr(strconv.FormatFloat(f, 'E', -1, 64))
|
// e.w.writestr(strconv.FormatFloat(f, 'E', -1, 64))
|
||||||
e.w.writeb(strconv.AppendFloat(e.b[:0], f, 'E', -1, 64))
|
e.w.writeb(strconv.AppendFloat(e.b[:0], f, 'E', -1, 64))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *jsonEncDriver) EncodeInt(v int64) {
|
func (e *jsonEncDriver) EncodeInt(v int64) {
|
||||||
|
if c := e.s.sc.sep(); c != 0 {
|
||||||
|
e.w.writen1(c)
|
||||||
|
}
|
||||||
e.w.writeb(strconv.AppendInt(e.b[:0], v, 10))
|
e.w.writeb(strconv.AppendInt(e.b[:0], v, 10))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *jsonEncDriver) EncodeUint(v uint64) {
|
func (e *jsonEncDriver) EncodeUint(v uint64) {
|
||||||
|
if c := e.s.sc.sep(); c != 0 {
|
||||||
|
e.w.writen1(c)
|
||||||
|
}
|
||||||
e.w.writeb(strconv.AppendUint(e.b[:0], v, 10))
|
e.w.writeb(strconv.AppendUint(e.b[:0], v, 10))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *jsonEncDriver) EncodeExt(rv interface{}, xtag uint64, ext Ext, en *Encoder) {
|
func (e *jsonEncDriver) EncodeExt(rv interface{}, xtag uint64, ext Ext, en *Encoder) {
|
||||||
|
if c := e.s.sc.sep(); c != 0 {
|
||||||
|
e.w.writen1(c)
|
||||||
|
}
|
||||||
if v := ext.ConvertExt(rv); v == nil {
|
if v := ext.ConvertExt(rv); v == nil {
|
||||||
e.EncodeNil()
|
e.w.writeb(jsonLiterals[9:13]) // null // e.EncodeNil()
|
||||||
} else {
|
} else {
|
||||||
|
e.s.sc.retryRead()
|
||||||
en.encode(v)
|
en.encode(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *jsonEncDriver) EncodeRawExt(re *RawExt, en *Encoder) {
|
func (e *jsonEncDriver) EncodeRawExt(re *RawExt, en *Encoder) {
|
||||||
|
if c := e.s.sc.sep(); c != 0 {
|
||||||
|
e.w.writen1(c)
|
||||||
|
}
|
||||||
// only encodes re.Value (never re.Data)
|
// only encodes re.Value (never re.Data)
|
||||||
if re.Value == nil {
|
if re.Value == nil {
|
||||||
e.EncodeNil()
|
e.w.writeb(jsonLiterals[9:13]) // null // e.EncodeNil()
|
||||||
} else {
|
} else {
|
||||||
|
e.s.sc.retryRead()
|
||||||
en.encode(re.Value)
|
en.encode(re.Value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *jsonEncDriver) EncodeArrayStart(length int) {
|
func (e *jsonEncDriver) EncodeArrayStart(length int) {
|
||||||
|
if c := e.s.sc.sep(); c != 0 {
|
||||||
|
e.w.writen1(c)
|
||||||
|
}
|
||||||
|
e.s.start(']')
|
||||||
e.w.writen1('[')
|
e.w.writen1('[')
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *jsonEncDriver) EncodeArrayEntrySeparator() {
|
|
||||||
e.w.writen1(',')
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *jsonEncDriver) EncodeArrayEnd() {
|
|
||||||
e.w.writen1(']')
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *jsonEncDriver) EncodeMapStart(length int) {
|
func (e *jsonEncDriver) EncodeMapStart(length int) {
|
||||||
|
if c := e.s.sc.sep(); c != 0 {
|
||||||
|
e.w.writen1(c)
|
||||||
|
}
|
||||||
|
e.s.start('}')
|
||||||
e.w.writen1('{')
|
e.w.writen1('{')
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *jsonEncDriver) EncodeMapEntrySeparator() {
|
func (e *jsonEncDriver) EncodeEnd() {
|
||||||
e.w.writen1(',')
|
b := e.s.sc.st
|
||||||
}
|
e.s.end()
|
||||||
|
e.w.writen1(b)
|
||||||
func (e *jsonEncDriver) EncodeMapKVSeparator() {
|
|
||||||
e.w.writen1(':')
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *jsonEncDriver) EncodeMapEnd() {
|
|
||||||
e.w.writen1('}')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *jsonEncDriver) EncodeString(c charEncoding, v string) {
|
func (e *jsonEncDriver) EncodeString(c charEncoding, v string) {
|
||||||
// e.w.writestr(strconv.Quote(v))
|
// e.w.writestr(strconv.Quote(v))
|
||||||
|
if c := e.s.sc.sep(); c != 0 {
|
||||||
|
e.w.writen1(c)
|
||||||
|
}
|
||||||
e.quoteStr(v)
|
e.quoteStr(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *jsonEncDriver) EncodeSymbol(v string) {
|
func (e *jsonEncDriver) EncodeSymbol(v string) {
|
||||||
// e.EncodeString(c_UTF8, v)
|
// e.EncodeString(c_UTF8, v)
|
||||||
|
if c := e.s.sc.sep(); c != 0 {
|
||||||
|
e.w.writen1(c)
|
||||||
|
}
|
||||||
e.quoteStr(v)
|
e.quoteStr(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *jsonEncDriver) EncodeStringBytes(c charEncoding, v []byte) {
|
func (e *jsonEncDriver) EncodeStringBytes(c charEncoding, v []byte) {
|
||||||
|
// if encoding raw bytes and RawBytesExt is configured, use it to encode
|
||||||
|
if c == c_RAW && e.se.i != nil {
|
||||||
|
e.EncodeExt(v, 0, &e.se, e.e)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if c := e.s.sc.sep(); c != 0 {
|
||||||
|
e.w.writen1(c)
|
||||||
|
}
|
||||||
if c == c_RAW {
|
if c == c_RAW {
|
||||||
slen := base64.StdEncoding.EncodedLen(len(v))
|
slen := base64.StdEncoding.EncodedLen(len(v))
|
||||||
if e.bs == nil {
|
if e.bs == nil {
|
||||||
|
@ -195,6 +333,13 @@ func (e *jsonEncDriver) EncodeStringBytes(c charEncoding, v []byte) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *jsonEncDriver) EncodeAsis(v []byte) {
|
||||||
|
if c := e.s.sc.sep(); c != 0 {
|
||||||
|
e.w.writen1(c)
|
||||||
|
}
|
||||||
|
e.w.writeb(v)
|
||||||
|
}
|
||||||
|
|
||||||
func (e *jsonEncDriver) quoteStr(s string) {
|
func (e *jsonEncDriver) quoteStr(s string) {
|
||||||
// adapted from std pkg encoding/json
|
// adapted from std pkg encoding/json
|
||||||
const hex = "0123456789abcdef"
|
const hex = "0123456789abcdef"
|
||||||
|
@ -356,9 +501,14 @@ type jsonDecDriver struct {
|
||||||
ct valueType // container type. one of unset, array or map.
|
ct valueType // container type. one of unset, array or map.
|
||||||
bstr [8]byte // scratch used for string \UXXX parsing
|
bstr [8]byte // scratch used for string \UXXX parsing
|
||||||
b [64]byte // scratch
|
b [64]byte // scratch
|
||||||
|
b2 [64]byte
|
||||||
|
|
||||||
wsSkipped bool // whitespace skipped
|
wsSkipped bool // whitespace skipped
|
||||||
|
|
||||||
|
se setExtWrapper
|
||||||
|
|
||||||
|
s jsonStack
|
||||||
|
|
||||||
n jsonNum
|
n jsonNum
|
||||||
noBuiltInTypes
|
noBuiltInTypes
|
||||||
}
|
}
|
||||||
|
@ -402,16 +552,27 @@ func (d *jsonDecDriver) readStrIdx(fromIdx, toIdx uint8) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *jsonDecDriver) TryDecodeAsNil() bool {
|
func (d *jsonDecDriver) TryDecodeAsNil() bool {
|
||||||
b := d.skipWhitespace(true)
|
// we mustn't consume the state here, and end up trying to read separator twice.
|
||||||
|
// Instead, we keep track of the state and restore it if we couldn't decode as nil.
|
||||||
|
|
||||||
|
if c := d.s.sc.sep(); c != 0 {
|
||||||
|
d.expectChar(c)
|
||||||
|
}
|
||||||
|
b := d.skipWhitespace(false)
|
||||||
if b == 'n' {
|
if b == 'n' {
|
||||||
d.readStrIdx(9, 13) // null
|
d.readStrIdx(10, 13) // ull
|
||||||
d.ct = valueTypeNil
|
d.ct = valueTypeNil
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
d.r.unreadn1()
|
||||||
|
d.s.sc.retryRead()
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *jsonDecDriver) DecodeBool() bool {
|
func (d *jsonDecDriver) DecodeBool() bool {
|
||||||
|
if c := d.s.sc.sep(); c != 0 {
|
||||||
|
d.expectChar(c)
|
||||||
|
}
|
||||||
b := d.skipWhitespace(false)
|
b := d.skipWhitespace(false)
|
||||||
if b == 'f' {
|
if b == 'f' {
|
||||||
d.readStrIdx(5, 9) // alse
|
d.readStrIdx(5, 9) // alse
|
||||||
|
@ -426,35 +587,35 @@ func (d *jsonDecDriver) DecodeBool() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *jsonDecDriver) ReadMapStart() int {
|
func (d *jsonDecDriver) ReadMapStart() int {
|
||||||
|
if c := d.s.sc.sep(); c != 0 {
|
||||||
|
d.expectChar(c)
|
||||||
|
}
|
||||||
|
d.s.start('}')
|
||||||
d.expectChar('{')
|
d.expectChar('{')
|
||||||
d.ct = valueTypeMap
|
d.ct = valueTypeMap
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *jsonDecDriver) ReadArrayStart() int {
|
func (d *jsonDecDriver) ReadArrayStart() int {
|
||||||
|
if c := d.s.sc.sep(); c != 0 {
|
||||||
|
d.expectChar(c)
|
||||||
|
}
|
||||||
|
d.s.start(']')
|
||||||
d.expectChar('[')
|
d.expectChar('[')
|
||||||
d.ct = valueTypeArray
|
d.ct = valueTypeArray
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
func (d *jsonDecDriver) ReadMapEnd() {
|
|
||||||
d.expectChar('}')
|
func (d *jsonDecDriver) ReadEnd() {
|
||||||
}
|
b := d.s.sc.st
|
||||||
func (d *jsonDecDriver) ReadArrayEnd() {
|
d.s.end()
|
||||||
d.expectChar(']')
|
d.expectChar(b)
|
||||||
}
|
|
||||||
func (d *jsonDecDriver) ReadArrayEntrySeparator() {
|
|
||||||
d.expectChar(',')
|
|
||||||
}
|
|
||||||
func (d *jsonDecDriver) ReadMapEntrySeparator() {
|
|
||||||
d.expectChar(',')
|
|
||||||
}
|
|
||||||
func (d *jsonDecDriver) ReadMapKVSeparator() {
|
|
||||||
d.expectChar(':')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *jsonDecDriver) expectChar(c uint8) {
|
func (d *jsonDecDriver) expectChar(c uint8) {
|
||||||
b := d.skipWhitespace(false)
|
b := d.skipWhitespace(false)
|
||||||
if b != c {
|
if b != c {
|
||||||
d.d.errorf("json: expect char %c but got char %c", c, b)
|
d.d.errorf("json: expect char '%c' but got char '%c'", c, b)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if jsonTrackSkipWhitespace {
|
if jsonTrackSkipWhitespace {
|
||||||
|
@ -462,6 +623,17 @@ func (d *jsonDecDriver) expectChar(c uint8) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// func (d *jsonDecDriver) maybeChar(c uint8) {
|
||||||
|
// b := d.skipWhitespace(false)
|
||||||
|
// if b != c {
|
||||||
|
// d.r.unreadn1()
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// if jsonTrackSkipWhitespace {
|
||||||
|
// d.wsSkipped = false
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
func (d *jsonDecDriver) IsContainerType(vt valueType) bool {
|
func (d *jsonDecDriver) IsContainerType(vt valueType) bool {
|
||||||
// check container type by checking the first char
|
// check container type by checking the first char
|
||||||
if d.ct == valueTypeUnset {
|
if d.ct == valueTypeUnset {
|
||||||
|
@ -635,6 +807,9 @@ LOOP:
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *jsonDecDriver) DecodeInt(bitsize uint8) (i int64) {
|
func (d *jsonDecDriver) DecodeInt(bitsize uint8) (i int64) {
|
||||||
|
if c := d.s.sc.sep(); c != 0 {
|
||||||
|
d.expectChar(c)
|
||||||
|
}
|
||||||
d.decNum(false)
|
d.decNum(false)
|
||||||
n := &d.n
|
n := &d.n
|
||||||
if n.manOverflow {
|
if n.manOverflow {
|
||||||
|
@ -667,6 +842,9 @@ func (d *jsonDecDriver) DecodeInt(bitsize uint8) (i int64) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *jsonDecDriver) DecodeUint(bitsize uint8) (u uint64) {
|
func (d *jsonDecDriver) DecodeUint(bitsize uint8) (u uint64) {
|
||||||
|
if c := d.s.sc.sep(); c != 0 {
|
||||||
|
d.expectChar(c)
|
||||||
|
}
|
||||||
d.decNum(false)
|
d.decNum(false)
|
||||||
n := &d.n
|
n := &d.n
|
||||||
if n.neg {
|
if n.neg {
|
||||||
|
@ -698,6 +876,9 @@ func (d *jsonDecDriver) DecodeUint(bitsize uint8) (u uint64) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *jsonDecDriver) DecodeFloat(chkOverflow32 bool) (f float64) {
|
func (d *jsonDecDriver) DecodeFloat(chkOverflow32 bool) (f float64) {
|
||||||
|
if c := d.s.sc.sep(); c != 0 {
|
||||||
|
d.expectChar(c)
|
||||||
|
}
|
||||||
d.decNum(true)
|
d.decNum(true)
|
||||||
n := &d.n
|
n := &d.n
|
||||||
f = n.floatVal()
|
f = n.floatVal()
|
||||||
|
@ -709,6 +890,10 @@ func (d *jsonDecDriver) DecodeFloat(chkOverflow32 bool) (f float64) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *jsonDecDriver) DecodeExt(rv interface{}, xtag uint64, ext Ext) (realxtag uint64) {
|
func (d *jsonDecDriver) DecodeExt(rv interface{}, xtag uint64, ext Ext) (realxtag uint64) {
|
||||||
|
// No need to call sep here, as d.d.decode() handles it
|
||||||
|
// if c := d.s.sc.sep(); c != 0 {
|
||||||
|
// d.expectChar(c)
|
||||||
|
// }
|
||||||
if ext == nil {
|
if ext == nil {
|
||||||
re := rv.(*RawExt)
|
re := rv.(*RawExt)
|
||||||
re.Tag = xtag
|
re.Tag = xtag
|
||||||
|
@ -722,14 +907,26 @@ func (d *jsonDecDriver) DecodeExt(rv interface{}, xtag uint64, ext Ext) (realxta
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *jsonDecDriver) DecodeBytes(bs []byte, isstring, zerocopy bool) (bsOut []byte) {
|
func (d *jsonDecDriver) DecodeBytes(bs []byte, isstring, zerocopy bool) (bsOut []byte) {
|
||||||
// zerocopy doesn't matter for json, as the bytes must be parsed.
|
// if decoding into raw bytes, and the RawBytesExt is configured, use it to decode.
|
||||||
|
if !isstring && d.se.i != nil {
|
||||||
|
bsOut = bs
|
||||||
|
d.DecodeExt(&bsOut, 0, &d.se)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if c := d.s.sc.sep(); c != 0 {
|
||||||
|
d.expectChar(c)
|
||||||
|
}
|
||||||
bs0 := d.appendStringAsBytes(d.b[:0])
|
bs0 := d.appendStringAsBytes(d.b[:0])
|
||||||
|
// if isstring, then just return the bytes, even if it is using the scratch buffer.
|
||||||
|
// the bytes will be converted to a string as needed.
|
||||||
if isstring {
|
if isstring {
|
||||||
return bs0
|
return bs0
|
||||||
}
|
}
|
||||||
slen := base64.StdEncoding.DecodedLen(len(bs0))
|
slen := base64.StdEncoding.DecodedLen(len(bs0))
|
||||||
if cap(bs) >= slen {
|
if slen <= cap(bs) {
|
||||||
bsOut = bs[:slen]
|
bsOut = bs[:slen]
|
||||||
|
} else if zerocopy && slen <= cap(d.b2) {
|
||||||
|
bsOut = d.b2[:slen]
|
||||||
} else {
|
} else {
|
||||||
bsOut = make([]byte, slen)
|
bsOut = make([]byte, slen)
|
||||||
}
|
}
|
||||||
|
@ -745,6 +942,9 @@ func (d *jsonDecDriver) DecodeBytes(bs []byte, isstring, zerocopy bool) (bsOut [
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *jsonDecDriver) DecodeString() (s string) {
|
func (d *jsonDecDriver) DecodeString() (s string) {
|
||||||
|
if c := d.s.sc.sep(); c != 0 {
|
||||||
|
d.expectChar(c)
|
||||||
|
}
|
||||||
return string(d.appendStringAsBytes(d.b[:0]))
|
return string(d.appendStringAsBytes(d.b[:0]))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -816,6 +1016,9 @@ func (d *jsonDecDriver) jsonU4(checkSlashU bool) rune {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *jsonDecDriver) DecodeNaked() (v interface{}, vt valueType, decodeFurther bool) {
|
func (d *jsonDecDriver) DecodeNaked() (v interface{}, vt valueType, decodeFurther bool) {
|
||||||
|
if c := d.s.sc.sep(); c != 0 {
|
||||||
|
d.expectChar(c)
|
||||||
|
}
|
||||||
n := d.skipWhitespace(true)
|
n := d.skipWhitespace(true)
|
||||||
switch n {
|
switch n {
|
||||||
case 'n':
|
case 'n':
|
||||||
|
@ -837,7 +1040,7 @@ func (d *jsonDecDriver) DecodeNaked() (v interface{}, vt valueType, decodeFurthe
|
||||||
decodeFurther = true
|
decodeFurther = true
|
||||||
case '"':
|
case '"':
|
||||||
vt = valueTypeString
|
vt = valueTypeString
|
||||||
v = d.DecodeString()
|
v = string(d.appendStringAsBytes(d.b[:0])) // same as d.DecodeString(), but skipping sep() call.
|
||||||
default: // number
|
default: // number
|
||||||
d.decNum(true)
|
d.decNum(true)
|
||||||
n := &d.n
|
n := &d.n
|
||||||
|
@ -878,6 +1081,9 @@ func (d *jsonDecDriver) DecodeNaked() (v interface{}, vt valueType, decodeFurthe
|
||||||
}
|
}
|
||||||
// fmt.Printf("DecodeNaked: Number: %T, %v\n", v, v)
|
// fmt.Printf("DecodeNaked: Number: %T, %v\n", v, v)
|
||||||
}
|
}
|
||||||
|
if decodeFurther {
|
||||||
|
d.s.sc.retryRead()
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -887,7 +1093,8 @@ func (d *jsonDecDriver) DecodeNaked() (v interface{}, vt valueType, decodeFurthe
|
||||||
//
|
//
|
||||||
// Json is comprehensively supported:
|
// Json is comprehensively supported:
|
||||||
// - decodes numbers into interface{} as int, uint or float64
|
// - decodes numbers into interface{} as int, uint or float64
|
||||||
// - encodes and decodes []byte using base64 Std Encoding
|
// - configurable way to encode/decode []byte .
|
||||||
|
// by default, encodes and decodes []byte using base64 Std Encoding
|
||||||
// - UTF-8 support for encoding and decoding
|
// - UTF-8 support for encoding and decoding
|
||||||
//
|
//
|
||||||
// It has better performance than the json library in the standard library,
|
// It has better performance than the json library in the standard library,
|
||||||
|
@ -901,19 +1108,29 @@ func (d *jsonDecDriver) DecodeNaked() (v interface{}, vt valueType, decodeFurthe
|
||||||
type JsonHandle struct {
|
type JsonHandle struct {
|
||||||
BasicHandle
|
BasicHandle
|
||||||
textEncodingType
|
textEncodingType
|
||||||
|
// RawBytesExt, if configured, is used to encode and decode raw bytes in a custom way.
|
||||||
|
// If not configured, raw bytes are encoded to/from base64 text.
|
||||||
|
RawBytesExt InterfaceExt
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *JsonHandle) newEncDriver(e *Encoder) encDriver {
|
func (h *JsonHandle) newEncDriver(e *Encoder) encDriver {
|
||||||
return &jsonEncDriver{e: e, w: e.w, h: h}
|
hd := jsonEncDriver{e: e, w: e.w, h: h}
|
||||||
|
hd.se.i = h.RawBytesExt
|
||||||
|
return &hd
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *JsonHandle) newDecDriver(d *Decoder) decDriver {
|
func (h *JsonHandle) newDecDriver(d *Decoder) decDriver {
|
||||||
// d := jsonDecDriver{r: r.(*bytesDecReader), h: h}
|
// d := jsonDecDriver{r: r.(*bytesDecReader), h: h}
|
||||||
hd := jsonDecDriver{d: d, r: d.r, h: h}
|
hd := jsonDecDriver{d: d, r: d.r, h: h}
|
||||||
|
hd.se.i = h.RawBytesExt
|
||||||
hd.n.bytes = d.b[:]
|
hd.n.bytes = d.b[:]
|
||||||
return &hd
|
return &hd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *JsonHandle) SetInterfaceExt(rt reflect.Type, tag uint64, ext InterfaceExt) (err error) {
|
||||||
|
return h.SetExt(rt, tag, &setExtWrapper{i: ext})
|
||||||
|
}
|
||||||
|
|
||||||
var jsonEncodeTerminate = []byte{' '}
|
var jsonEncodeTerminate = []byte{' '}
|
||||||
|
|
||||||
func (h *JsonHandle) rpcEncodeTerminate() []byte {
|
func (h *JsonHandle) rpcEncodeTerminate() []byte {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style license found in the LICENSE file.
|
// Use of this source code is governed by a MIT license found in the LICENSE file.
|
||||||
|
|
||||||
/*
|
/*
|
||||||
MSGPACK
|
MSGPACK
|
||||||
|
@ -24,6 +24,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"math"
|
"math"
|
||||||
"net/rpc"
|
"net/rpc"
|
||||||
|
"reflect"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -536,16 +537,12 @@ func (d *msgpackDecDriver) DecodeBytes(bs []byte, isstring, zerocopy bool) (bsOu
|
||||||
d.readNextBd()
|
d.readNextBd()
|
||||||
}
|
}
|
||||||
var clen int
|
var clen int
|
||||||
if isstring {
|
// ignore isstring. Expect that the bytes may be found from msgpackContainerStr or msgpackContainerBin
|
||||||
clen = d.readContainerLen(msgpackContainerStr)
|
|
||||||
} else {
|
|
||||||
// bytes can be decoded from msgpackContainerStr or msgpackContainerBin
|
|
||||||
if bd := d.bd; bd == mpBin8 || bd == mpBin16 || bd == mpBin32 {
|
if bd := d.bd; bd == mpBin8 || bd == mpBin16 || bd == mpBin32 {
|
||||||
clen = d.readContainerLen(msgpackContainerBin)
|
clen = d.readContainerLen(msgpackContainerBin)
|
||||||
} else {
|
} else {
|
||||||
clen = d.readContainerLen(msgpackContainerStr)
|
clen = d.readContainerLen(msgpackContainerStr)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// println("DecodeBytes: clen: ", clen)
|
// println("DecodeBytes: clen: ", clen)
|
||||||
d.bdRead = false
|
d.bdRead = false
|
||||||
// bytes may be nil, so handle it. if nil, clen=-1.
|
// bytes may be nil, so handle it. if nil, clen=-1.
|
||||||
|
@ -617,7 +614,7 @@ func (d *msgpackDecDriver) readContainerLen(ct msgpackContainerType) (clen int)
|
||||||
} else if (ct.bFixMin & bd) == ct.bFixMin {
|
} else if (ct.bFixMin & bd) == ct.bFixMin {
|
||||||
clen = int(ct.bFixMin ^ bd)
|
clen = int(ct.bFixMin ^ bd)
|
||||||
} else {
|
} else {
|
||||||
d.d.errorf("readContainerLen: %s: hex: %x, dec: %d", msgBadDesc, bd, bd)
|
d.d.errorf("readContainerLen: %s: hex: %x, decimal: %d", msgBadDesc, bd, bd)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
d.bdRead = false
|
d.bdRead = false
|
||||||
|
@ -730,6 +727,10 @@ func (h *MsgpackHandle) newDecDriver(d *Decoder) decDriver {
|
||||||
return &msgpackDecDriver{d: d, r: d.r, h: h, br: d.bytes}
|
return &msgpackDecDriver{d: d, r: d.r, h: h, br: d.bytes}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *MsgpackHandle) SetBytesExt(rt reflect.Type, tag uint64, ext BytesExt) (err error) {
|
||||||
|
return h.SetExt(rt, tag, &setExtWrapper{b: ext})
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
type msgpackSpecRpcCodec struct {
|
type msgpackSpecRpcCodec struct {
|
||||||
|
@ -781,7 +782,7 @@ func (c *msgpackSpecRpcCodec) ReadRequestBody(body interface{}) error {
|
||||||
|
|
||||||
func (c *msgpackSpecRpcCodec) parseCustomHeader(expectTypeByte byte, msgid *uint64, methodOrError *string) (err error) {
|
func (c *msgpackSpecRpcCodec) parseCustomHeader(expectTypeByte byte, msgid *uint64, methodOrError *string) (err error) {
|
||||||
|
|
||||||
if c.cls {
|
if c.isClosed() {
|
||||||
return io.EOF
|
return io.EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style license found in the LICENSE file.
|
// Use of this source code is governed by a MIT license found in the LICENSE file.
|
||||||
|
|
||||||
package codec
|
package codec
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ import (
|
||||||
// NoopHandle returns a no-op handle. It basically does nothing.
|
// NoopHandle returns a no-op handle. It basically does nothing.
|
||||||
// It is only useful for benchmarking, as it gives an idea of the
|
// It is only useful for benchmarking, as it gives an idea of the
|
||||||
// overhead from the codec framework.
|
// overhead from the codec framework.
|
||||||
|
//
|
||||||
// LIBRARY USERS: *** DO NOT USE ***
|
// LIBRARY USERS: *** DO NOT USE ***
|
||||||
func NoopHandle(slen int) *noopHandle {
|
func NoopHandle(slen int) *noopHandle {
|
||||||
h := noopHandle{}
|
h := noopHandle{}
|
||||||
|
@ -40,7 +41,8 @@ type noopDrv struct {
|
||||||
i int
|
i int
|
||||||
S []string
|
S []string
|
||||||
B [][]byte
|
B [][]byte
|
||||||
mk bool // are we about to read a map key?
|
mks []bool // stack. if map (true), else if array (false)
|
||||||
|
mk bool // top of stack. what container are we on? map or array?
|
||||||
ct valueType // last request for IsContainerType.
|
ct valueType // last request for IsContainerType.
|
||||||
cb bool // last response for IsContainerType.
|
cb bool // last response for IsContainerType.
|
||||||
rand *rand.Rand
|
rand *rand.Rand
|
||||||
|
@ -54,6 +56,22 @@ func (h *noopDrv) newDecDriver(_ *Decoder) decDriver { return h }
|
||||||
|
|
||||||
// --- encDriver
|
// --- encDriver
|
||||||
|
|
||||||
|
// stack functions (for map and array)
|
||||||
|
func (h *noopDrv) start(b bool) {
|
||||||
|
// println("start", len(h.mks)+1)
|
||||||
|
h.mks = append(h.mks, b)
|
||||||
|
h.mk = b
|
||||||
|
}
|
||||||
|
func (h *noopDrv) end() {
|
||||||
|
// println("end: ", len(h.mks)-1)
|
||||||
|
h.mks = h.mks[:len(h.mks)-1]
|
||||||
|
if len(h.mks) > 0 {
|
||||||
|
h.mk = h.mks[len(h.mks)-1]
|
||||||
|
} else {
|
||||||
|
h.mk = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (h *noopDrv) EncodeBuiltin(rt uintptr, v interface{}) {}
|
func (h *noopDrv) EncodeBuiltin(rt uintptr, v interface{}) {}
|
||||||
func (h *noopDrv) EncodeNil() {}
|
func (h *noopDrv) EncodeNil() {}
|
||||||
func (h *noopDrv) EncodeInt(i int64) {}
|
func (h *noopDrv) EncodeInt(i int64) {}
|
||||||
|
@ -62,13 +80,10 @@ func (h *noopDrv) EncodeBool(b bool) {}
|
||||||
func (h *noopDrv) EncodeFloat32(f float32) {}
|
func (h *noopDrv) EncodeFloat32(f float32) {}
|
||||||
func (h *noopDrv) EncodeFloat64(f float64) {}
|
func (h *noopDrv) EncodeFloat64(f float64) {}
|
||||||
func (h *noopDrv) EncodeRawExt(re *RawExt, e *Encoder) {}
|
func (h *noopDrv) EncodeRawExt(re *RawExt, e *Encoder) {}
|
||||||
func (h *noopDrv) EncodeArrayStart(length int) {}
|
func (h *noopDrv) EncodeArrayStart(length int) { h.start(true) }
|
||||||
func (h *noopDrv) EncodeArrayEnd() {}
|
func (h *noopDrv) EncodeMapStart(length int) { h.start(false) }
|
||||||
func (h *noopDrv) EncodeArrayEntrySeparator() {}
|
func (h *noopDrv) EncodeEnd() { h.end() }
|
||||||
func (h *noopDrv) EncodeMapStart(length int) {}
|
|
||||||
func (h *noopDrv) EncodeMapEnd() {}
|
|
||||||
func (h *noopDrv) EncodeMapEntrySeparator() {}
|
|
||||||
func (h *noopDrv) EncodeMapKVSeparator() {}
|
|
||||||
func (h *noopDrv) EncodeString(c charEncoding, v string) {}
|
func (h *noopDrv) EncodeString(c charEncoding, v string) {}
|
||||||
func (h *noopDrv) EncodeSymbol(v string) {}
|
func (h *noopDrv) EncodeSymbol(v string) {}
|
||||||
func (h *noopDrv) EncodeStringBytes(c charEncoding, v []byte) {}
|
func (h *noopDrv) EncodeStringBytes(c charEncoding, v []byte) {}
|
||||||
|
@ -90,15 +105,11 @@ func (h *noopDrv) DecodeString() (s string) { return h.S[h.m(8
|
||||||
|
|
||||||
func (h *noopDrv) DecodeBytes(bs []byte, isstring, zerocopy bool) []byte { return h.B[h.m(len(h.B))] }
|
func (h *noopDrv) DecodeBytes(bs []byte, isstring, zerocopy bool) []byte { return h.B[h.m(len(h.B))] }
|
||||||
|
|
||||||
func (h *noopDrv) ReadMapEnd() { h.mk = false }
|
func (h *noopDrv) ReadEnd() { h.end() }
|
||||||
func (h *noopDrv) ReadArrayEnd() {}
|
|
||||||
func (h *noopDrv) ReadArrayEntrySeparator() {}
|
|
||||||
func (h *noopDrv) ReadMapEntrySeparator() { h.mk = true }
|
|
||||||
func (h *noopDrv) ReadMapKVSeparator() { h.mk = false }
|
|
||||||
|
|
||||||
// toggle map/slice
|
// toggle map/slice
|
||||||
func (h *noopDrv) ReadMapStart() int { h.mk = true; return h.m(10) }
|
func (h *noopDrv) ReadMapStart() int { h.start(true); return h.m(10) }
|
||||||
func (h *noopDrv) ReadArrayStart() int { return h.m(10) }
|
func (h *noopDrv) ReadArrayStart() int { h.start(false); return h.m(10) }
|
||||||
|
|
||||||
func (h *noopDrv) IsContainerType(vt valueType) bool {
|
func (h *noopDrv) IsContainerType(vt valueType) bool {
|
||||||
// return h.m(2) == 0
|
// return h.m(2) == 0
|
||||||
|
|
|
@ -54,7 +54,7 @@ _build() {
|
||||||
|
|
||||||
cat > gen.generated.go <<EOF
|
cat > gen.generated.go <<EOF
|
||||||
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style license found in the LICENSE file.
|
// Use of this source code is governed by a MIT license found in the LICENSE file.
|
||||||
|
|
||||||
package codec
|
package codec
|
||||||
|
|
||||||
|
@ -90,8 +90,8 @@ func fastpathEncodeTypeSwitchMap(iv interface{}, e *Encoder) bool { return false
|
||||||
type fastpathE struct {
|
type fastpathE struct {
|
||||||
rtid uintptr
|
rtid uintptr
|
||||||
rt reflect.Type
|
rt reflect.Type
|
||||||
encfn func(encFnInfo, reflect.Value)
|
encfn func(*encFnInfo, reflect.Value)
|
||||||
decfn func(decFnInfo, reflect.Value)
|
decfn func(*decFnInfo, reflect.Value)
|
||||||
}
|
}
|
||||||
type fastpathA [0]fastpathE
|
type fastpathA [0]fastpathE
|
||||||
func (x fastpathA) index(rtid uintptr) int { return -1 }
|
func (x fastpathA) index(rtid uintptr) int { return -1 }
|
||||||
|
@ -135,16 +135,18 @@ EOF
|
||||||
|
|
||||||
_codegenerators() {
|
_codegenerators() {
|
||||||
if [[ $zforce == "1" ||
|
if [[ $zforce == "1" ||
|
||||||
"1" == $( _needgen "values_msgp${zsfx}" )
|
"1" == $( _needgen "values_codecgen${zsfx}" ) ||
|
||||||
|| "1" == $( _needgen "values_codecgen${zsfx}" ) ]]
|
"1" == $( _needgen "values_msgp${zsfx}" ) ||
|
||||||
|
"1" == $( _needgen "values_ffjson${zsfx}" ) ||
|
||||||
|
1 == 0 ]]
|
||||||
then
|
then
|
||||||
true && \
|
true && \
|
||||||
|
echo "codecgen - !unsafe ... " && \
|
||||||
|
codecgen -rt codecgen -t 'x,codecgen,!unsafe' -o values_codecgen${zsfx} -d 1978 $zfin && \
|
||||||
|
echo "codecgen - unsafe ... " && \
|
||||||
|
codecgen -u -rt codecgen -t 'x,codecgen,unsafe' -o values_codecgen_unsafe${zsfx} -d 1978 $zfin && \
|
||||||
echo "msgp ... " && \
|
echo "msgp ... " && \
|
||||||
msgp -tests=false -pkg=codec -o=values_msgp${zsfx} -file=$zfin && \
|
msgp -tests=false -pkg=codec -o=values_msgp${zsfx} -file=$zfin && \
|
||||||
echo "codecgen - !unsafe ... " && \
|
|
||||||
codecgen -rt codecgen -t 'x,codecgen,!unsafe' -o values_codecgen${zsfx} $zfin && \
|
|
||||||
echo "codecgen - unsafe ... " && \
|
|
||||||
codecgen -u -rt codecgen -t 'x,codecgen,unsafe' -o values_codecgen_unsafe${zsfx} $zfin && \
|
|
||||||
echo "ffjson ... " && \
|
echo "ffjson ... " && \
|
||||||
ffjson -w values_ffjson${zsfx} $zfin && \
|
ffjson -w values_ffjson${zsfx} $zfin && \
|
||||||
# remove (M|Unm)arshalJSON implementations, so they don't conflict with encoding/json bench \
|
# remove (M|Unm)arshalJSON implementations, so they don't conflict with encoding/json bench \
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
//+build x
|
//+build x
|
||||||
|
|
||||||
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style license found in the LICENSE file.
|
// Use of this source code is governed by a MIT license found in the LICENSE file.
|
||||||
|
|
||||||
package codec
|
package codec
|
||||||
|
|
||||||
// These tests are used to verify msgpack and cbor implementations against their python libraries.
|
// These tests are used to verify msgpack and cbor implementations against their python libraries.
|
||||||
// If you have the library installed, you can enable the tests back by removing the //+build ignore.
|
// If you have the library installed, you can enable the tests back by running: go test -tags=x .
|
||||||
|
// Look at test.py for how to setup your environment.
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style license found in the LICENSE file.
|
// Use of this source code is governed by a MIT license found in the LICENSE file.
|
||||||
|
|
||||||
package codec
|
package codec
|
||||||
|
|
||||||
|
@ -43,8 +43,10 @@ type rpcCodec struct {
|
||||||
bw *bufio.Writer
|
bw *bufio.Writer
|
||||||
br *bufio.Reader
|
br *bufio.Reader
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
cls bool
|
|
||||||
h Handle
|
h Handle
|
||||||
|
|
||||||
|
cls bool
|
||||||
|
clsmu sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func newRPCCodec(conn io.ReadWriteCloser, h Handle) rpcCodec {
|
func newRPCCodec(conn io.ReadWriteCloser, h Handle) rpcCodec {
|
||||||
|
@ -69,7 +71,7 @@ func (c *rpcCodec) BufferedWriter() *bufio.Writer {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *rpcCodec) write(obj1, obj2 interface{}, writeObj2, doFlush bool) (err error) {
|
func (c *rpcCodec) write(obj1, obj2 interface{}, writeObj2, doFlush bool) (err error) {
|
||||||
if c.cls {
|
if c.isClosed() {
|
||||||
return io.EOF
|
return io.EOF
|
||||||
}
|
}
|
||||||
if err = c.enc.Encode(obj1); err != nil {
|
if err = c.enc.Encode(obj1); err != nil {
|
||||||
|
@ -94,7 +96,7 @@ func (c *rpcCodec) write(obj1, obj2 interface{}, writeObj2, doFlush bool) (err e
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *rpcCodec) read(obj interface{}) (err error) {
|
func (c *rpcCodec) read(obj interface{}) (err error) {
|
||||||
if c.cls {
|
if c.isClosed() {
|
||||||
return io.EOF
|
return io.EOF
|
||||||
}
|
}
|
||||||
//If nil is passed in, we should still attempt to read content to nowhere.
|
//If nil is passed in, we should still attempt to read content to nowhere.
|
||||||
|
@ -105,11 +107,20 @@ func (c *rpcCodec) read(obj interface{}) (err error) {
|
||||||
return c.dec.Decode(obj)
|
return c.dec.Decode(obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *rpcCodec) isClosed() bool {
|
||||||
|
c.clsmu.RLock()
|
||||||
|
x := c.cls
|
||||||
|
c.clsmu.RUnlock()
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
func (c *rpcCodec) Close() error {
|
func (c *rpcCodec) Close() error {
|
||||||
if c.cls {
|
if c.isClosed() {
|
||||||
return io.EOF
|
return io.EOF
|
||||||
}
|
}
|
||||||
|
c.clsmu.Lock()
|
||||||
c.cls = true
|
c.cls = true
|
||||||
|
c.clsmu.Unlock()
|
||||||
return c.rwc.Close()
|
return c.rwc.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style license found in the LICENSE file.
|
// Use of this source code is governed by a MIT license found in the LICENSE file.
|
||||||
|
|
||||||
package codec
|
package codec
|
||||||
|
|
||||||
import "math"
|
import (
|
||||||
|
"math"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
_ uint8 = iota
|
_ uint8 = iota
|
||||||
|
@ -77,7 +80,7 @@ func (e *simpleEncDriver) encUint(v uint64, bd uint8) {
|
||||||
} else if v <= math.MaxUint32 {
|
} else if v <= math.MaxUint32 {
|
||||||
e.w.writen1(bd + 2)
|
e.w.writen1(bd + 2)
|
||||||
bigenHelper{e.b[:4], e.w}.writeUint32(uint32(v))
|
bigenHelper{e.b[:4], e.w}.writeUint32(uint32(v))
|
||||||
} else if v <= math.MaxUint64 {
|
} else { // if v <= math.MaxUint64 {
|
||||||
e.w.writen1(bd + 3)
|
e.w.writen1(bd + 3)
|
||||||
bigenHelper{e.b[:8], e.w}.writeUint64(v)
|
bigenHelper{e.b[:8], e.w}.writeUint64(v)
|
||||||
}
|
}
|
||||||
|
@ -501,5 +504,9 @@ func (h *SimpleHandle) newDecDriver(d *Decoder) decDriver {
|
||||||
return &simpleDecDriver{d: d, r: d.r, h: h, br: d.bytes}
|
return &simpleDecDriver{d: d, r: d.r, h: h, br: d.bytes}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *SimpleHandle) SetBytesExt(rt reflect.Type, tag uint64, ext BytesExt) (err error) {
|
||||||
|
return h.SetExt(rt, tag, &setExtWrapper{b: ext})
|
||||||
|
}
|
||||||
|
|
||||||
var _ decDriver = (*simpleDecDriver)(nil)
|
var _ decDriver = (*simpleDecDriver)(nil)
|
||||||
var _ encDriver = (*simpleEncDriver)(nil)
|
var _ encDriver = (*simpleEncDriver)(nil)
|
||||||
|
|
|
@ -5,8 +5,9 @@
|
||||||
# So it can process them (so we don't have to checkin the files).
|
# So it can process them (so we don't have to checkin the files).
|
||||||
|
|
||||||
# Ensure msgpack-python and cbor are installed first, using:
|
# Ensure msgpack-python and cbor are installed first, using:
|
||||||
# pip install --user msgpack-python
|
# sudo apt-get install python-dev
|
||||||
# pip install --user cbor
|
# sudo apt-get install python-pip
|
||||||
|
# pip install --user msgpack-python msgpack-rpc-python cbor
|
||||||
|
|
||||||
import cbor, msgpack, msgpackrpc, sys, os, threading
|
import cbor, msgpack, msgpackrpc, sys, os, threading
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Run all the different permutations of all the tests.
|
||||||
|
# This helps ensure that nothing gets broken.
|
||||||
|
|
||||||
|
_run() {
|
||||||
|
# 1. VARIATIONS: regular (t), canonical (c), IO R/W (i), binc-nosymbols (n), struct2array (s)
|
||||||
|
# 2. MODE: reflection (r), codecgen (x), codecgen+unsafe (u)
|
||||||
|
#
|
||||||
|
# Typically, you would run a combination of one value from a and b.
|
||||||
|
|
||||||
|
ztags=""
|
||||||
|
local OPTIND
|
||||||
|
OPTIND=1
|
||||||
|
while getopts "xurtcinsvg" flag
|
||||||
|
do
|
||||||
|
case "x$flag" in
|
||||||
|
'xr') ;;
|
||||||
|
'xg') ztags="$ztags codecgen" ;;
|
||||||
|
'xx') ztags="$ztags x" ;;
|
||||||
|
'xu') ztags="$ztags unsafe" ;;
|
||||||
|
'xv') zverbose="-tv" ;;
|
||||||
|
*) ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
# shift $((OPTIND-1))
|
||||||
|
printf '............. TAGS: %s .............\n' "$ztags"
|
||||||
|
# echo ">>>>>>> TAGS: $ztags"
|
||||||
|
|
||||||
|
OPTIND=1
|
||||||
|
while getopts "xurtcinsvg" flag
|
||||||
|
do
|
||||||
|
case "x$flag" in
|
||||||
|
'xt') printf ">>>>>>> REGULAR : "; go test "-tags=$ztags" "$zverbose" ; sleep 2 ;;
|
||||||
|
'xc') printf ">>>>>>> CANONICAL : "; go test "-tags=$ztags" "$zverbose" -tc; sleep 2 ;;
|
||||||
|
'xi') printf ">>>>>>> I/O : "; go test "-tags=$ztags" "$zverbose" -ti; sleep 2 ;;
|
||||||
|
'xn') printf ">>>>>>> NO_SYMBOLS : "; go test "-tags=$ztags" "$zverbose" -tn; sleep 2 ;;
|
||||||
|
'xs') printf ">>>>>>> TO_ARRAY : "; go test "-tags=$ztags" "$zverbose" -ts; sleep 2 ;;
|
||||||
|
*) ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
shift $((OPTIND-1))
|
||||||
|
|
||||||
|
OPTIND=1
|
||||||
|
}
|
||||||
|
|
||||||
|
# echo ">>>>>>> RUNNING VARIATIONS OF TESTS"
|
||||||
|
if [[ "x$@" = x ]]; then
|
||||||
|
# r, x, g, gu
|
||||||
|
_run "-rtcins"
|
||||||
|
_run "-xtcins"
|
||||||
|
_run "-gtcins"
|
||||||
|
_run "-gutcins"
|
||||||
|
else
|
||||||
|
_run "$@"
|
||||||
|
fi
|
|
@ -1,5 +1,5 @@
|
||||||
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style license found in the LICENSE file.
|
// Use of this source code is governed by a MIT license found in the LICENSE file.
|
||||||
|
|
||||||
package codec
|
package codec
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// // +build testing
|
// // +build testing
|
||||||
|
|
||||||
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style license found in the LICENSE file.
|
// Use of this source code is governed by a MIT license found in the LICENSE file.
|
||||||
|
|
||||||
package codec
|
package codec
|
||||||
|
|
||||||
|
@ -57,6 +57,11 @@ type TestStruc struct {
|
||||||
|
|
||||||
Iptrslice []*int64
|
Iptrslice []*int64
|
||||||
|
|
||||||
|
// TODO: test these separately, specifically for reflection and codecgen.
|
||||||
|
// Unfortunately, ffjson doesn't support these. Its compilation even fails.
|
||||||
|
// Ui64array [4]uint64
|
||||||
|
// Ui64slicearray [][4]uint64
|
||||||
|
|
||||||
AnonInTestStruc
|
AnonInTestStruc
|
||||||
|
|
||||||
//M map[interface{}]interface{} `json:"-",bson:"-"`
|
//M map[interface{}]interface{} `json:"-",bson:"-"`
|
||||||
|
|
Loading…
Reference in New Issue