You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

222 lines
4.3 KiB

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