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.

198 lines
3.8 KiB

package gen
import (
"fmt"
"io"
"github.com/tinylib/msgp/msgp"
)
func encode(w io.Writer) *encodeGen {
return &encodeGen{
p: printer{w: w},
}
}
type encodeGen struct {
passes
p printer
fuse []byte
}
func (e *encodeGen) Method() Method { return Encode }
func (e *encodeGen) Apply(dirs []string) error {
return nil
}
func (e *encodeGen) writeAndCheck(typ string, argfmt string, arg interface{}) {
e.p.printf("\nerr = en.Write%s(%s)", typ, fmt.Sprintf(argfmt, arg))
e.p.print(errcheck)
}
func (e *encodeGen) fuseHook() {
if len(e.fuse) > 0 {
e.appendraw(e.fuse)
e.fuse = e.fuse[:0]
}
}
func (e *encodeGen) Fuse(b []byte) {
if len(e.fuse) > 0 {
e.fuse = append(e.fuse, b...)
} else {
e.fuse = b
}
}
func (e *encodeGen) Execute(p Elem) error {
if !e.p.ok() {
return e.p.err
}
p = e.applyall(p)
if p == nil {
return nil
}
if !IsPrintable(p) {
return nil
}
e.p.comment("EncodeMsg implements msgp.Encodable")
e.p.printf("\nfunc (%s %s) EncodeMsg(en *msgp.Writer) (err error) {", p.Varname(), imutMethodReceiver(p))
next(e, p)
e.p.nakedReturn()
return e.p.err
}
func (e *encodeGen) gStruct(s *Struct) {
if !e.p.ok() {
return
}
if s.AsTuple {
e.tuple(s)
} else {
e.structmap(s)
}
return
}
func (e *encodeGen) tuple(s *Struct) {
nfields := len(s.Fields)
data := msgp.AppendArrayHeader(nil, uint32(nfields))
e.p.printf("\n// array header, size %d", nfields)
e.Fuse(data)
if len(s.Fields) == 0 {
e.fuseHook()
}
for i := range s.Fields {
if !e.p.ok() {
return
}
next(e, s.Fields[i].FieldElem)
}
}
func (e *encodeGen) appendraw(bts []byte) {
e.p.print("\nerr = en.Append(")
for i, b := range bts {
if i != 0 {
e.p.print(", ")
}
e.p.printf("0x%x", b)
}
e.p.print(")\nif err != nil { return }")
}
func (e *encodeGen) structmap(s *Struct) {
nfields := len(s.Fields)
data := msgp.AppendMapHeader(nil, uint32(nfields))
e.p.printf("\n// map header, size %d", nfields)
e.Fuse(data)
if len(s.Fields) == 0 {
e.fuseHook()
}
for i := range s.Fields {
if !e.p.ok() {
return
}
data = msgp.AppendString(nil, s.Fields[i].FieldTag)
e.p.printf("\n// write %q", s.Fields[i].FieldTag)
e.Fuse(data)
next(e, s.Fields[i].FieldElem)
}
}
func (e *encodeGen) gMap(m *Map) {
if !e.p.ok() {
return
}
e.fuseHook()
vname := m.Varname()
e.writeAndCheck(mapHeader, lenAsUint32, vname)
e.p.printf("\nfor %s, %s := range %s {", m.Keyidx, m.Validx, vname)
e.writeAndCheck(stringTyp, literalFmt, m.Keyidx)
next(e, m.Value)
e.p.closeblock()
}
func (e *encodeGen) gPtr(s *Ptr) {
if !e.p.ok() {
return
}
e.fuseHook()
e.p.printf("\nif %s == nil { err = en.WriteNil(); if err != nil { return; } } else {", s.Varname())
next(e, s.Value)
e.p.closeblock()
}
func (e *encodeGen) gSlice(s *Slice) {
if !e.p.ok() {
return
}
e.fuseHook()
e.writeAndCheck(arrayHeader, lenAsUint32, s.Varname())
e.p.rangeBlock(s.Index, s.Varname(), e, s.Els)
}
func (e *encodeGen) gArray(a *Array) {
if !e.p.ok() {
return
}
e.fuseHook()
// shortcut for [const]byte
if be, ok := a.Els.(*BaseElem); ok && (be.Value == Byte || be.Value == Uint8) {
e.p.printf("\nerr = en.WriteBytes((%s)[:])", a.Varname())
e.p.print(errcheck)
return
}
e.writeAndCheck(arrayHeader, literalFmt, coerceArraySize(a.Size))
e.p.rangeBlock(a.Index, a.Varname(), e, a.Els)
}
func (e *encodeGen) gBase(b *BaseElem) {
if !e.p.ok() {
return
}
e.fuseHook()
vname := b.Varname()
if b.Convert {
if b.ShimMode == Cast {
vname = tobaseConvert(b)
} else {
vname = randIdent()
e.p.printf("\nvar %s %s", vname, b.BaseType())
e.p.printf("\n%s, err = %s", vname, tobaseConvert(b))
e.p.printf(errcheck)
}
}
if b.Value == IDENT { // unknown identity
e.p.printf("\nerr = %s.EncodeMsg(en)", vname)
e.p.print(errcheck)
} else { // typical case
e.writeAndCheck(b.BaseName(), literalFmt, vname)
}
}