github.com/chrislusf/greenpack@v3.7.1-0.20170911073826-ad5bd10b7c47+incompatible/gen/encode.go (about)

     1  package gen
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  
     7  	"github.com/glycerine/greenpack/cfg"
     8  	"github.com/glycerine/greenpack/msgp"
     9  )
    10  
    11  func encode(w io.Writer, cfg *cfg.GreenConfig) *encodeGen {
    12  	return &encodeGen{
    13  		p:   printer{w: w},
    14  		cfg: cfg,
    15  	}
    16  }
    17  
    18  type encodeGen struct {
    19  	passes
    20  	p    printer
    21  	fuse []byte
    22  	cfg  *cfg.GreenConfig
    23  }
    24  
    25  func (e *encodeGen) MethodPrefix() string {
    26  	return e.cfg.MethodPrefix
    27  }
    28  
    29  func (e *encodeGen) Method() Method { return Encode }
    30  
    31  func (e *encodeGen) Apply(dirs []string) error {
    32  	return nil
    33  }
    34  
    35  func (e *encodeGen) writeAndCheck(typ string, argfmt string, arg interface{}) {
    36  	e.p.printf("\nerr = en.Write%s(%s)", typ, fmt.Sprintf(argfmt, arg))
    37  	e.p.print(errcheck)
    38  }
    39  
    40  func (e *encodeGen) fuseHook() {
    41  	if len(e.fuse) > 0 {
    42  		e.appendraw(e.fuse)
    43  		e.fuse = e.fuse[:0]
    44  	}
    45  }
    46  
    47  func (e *encodeGen) Fuse(b []byte) {
    48  	if len(e.fuse) > 0 {
    49  		e.fuse = append(e.fuse, b...)
    50  	} else {
    51  		e.fuse = b
    52  	}
    53  }
    54  
    55  func (e *encodeGen) Execute(p Elem) error {
    56  	if !e.p.ok() {
    57  		return e.p.err
    58  	}
    59  	p = e.applyall(p)
    60  	if p == nil {
    61  		return nil
    62  	}
    63  	if !IsPrintable(p) {
    64  		return nil
    65  	}
    66  
    67  	e.p.comment(fmt.Sprintf("%sEncodeMsg implements msgp.Encodable", e.cfg.MethodPrefix))
    68  
    69  	e.p.printf("\nfunc (%s %s) %sEncodeMsg(en *msgp.Writer) (err error) {", p.Varname(), imutMethodReceiver(p), e.cfg.MethodPrefix)
    70  	e.p.preSaveHook()
    71  	next(e, p)
    72  	e.p.nakedReturn()
    73  	return e.p.err
    74  }
    75  
    76  func (e *encodeGen) gStruct(s *Struct) {
    77  	if !e.p.ok() {
    78  		return
    79  	}
    80  
    81  	if e.cfg.AllTuple || s.AsTuple {
    82  		e.tuple(s)
    83  	} else {
    84  		e.structmap(s)
    85  	}
    86  	return
    87  }
    88  
    89  func (e *encodeGen) tuple(s *Struct) {
    90  	nfields := len(s.Fields) - s.SkipCount
    91  	data := msgp.AppendArrayHeader(nil, uint32(nfields))
    92  	e.p.printf("\n// array header, size %d", nfields)
    93  	e.Fuse(data)
    94  	for i := range s.Fields {
    95  		if s.Fields[i].Skip {
    96  			continue
    97  		}
    98  		if !e.p.ok() {
    99  			return
   100  		}
   101  		next(e, s.Fields[i].FieldElem)
   102  	}
   103  }
   104  
   105  func (e *encodeGen) appendraw(bts []byte) {
   106  	e.p.print("\nerr = en.Append(")
   107  	for i, b := range bts {
   108  		if i != 0 {
   109  			e.p.print(", ")
   110  		}
   111  		e.p.printf("0x%x", b)
   112  	}
   113  	e.p.print(")\nif err != nil { return err }")
   114  }
   115  
   116  func (e *encodeGen) structmap(s *Struct) {
   117  	nfields := len(s.Fields) - s.SkipCount
   118  	var data []byte
   119  	empty := "empty_" + gensym()
   120  	inUse := "fieldsInUse_" + gensym()
   121  
   122  	allOmitEmpty := !e.cfg.SerzEmpty
   123  	skipclue := e.cfg.SkipZidClue || e.cfg.Msgpack2
   124  
   125  	if allOmitEmpty || s.hasOmitEmptyTags {
   126  		e.p.printf("\n\n// honor the omitempty tags\n")
   127  		e.p.printf("var %s [%d]bool\n", empty, len(s.Fields))
   128  		e.p.printf("%s := %s.fieldsNotEmpty(%s[:])\n",
   129  			inUse, s.vname, empty)
   130  		e.p.printf("\n// map header\n")
   131  		e.p.printf("	err = en.WriteMapHeader(%s)\n", inUse)
   132  		e.p.printf("	if err != nil {\n")
   133  		e.p.printf("		return err\n}\n")
   134  	} else {
   135  		data = msgp.AppendMapHeader(nil, uint32(nfields))
   136  		e.p.printf("\n// map header, size %d", nfields)
   137  		e.Fuse(data)
   138  		e.fuseHook()
   139  	}
   140  
   141  	for i := range s.Fields {
   142  		if s.Fields[i].Skip {
   143  			continue
   144  		}
   145  		if !e.p.ok() {
   146  			return
   147  		}
   148  
   149  		if allOmitEmpty || (s.hasOmitEmptyTags && s.Fields[i].OmitEmpty) {
   150  			e.p.printf("\n if !%s[%d] {", empty, i)
   151  		}
   152  
   153  		fld := s.Fields[i].FieldTagZidClue
   154  		if skipclue {
   155  			fld = s.Fields[i].FieldTag
   156  		}
   157  		data = msgp.AppendString(nil, fld)
   158  		e.p.printf("\n// write %q", fld)
   159  		e.Fuse(data)
   160  		e.fuseHook()
   161  		next(e, s.Fields[i].FieldElem)
   162  
   163  		if allOmitEmpty || (s.hasOmitEmptyTags && s.Fields[i].OmitEmpty) {
   164  			e.p.printf("\n }\n")
   165  		}
   166  	}
   167  }
   168  
   169  func (e *encodeGen) gMap(m *Map) {
   170  	if !e.p.ok() {
   171  		return
   172  	}
   173  	e.fuseHook()
   174  	vname := m.Varname()
   175  	e.writeAndCheck(mapHeader, lenAsUint32, vname)
   176  
   177  	e.p.printf("\nfor %s, %s := range %s {", m.Keyidx, m.Validx, vname)
   178  	e.writeAndCheck(m.KeyTyp, literalFmt, m.Keyidx)
   179  	next(e, m.Value)
   180  	e.p.closeblock()
   181  }
   182  
   183  func (e *encodeGen) gPtr(s *Ptr) {
   184  	if !e.p.ok() {
   185  		return
   186  	}
   187  	e.fuseHook()
   188  	e.p.printf("\nif %s == nil { err = en.WriteNil(); if err != nil { return; } } else {", s.Varname())
   189  	next(e, s.Value)
   190  	e.p.closeblock()
   191  }
   192  
   193  func (e *encodeGen) gSlice(s *Slice) {
   194  	if !e.p.ok() {
   195  		return
   196  	}
   197  	e.fuseHook()
   198  	e.writeAndCheck(arrayHeader, lenAsUint32, s.Varname())
   199  	e.p.rangeBlock(s.Index, s.Varname(), e, s.Els)
   200  }
   201  
   202  func (e *encodeGen) gArray(a *Array) {
   203  	if !e.p.ok() {
   204  		return
   205  	}
   206  	e.fuseHook()
   207  	// shortcut for [const]byte
   208  	if be, ok := a.Els.(*BaseElem); ok && (be.Value == Byte || be.Value == Uint8) {
   209  		e.p.printf("\nerr = en.WriteBytes(%s[:])", a.Varname())
   210  		e.p.print(errcheck)
   211  		return
   212  	}
   213  
   214  	e.writeAndCheck(arrayHeader, literalFmt, a.SizeResolved)
   215  	e.p.rangeBlock(a.Index, a.Varname(), e, a.Els)
   216  }
   217  
   218  func (e *encodeGen) gBase(b *BaseElem) {
   219  	if !e.p.ok() {
   220  		return
   221  	}
   222  	e.fuseHook()
   223  	vname := b.Varname()
   224  	if b.Convert {
   225  		vname = tobaseConvert(b)
   226  	}
   227  
   228  	if b.Value == IDENT { // unknown identity
   229  		e.p.printf("\nerr = %s.%sEncodeMsg(en)", vname, e.cfg.MethodPrefix)
   230  		e.p.print(errcheck)
   231  	} else { // typical case
   232  		e.writeAndCheck(b.BaseName(), literalFmt, vname)
   233  	}
   234  }