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 }