summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/hashicorp/go-msgpack/codec/encode.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/hashicorp/go-msgpack/codec/encode.go')
-rw-r--r--vendor/github.com/hashicorp/go-msgpack/codec/encode.go1001
1 files changed, 1001 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/go-msgpack/codec/encode.go b/vendor/github.com/hashicorp/go-msgpack/codec/encode.go
new file mode 100644
index 000000000..4914be0c7
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-msgpack/codec/encode.go
@@ -0,0 +1,1001 @@
+// Copyright (c) 2012, 2013 Ugorji Nwoke. All rights reserved.
+// Use of this source code is governed by a BSD-style license found in the LICENSE file.
+
+package codec
+
+import (
+ "io"
+ "reflect"
+)
+
+const (
+ // Some tagging information for error messages.
+ msgTagEnc = "codec.encoder"
+ defEncByteBufSize = 1 << 6 // 4:16, 6:64, 8:256, 10:1024
+ // maxTimeSecs32 = math.MaxInt32 / 60 / 24 / 366
+)
+
+// AsSymbolFlag defines what should be encoded as symbols.
+type AsSymbolFlag uint8
+
+const (
+ // AsSymbolDefault is default.
+ // Currently, this means only encode struct field names as symbols.
+ // The default is subject to change.
+ AsSymbolDefault AsSymbolFlag = iota
+
+ // AsSymbolAll means encode anything which could be a symbol as a symbol.
+ AsSymbolAll = 0xfe
+
+ // AsSymbolNone means do not encode anything as a symbol.
+ AsSymbolNone = 1 << iota
+
+ // AsSymbolMapStringKeys means encode keys in map[string]XXX as symbols.
+ AsSymbolMapStringKeysFlag
+
+ // AsSymbolStructFieldName means encode struct field names as symbols.
+ AsSymbolStructFieldNameFlag
+)
+
+// encWriter abstracting writing to a byte array or to an io.Writer.
+type encWriter interface {
+ writeUint16(uint16)
+ writeUint32(uint32)
+ writeUint64(uint64)
+ writeb([]byte)
+ writestr(string)
+ writen1(byte)
+ writen2(byte, byte)
+ atEndOfEncode()
+}
+
+// encDriver abstracts the actual codec (binc vs msgpack, etc)
+type encDriver interface {
+ isBuiltinType(rt uintptr) bool
+ encodeBuiltin(rt uintptr, v interface{})
+ encodeNil()
+ encodeInt(i int64)
+ encodeUint(i uint64)
+ encodeBool(b bool)
+ encodeFloat32(f float32)
+ encodeFloat64(f float64)
+ encodeExtPreamble(xtag byte, length int)
+ encodeArrayPreamble(length int)
+ encodeMapPreamble(length int)
+ encodeString(c charEncoding, v string)
+ encodeSymbol(v string)
+ encodeStringBytes(c charEncoding, v []byte)
+ //TODO
+ //encBignum(f *big.Int)
+ //encStringRunes(c charEncoding, v []rune)
+}
+
+type ioEncWriterWriter interface {
+ WriteByte(c byte) error
+ WriteString(s string) (n int, err error)
+ Write(p []byte) (n int, err error)
+}
+
+type ioEncStringWriter interface {
+ WriteString(s string) (n int, err error)
+}
+
+type EncodeOptions struct {
+ // Encode a struct as an array, and not as a map.
+ StructToArray 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
+}
+
+// ---------------------------------------------
+
+type simpleIoEncWriterWriter struct {
+ w io.Writer
+ bw io.ByteWriter
+ sw ioEncStringWriter
+}
+
+func (o *simpleIoEncWriterWriter) WriteByte(c byte) (err error) {
+ if o.bw != nil {
+ return o.bw.WriteByte(c)
+ }
+ _, err = o.w.Write([]byte{c})
+ return
+}
+
+func (o *simpleIoEncWriterWriter) WriteString(s string) (n int, err error) {
+ if o.sw != nil {
+ return o.sw.WriteString(s)
+ }
+ return o.w.Write([]byte(s))
+}
+
+func (o *simpleIoEncWriterWriter) Write(p []byte) (n int, err error) {
+ return o.w.Write(p)
+}
+
+// ----------------------------------------
+
+// ioEncWriter implements encWriter and can write to an io.Writer implementation
+type ioEncWriter struct {
+ w ioEncWriterWriter
+ x [8]byte // temp byte array re-used internally for efficiency
+}
+
+func (z *ioEncWriter) writeUint16(v uint16) {
+ bigen.PutUint16(z.x[:2], v)
+ z.writeb(z.x[:2])
+}
+
+func (z *ioEncWriter) writeUint32(v uint32) {
+ bigen.PutUint32(z.x[:4], v)
+ z.writeb(z.x[:4])
+}
+
+func (z *ioEncWriter) writeUint64(v uint64) {
+ bigen.PutUint64(z.x[:8], v)
+ z.writeb(z.x[:8])
+}
+
+func (z *ioEncWriter) writeb(bs []byte) {
+ if len(bs) == 0 {
+ return
+ }
+ n, err := z.w.Write(bs)
+ if err != nil {
+ panic(err)
+ }
+ if n != len(bs) {
+ encErr("write: Incorrect num bytes written. Expecting: %v, Wrote: %v", len(bs), n)
+ }
+}
+
+func (z *ioEncWriter) writestr(s string) {
+ n, err := z.w.WriteString(s)
+ if err != nil {
+ panic(err)
+ }
+ if n != len(s) {
+ encErr("write: Incorrect num bytes written. Expecting: %v, Wrote: %v", len(s), n)
+ }
+}
+
+func (z *ioEncWriter) writen1(b byte) {
+ if err := z.w.WriteByte(b); err != nil {
+ panic(err)
+ }
+}
+
+func (z *ioEncWriter) writen2(b1 byte, b2 byte) {
+ z.writen1(b1)
+ z.writen1(b2)
+}
+
+func (z *ioEncWriter) atEndOfEncode() {}
+
+// ----------------------------------------
+
+// bytesEncWriter implements encWriter and can write to an byte slice.
+// It is used by Marshal function.
+type bytesEncWriter struct {
+ b []byte
+ c int // cursor
+ out *[]byte // write out on atEndOfEncode
+}
+
+func (z *bytesEncWriter) writeUint16(v uint16) {
+ c := z.grow(2)
+ z.b[c] = byte(v >> 8)
+ z.b[c+1] = byte(v)
+}
+
+func (z *bytesEncWriter) writeUint32(v uint32) {
+ c := z.grow(4)
+ z.b[c] = byte(v >> 24)
+ z.b[c+1] = byte(v >> 16)
+ z.b[c+2] = byte(v >> 8)
+ z.b[c+3] = byte(v)
+}
+
+func (z *bytesEncWriter) writeUint64(v uint64) {
+ c := z.grow(8)
+ z.b[c] = byte(v >> 56)
+ z.b[c+1] = byte(v >> 48)
+ z.b[c+2] = byte(v >> 40)
+ z.b[c+3] = byte(v >> 32)
+ z.b[c+4] = byte(v >> 24)
+ z.b[c+5] = byte(v >> 16)
+ z.b[c+6] = byte(v >> 8)
+ z.b[c+7] = byte(v)
+}
+
+func (z *bytesEncWriter) writeb(s []byte) {
+ if len(s) == 0 {
+ return
+ }
+ c := z.grow(len(s))
+ copy(z.b[c:], s)
+}
+
+func (z *bytesEncWriter) writestr(s string) {
+ c := z.grow(len(s))
+ copy(z.b[c:], s)
+}
+
+func (z *bytesEncWriter) writen1(b1 byte) {
+ c := z.grow(1)
+ z.b[c] = b1
+}
+
+func (z *bytesEncWriter) writen2(b1 byte, b2 byte) {
+ c := z.grow(2)
+ z.b[c] = b1
+ z.b[c+1] = b2
+}
+
+func (z *bytesEncWriter) atEndOfEncode() {
+ *(z.out) = z.b[:z.c]
+}
+
+func (z *bytesEncWriter) grow(n int) (oldcursor int) {
+ oldcursor = z.c
+ z.c = oldcursor + n
+ if z.c > cap(z.b) {
+ // Tried using appendslice logic: (if cap < 1024, *2, else *1.25).
+ // However, it was too expensive, causing too many iterations of copy.
+ // Using bytes.Buffer model was much better (2*cap + n)
+ bs := make([]byte, 2*cap(z.b)+n)
+ copy(bs, z.b[:oldcursor])
+ z.b = bs
+ } else if z.c > len(z.b) {
+ z.b = z.b[:cap(z.b)]
+ }
+ return
+}
+
+// ---------------------------------------------
+
+type encFnInfo struct {
+ ti *typeInfo
+ e *Encoder
+ ee encDriver
+ xfFn func(reflect.Value) ([]byte, error)
+ xfTag byte
+}
+
+func (f *encFnInfo) builtin(rv reflect.Value) {
+ f.ee.encodeBuiltin(f.ti.rtid, rv.Interface())
+}
+
+func (f *encFnInfo) rawExt(rv reflect.Value) {
+ f.e.encRawExt(rv.Interface().(RawExt))
+}
+
+func (f *encFnInfo) ext(rv reflect.Value) {
+ bs, fnerr := f.xfFn(rv)
+ if fnerr != nil {
+ panic(fnerr)
+ }
+ if bs == nil {
+ f.ee.encodeNil()
+ return
+ }
+ if f.e.hh.writeExt() {
+ f.ee.encodeExtPreamble(f.xfTag, len(bs))
+ f.e.w.writeb(bs)
+ } else {
+ f.ee.encodeStringBytes(c_RAW, bs)
+ }
+
+}
+
+func (f *encFnInfo) binaryMarshal(rv reflect.Value) {
+ var bm binaryMarshaler
+ if f.ti.mIndir == 0 {
+ bm = rv.Interface().(binaryMarshaler)
+ } else if f.ti.mIndir == -1 {
+ bm = rv.Addr().Interface().(binaryMarshaler)
+ } else {
+ for j, k := int8(0), f.ti.mIndir; j < k; j++ {
+ if rv.IsNil() {
+ f.ee.encodeNil()
+ return
+ }
+ rv = rv.Elem()
+ }
+ bm = rv.Interface().(binaryMarshaler)
+ }
+ // debugf(">>>> binaryMarshaler: %T", rv.Interface())
+ bs, fnerr := bm.MarshalBinary()
+ if fnerr != nil {
+ panic(fnerr)
+ }
+ if bs == nil {
+ f.ee.encodeNil()
+ } else {
+ f.ee.encodeStringBytes(c_RAW, bs)
+ }
+}
+
+func (f *encFnInfo) kBool(rv reflect.Value) {
+ f.ee.encodeBool(rv.Bool())
+}
+
+func (f *encFnInfo) kString(rv reflect.Value) {
+ f.ee.encodeString(c_UTF8, rv.String())
+}
+
+func (f *encFnInfo) kFloat64(rv reflect.Value) {
+ f.ee.encodeFloat64(rv.Float())
+}
+
+func (f *encFnInfo) kFloat32(rv reflect.Value) {
+ f.ee.encodeFloat32(float32(rv.Float()))
+}
+
+func (f *encFnInfo) kInt(rv reflect.Value) {
+ f.ee.encodeInt(rv.Int())
+}
+
+func (f *encFnInfo) kUint(rv reflect.Value) {
+ f.ee.encodeUint(rv.Uint())
+}
+
+func (f *encFnInfo) kInvalid(rv reflect.Value) {
+ f.ee.encodeNil()
+}
+
+func (f *encFnInfo) kErr(rv reflect.Value) {
+ encErr("Unsupported kind: %s, for: %#v", rv.Kind(), rv)
+}
+
+func (f *encFnInfo) kSlice(rv reflect.Value) {
+ if rv.IsNil() {
+ f.ee.encodeNil()
+ return
+ }
+
+ if shortCircuitReflectToFastPath {
+ switch f.ti.rtid {
+ case intfSliceTypId:
+ f.e.encSliceIntf(rv.Interface().([]interface{}))
+ return
+ case strSliceTypId:
+ f.e.encSliceStr(rv.Interface().([]string))
+ return
+ case uint64SliceTypId:
+ f.e.encSliceUint64(rv.Interface().([]uint64))
+ return
+ case int64SliceTypId:
+ f.e.encSliceInt64(rv.Interface().([]int64))
+ return
+ }
+ }
+
+ // If in this method, then there was no extension function defined.
+ // So it's okay to treat as []byte.
+ if f.ti.rtid == uint8SliceTypId || f.ti.rt.Elem().Kind() == reflect.Uint8 {
+ f.ee.encodeStringBytes(c_RAW, rv.Bytes())
+ return
+ }
+
+ l := rv.Len()
+ if f.ti.mbs {
+ if l%2 == 1 {
+ encErr("mapBySlice: invalid length (must be divisible by 2): %v", l)
+ }
+ f.ee.encodeMapPreamble(l / 2)
+ } else {
+ f.ee.encodeArrayPreamble(l)
+ }
+ if l == 0 {
+ return
+ }
+ for j := 0; j < l; j++ {
+ // TODO: Consider perf implication of encoding odd index values as symbols if type is string
+ f.e.encodeValue(rv.Index(j))
+ }
+}
+
+func (f *encFnInfo) kArray(rv reflect.Value) {
+ // We cannot share kSlice method, because the array may be non-addressable.
+ // E.g. type struct S{B [2]byte}; Encode(S{}) will bomb on "panic: slice of unaddressable array".
+ // So we have to duplicate the functionality here.
+ // f.e.encodeValue(rv.Slice(0, rv.Len()))
+ // f.kSlice(rv.Slice(0, rv.Len()))
+
+ l := rv.Len()
+ // Handle an array of bytes specially (in line with what is done for slices)
+ if f.ti.rt.Elem().Kind() == reflect.Uint8 {
+ if l == 0 {
+ f.ee.encodeStringBytes(c_RAW, nil)
+ return
+ }
+ var bs []byte
+ if rv.CanAddr() {
+ bs = rv.Slice(0, l).Bytes()
+ } else {
+ bs = make([]byte, l)
+ for i := 0; i < l; i++ {
+ bs[i] = byte(rv.Index(i).Uint())
+ }
+ }
+ f.ee.encodeStringBytes(c_RAW, bs)
+ return
+ }
+
+ if f.ti.mbs {
+ if l%2 == 1 {
+ encErr("mapBySlice: invalid length (must be divisible by 2): %v", l)
+ }
+ f.ee.encodeMapPreamble(l / 2)
+ } else {
+ f.ee.encodeArrayPreamble(l)
+ }
+ if l == 0 {
+ return
+ }
+ for j := 0; j < l; j++ {
+ // TODO: Consider perf implication of encoding odd index values as symbols if type is string
+ f.e.encodeValue(rv.Index(j))
+ }
+}
+
+func (f *encFnInfo) kStruct(rv reflect.Value) {
+ fti := f.ti
+ newlen := len(fti.sfi)
+ rvals := make([]reflect.Value, newlen)
+ var encnames []string
+ e := f.e
+ tisfi := fti.sfip
+ 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.sfi
+ encnames = make([]string, newlen)
+ }
+ newlen = 0
+ for _, si := range tisfi {
+ if si.i != -1 {
+ rvals[newlen] = rv.Field(int(si.i))
+ } else {
+ rvals[newlen] = rv.FieldByIndex(si.is)
+ }
+ if toMap {
+ if si.omitEmpty && isEmptyValue(rvals[newlen]) {
+ continue
+ }
+ encnames[newlen] = si.encName
+ } else {
+ if si.omitEmpty && isEmptyValue(rvals[newlen]) {
+ rvals[newlen] = reflect.Value{} //encode as nil
+ }
+ }
+ newlen++
+ }
+
+ // debugf(">>>> kStruct: newlen: %v", newlen)
+ if toMap {
+ ee := f.ee //don't dereference everytime
+ ee.encodeMapPreamble(newlen)
+ // asSymbols := e.h.AsSymbols&AsSymbolStructFieldNameFlag != 0
+ asSymbols := e.h.AsSymbols == AsSymbolDefault || e.h.AsSymbols&AsSymbolStructFieldNameFlag != 0
+ for j := 0; j < newlen; j++ {
+ if asSymbols {
+ ee.encodeSymbol(encnames[j])
+ } else {
+ ee.encodeString(c_UTF8, encnames[j])
+ }
+ e.encodeValue(rvals[j])
+ }
+ } else {
+ f.ee.encodeArrayPreamble(newlen)
+ for j := 0; j < newlen; j++ {
+ e.encodeValue(rvals[j])
+ }
+ }
+}
+
+// func (f *encFnInfo) kPtr(rv reflect.Value) {
+// debugf(">>>>>>> ??? encode kPtr called - shouldn't get called")
+// if rv.IsNil() {
+// f.ee.encodeNil()
+// return
+// }
+// f.e.encodeValue(rv.Elem())
+// }
+
+func (f *encFnInfo) kInterface(rv reflect.Value) {
+ if rv.IsNil() {
+ f.ee.encodeNil()
+ return
+ }
+ f.e.encodeValue(rv.Elem())
+}
+
+func (f *encFnInfo) kMap(rv reflect.Value) {
+ if rv.IsNil() {
+ f.ee.encodeNil()
+ return
+ }
+
+ if shortCircuitReflectToFastPath {
+ switch f.ti.rtid {
+ case mapIntfIntfTypId:
+ f.e.encMapIntfIntf(rv.Interface().(map[interface{}]interface{}))
+ return
+ case mapStrIntfTypId:
+ f.e.encMapStrIntf(rv.Interface().(map[string]interface{}))
+ return
+ case mapStrStrTypId:
+ f.e.encMapStrStr(rv.Interface().(map[string]string))
+ return
+ case mapInt64IntfTypId:
+ f.e.encMapInt64Intf(rv.Interface().(map[int64]interface{}))
+ return
+ case mapUint64IntfTypId:
+ f.e.encMapUint64Intf(rv.Interface().(map[uint64]interface{}))
+ return
+ }
+ }
+
+ l := rv.Len()
+ f.ee.encodeMapPreamble(l)
+ if l == 0 {
+ return
+ }
+ // keyTypeIsString := f.ti.rt.Key().Kind() == reflect.String
+ keyTypeIsString := f.ti.rt.Key() == stringTyp
+ var asSymbols bool
+ if keyTypeIsString {
+ asSymbols = f.e.h.AsSymbols&AsSymbolMapStringKeysFlag != 0
+ }
+ mks := rv.MapKeys()
+ // for j, lmks := 0, len(mks); j < lmks; j++ {
+ for j := range mks {
+ if keyTypeIsString {
+ if asSymbols {
+ f.ee.encodeSymbol(mks[j].String())
+ } else {
+ f.ee.encodeString(c_UTF8, mks[j].String())
+ }
+ } else {
+ f.e.encodeValue(mks[j])
+ }
+ f.e.encodeValue(rv.MapIndex(mks[j]))
+ }
+
+}
+
+// --------------------------------------------------
+
+// encFn encapsulates the captured variables and the encode function.
+// This way, we only do some calculations one times, and pass to the
+// code block that should be called (encapsulated in a function)
+// instead of executing the checks every time.
+type encFn struct {
+ i *encFnInfo
+ f func(*encFnInfo, reflect.Value)
+}
+
+// --------------------------------------------------
+
+// An Encoder writes an object to an output stream in the codec format.
+type Encoder struct {
+ w encWriter
+ e encDriver
+ h *BasicHandle
+ hh Handle
+ f map[uintptr]encFn
+ x []uintptr
+ s []encFn
+}
+
+// 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 {
+ ww, ok := w.(ioEncWriterWriter)
+ if !ok {
+ sww := simpleIoEncWriterWriter{w: w}
+ sww.bw, _ = w.(io.ByteWriter)
+ sww.sw, _ = w.(ioEncStringWriter)
+ ww = &sww
+ //ww = bufio.NewWriterSize(w, defEncByteBufSize)
+ }
+ z := ioEncWriter{
+ w: ww,
+ }
+ return &Encoder{w: &z, hh: h, h: h.getBasicHandle(), e: h.newEncDriver(&z)}
+}
+
+// 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 {
+ in := *out
+ if in == nil {
+ in = make([]byte, defEncByteBufSize)
+ }
+ z := bytesEncWriter{
+ b: in,
+ out: out,
+ }
+ return &Encoder{w: &z, hh: h, h: h.getBasicHandle(), e: h.newEncDriver(&z)}
+}
+
+// Encode writes an object into a stream in the codec format.
+//
+// Encoding can be configured via the "codec" struct tag for the fields.
+//
+// The "codec" 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.
+//
+// Struct values "usually" encode as maps. Each exported struct field is encoded unless:
+// - the field's codec tag is "-", OR
+// - the field is empty and its codec 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.
+//
+// However, struct values may encode as arrays. This happens when:
+// - StructToArray Encode option is set, OR
+// - the codec tag on the _struct field sets the "toarray" option
+//
+// 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 if no struct tag is present.
+// Else they are encoded as regular fields.
+//
+// Examples:
+//
+// 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.
+// ...
+// }
+//
+// type MyStruct struct {
+// _struct bool `codec:",omitempty,toarray"` //set omitempty for every field
+// //and encode struct as an array
+// }
+//
+// The mode of encoding is based on the type of the value. When a value is seen:
+// - If an extension is registered for it, call that extension function
+// - If it implements BinaryMarshaler, call its MarshalBinary() (data []byte, err error)
+// - 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 panicToErr(&err)
+ e.encode(v)
+ e.w.atEndOfEncode()
+ return
+}
+
+func (e *Encoder) encode(iv interface{}) {
+ switch v := iv.(type) {
+ case nil:
+ e.e.encodeNil()
+
+ case reflect.Value:
+ e.encodeValue(v)
+
+ case string:
+ e.e.encodeString(c_UTF8, 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 float32:
+ e.e.encodeFloat32(v)
+ case float64:
+ e.e.encodeFloat64(v)
+
+ case []interface{}:
+ e.encSliceIntf(v)
+ case []string:
+ e.encSliceStr(v)
+ case []int64:
+ e.encSliceInt64(v)
+ case []uint64:
+ e.encSliceUint64(v)
+ case []uint8:
+ e.e.encodeStringBytes(c_RAW, v)
+
+ case map[interface{}]interface{}:
+ e.encMapIntfIntf(v)
+ case map[string]interface{}:
+ e.encMapStrIntf(v)
+ case map[string]string:
+ e.encMapStrStr(v)
+ case map[int64]interface{}:
+ e.encMapInt64Intf(v)
+ case map[uint64]interface{}:
+ e.encMapUint64Intf(v)
+
+ case *string:
+ e.e.encodeString(c_UTF8, *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 *float32:
+ e.e.encodeFloat32(*v)
+ case *float64:
+ e.e.encodeFloat64(*v)
+
+ case *[]interface{}:
+ e.encSliceIntf(*v)
+ case *[]string:
+ e.encSliceStr(*v)
+ case *[]int64:
+ e.encSliceInt64(*v)
+ case *[]uint64:
+ e.encSliceUint64(*v)
+ case *[]uint8:
+ e.e.encodeStringBytes(c_RAW, *v)
+
+ case *map[interface{}]interface{}:
+ e.encMapIntfIntf(*v)
+ case *map[string]interface{}:
+ e.encMapStrIntf(*v)
+ case *map[string]string:
+ e.encMapStrStr(*v)
+ case *map[int64]interface{}:
+ e.encMapInt64Intf(*v)
+ case *map[uint64]interface{}:
+ e.encMapUint64Intf(*v)
+
+ default:
+ e.encodeValue(reflect.ValueOf(iv))
+ }
+}
+
+func (e *Encoder) encodeValue(rv reflect.Value) {
+ for rv.Kind() == reflect.Ptr {
+ if rv.IsNil() {
+ e.e.encodeNil()
+ return
+ }
+ rv = rv.Elem()
+ }
+
+ rt := rv.Type()
+ rtid := reflect.ValueOf(rt).Pointer()
+
+ // if e.f == nil && e.s == nil { debugf("---->Creating new enc f map for type: %v\n", rt) }
+ var fn encFn
+ var ok bool
+ if useMapForCodecCache {
+ fn, ok = e.f[rtid]
+ } else {
+ for i, v := range e.x {
+ if v == rtid {
+ fn, ok = e.s[i], true
+ break
+ }
+ }
+ }
+ if !ok {
+ // debugf("\tCreating new enc fn for type: %v\n", rt)
+ fi := encFnInfo{ti: getTypeInfo(rtid, rt), e: e, ee: e.e}
+ fn.i = &fi
+ if rtid == rawExtTypId {
+ fn.f = (*encFnInfo).rawExt
+ } else if e.e.isBuiltinType(rtid) {
+ fn.f = (*encFnInfo).builtin
+ } else if xfTag, xfFn := e.h.getEncodeExt(rtid); xfFn != nil {
+ fi.xfTag, fi.xfFn = xfTag, xfFn
+ fn.f = (*encFnInfo).ext
+ } else if supportBinaryMarshal && fi.ti.m {
+ fn.f = (*encFnInfo).binaryMarshal
+ } else {
+ switch rk := rt.Kind(); rk {
+ case reflect.Bool:
+ fn.f = (*encFnInfo).kBool
+ case reflect.String:
+ fn.f = (*encFnInfo).kString
+ case reflect.Float64:
+ fn.f = (*encFnInfo).kFloat64
+ case reflect.Float32:
+ fn.f = (*encFnInfo).kFloat32
+ case reflect.Int, reflect.Int8, reflect.Int64, reflect.Int32, reflect.Int16:
+ fn.f = (*encFnInfo).kInt
+ case reflect.Uint8, reflect.Uint64, reflect.Uint, reflect.Uint32, reflect.Uint16:
+ fn.f = (*encFnInfo).kUint
+ case reflect.Invalid:
+ fn.f = (*encFnInfo).kInvalid
+ case reflect.Slice:
+ fn.f = (*encFnInfo).kSlice
+ case reflect.Array:
+ fn.f = (*encFnInfo).kArray
+ case reflect.Struct:
+ fn.f = (*encFnInfo).kStruct
+ // case reflect.Ptr:
+ // fn.f = (*encFnInfo).kPtr
+ case reflect.Interface:
+ fn.f = (*encFnInfo).kInterface
+ case reflect.Map:
+ fn.f = (*encFnInfo).kMap
+ default:
+ fn.f = (*encFnInfo).kErr
+ }
+ }
+ if useMapForCodecCache {
+ if e.f == nil {
+ e.f = make(map[uintptr]encFn, 16)
+ }
+ e.f[rtid] = fn
+ } else {
+ e.s = append(e.s, fn)
+ e.x = append(e.x, rtid)
+ }
+ }
+
+ fn.f(fn.i, rv)
+
+}
+
+func (e *Encoder) encRawExt(re RawExt) {
+ if re.Data == nil {
+ e.e.encodeNil()
+ return
+ }
+ if e.hh.writeExt() {
+ e.e.encodeExtPreamble(re.Tag, len(re.Data))
+ e.w.writeb(re.Data)
+ } else {
+ e.e.encodeStringBytes(c_RAW, re.Data)
+ }
+}
+
+// ---------------------------------------------
+// short circuit functions for common maps and slices
+
+func (e *Encoder) encSliceIntf(v []interface{}) {
+ e.e.encodeArrayPreamble(len(v))
+ for _, v2 := range v {
+ e.encode(v2)
+ }
+}
+
+func (e *Encoder) encSliceStr(v []string) {
+ e.e.encodeArrayPreamble(len(v))
+ for _, v2 := range v {
+ e.e.encodeString(c_UTF8, v2)
+ }
+}
+
+func (e *Encoder) encSliceInt64(v []int64) {
+ e.e.encodeArrayPreamble(len(v))
+ for _, v2 := range v {
+ e.e.encodeInt(v2)
+ }
+}
+
+func (e *Encoder) encSliceUint64(v []uint64) {
+ e.e.encodeArrayPreamble(len(v))
+ for _, v2 := range v {
+ e.e.encodeUint(v2)
+ }
+}
+
+func (e *Encoder) encMapStrStr(v map[string]string) {
+ e.e.encodeMapPreamble(len(v))
+ asSymbols := e.h.AsSymbols&AsSymbolMapStringKeysFlag != 0
+ for k2, v2 := range v {
+ if asSymbols {
+ e.e.encodeSymbol(k2)
+ } else {
+ e.e.encodeString(c_UTF8, k2)
+ }
+ e.e.encodeString(c_UTF8, v2)
+ }
+}
+
+func (e *Encoder) encMapStrIntf(v map[string]interface{}) {
+ e.e.encodeMapPreamble(len(v))
+ asSymbols := e.h.AsSymbols&AsSymbolMapStringKeysFlag != 0
+ for k2, v2 := range v {
+ if asSymbols {
+ e.e.encodeSymbol(k2)
+ } else {
+ e.e.encodeString(c_UTF8, k2)
+ }
+ e.encode(v2)
+ }
+}
+
+func (e *Encoder) encMapInt64Intf(v map[int64]interface{}) {
+ e.e.encodeMapPreamble(len(v))
+ for k2, v2 := range v {
+ e.e.encodeInt(k2)
+ e.encode(v2)
+ }
+}
+
+func (e *Encoder) encMapUint64Intf(v map[uint64]interface{}) {
+ e.e.encodeMapPreamble(len(v))
+ for k2, v2 := range v {
+ e.e.encodeUint(uint64(k2))
+ e.encode(v2)
+ }
+}
+
+func (e *Encoder) encMapIntfIntf(v map[interface{}]interface{}) {
+ e.e.encodeMapPreamble(len(v))
+ for k2, v2 := range v {
+ e.encode(k2)
+ e.encode(v2)
+ }
+}
+
+// ----------------------------------------
+
+func encErr(format string, params ...interface{}) {
+ doPanic(msgTagEnc, format, params...)
+}