go-hep.org/x/hep@v0.38.1/groot/rdict/gen_streamer.go (about)

     1  // Copyright ©2019 The go-hep Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package rdict
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"go/format"
    11  	"go/types"
    12  	"log"
    13  	"reflect"
    14  
    15  	"go-hep.org/x/hep/groot/rmeta"
    16  	"golang.org/x/tools/go/packages"
    17  )
    18  
    19  // genStreamer holds the state of the ROOT streamer generation.
    20  type genStreamer struct {
    21  	buf *bytes.Buffer
    22  	pkg *types.Package
    23  
    24  	// set of imported packages.
    25  	// usually: "encoding/binary", "math"
    26  	imps map[string]int
    27  
    28  	verbose bool // enable verbose mode
    29  
    30  	binMa *types.Interface // encoding.BinaryMarshaler
    31  	binUn *types.Interface // encoding.BinaryUnmarshaler
    32  	rvers *types.Interface // rbytes.RVersioner
    33  
    34  	gosizes types.Sizes
    35  }
    36  
    37  func importPkg(p string) (*types.Package, error) {
    38  	cfg := &packages.Config{Mode: packages.NeedTypes | packages.NeedTypesInfo | packages.NeedTypesSizes | packages.NeedDeps}
    39  	pkgs, err := packages.Load(cfg, p)
    40  	if err != nil {
    41  		return nil, fmt.Errorf("could not load package %q: %w", p, err)
    42  	}
    43  
    44  	return pkgs[0].Types, nil
    45  }
    46  
    47  // NewGenStreamer returns a new code generator for package p,
    48  // where p is the package's import path.
    49  func NewGenStreamer(p string, verbose bool) (Generator, error) {
    50  	pkg, err := importPkg(p)
    51  	if err != nil {
    52  		return nil, err
    53  	}
    54  	g := &genStreamer{
    55  		buf: new(bytes.Buffer),
    56  		pkg: pkg,
    57  		imps: map[string]int{
    58  			"go-hep.org/x/hep/groot/rbytes": 1,
    59  			"go-hep.org/x/hep/groot/rdict":  1,
    60  			"go-hep.org/x/hep/groot/rmeta":  1,
    61  		},
    62  		verbose: verbose,
    63  	}
    64  
    65  	err = g.init()
    66  	if err != nil {
    67  		return nil, err
    68  	}
    69  
    70  	return g, nil
    71  }
    72  
    73  func (g *genStreamer) init() error {
    74  	pkg, err := importPkg("encoding")
    75  	if err != nil {
    76  		return fmt.Errorf("rdict: could not find package \"encoding\": %w", err)
    77  	}
    78  
    79  	o := pkg.Scope().Lookup("BinaryMarshaler")
    80  	if o == nil {
    81  		return fmt.Errorf("rdict: could not find interface encoding.BinaryMarshaler")
    82  	}
    83  	g.binMa = o.(*types.TypeName).Type().Underlying().(*types.Interface)
    84  
    85  	o = pkg.Scope().Lookup("BinaryUnmarshaler")
    86  	if o == nil {
    87  		return fmt.Errorf("rdict: could not find interface encoding.BinaryUnmarshaler")
    88  	}
    89  	g.binUn = o.(*types.TypeName).Type().Underlying().(*types.Interface)
    90  
    91  	pkg, err = importPkg("go-hep.org/x/hep/groot/rbytes")
    92  	if err != nil {
    93  		return fmt.Errorf("rdict: could not find package %q: %w", "go-hep.org/x/hep/groot/rbytes", err)
    94  	}
    95  
    96  	o = pkg.Scope().Lookup("RVersioner")
    97  	if o == nil {
    98  		return fmt.Errorf("rdict: could not find interface rbytes.RVersioner")
    99  	}
   100  	g.rvers = o.(*types.TypeName).Type().Underlying().(*types.Interface)
   101  
   102  	sz := int64(reflect.TypeOf(int(0)).Size())
   103  	g.gosizes = &types.StdSizes{WordSize: sz, MaxAlign: sz}
   104  	return nil
   105  }
   106  
   107  func (g *genStreamer) printf(format string, args ...any) {
   108  	fmt.Fprintf(g.buf, format, args...)
   109  }
   110  
   111  // Generate implements rdict.Generator
   112  func (g *genStreamer) Generate(typeName string) error {
   113  	scope := g.pkg.Scope()
   114  	obj := scope.Lookup(typeName)
   115  	if obj == nil {
   116  		return fmt.Errorf("no such type %q in package %q", typeName, g.pkg.Path()+"/"+g.pkg.Name())
   117  	}
   118  
   119  	tn, ok := obj.(*types.TypeName)
   120  	if !ok {
   121  		return fmt.Errorf("%q is not a type (%v)", typeName, obj)
   122  	}
   123  
   124  	typ, ok := tn.Type().Underlying().(*types.Struct)
   125  	if !ok {
   126  		return fmt.Errorf("%q is not a named struct (%v)", typeName, tn)
   127  	}
   128  	if g.verbose {
   129  		log.Printf("typ: %q: %+v\n", typeName, typ)
   130  	}
   131  
   132  	if !types.Implements(tn.Type(), g.rvers) && !types.Implements(types.NewPointer(tn.Type()), g.rvers) {
   133  		g.genRVersioner(typ, typeName)
   134  	}
   135  
   136  	g.genStreamer(typ, typeName)
   137  	g.genMarshal(typ, typeName)
   138  	// g.genUnmarshal(typ, typeName)
   139  
   140  	return nil
   141  }
   142  
   143  func (g *genStreamer) genMarshal(t types.Type, typeName string) {
   144  	g.printf(`// MarshalROOT implements rbytes.Marshaler
   145  func (o *%[1]s) MarshalROOT(w *rbytes.WBuffer) (int, error) {
   146  	if w.Err() != nil {
   147  		return 0, w.Err()
   148  	}
   149  
   150  	hdr := w.WriteHeader(o.Class(), o.RVersion())
   151  
   152  `,
   153  		typeName,
   154  	)
   155  
   156  	typ := t.Underlying().(*types.Struct)
   157  	for i := range typ.NumFields() {
   158  		ft := typ.Field(i)
   159  		n := ft.Name() // no `groot:"foo"` redirection.
   160  		g.genMarshalType(ft.Type(), n)
   161  	}
   162  
   163  	g.printf("\n\treturn w.SetHeader(hdr)\n}\n\n")
   164  }
   165  
   166  // func (g *genStreamer) genUnmarshal(t types.Type, typeName string) {
   167  // 	g.printf(`// UnmarshalROOT implements rbytes.Unmarshaler
   168  // func (o *%[1]s) UnmarshalROOT(r *rbytes.RBuffer) error {
   169  // 	rs, err := rdict.RStreamer(r, o)
   170  // 	if err != nil {
   171  // 		return err
   172  // 	}
   173  // 	return rs.RStreamROOT(r)
   174  // }
   175  // `,
   176  // 		typeName,
   177  // 	)
   178  // }
   179  
   180  func (g *genStreamer) genRVersioner(t types.Type, typeName string) {
   181  	g.printf("func (*%s) RVersion() int16 { return 1 }\n\n", typeName)
   182  }
   183  
   184  func (g *genStreamer) genStreamer(t types.Type, typeName string) {
   185  	g.printf(`func init() {
   186  	// Streamer for %[1]s.
   187  	rdict.StreamerInfos.Add(rdict.NewStreamerInfo(%[2]q, int(((*%[1]s)(nil)).RVersion()), []rbytes.StreamerElement{
   188  `,
   189  		typeName,
   190  		g.pkg.Path()+"."+typeName,
   191  	)
   192  
   193  	typ := t.Underlying().(*types.Struct)
   194  	for i := range typ.NumFields() {
   195  		ft := typ.Field(i)
   196  		n := ft.Name()
   197  		if tag := typ.Tag(i); tag != "" {
   198  			nn := reflect.StructTag(tag).Get("groot")
   199  			if nn != "" {
   200  				n = nn
   201  			}
   202  		}
   203  		g.genStreamerType(ft.Type(), n)
   204  	}
   205  
   206  	g.printf("}))\n}\n\n")
   207  }
   208  
   209  func (g *genStreamer) genStreamerType(t types.Type, n string) {
   210  	ut := t.Underlying()
   211  	switch ut := ut.(type) {
   212  	case *types.Basic:
   213  		switch kind := ut.Kind(); kind {
   214  		case types.Bool:
   215  			g.printf("&rdict.StreamerBasicType{StreamerElement: %s},\n", g.se(ut, n, "", 0))
   216  		case types.Uint8:
   217  			g.printf("&rdict.StreamerBasicType{StreamerElement: %s},\n", g.se(ut, n, "", 0))
   218  		case types.Uint16:
   219  			g.printf("&rdict.StreamerBasicType{StreamerElement: %s},\n", g.se(ut, n, "", 0))
   220  		case types.Uint32, types.Uint:
   221  			g.printf("&rdict.StreamerBasicType{StreamerElement: %s},\n", g.se(ut, n, "", 0))
   222  		case types.Uint64:
   223  			g.printf("&rdict.StreamerBasicType{StreamerElement: %s},\n", g.se(ut, n, "", 0))
   224  		case types.Int8:
   225  			g.printf("&rdict.StreamerBasicType{StreamerElement: %s},\n", g.se(ut, n, "", 0))
   226  		case types.Int16:
   227  			g.printf("&rdict.StreamerBasicType{StreamerElement: %s},\n", g.se(ut, n, "", 0))
   228  		case types.Int32, types.Int:
   229  			g.printf("&rdict.StreamerBasicType{StreamerElement: %s},\n", g.se(ut, n, "", 0))
   230  		case types.Int64:
   231  			g.printf("&rdict.StreamerBasicType{StreamerElement: %s},\n", g.se(ut, n, "", 0))
   232  		case types.Float32:
   233  			g.printf("&rdict.StreamerBasicType{StreamerElement: %s},\n", g.se(ut, n, "", 0))
   234  		case types.Float64:
   235  			g.printf("&rdict.StreamerBasicType{StreamerElement: %s},\n", g.se(ut, n, "", 0))
   236  		case types.Complex64:
   237  			log.Fatalf("unhandled type: %v (underlying %v)\n", t, ut) // FIXME(sbinet)
   238  
   239  		case types.Complex128:
   240  			log.Fatalf("unhandled type: %v (underlying %v)\n", t, ut) // FIXME(sbinet)
   241  
   242  		case types.String:
   243  			g.printf("%s,\n", g.se(ut, n, "", 0))
   244  
   245  		default:
   246  			log.Fatalf("unhandled type: %v (underlying: %v)\n", t, ut)
   247  		}
   248  
   249  	case *types.Array:
   250  		// FIXME(sbinet): collect+visit element type.
   251  		switch eut := ut.Elem().Underlying().(type) {
   252  		case *types.Basic:
   253  			switch kind := eut.Kind(); kind {
   254  			default:
   255  				g.printf(
   256  					"&rdict.StreamerBasicType{StreamerElement: %s},\n",
   257  					g.se(ut.Elem(), n, "+ rmeta.OffsetL", ut.Len()),
   258  				)
   259  			case types.String:
   260  				g.printf(
   261  					"%s,\n",
   262  					g.se(ut.Elem(), n, "+ rmeta.OffsetL", ut.Len()),
   263  				)
   264  			}
   265  		default:
   266  			g.printf(
   267  				"%s\n",
   268  				g.se(ut.Elem(), n, "+ rmeta.OffsetL", ut.Len()),
   269  			)
   270  		}
   271  	case *types.Slice:
   272  		// FIXME(sbinet): collect+visit element type.
   273  		g.printf("rdict.NewStreamerSTL(%q, rmeta.STLvector, rmeta.%v),\n", n, gotype2RMeta(ut.Elem()))
   274  
   275  	case *types.Struct:
   276  		g.imps["go-hep.org/x/hep/groot/rbase"]++
   277  		g.printf(
   278  			"&rdict.StreamerObjectAny{StreamerElement:rdict.Element{\nName: *rbase.NewNamed(%[1]q, %[2]q),\nType: rmeta.Any,\nSize: %[4]d,\nEName:rdict.GoName2Cxx(%[3]q),\n}.New()},\n",
   279  			n, "",
   280  			t.String(), g.gosizes.Sizeof(ut),
   281  		)
   282  
   283  	default:
   284  		log.Fatalf("unhandled type: %v (underlying: %v)\n", t, ut)
   285  	}
   286  }
   287  
   288  func (g *genStreamer) wt(t types.Type, n, meth, arr string) {
   289  	ut := t.Underlying()
   290  	switch ut := ut.(type) {
   291  	case *types.Basic:
   292  		switch kind := ut.Kind(); kind {
   293  		case types.Bool:
   294  			g.printf("w.Write%sBool(o.%s%s)\n", meth, n, arr)
   295  		case types.Uint8:
   296  			g.printf("w.Write%sU8(o.%s%s)\n", meth, n, arr)
   297  		case types.Uint16:
   298  			g.printf("w.Write%sU16(o.%s%s)\n", meth, n, arr)
   299  		case types.Uint32:
   300  			g.printf("w.Write%sU32(o.%s%s)\n", meth, n, arr)
   301  		case types.Uint64:
   302  			g.printf("w.Write%sU64(o.%s%s)\n", meth, n, arr)
   303  		case types.Int8:
   304  			g.printf("w.Write%sI8(o.%s%s)\n", meth, n, arr)
   305  		case types.Int16:
   306  			g.printf("w.Write%sI16(o.%s%s)\n", meth, n, arr)
   307  		case types.Int32:
   308  			g.printf("w.Write%sI32(o.%s%s)\n", meth, n, arr)
   309  		case types.Int64:
   310  			g.printf("w.Write%sI64(o.%s%s)\n", meth, n, arr)
   311  		case types.Float32:
   312  			g.printf("w.Write%sF32(o.%s%s)\n", meth, n, arr)
   313  		case types.Float64:
   314  			g.printf("w.Write%sF64(o.%s%s)\n", meth, n, arr)
   315  
   316  		case types.Uint:
   317  			g.printf("w.Write%sU64(uint64(o.%s%s))\n", meth, n, arr)
   318  		case types.Int:
   319  			g.printf("w.Write%sI64(int64(o.%s%s))\n", meth, n, arr)
   320  
   321  		case types.Complex64:
   322  			log.Fatalf("unhandled type: %v (underlying %v)\n", t, ut) // FIXME(sbinet)
   323  		case types.Complex128:
   324  			log.Fatalf("unhandled type: %v (underlying %v)\n", t, ut) // FIXME(sbinet)
   325  
   326  		case types.String:
   327  			g.printf("w.Write%sString(o.%s%s)\n", meth, n, arr)
   328  
   329  		default:
   330  			log.Fatalf("unhandled type: %v (underlying: %v)\n", t, ut)
   331  		}
   332  
   333  	case *types.Struct:
   334  		g.printf("w.WriteObject(&o.%s)\n", n)
   335  
   336  	default:
   337  		log.Fatalf("unhandled marshal type: %v (underlying %v)", t, ut)
   338  	}
   339  }
   340  
   341  func (g *genStreamer) se(t types.Type, n, rtype string, arrlen int64) string {
   342  	elmt := Element{
   343  		Size: 1,
   344  	}
   345  	if arrlen > 0 {
   346  		elmt.Size = int32(arrlen)
   347  		elmt.ArrLen = int32(arrlen)
   348  		elmt.ArrDim = 1
   349  		elmt.MaxIdx[0] = elmt.ArrLen // FIXME(sbinet): handle n-dim arrays [n][m][u][v][w]T
   350  	}
   351  
   352  	ut := t.Underlying()
   353  	switch ut := ut.(type) {
   354  	case *types.Basic:
   355  		g.imps["go-hep.org/x/hep/groot/rbase"]++
   356  		switch kind := ut.Kind(); kind {
   357  		case types.Bool:
   358  			return fmt.Sprintf("rdict.Element{\nName: *rbase.NewNamed(%[1]q, %[2]q),\nType: rmeta.Bool %[4]s,\nSize: %[5]d,\nEName:%[3]q,\nArrLen:%[6]d,\nArrDim:%[7]d,\nMaxIdx:%#[8]v,\n}.New()",
   359  				n, "",
   360  				rmeta.GoType2Cxx[ut.Name()],
   361  				rtype,
   362  				1*elmt.Size,
   363  				elmt.ArrLen,
   364  				elmt.ArrDim,
   365  				elmt.MaxIdx,
   366  			)
   367  		case types.Uint8:
   368  			return fmt.Sprintf("rdict.Element{\nName: *rbase.NewNamed(%[1]q, %[2]q),\nType: rmeta.Uint8 %[4]s,\nSize: %[5]d,\nEName:%[3]q,\nArrLen:%[6]d,\nArrDim:%[7]d,\nMaxIdx:%#[8]v,\n}.New()",
   369  				n, "",
   370  				rmeta.GoType2Cxx[ut.Name()],
   371  				rtype,
   372  				1*elmt.Size,
   373  				elmt.ArrLen,
   374  				elmt.ArrDim,
   375  				elmt.MaxIdx,
   376  			)
   377  		case types.Uint16:
   378  			return fmt.Sprintf("rdict.Element{\nName: *rbase.NewNamed(%[1]q, %[2]q),\nType: rmeta.Uint16 %[4]s,\nSize: %[5]d,\nEName:%[3]q,\nArrLen:%[6]d,\nArrDim:%[7]d,\nMaxIdx:%#[8]v,\n}.New()",
   379  				n, "",
   380  				rmeta.GoType2Cxx[ut.Name()],
   381  				rtype,
   382  				2*elmt.Size,
   383  				elmt.ArrLen,
   384  				elmt.ArrDim,
   385  				elmt.MaxIdx,
   386  			)
   387  		case types.Uint32, types.Uint:
   388  			return fmt.Sprintf("rdict.Element{\nName: *rbase.NewNamed(%[1]q, %[2]q),\nType: rmeta.Uint32 %[4]s,\nSize: %[5]d,\nEName:%[3]q,\nArrLen:%[6]d,\nArrDim:%[7]d,\nMaxIdx:%#[8]v,\n}.New()",
   389  				n, "",
   390  				rmeta.GoType2Cxx[ut.Name()],
   391  				rtype,
   392  				4*elmt.Size,
   393  				elmt.ArrLen,
   394  				elmt.ArrDim,
   395  				elmt.MaxIdx,
   396  			)
   397  		case types.Uint64:
   398  			return fmt.Sprintf("rdict.Element{\nName: *rbase.NewNamed(%[1]q, %[2]q),\nType: rmeta.Uint64 %[4]s,\nSize: %[5]d,\nEName:%[3]q,\nArrLen:%[6]d,\nArrDim:%[7]d,\nMaxIdx:%#[8]v,\n}.New()",
   399  				n, "",
   400  				rmeta.GoType2Cxx[ut.Name()],
   401  				rtype,
   402  				8*elmt.Size,
   403  				elmt.ArrLen,
   404  				elmt.ArrDim,
   405  				elmt.MaxIdx,
   406  			)
   407  		case types.Int8:
   408  			return fmt.Sprintf("rdict.Element{\nName: *rbase.NewNamed(%[1]q, %[2]q),\nType: rmeta.Int8 %[4]s,\nSize: %[5]d,\nEName:%[3]q,\nArrLen:%[6]d,\nArrDim:%[7]d,\nMaxIdx:%#[8]v,\n}.New()",
   409  				n, "",
   410  				rmeta.GoType2Cxx[ut.Name()],
   411  				rtype,
   412  				1*elmt.Size,
   413  				elmt.ArrLen,
   414  				elmt.ArrDim,
   415  				elmt.MaxIdx,
   416  			)
   417  		case types.Int16:
   418  			return fmt.Sprintf("rdict.Element{\nName: *rbase.NewNamed(%[1]q, %[2]q),\nType: rmeta.Int16 %[4]s,\nSize: %[5]d,\nEName:%[3]q,\nArrLen:%[6]d,\nArrDim:%[7]d,\nMaxIdx:%#[8]v,\n}.New()",
   419  				n, "",
   420  				rmeta.GoType2Cxx[ut.Name()],
   421  				rtype,
   422  				2*elmt.Size,
   423  				elmt.ArrLen,
   424  				elmt.ArrDim,
   425  				elmt.MaxIdx,
   426  			)
   427  		case types.Int32, types.Int:
   428  			return fmt.Sprintf("rdict.Element{\nName: *rbase.NewNamed(%[1]q, %[2]q),\nType: rmeta.Int32 %[4]s,\nSize: %[5]d,\nEName:%[3]q,\nArrLen:%[6]d,\nArrDim:%[7]d,\nMaxIdx:%#[8]v,\n}.New()",
   429  				n, "",
   430  				rmeta.GoType2Cxx[ut.Name()],
   431  				rtype,
   432  				4*elmt.Size,
   433  				elmt.ArrLen,
   434  				elmt.ArrDim,
   435  				elmt.MaxIdx,
   436  			)
   437  		case types.Int64:
   438  			return fmt.Sprintf("rdict.Element{\nName: *rbase.NewNamed(%[1]q, %[2]q),\nType: rmeta.Int64 %[4]s,\nSize: %[5]d,\nEName:%[3]q,\nArrLen:%[6]d,\nArrDim:%[7]d,\nMaxIdx:%#[8]v,\n}.New()",
   439  				n, "",
   440  				rmeta.GoType2Cxx[ut.Name()],
   441  				rtype,
   442  				8*elmt.Size,
   443  				elmt.ArrLen,
   444  				elmt.ArrDim,
   445  				elmt.MaxIdx,
   446  			)
   447  		case types.Float32:
   448  			return fmt.Sprintf("rdict.Element{\nName: *rbase.NewNamed(%[1]q, %[2]q),\nType: rmeta.Float32 %[4]s,\nSize: %[5]d,\nEName:%[3]q,\nArrLen:%[6]d,\nArrDim:%[7]d,\nMaxIdx:%#[8]v,\n}.New()",
   449  				n, "",
   450  				rmeta.GoType2Cxx[ut.Name()],
   451  				rtype,
   452  				4*elmt.Size,
   453  				elmt.ArrLen,
   454  				elmt.ArrDim,
   455  				elmt.MaxIdx,
   456  			)
   457  		case types.Float64:
   458  			return fmt.Sprintf("rdict.Element{\nName: *rbase.NewNamed(%[1]q, %[2]q),\nType: rmeta.Float64 %[4]s,\nSize: %[5]d,\nEName:%[3]q,\nArrLen:%[6]d,\nArrDim:%[7]d,\nMaxIdx:%#[8]v,\n}.New()",
   459  				n, "",
   460  				rmeta.GoType2Cxx[ut.Name()],
   461  				rtype,
   462  				8*elmt.Size,
   463  				elmt.ArrLen,
   464  				elmt.ArrDim,
   465  				elmt.MaxIdx,
   466  			)
   467  		case types.Complex64:
   468  			log.Fatalf("unhandled type: %v (underlying %v)\n", t, ut) // FIXME(sbinet)
   469  
   470  		case types.Complex128:
   471  			log.Fatalf("unhandled type: %v (underlying %v)\n", t, ut) // FIXME(sbinet)
   472  
   473  		case types.String:
   474  			return fmt.Sprintf("&rdict.StreamerString{rdict.Element{\nName: *rbase.NewNamed(%[1]q, %[2]q),\nType: rmeta.TString %[4]s,\nSize: %[5]d,\nEName:%[3]q,\nArrLen:%[6]d,\nArrDim:%[7]d,\nMaxIdx:%#[8]v,\n}.New()}",
   475  				n, "",
   476  				"TString",
   477  				rtype,
   478  				24*elmt.Size,
   479  				elmt.ArrLen,
   480  				elmt.ArrDim,
   481  				elmt.MaxIdx,
   482  			)
   483  		}
   484  	case *types.Struct:
   485  		// FIXME(sbinet): implement.
   486  		// FIXME(sbinet): prevent recursion.
   487  		old := g.buf
   488  		g.buf = new(bytes.Buffer)
   489  		g.genStreamerType(t, n)
   490  		str := g.buf.String()
   491  		g.buf = old
   492  		return str
   493  	}
   494  
   495  	log.Printf("gen-streamer: unhandled type: %v (underlying %v)", t, ut)
   496  	return ""
   497  }
   498  
   499  func (g *genStreamer) genMarshalType(t types.Type, n string) {
   500  	ut := t.Underlying()
   501  	switch ut := ut.(type) {
   502  	case *types.Basic:
   503  		switch kind := ut.Kind(); kind {
   504  		case types.Bool:
   505  			g.wt(ut, n, "", "")
   506  		case types.Uint8:
   507  			g.wt(ut, n, "", "")
   508  		case types.Uint16:
   509  			g.wt(ut, n, "", "")
   510  		case types.Uint32:
   511  			g.wt(ut, n, "", "")
   512  		case types.Uint64:
   513  			g.wt(ut, n, "", "")
   514  		case types.Int8:
   515  			g.wt(ut, n, "", "")
   516  		case types.Int16:
   517  			g.wt(ut, n, "", "")
   518  		case types.Int32:
   519  			g.wt(ut, n, "", "")
   520  		case types.Int64:
   521  			g.wt(ut, n, "", "")
   522  		case types.Float32:
   523  			g.wt(ut, n, "", "")
   524  		case types.Float64:
   525  			g.wt(ut, n, "", "")
   526  
   527  		case types.Uint:
   528  			g.wt(ut, n, "", "")
   529  		case types.Int:
   530  			g.wt(ut, n, "", "")
   531  
   532  		case types.Complex64:
   533  			log.Fatalf("unhandled type: %v (underlying %v)\n", t, ut) // FIXME(sbinet)
   534  		case types.Complex128:
   535  			log.Fatalf("unhandled type: %v (underlying %v)\n", t, ut) // FIXME(sbinet)
   536  
   537  		case types.String:
   538  			g.wt(ut, n, "", "")
   539  
   540  		default:
   541  			log.Fatalf("unhandled type: %v (underlying: %v)\n", t, ut)
   542  		}
   543  
   544  	case *types.Array:
   545  		switch ut.Elem().Underlying().(type) {
   546  		case *types.Basic:
   547  			g.wt(ut.Elem(), n, "Array", "[:]")
   548  		default:
   549  			g.printf("for i := range o.%s {\n", n)
   550  			g.wt(ut.Elem(), n+"[i]", "", "")
   551  			g.printf("}\n")
   552  		}
   553  
   554  	case *types.Slice:
   555  		g.wt(ut.Elem(), n, "Array", "")
   556  
   557  	case *types.Struct:
   558  		g.printf("w.WriteObject(&o.%s)\n", n)
   559  
   560  	default:
   561  		log.Fatalf("gen-marshal-type: unhandled type: %v (underlying: %v)\n", t, ut)
   562  	}
   563  }
   564  
   565  // Generate implements rdict.Generator
   566  func (g *genStreamer) Format() ([]byte, error) {
   567  	buf := new(bytes.Buffer)
   568  
   569  	buf.WriteString(fmt.Sprintf(`// DO NOT EDIT; automatically generated by %[1]s
   570  
   571  package %[2]s
   572  
   573  import (
   574  `,
   575  		"root-gen-streamer",
   576  		g.pkg.Name(),
   577  	))
   578  
   579  	// FIXME(sbinet): separate stdlib from 3rd-party imports.
   580  
   581  	for k := range g.imps {
   582  		fmt.Fprintf(buf, "%q\n", k)
   583  	}
   584  	fmt.Fprintf(buf, ")\n\n")
   585  
   586  	buf.Write(g.buf.Bytes())
   587  
   588  	src, err := format.Source(buf.Bytes())
   589  	if err != nil {
   590  		log.Printf("=== error ===\n%s\n", buf.Bytes())
   591  	}
   592  	return src, err
   593  }
   594  
   595  var (
   596  	_ Generator = (*genStreamer)(nil)
   597  )