go-hep.org/x/hep@v0.40.0/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.TypeFor[int]().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 ft := range typ.Fields() {
   158  		n := ft.Name() // no `groot:"foo"` redirection.
   159  		g.genMarshalType(ft.Type(), n)
   160  	}
   161  
   162  	g.printf("\n\treturn w.SetHeader(hdr)\n}\n\n")
   163  }
   164  
   165  // func (g *genStreamer) genUnmarshal(t types.Type, typeName string) {
   166  // 	g.printf(`// UnmarshalROOT implements rbytes.Unmarshaler
   167  // func (o *%[1]s) UnmarshalROOT(r *rbytes.RBuffer) error {
   168  // 	rs, err := rdict.RStreamer(r, o)
   169  // 	if err != nil {
   170  // 		return err
   171  // 	}
   172  // 	return rs.RStreamROOT(r)
   173  // }
   174  // `,
   175  // 		typeName,
   176  // 	)
   177  // }
   178  
   179  func (g *genStreamer) genRVersioner(t types.Type, typeName string) {
   180  	g.printf("func (*%s) RVersion() int16 { return 1 }\n\n", typeName)
   181  }
   182  
   183  func (g *genStreamer) genStreamer(t types.Type, typeName string) {
   184  	g.printf(`func init() {
   185  	// Streamer for %[1]s.
   186  	rdict.StreamerInfos.Add(rdict.NewStreamerInfo(%[2]q, int(((*%[1]s)(nil)).RVersion()), []rbytes.StreamerElement{
   187  `,
   188  		typeName,
   189  		g.pkg.Path()+"."+typeName,
   190  	)
   191  
   192  	typ := t.Underlying().(*types.Struct)
   193  	for i := range typ.NumFields() {
   194  		ft := typ.Field(i)
   195  		n := ft.Name()
   196  		if tag := typ.Tag(i); tag != "" {
   197  			nn := reflect.StructTag(tag).Get("groot")
   198  			if nn != "" {
   199  				n = nn
   200  			}
   201  		}
   202  		g.genStreamerType(ft.Type(), n)
   203  	}
   204  
   205  	g.printf("}))\n}\n\n")
   206  }
   207  
   208  func (g *genStreamer) genStreamerType(t types.Type, n string) {
   209  	ut := t.Underlying()
   210  	switch ut := ut.(type) {
   211  	case *types.Basic:
   212  		switch kind := ut.Kind(); kind {
   213  		case types.Bool:
   214  			g.printf("&rdict.StreamerBasicType{StreamerElement: %s},\n", g.se(ut, n, "", 0))
   215  		case types.Uint8:
   216  			g.printf("&rdict.StreamerBasicType{StreamerElement: %s},\n", g.se(ut, n, "", 0))
   217  		case types.Uint16:
   218  			g.printf("&rdict.StreamerBasicType{StreamerElement: %s},\n", g.se(ut, n, "", 0))
   219  		case types.Uint32, types.Uint:
   220  			g.printf("&rdict.StreamerBasicType{StreamerElement: %s},\n", g.se(ut, n, "", 0))
   221  		case types.Uint64:
   222  			g.printf("&rdict.StreamerBasicType{StreamerElement: %s},\n", g.se(ut, n, "", 0))
   223  		case types.Int8:
   224  			g.printf("&rdict.StreamerBasicType{StreamerElement: %s},\n", g.se(ut, n, "", 0))
   225  		case types.Int16:
   226  			g.printf("&rdict.StreamerBasicType{StreamerElement: %s},\n", g.se(ut, n, "", 0))
   227  		case types.Int32, types.Int:
   228  			g.printf("&rdict.StreamerBasicType{StreamerElement: %s},\n", g.se(ut, n, "", 0))
   229  		case types.Int64:
   230  			g.printf("&rdict.StreamerBasicType{StreamerElement: %s},\n", g.se(ut, n, "", 0))
   231  		case types.Float32:
   232  			g.printf("&rdict.StreamerBasicType{StreamerElement: %s},\n", g.se(ut, n, "", 0))
   233  		case types.Float64:
   234  			g.printf("&rdict.StreamerBasicType{StreamerElement: %s},\n", g.se(ut, n, "", 0))
   235  		case types.Complex64:
   236  			log.Fatalf("unhandled type: %v (underlying %v)\n", t, ut) // FIXME(sbinet)
   237  
   238  		case types.Complex128:
   239  			log.Fatalf("unhandled type: %v (underlying %v)\n", t, ut) // FIXME(sbinet)
   240  
   241  		case types.String:
   242  			g.printf("%s,\n", g.se(ut, n, "", 0))
   243  
   244  		default:
   245  			log.Fatalf("unhandled type: %v (underlying: %v)\n", t, ut)
   246  		}
   247  
   248  	case *types.Array:
   249  		// FIXME(sbinet): collect+visit element type.
   250  		switch eut := ut.Elem().Underlying().(type) {
   251  		case *types.Basic:
   252  			switch kind := eut.Kind(); kind {
   253  			default:
   254  				g.printf(
   255  					"&rdict.StreamerBasicType{StreamerElement: %s},\n",
   256  					g.se(ut.Elem(), n, "+ rmeta.OffsetL", ut.Len()),
   257  				)
   258  			case types.String:
   259  				g.printf(
   260  					"%s,\n",
   261  					g.se(ut.Elem(), n, "+ rmeta.OffsetL", ut.Len()),
   262  				)
   263  			}
   264  		default:
   265  			g.printf(
   266  				"%s\n",
   267  				g.se(ut.Elem(), n, "+ rmeta.OffsetL", ut.Len()),
   268  			)
   269  		}
   270  	case *types.Slice:
   271  		// FIXME(sbinet): collect+visit element type.
   272  		g.printf("rdict.NewStreamerSTL(%q, rmeta.STLvector, rmeta.%v),\n", n, gotype2RMeta(ut.Elem()))
   273  
   274  	case *types.Struct:
   275  		g.imps["go-hep.org/x/hep/groot/rbase"]++
   276  		g.printf(
   277  			"&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",
   278  			n, "",
   279  			t.String(), g.gosizes.Sizeof(ut),
   280  		)
   281  
   282  	default:
   283  		log.Fatalf("unhandled type: %v (underlying: %v)\n", t, ut)
   284  	}
   285  }
   286  
   287  func (g *genStreamer) wt(t types.Type, n, meth, arr string) {
   288  	ut := t.Underlying()
   289  	switch ut := ut.(type) {
   290  	case *types.Basic:
   291  		switch kind := ut.Kind(); kind {
   292  		case types.Bool:
   293  			g.printf("w.Write%sBool(o.%s%s)\n", meth, n, arr)
   294  		case types.Uint8:
   295  			g.printf("w.Write%sU8(o.%s%s)\n", meth, n, arr)
   296  		case types.Uint16:
   297  			g.printf("w.Write%sU16(o.%s%s)\n", meth, n, arr)
   298  		case types.Uint32:
   299  			g.printf("w.Write%sU32(o.%s%s)\n", meth, n, arr)
   300  		case types.Uint64:
   301  			g.printf("w.Write%sU64(o.%s%s)\n", meth, n, arr)
   302  		case types.Int8:
   303  			g.printf("w.Write%sI8(o.%s%s)\n", meth, n, arr)
   304  		case types.Int16:
   305  			g.printf("w.Write%sI16(o.%s%s)\n", meth, n, arr)
   306  		case types.Int32:
   307  			g.printf("w.Write%sI32(o.%s%s)\n", meth, n, arr)
   308  		case types.Int64:
   309  			g.printf("w.Write%sI64(o.%s%s)\n", meth, n, arr)
   310  		case types.Float32:
   311  			g.printf("w.Write%sF32(o.%s%s)\n", meth, n, arr)
   312  		case types.Float64:
   313  			g.printf("w.Write%sF64(o.%s%s)\n", meth, n, arr)
   314  
   315  		case types.Uint:
   316  			g.printf("w.Write%sU64(uint64(o.%s%s))\n", meth, n, arr)
   317  		case types.Int:
   318  			g.printf("w.Write%sI64(int64(o.%s%s))\n", meth, n, arr)
   319  
   320  		case types.Complex64:
   321  			log.Fatalf("unhandled type: %v (underlying %v)\n", t, ut) // FIXME(sbinet)
   322  		case types.Complex128:
   323  			log.Fatalf("unhandled type: %v (underlying %v)\n", t, ut) // FIXME(sbinet)
   324  
   325  		case types.String:
   326  			g.printf("w.Write%sString(o.%s%s)\n", meth, n, arr)
   327  
   328  		default:
   329  			log.Fatalf("unhandled type: %v (underlying: %v)\n", t, ut)
   330  		}
   331  
   332  	case *types.Struct:
   333  		g.printf("w.WriteObject(&o.%s)\n", n)
   334  
   335  	default:
   336  		log.Fatalf("unhandled marshal type: %v (underlying %v)", t, ut)
   337  	}
   338  }
   339  
   340  func (g *genStreamer) se(t types.Type, n, rtype string, arrlen int64) string {
   341  	elmt := Element{
   342  		Size: 1,
   343  	}
   344  	if arrlen > 0 {
   345  		elmt.Size = int32(arrlen)
   346  		elmt.ArrLen = int32(arrlen)
   347  		elmt.ArrDim = 1
   348  		elmt.MaxIdx[0] = elmt.ArrLen // FIXME(sbinet): handle n-dim arrays [n][m][u][v][w]T
   349  	}
   350  
   351  	ut := t.Underlying()
   352  	switch ut := ut.(type) {
   353  	case *types.Basic:
   354  		g.imps["go-hep.org/x/hep/groot/rbase"]++
   355  		switch kind := ut.Kind(); kind {
   356  		case types.Bool:
   357  			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()",
   358  				n, "",
   359  				rmeta.GoType2Cxx[ut.Name()],
   360  				rtype,
   361  				1*elmt.Size,
   362  				elmt.ArrLen,
   363  				elmt.ArrDim,
   364  				elmt.MaxIdx,
   365  			)
   366  		case types.Uint8:
   367  			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()",
   368  				n, "",
   369  				rmeta.GoType2Cxx[ut.Name()],
   370  				rtype,
   371  				1*elmt.Size,
   372  				elmt.ArrLen,
   373  				elmt.ArrDim,
   374  				elmt.MaxIdx,
   375  			)
   376  		case types.Uint16:
   377  			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()",
   378  				n, "",
   379  				rmeta.GoType2Cxx[ut.Name()],
   380  				rtype,
   381  				2*elmt.Size,
   382  				elmt.ArrLen,
   383  				elmt.ArrDim,
   384  				elmt.MaxIdx,
   385  			)
   386  		case types.Uint32, types.Uint:
   387  			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()",
   388  				n, "",
   389  				rmeta.GoType2Cxx[ut.Name()],
   390  				rtype,
   391  				4*elmt.Size,
   392  				elmt.ArrLen,
   393  				elmt.ArrDim,
   394  				elmt.MaxIdx,
   395  			)
   396  		case types.Uint64:
   397  			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()",
   398  				n, "",
   399  				rmeta.GoType2Cxx[ut.Name()],
   400  				rtype,
   401  				8*elmt.Size,
   402  				elmt.ArrLen,
   403  				elmt.ArrDim,
   404  				elmt.MaxIdx,
   405  			)
   406  		case types.Int8:
   407  			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()",
   408  				n, "",
   409  				rmeta.GoType2Cxx[ut.Name()],
   410  				rtype,
   411  				1*elmt.Size,
   412  				elmt.ArrLen,
   413  				elmt.ArrDim,
   414  				elmt.MaxIdx,
   415  			)
   416  		case types.Int16:
   417  			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()",
   418  				n, "",
   419  				rmeta.GoType2Cxx[ut.Name()],
   420  				rtype,
   421  				2*elmt.Size,
   422  				elmt.ArrLen,
   423  				elmt.ArrDim,
   424  				elmt.MaxIdx,
   425  			)
   426  		case types.Int32, types.Int:
   427  			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()",
   428  				n, "",
   429  				rmeta.GoType2Cxx[ut.Name()],
   430  				rtype,
   431  				4*elmt.Size,
   432  				elmt.ArrLen,
   433  				elmt.ArrDim,
   434  				elmt.MaxIdx,
   435  			)
   436  		case types.Int64:
   437  			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()",
   438  				n, "",
   439  				rmeta.GoType2Cxx[ut.Name()],
   440  				rtype,
   441  				8*elmt.Size,
   442  				elmt.ArrLen,
   443  				elmt.ArrDim,
   444  				elmt.MaxIdx,
   445  			)
   446  		case types.Float32:
   447  			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()",
   448  				n, "",
   449  				rmeta.GoType2Cxx[ut.Name()],
   450  				rtype,
   451  				4*elmt.Size,
   452  				elmt.ArrLen,
   453  				elmt.ArrDim,
   454  				elmt.MaxIdx,
   455  			)
   456  		case types.Float64:
   457  			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()",
   458  				n, "",
   459  				rmeta.GoType2Cxx[ut.Name()],
   460  				rtype,
   461  				8*elmt.Size,
   462  				elmt.ArrLen,
   463  				elmt.ArrDim,
   464  				elmt.MaxIdx,
   465  			)
   466  		case types.Complex64:
   467  			log.Fatalf("unhandled type: %v (underlying %v)\n", t, ut) // FIXME(sbinet)
   468  
   469  		case types.Complex128:
   470  			log.Fatalf("unhandled type: %v (underlying %v)\n", t, ut) // FIXME(sbinet)
   471  
   472  		case types.String:
   473  			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()}",
   474  				n, "",
   475  				"TString",
   476  				rtype,
   477  				24*elmt.Size,
   478  				elmt.ArrLen,
   479  				elmt.ArrDim,
   480  				elmt.MaxIdx,
   481  			)
   482  		}
   483  	case *types.Struct:
   484  		// FIXME(sbinet): implement.
   485  		// FIXME(sbinet): prevent recursion.
   486  		old := g.buf
   487  		g.buf = new(bytes.Buffer)
   488  		g.genStreamerType(t, n)
   489  		str := g.buf.String()
   490  		g.buf = old
   491  		return str
   492  	}
   493  
   494  	log.Printf("gen-streamer: unhandled type: %v (underlying %v)", t, ut)
   495  	return ""
   496  }
   497  
   498  func (g *genStreamer) genMarshalType(t types.Type, n string) {
   499  	ut := t.Underlying()
   500  	switch ut := ut.(type) {
   501  	case *types.Basic:
   502  		switch kind := ut.Kind(); kind {
   503  		case types.Bool:
   504  			g.wt(ut, n, "", "")
   505  		case types.Uint8:
   506  			g.wt(ut, n, "", "")
   507  		case types.Uint16:
   508  			g.wt(ut, n, "", "")
   509  		case types.Uint32:
   510  			g.wt(ut, n, "", "")
   511  		case types.Uint64:
   512  			g.wt(ut, n, "", "")
   513  		case types.Int8:
   514  			g.wt(ut, n, "", "")
   515  		case types.Int16:
   516  			g.wt(ut, n, "", "")
   517  		case types.Int32:
   518  			g.wt(ut, n, "", "")
   519  		case types.Int64:
   520  			g.wt(ut, n, "", "")
   521  		case types.Float32:
   522  			g.wt(ut, n, "", "")
   523  		case types.Float64:
   524  			g.wt(ut, n, "", "")
   525  
   526  		case types.Uint:
   527  			g.wt(ut, n, "", "")
   528  		case types.Int:
   529  			g.wt(ut, n, "", "")
   530  
   531  		case types.Complex64:
   532  			log.Fatalf("unhandled type: %v (underlying %v)\n", t, ut) // FIXME(sbinet)
   533  		case types.Complex128:
   534  			log.Fatalf("unhandled type: %v (underlying %v)\n", t, ut) // FIXME(sbinet)
   535  
   536  		case types.String:
   537  			g.wt(ut, n, "", "")
   538  
   539  		default:
   540  			log.Fatalf("unhandled type: %v (underlying: %v)\n", t, ut)
   541  		}
   542  
   543  	case *types.Array:
   544  		switch ut.Elem().Underlying().(type) {
   545  		case *types.Basic:
   546  			g.wt(ut.Elem(), n, "Array", "[:]")
   547  		default:
   548  			g.printf("for i := range o.%s {\n", n)
   549  			g.wt(ut.Elem(), n+"[i]", "", "")
   550  			g.printf("}\n")
   551  		}
   552  
   553  	case *types.Slice:
   554  		g.wt(ut.Elem(), n, "Array", "")
   555  
   556  	case *types.Struct:
   557  		g.printf("w.WriteObject(&o.%s)\n", n)
   558  
   559  	default:
   560  		log.Fatalf("gen-marshal-type: unhandled type: %v (underlying: %v)\n", t, ut)
   561  	}
   562  }
   563  
   564  // Generate implements rdict.Generator
   565  func (g *genStreamer) Format() ([]byte, error) {
   566  	buf := new(bytes.Buffer)
   567  
   568  	buf.WriteString(fmt.Sprintf(`// DO NOT EDIT; automatically generated by %[1]s
   569  
   570  package %[2]s
   571  
   572  import (
   573  `,
   574  		"root-gen-streamer",
   575  		g.pkg.Name(),
   576  	))
   577  
   578  	// FIXME(sbinet): separate stdlib from 3rd-party imports.
   579  
   580  	for k := range g.imps {
   581  		fmt.Fprintf(buf, "%q\n", k)
   582  	}
   583  	fmt.Fprintf(buf, ")\n\n")
   584  
   585  	buf.Write(g.buf.Bytes())
   586  
   587  	src, err := format.Source(buf.Bytes())
   588  	if err != nil {
   589  		log.Printf("=== error ===\n%s\n", buf.Bytes())
   590  	}
   591  	return src, err
   592  }
   593  
   594  var (
   595  	_ Generator = (*genStreamer)(nil)
   596  )