github.com/chrislusf/greenpack@v3.7.1-0.20170911073826-ad5bd10b7c47+incompatible/gen/decode.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 decode(w io.Writer, cfg *cfg.GreenConfig) *decodeGen {
    13  	return &decodeGen{
    14  		p:        printer{w: w},
    15  		hasfield: false,
    16  		cfg:      cfg,
    17  	}
    18  }
    19  
    20  type decodeGen struct {
    21  	passes
    22  	p        printer
    23  	hasfield bool
    24  	depth    int
    25  	cfg      *cfg.GreenConfig
    26  	lifo     []bool
    27  
    28  	post postDefs
    29  }
    30  
    31  func (s *decodeGen) MethodPrefix() string {
    32  	return s.cfg.MethodPrefix
    33  }
    34  
    35  type postDefs struct {
    36  	varnames map[string]int
    37  	endlines []string // var declarations declared after method defitions.
    38  }
    39  
    40  func (d *postDefs) add(key string, format string, args ...interface{}) {
    41  	if len(d.varnames) == 0 {
    42  		d.varnames = make(map[string]int)
    43  		d.varnames[key] = 0
    44  	} else {
    45  		_, already := d.varnames[key]
    46  		if already {
    47  			return
    48  		}
    49  	}
    50  	d.endlines = append(d.endlines, fmt.Sprintf(format, args...))
    51  }
    52  
    53  func (d *postDefs) reset() {
    54  	d.varnames = nil
    55  	d.endlines = d.endlines[:0]
    56  }
    57  
    58  func (d *decodeGen) postLines() {
    59  	lines := strings.Join(d.post.endlines, "\n")
    60  	d.p.printf("\n%s\n", lines)
    61  	d.post.reset()
    62  }
    63  
    64  func (d *decodeGen) Method() Method { return Decode }
    65  
    66  func (d *decodeGen) needsField() {
    67  	if d.hasfield {
    68  		return
    69  	}
    70  	d.p.print("\nvar field []byte; _ = field")
    71  	d.hasfield = true
    72  }
    73  
    74  func (d *decodeGen) Execute(p Elem) error {
    75  	p = d.applyall(p)
    76  	if p == nil {
    77  		return nil
    78  	}
    79  	d.hasfield = false
    80  	if !d.p.ok() {
    81  		return d.p.err
    82  	}
    83  
    84  	if !IsPrintable(p) {
    85  		return nil
    86  	}
    87  
    88  	d.p.comment(fmt.Sprintf("%sDecodeMsg implements msgp.Decodable", d.cfg.MethodPrefix))
    89  	d.p.comment("We treat empty fields as if we read a Nil from the wire.")
    90  	d.p.printf("\nfunc (%s %s) %sDecodeMsg(dc *msgp.Reader) (err error) {\n", p.Varname(), methodReceiver(p), d.cfg.MethodPrefix)
    91  
    92  	if !d.cfg.AllTuple {
    93  		d.p.printf(`var sawTopNil bool
    94    if dc.IsNil() {
    95      sawTopNil = true
    96      err = dc.ReadNil()
    97      if err != nil {
    98         return
    99      }
   100      dc.PushAlwaysNil()
   101    }
   102  `)
   103  	}
   104  
   105  	// next will increment k, but we want the first, top level DecodeMsg
   106  	// to refer to this same k ...
   107  	next(d, p)
   108  
   109  	if !d.cfg.AllTuple {
   110  
   111  		d.p.printf(`
   112  	if sawTopNil {
   113  		dc.PopAlwaysNil()
   114  	}
   115  `)
   116  	}
   117  
   118  	d.p.postLoadHook()
   119  	d.p.nakedReturn()
   120  	unsetReceiver(p)
   121  	d.postLines()
   122  	return d.p.err
   123  }
   124  
   125  func (d *decodeGen) gStruct(s *Struct) {
   126  	d.depth++
   127  	defer func() {
   128  		d.depth--
   129  	}()
   130  
   131  	if !d.p.ok() {
   132  		return
   133  	}
   134  	if d.cfg.AllTuple || s.AsTuple {
   135  		d.structAsTuple(s)
   136  	} else {
   137  		d.structAsMap(s)
   138  	}
   139  	return
   140  }
   141  
   142  func (d *decodeGen) assignAndCheck(name string, typ string) {
   143  	if !d.p.ok() {
   144  		return
   145  	}
   146  	d.p.printf("\n%s, err = dc.Read%s()", name, typ)
   147  	d.p.print(errcheck)
   148  }
   149  
   150  func (d *decodeGen) structAsTuple(s *Struct) {
   151  	nfields := len(s.Fields) - s.SkipCount
   152  
   153  	sz := gensym()
   154  	d.p.declare(sz, u32)
   155  	d.assignAndCheck(sz, arrayHeader)
   156  	d.p.arrayCheck(strconv.Itoa(nfields), sz, "")
   157  	for i := range s.Fields {
   158  		if s.Fields[i].Skip {
   159  			continue
   160  		}
   161  		if !d.p.ok() {
   162  			return
   163  		}
   164  		next(d, s.Fields[i].FieldElem)
   165  	}
   166  }
   167  
   168  /* func (d *decodeGen) structAsMap(s *Struct):
   169  //
   170  // Missing (empty) field handling logic:
   171  //
   172  // The approach to missing field handling is to
   173  // keep the logic the same whether the field is
   174  // missing or nil on the wire. To do so we use
   175  // the Reader.PushAlwaysNil() method to tell
   176  // the Reader to pretend to supply
   177  // only nils until further notice. The further
   178  // notice comes from the terminating dc.PopAlwaysNil()
   179  // calls emptying the LIFO. The stack is
   180  // needed because multiple struct decodes may
   181  // be nested due to inlining.
   182  */
   183  func (d *decodeGen) structAsMap(s *Struct) {
   184  	n := len(s.Fields) // - s.SkipCount
   185  	//fmt.Printf("\n in structAsMap!... n = %v. SkipCount=%v\n", n, s.SkipCount)
   186  	if n == 0 {
   187  		return
   188  	}
   189  	d.needsField()
   190  
   191  	k := genSerial()
   192  	skipclue := d.cfg.SkipZidClue || d.cfg.Msgpack2
   193  
   194  	tmpl, nStr := genDecodeMsgTemplate(k)
   195  
   196  	fieldOrder := fmt.Sprintf("\n var decodeMsgFieldOrder%s = []string{", nStr)
   197  	fieldSkip := fmt.Sprintf("\n var decodeMsgFieldSkip%s = []bool{", nStr)
   198  	for i := range s.Fields {
   199  		if s.Fields[i].Skip {
   200  			fieldSkip += fmt.Sprintf("true,")
   201  		} else {
   202  			fieldSkip += fmt.Sprintf("false,")
   203  		}
   204  		fld := s.Fields[i].FieldTagZidClue
   205  		if skipclue {
   206  			fld = s.Fields[i].FieldTag
   207  		}
   208  		fieldOrder += fmt.Sprintf("%q,", fld)
   209  	}
   210  	fieldOrder += "}\n"
   211  	fieldSkip += "}\n"
   212  	varname := strings.Replace(s.TypeName(), "\n", ";", -1)
   213  	d.post.add(varname, "\n// fields of %s%s%s",
   214  		varname, fieldOrder, fieldSkip)
   215  
   216  	//fmt.Printf("\n printing maxField%s to be %v\n", nStr, n)
   217  	d.p.printf("\n const maxFields%s = %d\n", nStr, n)
   218  
   219  	found := "found" + nStr
   220  	d.p.printf(tmpl)
   221  	// after printing tmpl, we are at this point:
   222  	// switch curField_ {
   223  	// -- templateDecodeMsg ends here --
   224  
   225  	for i := range s.Fields {
   226  		if s.Fields[i].Skip {
   227  			continue
   228  		}
   229  		fld := s.Fields[i].FieldTagZidClue
   230  		if skipclue {
   231  			fld = s.Fields[i].FieldTag
   232  		}
   233  
   234  		d.p.printf("\ncase \"%s\":", fld)
   235  		d.p.printf("\n%s[%d]=true;", found, i)
   236  		//d.p.printf("\n fmt.Printf(\"I found field '%s' at depth=%d. dc.AlwaysNil = %%v\", dc.AlwaysNil);\n", fld, d.depth)
   237  		d.depth++
   238  		next(d, s.Fields[i].FieldElem)
   239  		d.depth--
   240  		if !d.p.ok() {
   241  			return
   242  		}
   243  	}
   244  	d.p.print("\ndefault:\nerr = dc.Skip()")
   245  	d.p.print(errcheck)
   246  	d.p.closeblock() // close switch
   247  	d.p.closeblock() // close for loop
   248  
   249  	d.p.printf("\n if nextMiss%s != -1 {dc.PopAlwaysNil(); }\n", nStr)
   250  }
   251  
   252  func (d *decodeGen) gBase(b *BaseElem) {
   253  	if !d.p.ok() {
   254  		return
   255  	}
   256  
   257  	// open block for 'tmp'
   258  	var tmp string
   259  	if b.Convert {
   260  		tmp = gensym()
   261  		d.p.printf("\n{ var %s %s", tmp, b.BaseType())
   262  	}
   263  
   264  	vname := b.Varname()  // e.g. "z.FieldOne"
   265  	bname := b.BaseName() // e.g. "Float64"
   266  
   267  	// handle special cases
   268  	// for object type.
   269  	switch b.Value {
   270  	case Bytes:
   271  		if b.Convert {
   272  			d.p.printf("\n%s, err = dc.ReadBytes([]byte(%s))", tmp, vname)
   273  		} else {
   274  			d.p.printf("\n%s, err = dc.ReadBytes(%s)", vname, vname)
   275  		}
   276  	case IDENT:
   277  		d.p.printf("\nerr = %s.%sDecodeMsg(dc)", vname, d.cfg.MethodPrefix)
   278  	case Ext:
   279  		d.p.printf("\n if !dc.IsNil() {")
   280  		d.p.printf("\nerr = dc.ReadExtension(%s)\n} else { err = dc.ReadNil() }\n", vname)
   281  	default:
   282  		if b.Convert {
   283  			d.p.printf("\n%s, err = dc.Read%s()", tmp, bname)
   284  		} else {
   285  			d.p.printf("\n%s, err = dc.Read%s()", vname, bname)
   286  		}
   287  	}
   288  
   289  	// close block for 'tmp'
   290  	if b.Convert {
   291  		d.p.printf("\n%s = %s(%s)\n}", vname, b.FromBase(), tmp)
   292  	}
   293  
   294  	d.p.print(errcheck)
   295  }
   296  
   297  func (d *decodeGen) gMap(m *Map) {
   298  	d.depth++
   299  	defer func() {
   300  		d.depth--
   301  	}()
   302  
   303  	if !d.p.ok() {
   304  		return
   305  	}
   306  	sz := gensym()
   307  
   308  	// resize or allocate map
   309  	d.p.declare(sz, u32)
   310  	d.assignAndCheck(sz, mapHeader)
   311  	d.p.resizeMap(sz, m)
   312  
   313  	// for element in map, read string/value
   314  	// pair and assign
   315  	d.p.printf("\nfor %s > 0 {\n%s--", sz, sz)
   316  	d.p.declare(m.Keyidx, m.KeyDeclTyp)
   317  	d.p.declare(m.Validx, m.Value.TypeName())
   318  	d.assignAndCheck(m.Keyidx, m.KeyTyp)
   319  	next(d, m.Value)
   320  	d.p.mapAssign(m)
   321  	d.p.closeblock()
   322  }
   323  
   324  func (d *decodeGen) gSlice(s *Slice) {
   325  	if !d.p.ok() {
   326  		return
   327  	}
   328  	sz := gensym()
   329  	d.p.declare(sz, u32)
   330  	d.assignAndCheck(sz, arrayHeader)
   331  	d.p.resizeSlice(sz, s)
   332  	d.p.rangeBlock(s.Index, s.Varname(), d, s.Els)
   333  }
   334  
   335  func (d *decodeGen) gArray(a *Array) {
   336  	if !d.p.ok() {
   337  		return
   338  	}
   339  	d.p.printf(`
   340              if dc.AlwaysNil {
   341                  // nothing more here
   342              } else if dc.IsNil() {
   343                  err = dc.ReadNil()
   344                  if err != nil {
   345                      return
   346                  }
   347              }`) // possible else next
   348  
   349  	// special case if we have [const]byte
   350  	if be, ok := a.Els.(*BaseElem); ok && (be.Value == Byte || be.Value == Uint8) {
   351  		d.p.printf("\nerr = dc.ReadExactBytes(%s[:])", a.Varname())
   352  		d.p.print(errcheck)
   353  		return
   354  	} else {
   355  		d.p.printf(" else {\n")
   356  	}
   357  	sz := gensym()
   358  	d.p.declare(sz, u32)
   359  	d.assignAndCheck(sz, arrayHeader)
   360  	d.p.arrayCheck(a.SizeResolved, sz, "!dc.IsNil() && ")
   361  	d.p.closeblock()
   362  	d.p.rangeBlock(a.Index, a.Varname(), d, a.Els)
   363  }
   364  
   365  func (d *decodeGen) gPtr(p *Ptr) {
   366  	if !d.p.ok() {
   367  		return
   368  	}
   369  
   370  	d.p.printf(`
   371                  if dc.IsNil() {
   372  				  err = dc.ReadNil()
   373  				  if err != nil {
   374  				     return
   375  				  }
   376  `)
   377  
   378  	vname := p.Varname()
   379  	base, isBase := p.Value.(*BaseElem)
   380  	if isBase {
   381  		//d.p.printf("\n // we have a BaseElem: %#v  \n", base)
   382  		switch base.Value {
   383  		case IDENT:
   384  			//d.p.printf("\n // we have an IDENT: \n")
   385  			d.p.printf(
   386  				`
   387                  if %s != nil {
   388  				dc.PushAlwaysNil()
   389  				err = %s.%sDecodeMsg(dc)
   390  				if err != nil {
   391  					return
   392  				}
   393  				dc.PopAlwaysNil()
   394                }
   395              } else {
   396                 // not Nil, we have something to read
   397  `, vname, vname, d.cfg.MethodPrefix)
   398  		case Ext:
   399  			d.p.printf("\n // we have an base.Value of Ext: replace the Ext iff already allocated")
   400  			d.p.printf("\nif %s != nil {\n  %s = new(msgp.RawExtension) } \n"+
   401  				" } else {\n // we have bytes in dc to read\n", vname, vname)
   402  		default:
   403  			//d.p.printf("\n // we have an unknown base.Value type= %T/val=%#v: \n", base.Value, base.Value)
   404  			d.p.printf("\n } else { \n")
   405  		}
   406  	} else {
   407  		// !isBase
   408  		d.p.printf("\n%s = nil\n} else {", vname)
   409  	}
   410  	d.p.initPtr(p)
   411  	next(d, p.Value)
   412  	d.p.closeblock()
   413  }