Merge pull request #15534 from wojtek-t/update_goetcd_and_ugorji

Update github.com/coreos/go-etcd and github.com/ugorji/go/codec dependencies
pull/6/head
Dawn Chen 2015-10-13 16:25:02 -07:00
commit 9b45ed8897
39 changed files with 6112 additions and 9681 deletions

6
Godeps/Godeps.json generated
View File

@ -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",

View File

@ -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() {

View File

@ -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))
} }

View File

@ -348,7 +348,7 @@ func DefaultCheckRetry(cluster *Cluster, numReqs int, lastResp http.Response,
} }
// sleep some time and expect leader election finish // sleep some time and expect leader election finish
time.Sleep(time.Millisecond * 200) time.Sleep(time.Millisecond * 200)
logger.Warning("bad response status code", lastResp.StatusCode) logger.Warning("bad response status code ", lastResp.StatusCode)
return nil return nil
} }

File diff suppressed because it is too large Load Diff

View File

@ -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
}

View File

@ -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

View File

@ -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)

View File

@ -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) {
e.encLen(cborBaseBytes, len(v)) if c == c_RAW {
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)

View File

@ -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

View File

@ -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)
} }

View File

@ -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)

View File

@ -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

View File

@ -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 {
v = rv.Addr().Interface() // 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()
} 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,88 +456,38 @@ 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++ {
for j := 0; j < l; j++ { if f.seq == seqTypeChan {
if j > 0 { if rv2, ok2 := rv.Recv(); ok2 {
if ti.mbs { e.encodeValue(rv2, fn)
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++ {
if f.seq == seqTypeChan {
if rv2, ok2 := rv.Recv(); ok2 {
e.encodeValue(rv2, fn)
}
} else {
e.encodeValue(rv.Index(j), fn)
} }
} else {
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,60 +522,30 @@ 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 { if toMap {
ee.EncodeMapStart(newlen) ee.EncodeMapStart(newlen)
// asSymbols := e.h.AsSymbols&AsSymbolStructFieldNameFlag != 0 // asSymbols := e.h.AsSymbols&AsSymbolStructFieldNameFlag != 0
asSymbols := e.h.AsSymbols == AsSymbolDefault || e.h.AsSymbols&AsSymbolStructFieldNameFlag != 0 asSymbols := e.h.AsSymbols == AsSymbolDefault || e.h.AsSymbols&AsSymbolStructFieldNameFlag != 0
for j := 0; j < newlen; j++ { for j := 0; j < newlen; j++ {
kv = fkvs[j] kv = fkvs[j]
if j > 0 { if asSymbols {
ee.EncodeMapEntrySeparator() ee.EncodeSymbol(kv.k)
} } else {
if asSymbols { ee.EncodeString(c_UTF8, kv.k)
ee.EncodeSymbol(kv.k)
} else {
ee.EncodeString(c_UTF8, kv.k)
}
ee.EncodeMapKVSeparator()
e.encodeValue(kv.v, encFn{})
} }
ee.EncodeMapEnd() e.encodeValue(kv.v, nil)
} 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 { } else {
if toMap { ee.EncodeArrayStart(newlen)
ee.EncodeMapStart(newlen) for j := 0; j < newlen; j++ {
// asSymbols := e.h.AsSymbols&AsSymbolStructFieldNameFlag != 0 kv = fkvs[j]
asSymbols := e.h.AsSymbols == AsSymbolDefault || e.h.AsSymbols&AsSymbolStructFieldNameFlag != 0 e.encodeValue(kv.v, nil)
for j := 0; j < newlen; j++ {
kv = fkvs[j]
if asSymbols {
ee.EncodeSymbol(kv.k)
} else {
ee.EncodeString(c_UTF8, kv.k)
}
e.encodeValue(kv.v, encFn{})
}
} else {
ee.EncodeArrayStart(newlen)
for j := 0; j < newlen; j++ {
kv = fkvs[j]
e.encodeValue(kv.v, encFn{})
}
} }
} }
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
} }
@ -796,17 +677,21 @@ type rtidEncFn struct {
// An Encoder writes an object to an output stream in the codec format. // An Encoder writes an object to an output stream in the codec format.
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

View File

@ -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 {
for j, v2 := range v {
if j > 0 {
ee.EncodeArrayEntrySeparator()
}
{{ encmd .Elem "v2"}}
}
ee.EncodeArrayEnd()
} }
ee.EncodeEnd()
} }
{{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,32 +183,15 @@ 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) } else {
} else { ee.EncodeString(c_UTF8, k2)
ee.EncodeString(c_UTF8, k2) }{{else}}{{ encmd .MapKey "k2"}}{{end}}
}{{else}}{{ encmd .MapKey "k2"}}{{end}} {{ encmd .Elem "v2"}}
{{ encmd .Elem "v2"}}
}
} else {
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()
} }
ee.EncodeEnd()
} }
{{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,47 +258,59 @@ 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 {
if canChange && len(v) != 0 { if canChange && len(v) != 0 {
v = v[:0] v = v[:0]
changed = true changed = true
}{{/* }{{/*
// slh.End() // dd.ReadArrayEnd() // slh.End() // dd.ReadArrayEnd()
*/}} */}}
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
} }

View File

@ -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 }}

View File

@ -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?

View File

@ -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)
}

View File

@ -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)
}
{{/* {{/*

View File

@ -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

View File

@ -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 { // 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 converts a value to a []byte.
// It is used by codecs (e.g. binc, msgpack, simple) which do custom serialization of the types.
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 ||

View File

@ -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
}

View File

@ -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

View File

@ -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

View File

@ -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))
} }

View File

@ -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 {

View File

@ -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,15 +537,11 @@ 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) if bd := d.bd; bd == mpBin8 || bd == mpBin16 || bd == mpBin32 {
clen = d.readContainerLen(msgpackContainerBin)
} else { } else {
// bytes can be decoded from msgpackContainerStr or msgpackContainerBin clen = d.readContainerLen(msgpackContainerStr)
if bd := d.bd; bd == mpBin8 || bd == mpBin16 || bd == mpBin32 {
clen = d.readContainerLen(msgpackContainerBin)
} else {
clen = d.readContainerLen(msgpackContainerStr)
}
} }
// println("DecodeBytes: clen: ", clen) // println("DecodeBytes: clen: ", clen)
d.bdRead = false d.bdRead = false
@ -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
} }

View File

@ -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,21 +56,34 @@ func (h *noopDrv) newDecDriver(_ *Decoder) decDriver { return h }
// --- encDriver // --- encDriver
func (h *noopDrv) EncodeBuiltin(rt uintptr, v interface{}) {} // stack functions (for map and array)
func (h *noopDrv) EncodeNil() {} func (h *noopDrv) start(b bool) {
func (h *noopDrv) EncodeInt(i int64) {} // println("start", len(h.mks)+1)
func (h *noopDrv) EncodeUint(i uint64) {} h.mks = append(h.mks, b)
func (h *noopDrv) EncodeBool(b bool) {} h.mk = b
func (h *noopDrv) EncodeFloat32(f float32) {} }
func (h *noopDrv) EncodeFloat64(f float64) {} func (h *noopDrv) end() {
func (h *noopDrv) EncodeRawExt(re *RawExt, e *Encoder) {} // println("end: ", len(h.mks)-1)
func (h *noopDrv) EncodeArrayStart(length int) {} h.mks = h.mks[:len(h.mks)-1]
func (h *noopDrv) EncodeArrayEnd() {} if len(h.mks) > 0 {
func (h *noopDrv) EncodeArrayEntrySeparator() {} h.mk = h.mks[len(h.mks)-1]
func (h *noopDrv) EncodeMapStart(length int) {} } else {
func (h *noopDrv) EncodeMapEnd() {} h.mk = false
func (h *noopDrv) EncodeMapEntrySeparator() {} }
func (h *noopDrv) EncodeMapKVSeparator() {} }
func (h *noopDrv) EncodeBuiltin(rt uintptr, v interface{}) {}
func (h *noopDrv) EncodeNil() {}
func (h *noopDrv) EncodeInt(i int64) {}
func (h *noopDrv) EncodeUint(i uint64) {}
func (h *noopDrv) EncodeBool(b bool) {}
func (h *noopDrv) EncodeFloat32(f float32) {}
func (h *noopDrv) EncodeFloat64(f float64) {}
func (h *noopDrv) EncodeRawExt(re *RawExt, e *Encoder) {}
func (h *noopDrv) EncodeArrayStart(length int) { h.start(true) }
func (h *noopDrv) EncodeMapStart(length int) { h.start(false) }
func (h *noopDrv) EncodeEnd() { h.end() }
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

View File

@ -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 \

View File

@ -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"

View File

@ -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()
} }

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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:"-"`