github.com/chrislusf/greenpack@v3.7.1-0.20170911073826-ad5bd10b7c47+incompatible/gen/unmarshal.go (about) 1 package gen 2 3 import ( 4 "fmt" 5 "io" 6 "strconv" 7 "strings" 8 9 "github.com/glycerine/greenpack/cfg" 10 ) 11 12 func unmarshal(w io.Writer, cfg *cfg.GreenConfig) *unmarshalGen { 13 return &unmarshalGen{ 14 p: printer{w: w}, 15 cfg: cfg, 16 } 17 } 18 19 type unmarshalGen struct { 20 passes 21 p printer 22 hasfield bool 23 depth int 24 cfg *cfg.GreenConfig 25 post postDefs 26 } 27 28 func (u *unmarshalGen) MethodPrefix() string { 29 return u.cfg.MethodPrefix 30 } 31 32 func (d *unmarshalGen) postLines() { 33 lines := strings.Join(d.post.endlines, "\n") 34 d.p.printf("\n%s\n", lines) 35 d.post.reset() 36 } 37 38 func (u *unmarshalGen) Method() Method { return Unmarshal } 39 40 func (u *unmarshalGen) needsField() { 41 if u.hasfield { 42 return 43 } 44 u.p.print("\nvar field []byte; _ = field") 45 u.hasfield = true 46 } 47 48 func (u *unmarshalGen) Execute(p Elem) error { 49 u.hasfield = false 50 if !u.p.ok() { 51 return u.p.err 52 } 53 if !IsPrintable(p) { 54 return nil 55 } 56 57 u.p.comment(fmt.Sprintf("%sUnmarshalMsg implements msgp.Unmarshaler", u.cfg.MethodPrefix)) 58 59 vname := p.Varname() 60 methRcvr := methodReceiver(p) 61 if u.cfg.ReadStringsFast { 62 u.p.printf("\nfunc (%s %s) %sUnmarshalMsg(bts []byte) (o []byte, err error) {\n cfg := &msgp.RuntimeConfig{UnsafeZeroCopy:true}; return %s.%sUnmarshalMsgWithCfg(bts, cfg)\n}", vname, methRcvr, u.cfg.MethodPrefix, vname, u.cfg.MethodPrefix) 63 } else { 64 u.p.printf("\nfunc (%s %s) %sUnmarshalMsg(bts []byte) (o []byte, err error) {\n return %s.%sUnmarshalMsgWithCfg(bts, nil)\n}", vname, methRcvr, u.cfg.MethodPrefix, vname, u.cfg.MethodPrefix) 65 } 66 u.p.printf("\nfunc (%s %s) %sUnmarshalMsgWithCfg(bts []byte, cfg *msgp.RuntimeConfig) (o []byte, err error) {", vname, methRcvr, u.cfg.MethodPrefix) 67 // u.p.printf("\nvar nbs msgp.NilBitsStack;\nvar sawTopNil bool\n if msgp.IsNil(bts) {\n sawTopNil = true\n fmt.Printf(\"len of bts pre push: %%v\\n\", len(bts)); bts = nbs.PushAlwaysNil(bts[1:]);\n fmt.Printf(\"len of bts post push: %%v\\n\", len(bts));\n }\n") 68 u.p.printf("\nvar nbs msgp.NilBitsStack;\nnbs.Init(cfg)\nvar sawTopNil bool\n if msgp.IsNil(bts) {\n sawTopNil = true\n bts = nbs.PushAlwaysNil(bts[1:]);\n }\n") 69 next(u, p) 70 u.p.print("\n if sawTopNil {bts = nbs.PopAlwaysNil()}\n o = bts") 71 72 u.p.postLoadHook() 73 u.p.nakedReturn() 74 unsetReceiver(p) 75 u.postLines() 76 return u.p.err 77 } 78 79 // does assignment to the variable "name" with the type "base" 80 func (u *unmarshalGen) assignAndCheck(name string, base string) { 81 if !u.p.ok() { 82 return 83 } 84 u.p.printf("\n%s, bts, err = nbs.Read%sBytes(bts)", name, base) 85 u.p.print(errcheck) 86 } 87 88 func (u *unmarshalGen) gStruct(s *Struct) { 89 u.depth++ 90 defer func() { 91 u.depth-- 92 }() 93 94 if !u.p.ok() { 95 return 96 } 97 if u.cfg.AllTuple || s.AsTuple { 98 u.tuple(s) 99 } else { 100 u.mapstruct(s) 101 } 102 return 103 } 104 105 func (u *unmarshalGen) tuple(s *Struct) { 106 107 // open block 108 sz := gensym() 109 u.p.declare(sz, u32) 110 u.assignAndCheck(sz, arrayHeader) 111 u.p.arrayCheck(strconv.Itoa(len(s.Fields)-s.SkipCount), sz, "") 112 for i := range s.Fields { 113 if s.Fields[i].Skip { 114 continue 115 } 116 117 if !u.p.ok() { 118 return 119 } 120 next(u, s.Fields[i].FieldElem) 121 } 122 } 123 124 func (u *unmarshalGen) mapstruct(s *Struct) { 125 n := len(s.Fields) // - s.SkipCount 126 if n == 0 { 127 return 128 } 129 130 skipclue := u.cfg.SkipZidClue || u.cfg.Msgpack2 131 132 u.needsField() 133 k := genSerial() 134 tmpl, nStr := genUnmarshalMsgTemplate(k) 135 136 fieldOrder := fmt.Sprintf("\n var unmarshalMsgFieldOrder%s = []string{", nStr) 137 fieldSkip := fmt.Sprintf("\n var unmarshalMsgFieldSkip%s = []bool{", nStr) 138 for i := range s.Fields { 139 if s.Fields[i].Skip { 140 fieldSkip += fmt.Sprintf("true,") 141 } else { 142 fieldSkip += fmt.Sprintf("false,") 143 } 144 fld := s.Fields[i].FieldTagZidClue 145 if skipclue { 146 fld = s.Fields[i].FieldTag 147 } 148 149 fieldOrder += fmt.Sprintf("%q,", fld) 150 } 151 fieldOrder += "}\n" 152 fieldSkip += "}\n" 153 154 varname := strings.Replace(s.TypeName(), "\n", ";", -1) 155 u.post.add(varname, "\n// fields of %s%s%s", varname, fieldOrder, fieldSkip) 156 157 u.p.printf("\n const maxFields%s = %d\n", nStr, n) 158 159 found := "found" + nStr 160 u.p.printf(tmpl) 161 162 for i := range s.Fields { 163 if s.Fields[i].Skip { 164 continue 165 } 166 fld := s.Fields[i].FieldTagZidClue 167 if skipclue { 168 fld = s.Fields[i].FieldTag 169 } 170 171 u.p.printf("\ncase \"%s\":", fld) 172 u.p.printf("\n%s[%d]=true;", found, i) 173 u.depth++ 174 next(u, s.Fields[i].FieldElem) 175 u.depth-- 176 if !u.p.ok() { 177 return 178 } 179 } 180 u.p.print("\ndefault:\nbts, err = msgp.Skip(bts)") 181 u.p.print(errcheck) 182 u.p.print("\n}\n}") // close switch and for loop 183 184 u.p.printf("\n if nextMiss%s != -1 { bts = nbs.PopAlwaysNil(); }\n", nStr) 185 } 186 187 func (u *unmarshalGen) gBase(b *BaseElem) { 188 if !u.p.ok() { 189 return 190 } 191 192 refname := b.Varname() // assigned to 193 lowered := b.Varname() // passed as argument 194 if b.Convert { 195 // begin 'tmp' block 196 refname = gensym() 197 lowered = b.ToBase() + "(" + lowered + ")" 198 u.p.printf("\n{\nvar %s %s", refname, b.BaseType()) 199 } 200 201 switch b.Value { 202 case Bytes: 203 u.p.printf("\n if nbs.AlwaysNil || msgp.IsNil(bts) {\n if !nbs.AlwaysNil { bts = bts[1:] }\n %s = %s[:0]} else { %s, bts, err = nbs.ReadBytesBytes(bts, %s)\n", refname, refname, refname, lowered) 204 u.p.print(errcheck) 205 u.p.closeblock() 206 case Ext: 207 vn := b.Varname()[1:] 208 u.p.printf("\n if nbs.AlwaysNil || msgp.IsNil(bts) { if !nbs.AlwaysNil { bts = bts[1:] }\n %s = msgp.RawExtension{} \n} else {\n bts, err = nbs.ReadExtensionBytes(bts, %s) \n", vn, lowered) 209 u.p.print(errcheck) 210 u.p.closeblock() 211 case IDENT: 212 u.p.printf("\n bts, err = %s.%sUnmarshalMsg(bts);", lowered, u.cfg.MethodPrefix) 213 u.p.print(errcheck) 214 default: 215 // u.p.printf("\n if nbs.AlwaysNil || msgp.IsNil(bts) { if !nbs.AlwaysNil { bts=bts[1:]}\n %s \n} else { %s, bts, err = nbs.Read%sBytes(bts)\n", b.ZeroLiteral(refname), refname, b.BaseName()) 216 u.p.printf("\n %s, bts, err = nbs.Read%sBytes(bts)\n", refname, b.BaseName()) 217 } 218 u.p.print(errcheck) 219 if b.Convert { 220 // close 'tmp' block 221 u.p.printf("\n%s = %s(%s)\n}", b.Varname(), b.FromBase(), refname) 222 } 223 } 224 225 func (u *unmarshalGen) gArray(a *Array) { 226 if !u.p.ok() { 227 return 228 } 229 230 // special case for [const]byte objects 231 // see decode.go for symmetry 232 if be, ok := a.Els.(*BaseElem); ok && be.Value == Byte { 233 u.p.printf("\nbts, err = nbs.ReadExactBytes(bts, %s[:])", a.Varname()) 234 u.p.print(errcheck) 235 return 236 } 237 238 sz := gensym() 239 u.p.declare(sz, u32) 240 u.assignAndCheck(sz, arrayHeader) 241 u.p.arrayCheck(a.SizeResolved, sz, "!nbs.IsNil(bts) && ") 242 u.p.rangeBlock(a.Index, a.Varname(), u, a.Els) 243 } 244 245 func (u *unmarshalGen) gSlice(s *Slice) { 246 if !u.p.ok() { 247 return 248 } 249 u.p.printf("\n if nbs.AlwaysNil { %s \n} else {\n", 250 s.ZeroLiteral(`(`+s.Varname()+`)`)) 251 sz := gensym() 252 u.p.declare(sz, u32) 253 u.assignAndCheck(sz, arrayHeader) 254 u.p.resizeSlice(sz, s) 255 u.p.rangeBlock(s.Index, s.Varname(), u, s.Els) 256 u.p.closeblock() 257 } 258 259 func (u *unmarshalGen) gMap(m *Map) { 260 u.depth++ 261 defer func() { 262 u.depth-- 263 }() 264 265 if !u.p.ok() { 266 return 267 } 268 u.p.printf("\n if nbs.AlwaysNil { %s \n} else {\n", 269 m.ZeroLiteral(m.Varname())) 270 sz := gensym() 271 u.p.declare(sz, u32) 272 u.assignAndCheck(sz, mapHeader) 273 274 // allocate or clear map 275 u.p.resizeMap(sz, m) 276 277 // loop and get key,value 278 u.p.printf("\nfor %s > 0 {", sz) 279 u.p.printf("\nvar %s %s; var %s %s; %s--", m.Keyidx, m.KeyDeclTyp, m.Validx, m.Value.TypeName(), sz) 280 u.assignAndCheck(m.Keyidx, m.KeyTyp) 281 next(u, m.Value) 282 u.p.mapAssign(m) 283 u.p.closeblock() 284 u.p.closeblock() 285 } 286 287 func (u *unmarshalGen) gPtr(p *Ptr) { 288 vname := p.Varname() 289 290 base, isBase := p.Value.(*BaseElem) 291 if isBase { 292 //u.p.printf("\n // we have a BaseElem: %#v \n", base) 293 switch base.Value { 294 case IDENT: 295 //u.p.printf("\n // we have an IDENT: \n") 296 297 u.p.printf("\n if nbs.AlwaysNil { ") 298 u.p.printf("\n if %s != nil { \n", vname) 299 300 niller := fmt.Sprintf("; %s.%sUnmarshalMsg(msgp.OnlyNilSlice);", vname, u.cfg.MethodPrefix) 301 302 u.p.printf("%s\n}\n } else { \n // not nbs.AlwaysNil \n", niller) 303 u.p.printf("if msgp.IsNil(bts) { bts = bts[1:]; if nil != %s { \n %s}", vname, niller) 304 u.p.printf("} else { \n // not nbs.AlwaysNil and not IsNil(bts): have something to read \n") 305 u.p.initPtr(p) 306 next(u, p.Value) 307 u.p.closeblock() 308 u.p.closeblock() 309 return 310 case Ext: 311 //u.p.printf("\n // we have an base.Value of Ext: \n") 312 313 u.p.printf("\n if (nbs.AlwaysNil || msgp.IsNil(bts)) { \n // don't try to re-use extension pointers\n if !nbs.AlwaysNil { bts=bts[1:] }\n %s = nil } else {\n // we have data \n", vname) 314 u.p.initPtr(p) 315 u.p.printf("\n bts, err = nbs.ReadExtensionBytes(bts, %s)\n", vname) 316 u.p.print(errcheck) 317 u.p.closeblock() 318 return 319 } 320 } 321 322 u.p.printf("\n // default gPtr logic.") 323 u.p.printf("\nif nbs.PeekNil(bts) && %s == nil { \n // consume the nil\n bts, err = nbs.ReadNilBytes(bts) \n if err != nil { return } } else { \n // read as-if the wire has bytes, letting nbs take care of nils. \n", vname) 324 u.p.initPtr(p) 325 next(u, p.Value) 326 u.p.closeblock() 327 }