package gen
|
|
|
|
import (
|
|
"io"
|
|
"strconv"
|
|
)
|
|
|
|
func decode(w io.Writer) *decodeGen {
|
|
return &decodeGen{
|
|
p: printer{w: w},
|
|
hasfield: false,
|
|
}
|
|
}
|
|
|
|
type decodeGen struct {
|
|
passes
|
|
p printer
|
|
hasfield bool
|
|
}
|
|
|
|
func (d *decodeGen) Method() Method { return Decode }
|
|
|
|
func (d *decodeGen) needsField() {
|
|
if d.hasfield {
|
|
return
|
|
}
|
|
d.p.print("\nvar field []byte; _ = field")
|
|
d.hasfield = true
|
|
}
|
|
|
|
func (d *decodeGen) Execute(p Elem) error {
|
|
p = d.applyall(p)
|
|
if p == nil {
|
|
return nil
|
|
}
|
|
d.hasfield = false
|
|
if !d.p.ok() {
|
|
return d.p.err
|
|
}
|
|
|
|
if !IsPrintable(p) {
|
|
return nil
|
|
}
|
|
|
|
d.p.comment("DecodeMsg implements msgp.Decodable")
|
|
|
|
d.p.printf("\nfunc (%s %s) DecodeMsg(dc *msgp.Reader) (err error) {", p.Varname(), methodReceiver(p))
|
|
next(d, p)
|
|
d.p.nakedReturn()
|
|
unsetReceiver(p)
|
|
return d.p.err
|
|
}
|
|
|
|
func (d *decodeGen) gStruct(s *Struct) {
|
|
if !d.p.ok() {
|
|
return
|
|
}
|
|
if s.AsTuple {
|
|
d.structAsTuple(s)
|
|
} else {
|
|
d.structAsMap(s)
|
|
}
|
|
return
|
|
}
|
|
|
|
func (d *decodeGen) assignAndCheck(name string, typ string) {
|
|
if !d.p.ok() {
|
|
return
|
|
}
|
|
d.p.printf("\n%s, err = dc.Read%s()", name, typ)
|
|
d.p.print(errcheck)
|
|
}
|
|
|
|
func (d *decodeGen) structAsTuple(s *Struct) {
|
|
nfields := len(s.Fields)
|
|
|
|
sz := randIdent()
|
|
d.p.declare(sz, u32)
|
|
d.assignAndCheck(sz, arrayHeader)
|
|
d.p.arrayCheck(strconv.Itoa(nfields), sz)
|
|
for i := range s.Fields {
|
|
if !d.p.ok() {
|
|
return
|
|
}
|
|
next(d, s.Fields[i].FieldElem)
|
|
}
|
|
}
|
|
|
|
func (d *decodeGen) structAsMap(s *Struct) {
|
|
d.needsField()
|
|
sz := randIdent()
|
|
d.p.declare(sz, u32)
|
|
d.assignAndCheck(sz, mapHeader)
|
|
|
|
d.p.printf("\nfor %s > 0 {\n%s--", sz, sz)
|
|
d.assignAndCheck("field", mapKey)
|
|
d.p.print("\nswitch msgp.UnsafeString(field) {")
|
|
for i := range s.Fields {
|
|
d.p.printf("\ncase \"%s\":", s.Fields[i].FieldTag)
|
|
next(d, s.Fields[i].FieldElem)
|
|
if !d.p.ok() {
|
|
return
|
|
}
|
|
}
|
|
d.p.print("\ndefault:\nerr = dc.Skip()")
|
|
d.p.print(errcheck)
|
|
d.p.closeblock() // close switch
|
|
d.p.closeblock() // close for loop
|
|
}
|
|
|
|
func (d *decodeGen) gBase(b *BaseElem) {
|
|
if !d.p.ok() {
|
|
return
|
|
}
|
|
|
|
// open block for 'tmp'
|
|
var tmp string
|
|
if b.Convert {
|
|
tmp = randIdent()
|
|
d.p.printf("\n{ var %s %s", tmp, b.BaseType())
|
|
}
|
|
|
|
vname := b.Varname() // e.g. "z.FieldOne"
|
|
bname := b.BaseName() // e.g. "Float64"
|
|
|
|
// handle special cases
|
|
// for object type.
|
|
switch b.Value {
|
|
case Bytes:
|
|
if b.Convert {
|
|
d.p.printf("\n%s, err = dc.ReadBytes([]byte(%s))", tmp, vname)
|
|
} else {
|
|
d.p.printf("\n%s, err = dc.ReadBytes(%s)", vname, vname)
|
|
}
|
|
case IDENT:
|
|
d.p.printf("\nerr = %s.DecodeMsg(dc)", vname)
|
|
case Ext:
|
|
d.p.printf("\nerr = dc.ReadExtension(%s)", vname)
|
|
default:
|
|
if b.Convert {
|
|
d.p.printf("\n%s, err = dc.Read%s()", tmp, bname)
|
|
} else {
|
|
d.p.printf("\n%s, err = dc.Read%s()", vname, bname)
|
|
}
|
|
}
|
|
d.p.print(errcheck)
|
|
|
|
// close block for 'tmp'
|
|
if b.Convert {
|
|
if b.ShimMode == Cast {
|
|
d.p.printf("\n%s = %s(%s)\n}", vname, b.FromBase(), tmp)
|
|
} else {
|
|
d.p.printf("\n%s, err = %s(%s)\n}", vname, b.FromBase(), tmp)
|
|
d.p.print(errcheck)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (d *decodeGen) gMap(m *Map) {
|
|
if !d.p.ok() {
|
|
return
|
|
}
|
|
sz := randIdent()
|
|
|
|
// resize or allocate map
|
|
d.p.declare(sz, u32)
|
|
d.assignAndCheck(sz, mapHeader)
|
|
d.p.resizeMap(sz, m)
|
|
|
|
// for element in map, read string/value
|
|
// pair and assign
|
|
d.p.printf("\nfor %s > 0 {\n%s--", sz, sz)
|
|
d.p.declare(m.Keyidx, "string")
|
|
d.p.declare(m.Validx, m.Value.TypeName())
|
|
d.assignAndCheck(m.Keyidx, stringTyp)
|
|
next(d, m.Value)
|
|
d.p.mapAssign(m)
|
|
d.p.closeblock()
|
|
}
|
|
|
|
func (d *decodeGen) gSlice(s *Slice) {
|
|
if !d.p.ok() {
|
|
return
|
|
}
|
|
sz := randIdent()
|
|
d.p.declare(sz, u32)
|
|
d.assignAndCheck(sz, arrayHeader)
|
|
d.p.resizeSlice(sz, s)
|
|
d.p.rangeBlock(s.Index, s.Varname(), d, s.Els)
|
|
}
|
|
|
|
func (d *decodeGen) gArray(a *Array) {
|
|
if !d.p.ok() {
|
|
return
|
|
}
|
|
|
|
// special case if we have [const]byte
|
|
if be, ok := a.Els.(*BaseElem); ok && (be.Value == Byte || be.Value == Uint8) {
|
|
d.p.printf("\nerr = dc.ReadExactBytes((%s)[:])", a.Varname())
|
|
d.p.print(errcheck)
|
|
return
|
|
}
|
|
sz := randIdent()
|
|
d.p.declare(sz, u32)
|
|
d.assignAndCheck(sz, arrayHeader)
|
|
d.p.arrayCheck(coerceArraySize(a.Size), sz)
|
|
|
|
d.p.rangeBlock(a.Index, a.Varname(), d, a.Els)
|
|
}
|
|
|
|
func (d *decodeGen) gPtr(p *Ptr) {
|
|
if !d.p.ok() {
|
|
return
|
|
}
|
|
d.p.print("\nif dc.IsNil() {")
|
|
d.p.print("\nerr = dc.ReadNil()")
|
|
d.p.print(errcheck)
|
|
d.p.printf("\n%s = nil\n} else {", p.Varname())
|
|
d.p.initPtr(p)
|
|
next(d, p.Value)
|
|
d.p.closeblock()
|
|
}
|