185 lines
3.5 KiB
Go
185 lines
3.5 KiB
Go
package gen
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/tinylib/msgp/msgp"
|
|
"io"
|
|
)
|
|
|
|
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)
|
|
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 err }")
|
|
}
|
|
|
|
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)
|
|
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, 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 {
|
|
vname = tobaseConvert(b)
|
|
}
|
|
|
|
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)
|
|
}
|
|
}
|