bump(ugoriji/go/codec): ded73eae5db7e7a0ef6f55aace87a2873c5d2b74

This commit is contained in:
Dr. Stefan Schimanski
2016-11-28 16:23:01 +01:00
committed by Dr. Stefan Schimanski
parent 1122bf2c58
commit 9045892464
35 changed files with 1609 additions and 378 deletions

View File

@@ -12,7 +12,6 @@ import (
"io"
"io/ioutil"
"math/rand"
"os"
"reflect"
"regexp"
"sort"
@@ -21,11 +20,14 @@ import (
"sync"
"text/template"
"time"
"unicode"
"unicode/utf8"
)
// ---------------------------------------------------
// codecgen supports the full cycle of reflection-based codec:
// - RawExt
// - Raw
// - Builtins
// - Extensions
// - (Binary|Text|JSON)(Unm|M)arshal
@@ -76,7 +78,7 @@ import (
// codecgen will panic if the file was generated with an old version of the library in use.
//
// Note:
// It was a concious decision to have gen.go always explicitly call EncodeNil or TryDecodeAsNil.
// It was a conscious decision to have gen.go always explicitly call EncodeNil or TryDecodeAsNil.
// This way, there isn't a function call overhead just to see that we should not enter a block of code.
// GenVersion is the current version of codecgen.
@@ -124,6 +126,7 @@ var (
genExpectArrayOrMapErr = errors.New("unexpected type. Expecting array/map/slice")
genBase64enc = base64.NewEncoding("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789__")
genQNameRegex = regexp.MustCompile(`[A-Za-z_.]+`)
genCheckVendor bool
)
// genRunner holds some state used during a Gen run.
@@ -162,6 +165,10 @@ type genRunner struct {
//
// Library users: *DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINOUSLY WITHOUT NOTICE.*
func Gen(w io.Writer, buildTags, pkgName, uid string, useUnsafe bool, ti *TypeInfos, typ ...reflect.Type) {
// All types passed to this method do not have a codec.Selfer method implemented directly.
// codecgen already checks the AST and skips any types that define the codec.Selfer methods.
// Consequently, there's no need to check and trim them if they implement codec.Selfer
if len(typ) == 0 {
return
}
@@ -199,7 +206,7 @@ func Gen(w io.Writer, buildTags, pkgName, uid string, useUnsafe bool, ti *TypeIn
x.genRefPkgs(t)
}
if buildTags != "" {
x.line("//+build " + buildTags)
x.line("// +build " + buildTags)
x.line("")
}
x.line(`
@@ -266,6 +273,7 @@ func Gen(w io.Writer, buildTags, pkgName, uid string, useUnsafe bool, ti *TypeIn
x.line("type " + x.hn + " struct{}")
x.line("")
x.varsfxreset()
x.line("func init() {")
x.linef("if %sGenVersion != %v {", x.cpfx, GenVersion)
x.line("_, file, _, _ := runtime.Caller(0)")
@@ -309,6 +317,7 @@ func Gen(w io.Writer, buildTags, pkgName, uid string, useUnsafe bool, ti *TypeIn
for _, t := range x.ts {
rtid := reflect.ValueOf(t).Pointer()
// generate enc functions for all these slice/map types.
x.varsfxreset()
x.linef("func (x %s) enc%s(v %s%s, e *%sEncoder) {", x.hn, x.genMethodNameT(t), x.arr2str(t, "*"), x.genTypeName(t), x.cpfx)
x.genRequiredMethodVars(true)
switch t.Kind() {
@@ -323,6 +332,7 @@ func Gen(w io.Writer, buildTags, pkgName, uid string, useUnsafe bool, ti *TypeIn
x.line("")
// generate dec functions for all these slice/map types.
x.varsfxreset()
x.linef("func (x %s) dec%s(v *%s, d *%sDecoder) {", x.hn, x.genMethodNameT(t), x.genTypeName(t), x.cpfx)
x.genRequiredMethodVars(false)
switch t.Kind() {
@@ -377,7 +387,7 @@ func (x *genRunner) genRefPkgs(t reflect.Type) {
x.imn[tpkg] = tpkg
} else {
x.imc++
x.imn[tpkg] = "pkg" + strconv.FormatUint(x.imc, 10) + "_" + tpkg[idx+1:]
x.imn[tpkg] = "pkg" + strconv.FormatUint(x.imc, 10) + "_" + genGoIdentifier(tpkg[idx+1:], false)
}
}
}
@@ -408,6 +418,10 @@ func (x *genRunner) varsfx() string {
return strconv.FormatUint(x.c, 10)
}
func (x *genRunner) varsfxreset() {
x.c = 0
}
func (x *genRunner) out(s string) {
if _, err := io.WriteString(x.w, s); err != nil {
panic(err)
@@ -494,6 +508,7 @@ func (x *genRunner) selfer(encode bool) {
// always make decode use a pointer receiver,
// and structs always use a ptr receiver (encode|decode)
isptr := !encode || t.Kind() == reflect.Struct
x.varsfxreset()
fnSigPfx := "func (x "
if isptr {
fnSigPfx += "*"
@@ -566,9 +581,28 @@ func (x *genRunner) xtraSM(varname string, encode bool, t reflect.Type) {
} else {
x.linef("h.dec%s((*%s)(%s), d)", x.genMethodNameT(t), x.genTypeName(t), varname)
}
if _, ok := x.tm[t]; !ok {
x.tm[t] = struct{}{}
x.ts = append(x.ts, t)
x.registerXtraT(t)
}
func (x *genRunner) registerXtraT(t reflect.Type) {
// recursively register the types
if _, ok := x.tm[t]; ok {
return
}
var tkey reflect.Type
switch t.Kind() {
case reflect.Chan, reflect.Slice, reflect.Array:
case reflect.Map:
tkey = t.Key()
default:
return
}
x.tm[t] = struct{}{}
x.ts = append(x.ts, t)
// check if this refers to any xtra types eg. a slice of array: add the array
x.registerXtraT(t.Elem())
if tkey != nil {
x.registerXtraT(tkey)
}
}
@@ -608,22 +642,33 @@ func (x *genRunner) encVar(varname string, t reflect.Type) {
}
// enc will encode a variable (varname) of type T,
// except t is of kind reflect.Struct or reflect.Array, wherein varname is of type *T (to prevent copying)
// enc will encode a variable (varname) of type t,
// except t is of kind reflect.Struct or reflect.Array, wherein varname is of type ptrTo(T) (to prevent copying)
func (x *genRunner) enc(varname string, t reflect.Type) {
// varName here must be to a pointer to a struct/array, or to a value directly.
rtid := reflect.ValueOf(t).Pointer()
// We call CodecEncodeSelf if one of the following are honored:
// - the type already implements Selfer, call that
// - the type has a Selfer implementation just created, use that
// - the type is in the list of the ones we will generate for, but it is not currently being generated
mi := x.varsfx()
tptr := reflect.PtrTo(t)
tk := t.Kind()
if x.checkForSelfer(t, varname) {
if t.Implements(selferTyp) || (tptr.Implements(selferTyp) && (tk == reflect.Array || tk == reflect.Struct)) {
x.line(varname + ".CodecEncodeSelf(e)")
return
if tk == reflect.Array || tk == reflect.Struct { // varname is of type *T
if tptr.Implements(selferTyp) || t.Implements(selferTyp) {
x.line(varname + ".CodecEncodeSelf(e)")
return
}
} else { // varname is of type T
if t.Implements(selferTyp) {
x.line(varname + ".CodecEncodeSelf(e)")
return
} else if tptr.Implements(selferTyp) {
x.linef("%ssf%s := &%s", genTempVarPfx, mi, varname)
x.linef("%ssf%s.CodecEncodeSelf(e)", genTempVarPfx, mi)
return
}
}
if _, ok := x.te[rtid]; ok {
@@ -651,14 +696,17 @@ func (x *genRunner) enc(varname string, t reflect.Type) {
}
// check if
// - type is RawExt
// - type is RawExt, Raw
// - the type implements (Text|JSON|Binary)(Unm|M)arshal
mi := x.varsfx()
x.linef("%sm%s := z.EncBinary()", genTempVarPfx, mi)
x.linef("_ = %sm%s", genTempVarPfx, mi)
x.line("if false {") //start if block
defer func() { x.line("}") }() //end if block
if t == rawTyp {
x.linef("} else { z.EncRaw(%v)", varname)
return
}
if t == rawExtTyp {
x.linef("} else { r.EncodeRawExt(%v, e)", varname)
return
@@ -676,15 +724,31 @@ func (x *genRunner) enc(varname string, t reflect.Type) {
// first check if extensions are configued, before doing the interface conversion
x.linef("} else if z.HasExtensions() && z.EncExt(%s) {", varname)
}
if t.Implements(binaryMarshalerTyp) || tptr.Implements(binaryMarshalerTyp) {
x.linef("} else if %sm%s { z.EncBinaryMarshal(%v) ", genTempVarPfx, mi, varname)
if tk == reflect.Array || tk == reflect.Struct { // varname is of type *T
if t.Implements(binaryMarshalerTyp) || tptr.Implements(binaryMarshalerTyp) {
x.linef("} else if %sm%s { z.EncBinaryMarshal(%v) ", genTempVarPfx, mi, varname)
}
if t.Implements(jsonMarshalerTyp) || tptr.Implements(jsonMarshalerTyp) {
x.linef("} else if !%sm%s && z.IsJSONHandle() { z.EncJSONMarshal(%v) ", genTempVarPfx, mi, varname)
} else if t.Implements(textMarshalerTyp) || tptr.Implements(textMarshalerTyp) {
x.linef("} else if !%sm%s { z.EncTextMarshal(%v) ", genTempVarPfx, mi, varname)
}
} else { // varname is of type T
if t.Implements(binaryMarshalerTyp) {
x.linef("} else if %sm%s { z.EncBinaryMarshal(%v) ", genTempVarPfx, mi, varname)
} else if tptr.Implements(binaryMarshalerTyp) {
x.linef("} else if %sm%s { z.EncBinaryMarshal(&%v) ", genTempVarPfx, mi, varname)
}
if t.Implements(jsonMarshalerTyp) {
x.linef("} else if !%sm%s && z.IsJSONHandle() { z.EncJSONMarshal(%v) ", genTempVarPfx, mi, varname)
} else if tptr.Implements(jsonMarshalerTyp) {
x.linef("} else if !%sm%s && z.IsJSONHandle() { z.EncJSONMarshal(&%v) ", genTempVarPfx, mi, varname)
} else if t.Implements(textMarshalerTyp) {
x.linef("} else if !%sm%s { z.EncTextMarshal(%v) ", genTempVarPfx, mi, varname)
} else if tptr.Implements(textMarshalerTyp) {
x.linef("} else if !%sm%s { z.EncTextMarshal(&%v) ", genTempVarPfx, mi, varname)
}
}
if t.Implements(jsonMarshalerTyp) || tptr.Implements(jsonMarshalerTyp) {
x.linef("} else if !%sm%s && z.IsJSONHandle() { z.EncJSONMarshal(%v) ", genTempVarPfx, mi, varname)
} else if t.Implements(textMarshalerTyp) || tptr.Implements(textMarshalerTyp) {
x.linef("} else if !%sm%s { z.EncTextMarshal(%v) ", genTempVarPfx, mi, varname)
}
x.line("} else {")
switch t.Kind() {
@@ -922,6 +986,14 @@ func (x *genRunner) encStruct(varname string, rtid uintptr, t reflect.Type) {
}
func (x *genRunner) encListFallback(varname string, t reflect.Type) {
if t.AssignableTo(uint8SliceTyp) {
x.linef("r.EncodeStringBytes(codecSelferC_RAW%s, []byte(%s))", x.xs, varname)
return
}
if t.Kind() == reflect.Array && t.Elem().Kind() == reflect.Uint8 {
x.linef("r.EncodeStringBytes(codecSelferC_RAW%s, ([%v]byte(%s))[:])", x.xs, t.Len(), varname)
return
}
i := x.varsfx()
g := genTempVarPfx
x.line("r.EncodeArrayStart(len(" + varname + "))")
@@ -1020,6 +1092,8 @@ func (x *genRunner) decVar(varname string, t reflect.Type, canBeNil bool) {
}
}
// dec will decode a variable (varname) of type ptrTo(t).
// t is always a basetype (i.e. not of kind reflect.Ptr).
func (x *genRunner) dec(varname string, t reflect.Type) {
// assumptions:
// - the varname is to a pointer already. No need to take address of it
@@ -1056,7 +1130,7 @@ func (x *genRunner) dec(varname string, t reflect.Type) {
}
// check if
// - type is RawExt
// - type is Raw, RawExt
// - the type implements (Text|JSON|Binary)(Unm|M)arshal
mi := x.varsfx()
x.linef("%sm%s := z.DecBinary()", genTempVarPfx, mi)
@@ -1064,6 +1138,10 @@ func (x *genRunner) dec(varname string, t reflect.Type) {
x.line("if false {") //start if block
defer func() { x.line("}") }() //end if block
if t == rawTyp {
x.linef("} else { *%v = z.DecRaw()", varname)
return
}
if t == rawExtTyp {
x.linef("} else { r.DecodeExt(%v, 0, nil)", varname)
return
@@ -1189,59 +1267,49 @@ func (x *genRunner) dec(varname string, t reflect.Type) {
}
func (x *genRunner) decTryAssignPrimitive(varname string, t reflect.Type) (tryAsPtr bool) {
// We have to use the actual type name when doing a direct assignment.
// We don't have the luxury of casting the pointer to the underlying type.
//
// Consequently, in the situation of a
// type Message int32
// var x Message
// var i int32 = 32
// x = i // this will bomb
// x = Message(i) // this will work
// *((*int32)(&x)) = i // this will work
//
// Consequently, we replace:
// case reflect.Uint32: x.line(varname + " = uint32(r.DecodeUint(32))")
// with:
// case reflect.Uint32: x.line(varname + " = " + genTypeNamePrim(t, x.tc) + "(r.DecodeUint(32))")
// This should only be used for exact primitives (ie un-named types).
// Named types may be implementations of Selfer, Unmarshaler, etc.
// They should be handled by dec(...)
xfn := func(t reflect.Type) string {
return x.genTypeNamePrim(t)
if t.Name() != "" {
tryAsPtr = true
return
}
switch t.Kind() {
case reflect.Int:
x.linef("%s = %s(r.DecodeInt(codecSelferBitsize%s))", varname, xfn(t), x.xs)
x.linef("%s = r.DecodeInt(codecSelferBitsize%s)", varname, x.xs)
case reflect.Int8:
x.linef("%s = %s(r.DecodeInt(8))", varname, xfn(t))
x.linef("%s = r.DecodeInt(8)", varname)
case reflect.Int16:
x.linef("%s = %s(r.DecodeInt(16))", varname, xfn(t))
x.linef("%s = r.DecodeInt(16)", varname)
case reflect.Int32:
x.linef("%s = %s(r.DecodeInt(32))", varname, xfn(t))
x.linef("%s = r.DecodeInt(32)", varname)
case reflect.Int64:
x.linef("%s = %s(r.DecodeInt(64))", varname, xfn(t))
x.linef("%s = r.DecodeInt(64)", varname)
case reflect.Uint:
x.linef("%s = %s(r.DecodeUint(codecSelferBitsize%s))", varname, xfn(t), x.xs)
x.linef("%s = r.DecodeUint(codecSelferBitsize%s)", varname, x.xs)
case reflect.Uint8:
x.linef("%s = %s(r.DecodeUint(8))", varname, xfn(t))
x.linef("%s = r.DecodeUint(8)", varname)
case reflect.Uint16:
x.linef("%s = %s(r.DecodeUint(16))", varname, xfn(t))
x.linef("%s = r.DecodeUint(16)", varname)
case reflect.Uint32:
x.linef("%s = %s(r.DecodeUint(32))", varname, xfn(t))
x.linef("%s = r.DecodeUint(32)", varname)
case reflect.Uint64:
x.linef("%s = %s(r.DecodeUint(64))", varname, xfn(t))
x.linef("%s = r.DecodeUint(64)", varname)
case reflect.Uintptr:
x.linef("%s = %s(r.DecodeUint(codecSelferBitsize%s))", varname, xfn(t), x.xs)
x.linef("%s = r.DecodeUint(codecSelferBitsize%s)", varname, x.xs)
case reflect.Float32:
x.linef("%s = %s(r.DecodeFloat(true))", varname, xfn(t))
x.linef("%s = r.DecodeFloat(true)", varname)
case reflect.Float64:
x.linef("%s = %s(r.DecodeFloat(false))", varname, xfn(t))
x.linef("%s = r.DecodeFloat(false)", varname)
case reflect.Bool:
x.linef("%s = %s(r.DecodeBool())", varname, xfn(t))
x.linef("%s = r.DecodeBool()", varname)
case reflect.String:
x.linef("%s = %s(r.DecodeString())", varname, xfn(t))
x.linef("%s = r.DecodeString()", varname)
default:
tryAsPtr = true
}
@@ -1249,6 +1317,14 @@ func (x *genRunner) decTryAssignPrimitive(varname string, t reflect.Type) (tryAs
}
func (x *genRunner) decListFallback(varname string, rtid uintptr, t reflect.Type) {
if t.AssignableTo(uint8SliceTyp) {
x.line("*" + varname + " = r.DecodeBytes(*((*[]byte)(" + varname + ")), false, false)")
return
}
if t.Kind() == reflect.Array && t.Elem().Kind() == reflect.Uint8 {
x.linef("r.DecodeBytes( ((*[%s]byte)(%s))[:], false, true)", t.Len(), varname)
return
}
type tstruc struct {
TempVar string
Rand string
@@ -1364,7 +1440,7 @@ func (x *genRunner) decStructMapSwitch(kName string, varname string, rtid uintpt
if si.i != -1 {
t2 = t.Field(int(si.i))
} else {
//we must accomodate anonymous fields, where the embedded field is a nil pointer in the value.
//we must accommodate anonymous fields, where the embedded field is a nil pointer in the value.
// t2 = t.FieldByIndex(si.is)
t2typ := t
varname3 := varname
@@ -1452,7 +1528,7 @@ func (x *genRunner) decStructArray(varname, lenvarname, breakString string, rtid
if si.i != -1 {
t2 = t.Field(int(si.i))
} else {
//we must accomodate anonymous fields, where the embedded field is a nil pointer in the value.
//we must accommodate anonymous fields, where the embedded field is a nil pointer in the value.
// t2 = t.FieldByIndex(si.is)
t2typ := t
varname3 := varname
@@ -1569,8 +1645,6 @@ func (x *genV) MethodNamePfx(prefix string, prim bool) string {
}
var genCheckVendor = os.Getenv("GO15VENDOREXPERIMENT") == "1"
// genImportPath returns import path of a non-predeclared named typed, or an empty string otherwise.
//
// This handles the misbehaviour that occurs when 1.5-style vendoring is enabled,
@@ -1592,6 +1666,26 @@ func genImportPath(t reflect.Type) (s string) {
return
}
// A go identifier is (letter|_)[letter|number|_]*
func genGoIdentifier(s string, checkFirstChar bool) string {
b := make([]byte, 0, len(s))
t := make([]byte, 4)
var n int
for i, r := range s {
if checkFirstChar && i == 0 && !unicode.IsLetter(r) {
b = append(b, '_')
}
// r must be unicode_letter, unicode_digit or _
if unicode.IsLetter(r) || unicode.IsDigit(r) {
n = utf8.EncodeRune(t, r)
b = append(b, t[:n]...)
} else {
b = append(b, '_')
}
}
return string(b)
}
func genNonPtr(t reflect.Type) reflect.Type {
for t.Kind() == reflect.Ptr {
t = t.Elem()
@@ -1601,7 +1695,7 @@ func genNonPtr(t reflect.Type) reflect.Type {
func genTitleCaseName(s string) string {
switch s {
case "interface{}":
case "interface{}", "interface {}":
return "Intf"
default:
return strings.ToUpper(s[0:1]) + s[1:]
@@ -1704,7 +1798,7 @@ func (x genInternal) FastpathLen() (l int) {
func genInternalZeroValue(s string) string {
switch s {
case "interface{}":
case "interface{}", "interface {}":
return "nil"
case "bool":
return "false"
@@ -1856,7 +1950,7 @@ func genInternalInit() {
}
var gt genInternal
// For each slice or map type, there must be a (symetrical) Encode and Decode fast-path function
// For each slice or map type, there must be a (symmetrical) Encode and Decode fast-path function
for _, s := range types {
gt.Values = append(gt.Values, genV{Primitive: s, Size: mapvaltypes2[s]})
if s != "uint8" { // do not generate fast path for slice of bytes. Treat specially already.