This update provides:
1) workaround around the build failures. In
summary, it forces the download of some packages during the build
process.
2) update the set of packages that should go inside the vendor
directory
3) Update the dockerfile to use go 1.10
Change-Id: I2bfd090ce0f25b0c10aa214755ae2da7e5384d60
diff --git a/vendor/github.com/ugorji/go/codec/encode.go b/vendor/github.com/ugorji/go/codec/encode.go
new file mode 100644
index 0000000..ef46529
--- /dev/null
+++ b/vendor/github.com/ugorji/go/codec/encode.go
@@ -0,0 +1,1375 @@
+// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved.
+// Use of this source code is governed by a MIT license found in the LICENSE file.
+
+package codec
+
+import (
+ "bufio"
+ "encoding"
+ "errors"
+ "fmt"
+ "io"
+ "reflect"
+ "sort"
+ "strconv"
+ "sync"
+ "time"
+)
+
+const defEncByteBufSize = 1 << 6 // 4:16, 6:64, 8:256, 10:1024
+
+var errEncoderNotInitialized = errors.New("Encoder not initialized")
+
+// encWriter abstracts writing to a byte array or to an io.Writer.
+type encWriter interface {
+ writeb([]byte)
+ writestr(string)
+ writen1(byte)
+ writen2(byte, byte)
+ atEndOfEncode()
+}
+
+// encDriver abstracts the actual codec (binc vs msgpack, etc)
+type encDriver interface {
+ EncodeNil()
+ EncodeInt(i int64)
+ EncodeUint(i uint64)
+ EncodeBool(b bool)
+ EncodeFloat32(f float32)
+ EncodeFloat64(f float64)
+ // encodeExtPreamble(xtag byte, length int)
+ EncodeRawExt(re *RawExt, e *Encoder)
+ EncodeExt(v interface{}, xtag uint64, ext Ext, e *Encoder)
+ EncodeString(c charEncoding, v string)
+ // EncodeSymbol(v string)
+ EncodeStringBytes(c charEncoding, v []byte)
+ EncodeTime(time.Time)
+ //encBignum(f *big.Int)
+ //encStringRunes(c charEncoding, v []rune)
+ WriteArrayStart(length int)
+ WriteArrayElem()
+ WriteArrayEnd()
+ WriteMapStart(length int)
+ WriteMapElemKey()
+ WriteMapElemValue()
+ WriteMapEnd()
+
+ reset()
+ atEndOfEncode()
+}
+
+type ioEncStringWriter interface {
+ WriteString(s string) (n int, err error)
+}
+
+type encDriverAsis interface {
+ EncodeAsis(v []byte)
+}
+
+type encDriverNoopContainerWriter struct{}
+
+func (encDriverNoopContainerWriter) WriteArrayStart(length int) {}
+func (encDriverNoopContainerWriter) WriteArrayElem() {}
+func (encDriverNoopContainerWriter) WriteArrayEnd() {}
+func (encDriverNoopContainerWriter) WriteMapStart(length int) {}
+func (encDriverNoopContainerWriter) WriteMapElemKey() {}
+func (encDriverNoopContainerWriter) WriteMapElemValue() {}
+func (encDriverNoopContainerWriter) WriteMapEnd() {}
+func (encDriverNoopContainerWriter) atEndOfEncode() {}
+
+type encDriverTrackContainerWriter struct {
+ c containerState
+}
+
+func (e *encDriverTrackContainerWriter) WriteArrayStart(length int) { e.c = containerArrayStart }
+func (e *encDriverTrackContainerWriter) WriteArrayElem() { e.c = containerArrayElem }
+func (e *encDriverTrackContainerWriter) WriteArrayEnd() { e.c = containerArrayEnd }
+func (e *encDriverTrackContainerWriter) WriteMapStart(length int) { e.c = containerMapStart }
+func (e *encDriverTrackContainerWriter) WriteMapElemKey() { e.c = containerMapKey }
+func (e *encDriverTrackContainerWriter) WriteMapElemValue() { e.c = containerMapValue }
+func (e *encDriverTrackContainerWriter) WriteMapEnd() { e.c = containerMapEnd }
+func (e *encDriverTrackContainerWriter) atEndOfEncode() {}
+
+// type ioEncWriterWriter interface {
+// WriteByte(c byte) error
+// WriteString(s string) (n int, err error)
+// Write(p []byte) (n int, err error)
+// }
+
+// EncodeOptions captures configuration options during encode.
+type EncodeOptions struct {
+ // WriterBufferSize is the size of the buffer used when writing.
+ //
+ // if > 0, we use a smart buffer internally for performance purposes.
+ WriterBufferSize int
+
+ // ChanRecvTimeout is the timeout used when selecting from a chan.
+ //
+ // Configuring this controls how we receive from a chan during the encoding process.
+ // - If ==0, we only consume the elements currently available in the chan.
+ // - if <0, we consume until the chan is closed.
+ // - If >0, we consume until this timeout.
+ ChanRecvTimeout time.Duration
+
+ // StructToArray specifies to encode a struct as an array, and not as a map
+ StructToArray bool
+
+ // Canonical representation means that encoding a value will always result in the same
+ // sequence of bytes.
+ //
+ // This only affects maps, as the iteration order for maps is random.
+ //
+ // The implementation MAY use the natural sort order for the map keys if possible:
+ //
+ // - If there is a natural sort order (ie for number, bool, string or []byte keys),
+ // then the map keys are first sorted in natural order and then written
+ // with corresponding map values to the strema.
+ // - If there is no natural sort order, then 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
+
+ // CheckCircularRef controls whether we check for circular references
+ // and error fast during an encode.
+ //
+ // If enabled, an error is received if a pointer to a struct
+ // references itself either directly or through one of its fields (iteratively).
+ //
+ // This is opt-in, as there may be a performance hit to checking circular references.
+ CheckCircularRef bool
+
+ // RecursiveEmptyCheck controls whether we descend into interfaces, structs and pointers
+ // when checking if a value is empty.
+ //
+ // Note that this may make OmitEmpty more expensive, as it incurs a lot more reflect calls.
+ RecursiveEmptyCheck bool
+
+ // Raw controls whether we encode Raw values.
+ // This is a "dangerous" option and must be explicitly set.
+ // If set, we blindly encode Raw values as-is, without checking
+ // if they are a correct representation of a value in that format.
+ // If unset, we error out.
+ Raw bool
+
+ // // AsSymbols defines what should be encoded as symbols.
+ // //
+ // // Encoding as symbols can reduce the encoded size significantly.
+ // //
+ // // However, during decoding, each string to be encoded as a symbol must
+ // // be checked to see if it has been seen before. Consequently, encoding time
+ // // will increase if using symbols, because string comparisons has a clear cost.
+ // //
+ // // Sample values:
+ // // AsSymbolNone
+ // // AsSymbolAll
+ // // AsSymbolMapStringKeys
+ // // AsSymbolMapStringKeysFlag | AsSymbolStructFieldNameFlag
+ // AsSymbols AsSymbolFlag
+}
+
+// ---------------------------------------------
+
+// ioEncWriter implements encWriter and can write to an io.Writer implementation
+type ioEncWriter struct {
+ w io.Writer
+ ww io.Writer
+ bw io.ByteWriter
+ sw ioEncStringWriter
+ fw ioFlusher
+ b [8]byte
+}
+
+func (z *ioEncWriter) WriteByte(b byte) (err error) {
+ z.b[0] = b
+ _, err = z.w.Write(z.b[:1])
+ return
+}
+
+func (z *ioEncWriter) WriteString(s string) (n int, err error) {
+ return z.w.Write(bytesView(s))
+}
+
+func (z *ioEncWriter) writeb(bs []byte) {
+ if _, err := z.ww.Write(bs); err != nil {
+ panic(err)
+ }
+}
+
+func (z *ioEncWriter) writestr(s string) {
+ if _, err := z.sw.WriteString(s); err != nil {
+ panic(err)
+ }
+}
+
+func (z *ioEncWriter) writen1(b byte) {
+ if err := z.bw.WriteByte(b); err != nil {
+ panic(err)
+ }
+}
+
+func (z *ioEncWriter) writen2(b1, b2 byte) {
+ var err error
+ if err = z.bw.WriteByte(b1); err == nil {
+ if err = z.bw.WriteByte(b2); err == nil {
+ return
+ }
+ }
+ panic(err)
+}
+
+// func (z *ioEncWriter) writen5(b1, b2, b3, b4, b5 byte) {
+// z.b[0], z.b[1], z.b[2], z.b[3], z.b[4] = b1, b2, b3, b4, b5
+// if _, err := z.ww.Write(z.b[:5]); err != nil {
+// panic(err)
+// }
+// }
+
+func (z *ioEncWriter) atEndOfEncode() {
+ if z.fw != nil {
+ if err := z.fw.Flush(); err != nil {
+ panic(err)
+ }
+ }
+}
+
+// ---------------------------------------------
+
+// bytesEncAppender implements encWriter and can write to an byte slice.
+type bytesEncAppender struct {
+ b []byte
+ out *[]byte
+}
+
+func (z *bytesEncAppender) writeb(s []byte) {
+ z.b = append(z.b, s...)
+}
+func (z *bytesEncAppender) writestr(s string) {
+ z.b = append(z.b, s...)
+}
+func (z *bytesEncAppender) writen1(b1 byte) {
+ z.b = append(z.b, b1)
+}
+func (z *bytesEncAppender) writen2(b1, b2 byte) {
+ z.b = append(z.b, b1, b2)
+}
+func (z *bytesEncAppender) atEndOfEncode() {
+ *(z.out) = z.b
+}
+func (z *bytesEncAppender) reset(in []byte, out *[]byte) {
+ z.b = in[:0]
+ z.out = out
+}
+
+// ---------------------------------------------
+
+func (e *Encoder) rawExt(f *codecFnInfo, rv reflect.Value) {
+ e.e.EncodeRawExt(rv2i(rv).(*RawExt), e)
+}
+
+func (e *Encoder) ext(f *codecFnInfo, rv reflect.Value) {
+ e.e.EncodeExt(rv2i(rv), f.xfTag, f.xfFn, e)
+}
+
+func (e *Encoder) selferMarshal(f *codecFnInfo, rv reflect.Value) {
+ rv2i(rv).(Selfer).CodecEncodeSelf(e)
+}
+
+func (e *Encoder) binaryMarshal(f *codecFnInfo, rv reflect.Value) {
+ bs, fnerr := rv2i(rv).(encoding.BinaryMarshaler).MarshalBinary()
+ e.marshal(bs, fnerr, false, cRAW)
+}
+
+func (e *Encoder) textMarshal(f *codecFnInfo, rv reflect.Value) {
+ bs, fnerr := rv2i(rv).(encoding.TextMarshaler).MarshalText()
+ e.marshal(bs, fnerr, false, cUTF8)
+}
+
+func (e *Encoder) jsonMarshal(f *codecFnInfo, rv reflect.Value) {
+ bs, fnerr := rv2i(rv).(jsonMarshaler).MarshalJSON()
+ e.marshal(bs, fnerr, true, cUTF8)
+}
+
+func (e *Encoder) raw(f *codecFnInfo, rv reflect.Value) {
+ e.rawBytes(rv2i(rv).(Raw))
+}
+
+func (e *Encoder) kInvalid(f *codecFnInfo, rv reflect.Value) {
+ e.e.EncodeNil()
+}
+
+func (e *Encoder) kErr(f *codecFnInfo, rv reflect.Value) {
+ e.errorf("unsupported kind %s, for %#v", rv.Kind(), rv)
+}
+
+func (e *Encoder) kSlice(f *codecFnInfo, rv reflect.Value) {
+ ti := f.ti
+ ee := e.e
+ // array may be non-addressable, so we have to manage with care
+ // (don't call rv.Bytes, rv.Slice, etc).
+ // E.g. type struct S{B [2]byte};
+ // Encode(S{}) will bomb on "panic: slice of unaddressable array".
+ if f.seq != seqTypeArray {
+ if rv.IsNil() {
+ ee.EncodeNil()
+ return
+ }
+ // If in this method, then there was no extension function defined.
+ // So it's okay to treat as []byte.
+ if ti.rtid == uint8SliceTypId {
+ ee.EncodeStringBytes(cRAW, rv.Bytes())
+ return
+ }
+ }
+ if f.seq == seqTypeChan && ti.chandir&uint8(reflect.RecvDir) == 0 {
+ e.errorf("send-only channel cannot be encoded")
+ }
+ elemsep := e.esep
+ rtelem := ti.elem
+ rtelemIsByte := uint8TypId == rt2id(rtelem) // NOT rtelem.Kind() == reflect.Uint8
+ var l int
+ // if a slice, array or chan of bytes, treat specially
+ if rtelemIsByte {
+ switch f.seq {
+ case seqTypeSlice:
+ ee.EncodeStringBytes(cRAW, rv.Bytes())
+ case seqTypeArray:
+ l = rv.Len()
+ if rv.CanAddr() {
+ ee.EncodeStringBytes(cRAW, rv.Slice(0, l).Bytes())
+ } else {
+ var bs []byte
+ if l <= cap(e.b) {
+ bs = e.b[:l]
+ } else {
+ bs = make([]byte, l)
+ }
+ reflect.Copy(reflect.ValueOf(bs), rv)
+ ee.EncodeStringBytes(cRAW, bs)
+ }
+ case seqTypeChan:
+ // do not use range, so that the number of elements encoded
+ // does not change, and encoding does not hang waiting on someone to close chan.
+ // for b := range rv2i(rv).(<-chan byte) { bs = append(bs, b) }
+ // ch := rv2i(rv).(<-chan byte) // fix error - that this is a chan byte, not a <-chan byte.
+
+ if rv.IsNil() {
+ ee.EncodeNil()
+ break
+ }
+ bs := e.b[:0]
+ irv := rv2i(rv)
+ ch, ok := irv.(<-chan byte)
+ if !ok {
+ ch = irv.(chan byte)
+ }
+
+ L1:
+ switch timeout := e.h.ChanRecvTimeout; {
+ case timeout == 0: // only consume available
+ for {
+ select {
+ case b := <-ch:
+ bs = append(bs, b)
+ default:
+ break L1
+ }
+ }
+ case timeout > 0: // consume until timeout
+ tt := time.NewTimer(timeout)
+ for {
+ select {
+ case b := <-ch:
+ bs = append(bs, b)
+ case <-tt.C:
+ // close(tt.C)
+ break L1
+ }
+ }
+ default: // consume until close
+ for b := range ch {
+ bs = append(bs, b)
+ }
+ }
+
+ ee.EncodeStringBytes(cRAW, bs)
+ }
+ return
+ }
+
+ // if chan, consume chan into a slice, and work off that slice.
+ var rvcs reflect.Value
+ if f.seq == seqTypeChan {
+ rvcs = reflect.Zero(reflect.SliceOf(rtelem))
+ timeout := e.h.ChanRecvTimeout
+ if timeout < 0 { // consume until close
+ for {
+ recv, recvOk := rv.Recv()
+ if !recvOk {
+ break
+ }
+ rvcs = reflect.Append(rvcs, recv)
+ }
+ } else {
+ cases := make([]reflect.SelectCase, 2)
+ cases[0] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: rv}
+ if timeout == 0 {
+ cases[1] = reflect.SelectCase{Dir: reflect.SelectDefault}
+ } else {
+ tt := time.NewTimer(timeout)
+ cases[1] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(tt.C)}
+ }
+ for {
+ chosen, recv, recvOk := reflect.Select(cases)
+ if chosen == 1 || !recvOk {
+ break
+ }
+ rvcs = reflect.Append(rvcs, recv)
+ }
+ }
+ rv = rvcs // TODO: ensure this doesn't mess up anywhere that rv of kind chan is expected
+ }
+
+ l = rv.Len()
+ if ti.mbs {
+ if l%2 == 1 {
+ e.errorf("mapBySlice requires even slice length, but got %v", l)
+ return
+ }
+ ee.WriteMapStart(l / 2)
+ } else {
+ ee.WriteArrayStart(l)
+ }
+
+ if l > 0 {
+ var fn *codecFn
+ for rtelem.Kind() == reflect.Ptr {
+ rtelem = rtelem.Elem()
+ }
+ // if kind is reflect.Interface, do not pre-determine the
+ // encoding type, because preEncodeValue may break it down to
+ // a concrete type and kInterface will bomb.
+ if rtelem.Kind() != reflect.Interface {
+ fn = e.cfer().get(rtelem, true, true)
+ }
+ for j := 0; j < l; j++ {
+ if elemsep {
+ if ti.mbs {
+ if j%2 == 0 {
+ ee.WriteMapElemKey()
+ } else {
+ ee.WriteMapElemValue()
+ }
+ } else {
+ ee.WriteArrayElem()
+ }
+ }
+ e.encodeValue(rv.Index(j), fn, true)
+ }
+ }
+
+ if ti.mbs {
+ ee.WriteMapEnd()
+ } else {
+ ee.WriteArrayEnd()
+ }
+}
+
+func (e *Encoder) kStructNoOmitempty(f *codecFnInfo, rv reflect.Value) {
+ fti := f.ti
+ elemsep := e.esep
+ tisfi := fti.sfiSrc
+ toMap := !(fti.toArray || e.h.StructToArray)
+ if toMap {
+ tisfi = fti.sfiSort
+ }
+ ee := e.e
+
+ sfn := structFieldNode{v: rv, update: false}
+ if toMap {
+ ee.WriteMapStart(len(tisfi))
+ if elemsep {
+ for _, si := range tisfi {
+ ee.WriteMapElemKey()
+ // ee.EncodeString(cUTF8, si.encName)
+ encStructFieldKey(ee, fti.keyType, si.encName)
+ ee.WriteMapElemValue()
+ e.encodeValue(sfn.field(si), nil, true)
+ }
+ } else {
+ for _, si := range tisfi {
+ // ee.EncodeString(cUTF8, si.encName)
+ encStructFieldKey(ee, fti.keyType, si.encName)
+ e.encodeValue(sfn.field(si), nil, true)
+ }
+ }
+ ee.WriteMapEnd()
+ } else {
+ ee.WriteArrayStart(len(tisfi))
+ if elemsep {
+ for _, si := range tisfi {
+ ee.WriteArrayElem()
+ e.encodeValue(sfn.field(si), nil, true)
+ }
+ } else {
+ for _, si := range tisfi {
+ e.encodeValue(sfn.field(si), nil, true)
+ }
+ }
+ ee.WriteArrayEnd()
+ }
+}
+
+func encStructFieldKey(ee encDriver, keyType valueType, s string) {
+ var m must
+
+ // use if-else-if, not switch (which compiles to binary-search)
+ // since keyType is typically valueTypeString, branch prediction is pretty good.
+
+ if keyType == valueTypeString {
+ ee.EncodeString(cUTF8, s)
+ } else if keyType == valueTypeInt {
+ ee.EncodeInt(m.Int(strconv.ParseInt(s, 10, 64)))
+ } else if keyType == valueTypeUint {
+ ee.EncodeUint(m.Uint(strconv.ParseUint(s, 10, 64)))
+ } else if keyType == valueTypeFloat {
+ ee.EncodeFloat64(m.Float(strconv.ParseFloat(s, 64)))
+ } else {
+ ee.EncodeString(cUTF8, s)
+ }
+}
+
+func (e *Encoder) kStruct(f *codecFnInfo, rv reflect.Value) {
+ fti := f.ti
+ elemsep := e.esep
+ tisfi := fti.sfiSrc
+ toMap := !(fti.toArray || e.h.StructToArray)
+ // if toMap, use the sorted array. If toArray, use unsorted array (to match sequence in struct)
+ if toMap {
+ tisfi = fti.sfiSort
+ }
+ newlen := len(fti.sfiSort)
+ ee := e.e
+
+ // Use sync.Pool to reduce allocating slices unnecessarily.
+ // The cost of sync.Pool is less than the cost of new allocation.
+ //
+ // Each element of the array pools one of encStructPool(8|16|32|64).
+ // It allows the re-use of slices up to 64 in length.
+ // A performance cost of encoding structs was collecting
+ // which values were empty and should be omitted.
+ // We needed slices of reflect.Value and string to collect them.
+ // This shared pool reduces the amount of unnecessary creation we do.
+ // The cost is that of locking sometimes, but sync.Pool is efficient
+ // enough to reduce thread contention.
+
+ var spool *sync.Pool
+ var poolv interface{}
+ var fkvs []stringRv
+ // fmt.Printf(">>>>>>>>>>>>>> encode.kStruct: newlen: %d\n", newlen)
+ if newlen <= 8 {
+ spool, poolv = pool.stringRv8()
+ fkvs = poolv.(*[8]stringRv)[:newlen]
+ } else if newlen <= 16 {
+ spool, poolv = pool.stringRv16()
+ fkvs = poolv.(*[16]stringRv)[:newlen]
+ } else if newlen <= 32 {
+ spool, poolv = pool.stringRv32()
+ fkvs = poolv.(*[32]stringRv)[:newlen]
+ } else if newlen <= 64 {
+ spool, poolv = pool.stringRv64()
+ fkvs = poolv.(*[64]stringRv)[:newlen]
+ } else if newlen <= 128 {
+ spool, poolv = pool.stringRv128()
+ fkvs = poolv.(*[128]stringRv)[:newlen]
+ } else {
+ fkvs = make([]stringRv, newlen)
+ }
+
+ newlen = 0
+ var kv stringRv
+ recur := e.h.RecursiveEmptyCheck
+ sfn := structFieldNode{v: rv, update: false}
+ for _, si := range tisfi {
+ // kv.r = si.field(rv, false)
+ kv.r = sfn.field(si)
+ if toMap {
+ if si.omitEmpty() && isEmptyValue(kv.r, e.h.TypeInfos, recur, recur) {
+ continue
+ }
+ kv.v = si.encName
+ } else {
+ // use the zero value.
+ // if a reference or struct, set to nil (so you do not output too much)
+ if si.omitEmpty() && isEmptyValue(kv.r, e.h.TypeInfos, recur, recur) {
+ switch kv.r.Kind() {
+ case reflect.Struct, reflect.Interface, reflect.Ptr, reflect.Array, reflect.Map, reflect.Slice:
+ kv.r = reflect.Value{} //encode as nil
+ }
+ }
+ }
+ fkvs[newlen] = kv
+ newlen++
+ }
+
+ if toMap {
+ ee.WriteMapStart(newlen)
+ if elemsep {
+ for j := 0; j < newlen; j++ {
+ kv = fkvs[j]
+ ee.WriteMapElemKey()
+ // ee.EncodeString(cUTF8, kv.v)
+ encStructFieldKey(ee, fti.keyType, kv.v)
+ ee.WriteMapElemValue()
+ e.encodeValue(kv.r, nil, true)
+ }
+ } else {
+ for j := 0; j < newlen; j++ {
+ kv = fkvs[j]
+ // ee.EncodeString(cUTF8, kv.v)
+ encStructFieldKey(ee, fti.keyType, kv.v)
+ e.encodeValue(kv.r, nil, true)
+ }
+ }
+ ee.WriteMapEnd()
+ } else {
+ ee.WriteArrayStart(newlen)
+ if elemsep {
+ for j := 0; j < newlen; j++ {
+ ee.WriteArrayElem()
+ e.encodeValue(fkvs[j].r, nil, true)
+ }
+ } else {
+ for j := 0; j < newlen; j++ {
+ e.encodeValue(fkvs[j].r, nil, true)
+ }
+ }
+ ee.WriteArrayEnd()
+ }
+
+ // do not use defer. Instead, use explicit pool return at end of function.
+ // defer has a cost we are trying to avoid.
+ // If there is a panic and these slices are not returned, it is ok.
+ if spool != nil {
+ spool.Put(poolv)
+ }
+}
+
+func (e *Encoder) kMap(f *codecFnInfo, rv reflect.Value) {
+ ee := e.e
+ if rv.IsNil() {
+ ee.EncodeNil()
+ return
+ }
+
+ l := rv.Len()
+ ee.WriteMapStart(l)
+ elemsep := e.esep
+ if l == 0 {
+ ee.WriteMapEnd()
+ return
+ }
+ // var asSymbols bool
+ // determine the underlying key and val encFn's for the map.
+ // This eliminates some work which is done for each loop iteration i.e.
+ // rv.Type(), ref.ValueOf(rt).Pointer(), then check map/list for fn.
+ //
+ // However, if kind is reflect.Interface, do not pre-determine the
+ // encoding type, because preEncodeValue may break it down to
+ // a concrete type and kInterface will bomb.
+ var keyFn, valFn *codecFn
+ ti := f.ti
+ rtkey0 := ti.key
+ rtkey := rtkey0
+ rtval0 := ti.elem
+ rtval := rtval0
+ // rtkeyid := rt2id(rtkey0)
+ for rtval.Kind() == reflect.Ptr {
+ rtval = rtval.Elem()
+ }
+ if rtval.Kind() != reflect.Interface {
+ valFn = e.cfer().get(rtval, true, true)
+ }
+ mks := rv.MapKeys()
+
+ if e.h.Canonical {
+ e.kMapCanonical(rtkey, rv, mks, valFn)
+ ee.WriteMapEnd()
+ return
+ }
+
+ var keyTypeIsString = stringTypId == rt2id(rtkey0) // rtkeyid
+ if !keyTypeIsString {
+ for rtkey.Kind() == reflect.Ptr {
+ rtkey = rtkey.Elem()
+ }
+ if rtkey.Kind() != reflect.Interface {
+ // rtkeyid = rt2id(rtkey)
+ keyFn = e.cfer().get(rtkey, true, true)
+ }
+ }
+
+ // for j, lmks := 0, len(mks); j < lmks; j++ {
+ for j := range mks {
+ if elemsep {
+ ee.WriteMapElemKey()
+ }
+ if keyTypeIsString {
+ ee.EncodeString(cUTF8, mks[j].String())
+ } else {
+ e.encodeValue(mks[j], keyFn, true)
+ }
+ if elemsep {
+ ee.WriteMapElemValue()
+ }
+ e.encodeValue(rv.MapIndex(mks[j]), valFn, true)
+
+ }
+ ee.WriteMapEnd()
+}
+
+func (e *Encoder) kMapCanonical(rtkey reflect.Type, rv reflect.Value, mks []reflect.Value, valFn *codecFn) {
+ ee := e.e
+ elemsep := e.esep
+ // we previously did out-of-band if an extension was registered.
+ // This is not necessary, as the natural kind is sufficient for ordering.
+
+ switch rtkey.Kind() {
+ case reflect.Bool:
+ mksv := make([]boolRv, len(mks))
+ for i, k := range mks {
+ v := &mksv[i]
+ v.r = k
+ v.v = k.Bool()
+ }
+ sort.Sort(boolRvSlice(mksv))
+ for i := range mksv {
+ if elemsep {
+ ee.WriteMapElemKey()
+ }
+ ee.EncodeBool(mksv[i].v)
+ if elemsep {
+ ee.WriteMapElemValue()
+ }
+ e.encodeValue(rv.MapIndex(mksv[i].r), valFn, true)
+ }
+ case reflect.String:
+ mksv := make([]stringRv, len(mks))
+ for i, k := range mks {
+ v := &mksv[i]
+ v.r = k
+ v.v = k.String()
+ }
+ sort.Sort(stringRvSlice(mksv))
+ for i := range mksv {
+ if elemsep {
+ ee.WriteMapElemKey()
+ }
+ ee.EncodeString(cUTF8, mksv[i].v)
+ if elemsep {
+ ee.WriteMapElemValue()
+ }
+ e.encodeValue(rv.MapIndex(mksv[i].r), valFn, true)
+ }
+ case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint, reflect.Uintptr:
+ mksv := make([]uintRv, len(mks))
+ for i, k := range mks {
+ v := &mksv[i]
+ v.r = k
+ v.v = k.Uint()
+ }
+ sort.Sort(uintRvSlice(mksv))
+ for i := range mksv {
+ if elemsep {
+ ee.WriteMapElemKey()
+ }
+ ee.EncodeUint(mksv[i].v)
+ if elemsep {
+ ee.WriteMapElemValue()
+ }
+ e.encodeValue(rv.MapIndex(mksv[i].r), valFn, true)
+ }
+ case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
+ mksv := make([]intRv, len(mks))
+ for i, k := range mks {
+ v := &mksv[i]
+ v.r = k
+ v.v = k.Int()
+ }
+ sort.Sort(intRvSlice(mksv))
+ for i := range mksv {
+ if elemsep {
+ ee.WriteMapElemKey()
+ }
+ ee.EncodeInt(mksv[i].v)
+ if elemsep {
+ ee.WriteMapElemValue()
+ }
+ e.encodeValue(rv.MapIndex(mksv[i].r), valFn, true)
+ }
+ case reflect.Float32:
+ mksv := make([]floatRv, len(mks))
+ for i, k := range mks {
+ v := &mksv[i]
+ v.r = k
+ v.v = k.Float()
+ }
+ sort.Sort(floatRvSlice(mksv))
+ for i := range mksv {
+ if elemsep {
+ ee.WriteMapElemKey()
+ }
+ ee.EncodeFloat32(float32(mksv[i].v))
+ if elemsep {
+ ee.WriteMapElemValue()
+ }
+ e.encodeValue(rv.MapIndex(mksv[i].r), valFn, true)
+ }
+ case reflect.Float64:
+ mksv := make([]floatRv, len(mks))
+ for i, k := range mks {
+ v := &mksv[i]
+ v.r = k
+ v.v = k.Float()
+ }
+ sort.Sort(floatRvSlice(mksv))
+ for i := range mksv {
+ if elemsep {
+ ee.WriteMapElemKey()
+ }
+ ee.EncodeFloat64(mksv[i].v)
+ if elemsep {
+ ee.WriteMapElemValue()
+ }
+ e.encodeValue(rv.MapIndex(mksv[i].r), valFn, true)
+ }
+ case reflect.Struct:
+ if rv.Type() == timeTyp {
+ mksv := make([]timeRv, len(mks))
+ for i, k := range mks {
+ v := &mksv[i]
+ v.r = k
+ v.v = rv2i(k).(time.Time)
+ }
+ sort.Sort(timeRvSlice(mksv))
+ for i := range mksv {
+ if elemsep {
+ ee.WriteMapElemKey()
+ }
+ ee.EncodeTime(mksv[i].v)
+ if elemsep {
+ ee.WriteMapElemValue()
+ }
+ e.encodeValue(rv.MapIndex(mksv[i].r), valFn, true)
+ }
+ break
+ }
+ fallthrough
+ default:
+ // out-of-band
+ // first encode each key to a []byte first, then sort them, then record
+ var mksv []byte = make([]byte, 0, len(mks)*16) // temporary byte slice for the encoding
+ e2 := NewEncoderBytes(&mksv, e.hh)
+ mksbv := make([]bytesRv, len(mks))
+ for i, k := range mks {
+ v := &mksbv[i]
+ l := len(mksv)
+ e2.MustEncode(k)
+ v.r = k
+ v.v = mksv[l:]
+ }
+ sort.Sort(bytesRvSlice(mksbv))
+ for j := range mksbv {
+ if elemsep {
+ ee.WriteMapElemKey()
+ }
+ e.asis(mksbv[j].v)
+ if elemsep {
+ ee.WriteMapElemValue()
+ }
+ e.encodeValue(rv.MapIndex(mksbv[j].r), valFn, true)
+ }
+ }
+}
+
+// // --------------------------------------------------
+
+type encWriterSwitch struct {
+ wi *ioEncWriter
+ // wb bytesEncWriter
+ wb bytesEncAppender
+ wx bool // if bytes, wx=true
+ esep bool // whether it has elem separators
+ isas bool // whether e.as != nil
+}
+
+// // TODO: Uncomment after mid-stack inlining enabled in go 1.11
+
+// func (z *encWriterSwitch) writeb(s []byte) {
+// if z.wx {
+// z.wb.writeb(s)
+// } else {
+// z.wi.writeb(s)
+// }
+// }
+// func (z *encWriterSwitch) writestr(s string) {
+// if z.wx {
+// z.wb.writestr(s)
+// } else {
+// z.wi.writestr(s)
+// }
+// }
+// func (z *encWriterSwitch) writen1(b1 byte) {
+// if z.wx {
+// z.wb.writen1(b1)
+// } else {
+// z.wi.writen1(b1)
+// }
+// }
+// func (z *encWriterSwitch) writen2(b1, b2 byte) {
+// if z.wx {
+// z.wb.writen2(b1, b2)
+// } else {
+// z.wi.writen2(b1, b2)
+// }
+// }
+
+// An Encoder writes an object to an output stream in the codec format.
+type Encoder struct {
+ panicHdl
+ // hopefully, reduce derefencing cost by laying the encWriter inside the Encoder
+ e encDriver
+ // NOTE: Encoder shouldn't call it's write methods,
+ // as the handler MAY need to do some coordination.
+ w encWriter
+
+ h *BasicHandle
+ bw *bufio.Writer
+ as encDriverAsis
+
+ // ---- cpu cache line boundary?
+
+ // ---- cpu cache line boundary?
+ encWriterSwitch
+ err error
+
+ // ---- cpu cache line boundary?
+ codecFnPooler
+ ci set
+ js bool // here, so that no need to piggy back on *codecFner for this
+ be bool // here, so that no need to piggy back on *codecFner for this
+ _ [6]byte // padding
+
+ // ---- writable fields during execution --- *try* to keep in sep cache line
+
+ // ---- cpu cache line boundary?
+ // b [scratchByteArrayLen]byte
+ // _ [cacheLineSize - scratchByteArrayLen]byte // padding
+ b [cacheLineSize - 0]byte // used for encoding a chan or (non-addressable) array of bytes
+}
+
+// NewEncoder returns an Encoder for encoding into an io.Writer.
+//
+// For efficiency, Users are encouraged to pass in a memory buffered writer
+// (eg bufio.Writer, bytes.Buffer).
+func NewEncoder(w io.Writer, h Handle) *Encoder {
+ e := newEncoder(h)
+ e.Reset(w)
+ return e
+}
+
+// NewEncoderBytes returns an encoder for encoding directly and efficiently
+// into a byte slice, using zero-copying to temporary slices.
+//
+// It will potentially replace the output byte slice pointed to.
+// After encoding, the out parameter contains the encoded contents.
+func NewEncoderBytes(out *[]byte, h Handle) *Encoder {
+ e := newEncoder(h)
+ e.ResetBytes(out)
+ return e
+}
+
+func newEncoder(h Handle) *Encoder {
+ e := &Encoder{h: h.getBasicHandle(), err: errEncoderNotInitialized}
+ e.hh = h
+ e.esep = h.hasElemSeparators()
+ return e
+}
+
+func (e *Encoder) resetCommon() {
+ if e.e == nil || e.hh.recreateEncDriver(e.e) {
+ e.e = e.hh.newEncDriver(e)
+ e.as, e.isas = e.e.(encDriverAsis)
+ // e.cr, _ = e.e.(containerStateRecv)
+ }
+ e.be = e.hh.isBinary()
+ _, e.js = e.hh.(*JsonHandle)
+ e.e.reset()
+ e.err = nil
+}
+
+// Reset resets the Encoder with a new output stream.
+//
+// This accommodates using the state of the Encoder,
+// where it has "cached" information about sub-engines.
+func (e *Encoder) Reset(w io.Writer) {
+ if w == nil {
+ return
+ }
+ if e.wi == nil {
+ e.wi = new(ioEncWriter)
+ }
+ var ok bool
+ e.wx = false
+ e.wi.w = w
+ if e.h.WriterBufferSize > 0 {
+ e.bw = bufio.NewWriterSize(w, e.h.WriterBufferSize)
+ e.wi.bw = e.bw
+ e.wi.sw = e.bw
+ e.wi.fw = e.bw
+ e.wi.ww = e.bw
+ } else {
+ if e.wi.bw, ok = w.(io.ByteWriter); !ok {
+ e.wi.bw = e.wi
+ }
+ if e.wi.sw, ok = w.(ioEncStringWriter); !ok {
+ e.wi.sw = e.wi
+ }
+ e.wi.fw, _ = w.(ioFlusher)
+ e.wi.ww = w
+ }
+ e.w = e.wi
+ e.resetCommon()
+}
+
+// ResetBytes resets the Encoder with a new destination output []byte.
+func (e *Encoder) ResetBytes(out *[]byte) {
+ if out == nil {
+ return
+ }
+ var in []byte
+ if out != nil {
+ in = *out
+ }
+ if in == nil {
+ in = make([]byte, defEncByteBufSize)
+ }
+ e.wx = true
+ e.wb.reset(in, out)
+ e.w = &e.wb
+ e.resetCommon()
+}
+
+// Encode writes an object into a stream.
+//
+// Encoding can be configured via the struct tag for the fields.
+// The key (in the struct tags) that we look at is configurable.
+//
+// By default, we look up the "codec" key in the struct field's tags,
+// and fall bak to the "json" key if "codec" is absent.
+// That key in struct field's tag value is the key name,
+// followed by an optional comma and options.
+//
+// To set an option on all fields (e.g. omitempty on all fields), you
+// can create a field called _struct, and set flags on it. The options
+// which can be set on _struct are:
+// - omitempty: so all fields are omitted if empty
+// - toarray: so struct is encoded as an array
+// - int: so struct key names are encoded as signed integers (instead of strings)
+// - uint: so struct key names are encoded as unsigned integers (instead of strings)
+// - float: so struct key names are encoded as floats (instead of strings)
+// More details on these below.
+//
+// Struct values "usually" encode as maps. Each exported struct field is encoded unless:
+// - the field's tag is "-", OR
+// - the field is empty (empty or the zero value) and its tag specifies the "omitempty" option.
+//
+// When encoding as a map, the first string in the tag (before the comma)
+// is the map key string to use when encoding.
+// ...
+// This key is typically encoded as a string.
+// However, there are instances where the encoded stream has mapping keys encoded as numbers.
+// For example, some cbor streams have keys as integer codes in the stream, but they should map
+// to fields in a structured object. Consequently, a struct is the natural representation in code.
+// For these, configure the struct to encode/decode the keys as numbers (instead of string).
+// This is done with the int,uint or float option on the _struct field (see above).
+//
+// However, struct values may encode as arrays. This happens when:
+// - StructToArray Encode option is set, OR
+// - the tag on the _struct field sets the "toarray" option
+// Note that omitempty is ignored when encoding struct values as arrays,
+// as an entry must be encoded for each field, to maintain its position.
+//
+// Values with types that implement MapBySlice are encoded as stream maps.
+//
+// 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.
+//
+// Anonymous fields are encoded inline except:
+// - the struct tag specifies a replacement name (first value)
+// - the field is of an interface type
+//
+// Examples:
+//
+// // NOTE: 'json:' can be used as struct tag key, in place 'codec:' below.
+// type MyStruct struct {
+// _struct bool `codec:",omitempty"` //set omitempty for every field
+// Field1 string `codec:"-"` //skip this field
+// Field2 int `codec:"myName"` //Use key "myName" in encode stream
+// Field3 int32 `codec:",omitempty"` //use key "Field3". 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
+// ...
+// }
+//
+// type MyStruct struct {
+// _struct bool `codec:",toarray"` //encode struct as an array
+// }
+//
+// type MyStruct struct {
+// _struct bool `codec:",uint"` //encode struct with "unsigned integer" keys
+// Field1 string `codec:"1"` //encode Field1 key using: EncodeInt(1)
+// Field2 string `codec:"2"` //encode Field2 key using: EncodeInt(2)
+// }
+//
+// 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 implements encoding.(Binary|Text|JSON)Marshaler, call Marshal(Binary|Text|JSON) method
+// - Else encode it based on its reflect.Kind
+//
+// Note that struct field names and keys in map[string]XXX will be treated as symbols.
+// Some formats support symbols (e.g. binc) and will properly encode the string
+// only once in the stream, and use a tag to refer to it thereafter.
+func (e *Encoder) Encode(v interface{}) (err error) {
+ defer e.deferred(&err)
+ e.MustEncode(v)
+ return
+}
+
+// MustEncode is like Encode, but panics if unable to Encode.
+// This provides insight to the code location that triggered the error.
+func (e *Encoder) MustEncode(v interface{}) {
+ if e.err != nil {
+ panic(e.err)
+ }
+ e.encode(v)
+ e.e.atEndOfEncode()
+ e.w.atEndOfEncode()
+ e.alwaysAtEnd()
+}
+
+func (e *Encoder) deferred(err1 *error) {
+ e.alwaysAtEnd()
+ if recoverPanicToErr {
+ if x := recover(); x != nil {
+ panicValToErr(e, x, err1)
+ panicValToErr(e, x, &e.err)
+ }
+ }
+}
+
+// func (e *Encoder) alwaysAtEnd() {
+// e.codecFnPooler.alwaysAtEnd()
+// }
+
+func (e *Encoder) encode(iv interface{}) {
+ if iv == nil || definitelyNil(iv) {
+ e.e.EncodeNil()
+ return
+ }
+ if v, ok := iv.(Selfer); ok {
+ v.CodecEncodeSelf(e)
+ return
+ }
+
+ // a switch with only concrete types can be optimized.
+ // consequently, we deal with nil and interfaces outside.
+
+ switch v := iv.(type) {
+ case Raw:
+ e.rawBytes(v)
+ case reflect.Value:
+ e.encodeValue(v, nil, true)
+
+ case string:
+ e.e.EncodeString(cUTF8, v)
+ case bool:
+ e.e.EncodeBool(v)
+ case int:
+ e.e.EncodeInt(int64(v))
+ case int8:
+ e.e.EncodeInt(int64(v))
+ case int16:
+ e.e.EncodeInt(int64(v))
+ case int32:
+ e.e.EncodeInt(int64(v))
+ case int64:
+ e.e.EncodeInt(v)
+ case uint:
+ e.e.EncodeUint(uint64(v))
+ case uint8:
+ e.e.EncodeUint(uint64(v))
+ case uint16:
+ e.e.EncodeUint(uint64(v))
+ case uint32:
+ e.e.EncodeUint(uint64(v))
+ case uint64:
+ e.e.EncodeUint(v)
+ case uintptr:
+ e.e.EncodeUint(uint64(v))
+ case float32:
+ e.e.EncodeFloat32(v)
+ case float64:
+ e.e.EncodeFloat64(v)
+ case time.Time:
+ e.e.EncodeTime(v)
+ case []uint8:
+ e.e.EncodeStringBytes(cRAW, v)
+
+ case *Raw:
+ e.rawBytes(*v)
+
+ case *string:
+ e.e.EncodeString(cUTF8, *v)
+ case *bool:
+ e.e.EncodeBool(*v)
+ case *int:
+ e.e.EncodeInt(int64(*v))
+ case *int8:
+ e.e.EncodeInt(int64(*v))
+ case *int16:
+ e.e.EncodeInt(int64(*v))
+ case *int32:
+ e.e.EncodeInt(int64(*v))
+ case *int64:
+ e.e.EncodeInt(*v)
+ case *uint:
+ e.e.EncodeUint(uint64(*v))
+ case *uint8:
+ e.e.EncodeUint(uint64(*v))
+ case *uint16:
+ e.e.EncodeUint(uint64(*v))
+ case *uint32:
+ e.e.EncodeUint(uint64(*v))
+ case *uint64:
+ e.e.EncodeUint(*v)
+ case *uintptr:
+ e.e.EncodeUint(uint64(*v))
+ case *float32:
+ e.e.EncodeFloat32(*v)
+ case *float64:
+ e.e.EncodeFloat64(*v)
+ case *time.Time:
+ e.e.EncodeTime(*v)
+
+ case *[]uint8:
+ e.e.EncodeStringBytes(cRAW, *v)
+
+ default:
+ if !fastpathEncodeTypeSwitch(iv, e) {
+ // checkfastpath=true (not false), as underlying slice/map type may be fast-path
+ e.encodeValue(reflect.ValueOf(iv), nil, true)
+ }
+ }
+}
+
+func (e *Encoder) encodeValue(rv reflect.Value, fn *codecFn, checkFastpath bool) {
+ // if a valid fn is passed, it MUST BE for the dereferenced type of rv
+ var sptr uintptr
+ var rvp reflect.Value
+ var rvpValid bool
+TOP:
+ switch rv.Kind() {
+ case reflect.Ptr:
+ if rv.IsNil() {
+ e.e.EncodeNil()
+ return
+ }
+ rvpValid = true
+ rvp = rv
+ rv = rv.Elem()
+ if e.h.CheckCircularRef && rv.Kind() == reflect.Struct {
+ // TODO: Movable pointers will be an issue here. Future problem.
+ sptr = rv.UnsafeAddr()
+ break TOP
+ }
+ goto TOP
+ case reflect.Interface:
+ if rv.IsNil() {
+ e.e.EncodeNil()
+ return
+ }
+ rv = rv.Elem()
+ goto TOP
+ case reflect.Slice, reflect.Map:
+ if rv.IsNil() {
+ e.e.EncodeNil()
+ return
+ }
+ case reflect.Invalid, reflect.Func:
+ e.e.EncodeNil()
+ return
+ }
+
+ if sptr != 0 && (&e.ci).add(sptr) {
+ e.errorf("circular reference found: # %d", sptr)
+ }
+
+ if fn == nil {
+ rt := rv.Type()
+ // always pass checkCodecSelfer=true, in case T or ****T is passed, where *T is a Selfer
+ fn = e.cfer().get(rt, checkFastpath, true)
+ }
+ if fn.i.addrE {
+ if rvpValid {
+ fn.fe(e, &fn.i, rvp)
+ } else if rv.CanAddr() {
+ fn.fe(e, &fn.i, rv.Addr())
+ } else {
+ rv2 := reflect.New(rv.Type())
+ rv2.Elem().Set(rv)
+ fn.fe(e, &fn.i, rv2)
+ }
+ } else {
+ fn.fe(e, &fn.i, rv)
+ }
+ if sptr != 0 {
+ (&e.ci).remove(sptr)
+ }
+}
+
+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.isas {
+ e.as.EncodeAsis(v)
+ } else {
+ e.w.writeb(v)
+ }
+}
+
+func (e *Encoder) rawBytes(vv Raw) {
+ v := []byte(vv)
+ if !e.h.Raw {
+ e.errorf("Raw values cannot be encoded: %v", v)
+ }
+ e.asis(v)
+}
+
+func (e *Encoder) wrapErrstr(v interface{}, err *error) {
+ *err = fmt.Errorf("%s encode error: %v", e.hh.Name(), v)
+}