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  }