go-hep.org/x/hep@v0.38.1/groot/rdict/gen_type.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  	"io"
    12  	"log"
    13  	"path/filepath"
    14  	"sort"
    15  	"strings"
    16  
    17  	"go-hep.org/x/hep/groot/rbytes"
    18  	"go-hep.org/x/hep/groot/rmeta"
    19  	"go-hep.org/x/hep/groot/rtypes"
    20  )
    21  
    22  type genGoType struct {
    23  	pkg string
    24  	buf *bytes.Buffer
    25  	ctx rbytes.StreamerInfoContext
    26  
    27  	verbose bool
    28  
    29  	// set of imported packages.
    30  	// usually: "go-hep.org/x/hep/groot/rbase", ".../rcont
    31  	imps map[string]int
    32  
    33  	rdict string // whether to prepend 'rdict.'
    34  }
    35  
    36  // GenCxxStreamerInfo generates the textual representation of the provided streamer info.
    37  func GenCxxStreamerInfo(w io.Writer, si rbytes.StreamerInfo, verbose bool) error {
    38  	g, err := NewGenGoType("go-hep.org/x/hep/groot/rdict", nil, verbose)
    39  	if err != nil {
    40  		return fmt.Errorf("rdict: could not create streamer info generator: %w", err)
    41  	}
    42  	g.rdict = ""
    43  
    44  	g.printf("%sNewCxxStreamerInfo(%q, %d, 0x%x, []rbytes.StreamerElement{\n", g.rdict, si.Name(), si.ClassVersion(), si.CheckSum())
    45  	for i, se := range si.Elements() {
    46  		g.genStreamerType(si, i, se)
    47  	}
    48  	g.printf("})")
    49  
    50  	src, err := format.Source(g.buf.Bytes())
    51  	if err != nil {
    52  		return fmt.Errorf("rdict: could not format streamer code for %q: %w", si.Name(), err)
    53  	}
    54  
    55  	_, err = w.Write(src)
    56  	if err != nil {
    57  		return fmt.Errorf("rdict: could not write streamer info generated data: %w", err)
    58  	}
    59  
    60  	return err
    61  }
    62  
    63  // NewGenGoType generates code for Go types from a ROOT StreamerInfo.
    64  func NewGenGoType(pkg string, sictx rbytes.StreamerInfoContext, verbose bool) (*genGoType, error) {
    65  	return &genGoType{
    66  		pkg:     pkg,
    67  		buf:     new(bytes.Buffer),
    68  		ctx:     sictx,
    69  		verbose: verbose,
    70  		imps: map[string]int{
    71  			"reflect":                       1,
    72  			"go-hep.org/x/hep/groot/rbytes": 1,
    73  			"go-hep.org/x/hep/groot/root":   1,
    74  			"go-hep.org/x/hep/groot/rtypes": 1,
    75  		},
    76  		rdict: "rdict.",
    77  	}, nil
    78  }
    79  
    80  // Generate implements rdict.Generator
    81  func (g *genGoType) Generate(name string) error {
    82  	if g.verbose {
    83  		log.Printf("generating type for %q...", name)
    84  	}
    85  	si, err := g.ctx.StreamerInfo(name, -1)
    86  	if err != nil {
    87  		return fmt.Errorf("rdict: could not find streamer for %q: %w", name, err)
    88  	}
    89  
    90  	return g.genType(si)
    91  }
    92  
    93  func (g *genGoType) genType(si rbytes.StreamerInfo) error {
    94  	name := si.Name()
    95  	if title := si.Title(); title != "" {
    96  		g.printf("// %s has been automatically generated.\n", name)
    97  		g.printf("// %s\n", title)
    98  	}
    99  	goname := name
   100  	goname = strings.Replace(goname, "::", "__", -1) // handle namespaces
   101  	goname = strings.Replace(goname, "<", "_", -1)   // handle C++ templates
   102  	goname = strings.Replace(goname, ">", "_", -1)   // handle C++ templates
   103  	goname = strings.Replace(goname, ",", "_", -1)   // handle C++ templates
   104  	g.printf("type %s struct{\n", goname)
   105  	for i, se := range si.Elements() {
   106  		g.genField(si, i, se)
   107  	}
   108  	g.printf("}\n\n")
   109  	g.printf("func (*%s) Class() string {\nreturn %q\n}\n\n", goname, name)
   110  	g.printf("func (*%s) RVersion() int16 {\nreturn %d\n}\n", goname, si.ClassVersion())
   111  	g.printf("\n")
   112  	g.genMarshal(si)
   113  	g.genUnmarshal(si)
   114  
   115  	g.printf(`func init() {
   116  	f := func() reflect.Value {
   117  		var o %s
   118  		return reflect.ValueOf(&o)
   119  	}
   120  	rtypes.Factory.Add(%q, f)
   121  }
   122  
   123  `,
   124  		goname, name,
   125  	)
   126  
   127  	g.genStreamerInfo(si)
   128  
   129  	ifaces := []string{"root.Object", "rbytes.RVersioner", "rbytes.Marshaler", "rbytes.Unmarshaler"}
   130  	g.printf("var (\n")
   131  	for _, n := range ifaces {
   132  		g.printf("\t_ %s = (*%s)(nil)\n", n, goname)
   133  	}
   134  	g.printf(")\n\n")
   135  
   136  	return nil
   137  }
   138  
   139  func (g *genGoType) genField(si rbytes.StreamerInfo, i int, se rbytes.StreamerElement) {
   140  	const (
   141  		docFmt = "\t%s\t%s\t%s\t%s\n"
   142  	)
   143  	doc := g.doc(se.Title())
   144  	if doc != "" {
   145  		doc = "// " + doc
   146  	}
   147  	switch se := se.(type) {
   148  	case *StreamerBase:
   149  		g.printf(docFmt, fmt.Sprintf("base%d", i), g.typename(se), g.stag(i, se), "// base class")
   150  
   151  	case *StreamerBasicPointer:
   152  		g.printf(docFmt, se.Name(), g.typename(se), g.stag(i, se), doc)
   153  
   154  	case *StreamerBasicType:
   155  		tname := g.typename(se)
   156  		switch se.ArrayLen() {
   157  		case 0:
   158  		default:
   159  			tname = fmt.Sprintf("[%d]%s", se.ArrayLen(), tname)
   160  		}
   161  		g.printf(docFmt, se.Name(), tname, g.stag(i, se), doc)
   162  
   163  	case *StreamerLoop:
   164  		tname := g.typename(se)
   165  		g.printf(docFmt, se.Name(), tname, g.stag(i, se), doc)
   166  
   167  	case *StreamerObject:
   168  		tname := g.typename(se)
   169  		switch se.ArrayLen() {
   170  		case 0:
   171  		default:
   172  			tname = fmt.Sprintf("[%d]%s", se.ArrayLen(), tname)
   173  		}
   174  		g.printf(docFmt, se.Name(), tname, g.stag(i, se), doc)
   175  
   176  	case *StreamerObjectAny:
   177  		tname := g.typename(se)
   178  		switch se.ArrayLen() {
   179  		case 0:
   180  		default:
   181  			tname = fmt.Sprintf("[%d]%s", se.ArrayLen(), tname)
   182  		}
   183  		g.printf(docFmt, se.Name(), tname, g.stag(i, se), doc)
   184  
   185  	case *StreamerObjectAnyPointer:
   186  		tname := g.typename(se)
   187  		g.printf(docFmt, se.Name(), tname, g.stag(i, se), doc)
   188  
   189  	case *StreamerObjectPointer:
   190  		tname := g.typename(se)
   191  		g.printf(docFmt, se.Name(), tname, g.stag(i, se), doc)
   192  
   193  	case *StreamerString, *StreamerSTLstring:
   194  		g.printf(docFmt, se.Name(), "string", g.stag(i, se), doc)
   195  
   196  	case *StreamerSTL:
   197  		switch se.STLType() {
   198  		case rmeta.STLvector, rmeta.STLmap, rmeta.STLend:
   199  			tname := g.typename(se)
   200  			g.printf(docFmt, se.Name(), tname, g.stag(i, se), doc)
   201  		default:
   202  			panic(fmt.Errorf("STL-type not implemented %#v", se))
   203  		}
   204  	default:
   205  		g.printf("\t%s\t%s // %T -- %s\n", se.Name(), g.typename(se), se, doc)
   206  	}
   207  }
   208  
   209  func (g *genGoType) stag(i int, se rbytes.StreamerElement) string {
   210  	switch se := se.(type) {
   211  	case *StreamerBase:
   212  		return fmt.Sprintf("`groot:\"BASE-%s\"`", se.Name())
   213  	}
   214  	meta, _ := g.rcomment(se.Title())
   215  	if meta != "" {
   216  		return fmt.Sprintf("`groot:\"%s,meta=%s\"`", se.Name(), meta)
   217  	}
   218  	return fmt.Sprintf("`groot:%q`", se.Name())
   219  }
   220  
   221  func (g *genGoType) doc(title string) string {
   222  	_, doc := g.rcomment(title)
   223  	return doc
   224  }
   225  
   226  func (g *genGoType) rcomment(s string) (meta, comment string) {
   227  	comment = s
   228  	for strings.HasPrefix(comment, "[") {
   229  		beg := strings.Index(comment, "[")
   230  		end := strings.Index(comment, "]")
   231  		meta += comment[beg : end+1]
   232  		comment = comment[end+1:]
   233  	}
   234  	if strings.HasPrefix(comment, " ") {
   235  		comment = strings.TrimSpace(comment)
   236  	}
   237  	return meta, comment
   238  }
   239  
   240  func (g *genGoType) typename(se rbytes.StreamerElement) string {
   241  	tname := se.TypeName()
   242  	switch se := se.(type) {
   243  	case *StreamerBase:
   244  		return g.cxx2go(se.Name(), 0)
   245  
   246  	case *StreamerBasicPointer:
   247  		tname = tname[:len(tname)-1] // drop last '*'
   248  		t, ok := rmeta.CxxBuiltins[tname]
   249  		if !ok {
   250  			panic(fmt.Errorf("gen-type: unknown C++ builtin %q", tname))
   251  		}
   252  		switch {
   253  		case strings.HasPrefix(se.Title(), "["):
   254  			return g.cxx2go(t.Name(), qualSlice)
   255  		default:
   256  			return g.cxx2go(t.Name(), qualStar)
   257  		}
   258  
   259  	case *StreamerBasicType:
   260  		switch se.Type() {
   261  		case rmeta.Float16:
   262  			g.imps["go-hep.org/x/hep/groot/root"] = 1
   263  			return "root.Float16"
   264  		case rmeta.Double32:
   265  			g.imps["go-hep.org/x/hep/groot/root"] = 1
   266  			return "root.Double32"
   267  		}
   268  		t, ok := rmeta.CxxBuiltins[tname]
   269  		if !ok {
   270  			enum := se.Type().String()
   271  			switch se.Type() {
   272  			case rmeta.Uint8:
   273  				enum = "uint8_t"
   274  			case rmeta.Uint16:
   275  				enum = "uint16_t"
   276  			case rmeta.Uint32:
   277  				enum = "uint32_t"
   278  			case rmeta.Uint64:
   279  				enum = "uint64_t"
   280  			case rmeta.Int8:
   281  				enum = "int8_t"
   282  			case rmeta.Int16:
   283  				enum = "int16_t"
   284  			case rmeta.Int32:
   285  				enum = "int32_t"
   286  			case rmeta.Int64:
   287  				enum = "int64_t"
   288  			}
   289  			t, ok = rmeta.CxxBuiltins[enum]
   290  		}
   291  		if !ok {
   292  			panic(fmt.Errorf("gen-type: unknown C++ builtin %q", tname))
   293  		}
   294  		return t.Name()
   295  
   296  	case *StreamerLoop:
   297  		tname = strings.TrimSuffix(tname, "*")
   298  		return "[]" + g.cxx2go(tname, qualNone)
   299  
   300  	case *StreamerObject:
   301  		return g.cxx2go(tname, qualNone)
   302  
   303  	case *StreamerObjectAny:
   304  		return g.cxx2go(tname, qualNone)
   305  
   306  	case *StreamerObjectAnyPointer:
   307  		tname = tname[:len(tname)-1] // drop last '*'
   308  		return g.cxx2go(tname, qualStar)
   309  
   310  	case *StreamerObjectPointer:
   311  		tname = tname[:len(tname)-1] // drop last '*'
   312  		return g.cxx2go(tname, qualStar)
   313  
   314  	case *StreamerString, *StreamerSTLstring:
   315  		return "string"
   316  
   317  	case *StreamerSTL:
   318  		switch se.STLType() {
   319  		case rmeta.STLvector, rmeta.STLend:
   320  			switch se.ContainedType() {
   321  			case rmeta.Bool:
   322  				return "[]bool"
   323  			case rmeta.Int8:
   324  				return "[]int8"
   325  			case rmeta.Int16:
   326  				return "[]int16"
   327  			case rmeta.Int32:
   328  				return "[]int32"
   329  			case rmeta.Int64, rmeta.Long64:
   330  				return "[]int64"
   331  			case rmeta.Uint8:
   332  				return "[]uint8"
   333  			case rmeta.Uint16:
   334  				return "[]uint16"
   335  			case rmeta.Uint32:
   336  				return "[]uint32"
   337  			case rmeta.Uint64, rmeta.ULong64:
   338  				return "[]uint64"
   339  			case rmeta.Float32:
   340  				return "[]float32"
   341  			case rmeta.Float64:
   342  				return "[]float64"
   343  			case rmeta.Float16:
   344  				return "[]root.Float16"
   345  			case rmeta.Double32:
   346  				return "[]root.Double32"
   347  			case rmeta.Object:
   348  				etn := se.ElemTypeName()
   349  				switch etn[0] {
   350  				case "string":
   351  					return "[]string"
   352  				default:
   353  					etname := g.cxx2go(etn[0], qualNone)
   354  					return "[]" + etname
   355  				}
   356  			default:
   357  				panic(fmt.Errorf("invalid stl-vector element type: %v -- %#v", se.ContainedType(), se))
   358  			}
   359  		case rmeta.STLmap:
   360  			types := se.ElemTypeName()
   361  			k := g.cxx2go(types[0], qualNone)
   362  			v := g.cxx2go(types[1], qualNone)
   363  			return "map[" + k + "]" + v
   364  		default:
   365  			panic(fmt.Errorf("STL-type not implemented %#v", se))
   366  		}
   367  	}
   368  	return tname
   369  }
   370  
   371  type qualKind uint8
   372  
   373  func (q qualKind) String() string {
   374  	switch q {
   375  	case qualNone:
   376  		return ""
   377  	case qualStar:
   378  		return "*"
   379  	case qualSlice:
   380  		return "[]"
   381  	}
   382  	panic(fmt.Errorf("invalid qual-kind value %d", int(q)))
   383  }
   384  
   385  const (
   386  	qualNone  qualKind = 0
   387  	qualStar  qualKind = 1
   388  	qualSlice qualKind = 2
   389  )
   390  
   391  func (g *genGoType) cxx2go(name string, qual qualKind) string {
   392  	prefix := qual.String()
   393  	if rtypes.Factory.HasKey(name) {
   394  		t := rtypes.Factory.Get(name)().Type().Elem()
   395  		pkg := t.PkgPath()
   396  		g.imps[pkg]++
   397  		switch t.Name() {
   398  		case "tgraph":
   399  			if qual == qualStar {
   400  				prefix = ""
   401  			}
   402  			return prefix + "rhist.Graph"
   403  		case "tgrapherrs", "tgraphasymerrs":
   404  			if qual == qualStar {
   405  				prefix = ""
   406  			}
   407  			return prefix + "rhist.GraphErrors"
   408  		}
   409  
   410  		return prefix + filepath.Base(pkg) + "." + t.Name()
   411  	}
   412  	var f func(name string) string
   413  	f = func(name string) string {
   414  		switch {
   415  		case strings.HasSuffix(name, "*"):
   416  			return "*" + f(name[:len(name)-1])
   417  		}
   418  		return name
   419  	}
   420  	name = f(name)
   421  	name = strings.Replace(name, "::", "__", -1) // handle namespaces
   422  	name = strings.Replace(name, "<", "_", -1)   // handle C++ templates
   423  	name = strings.Replace(name, ">", "_", -1)   // handle C++ templates
   424  	name = strings.Replace(name, ",", "_", -1)   // handle C++ templates
   425  	return prefix + name
   426  }
   427  
   428  func (g *genGoType) genMarshal(si rbytes.StreamerInfo) {
   429  	g.printf(`// MarshalROOT implements rbytes.Marshaler
   430  func (o *%[1]s) MarshalROOT(w *rbytes.WBuffer) (int, error) {
   431  	if w.Err() != nil {
   432  		return 0, w.Err()
   433  	}
   434  
   435  	hdr := w.WriteHeader(o.Class(), o.RVersion())
   436  
   437  `,
   438  		g.cxx2go(si.Name(), qualNone),
   439  	)
   440  
   441  	for i, se := range si.Elements() {
   442  		g.genMarshalField(si, i, se)
   443  	}
   444  
   445  	g.printf("\n\treturn w.SetHeader(hdr)\n}\n\n")
   446  }
   447  
   448  func (g *genGoType) genMarshalField(si rbytes.StreamerInfo, i int, se rbytes.StreamerElement) {
   449  	switch se := se.(type) {
   450  	case *StreamerBase:
   451  		g.printf("w.WriteObject(&o.%s)\n", fmt.Sprintf("base%d", i))
   452  
   453  	case *StreamerBasicPointer:
   454  		title := se.Title()
   455  		switch {
   456  		case strings.HasPrefix(title, "["):
   457  			n := title[strings.Index(title, "[")+1 : strings.Index(title, "]")]
   458  			g.printf("w.WriteI8(1) // is-array\n")
   459  			wfunc := ""
   460  			switch se.Type() {
   461  			case rmeta.OffsetP + rmeta.Bool:
   462  				wfunc = "WriteArrayBool"
   463  			case rmeta.OffsetP + rmeta.Int8:
   464  				wfunc = "WriteArrayI8"
   465  			case rmeta.OffsetP + rmeta.Int16:
   466  				wfunc = "WriteArrayI16"
   467  			case rmeta.OffsetP + rmeta.Int32:
   468  				wfunc = "WriteArrayI32"
   469  			case rmeta.OffsetP + rmeta.Int64, rmeta.OffsetP + rmeta.Long64:
   470  				wfunc = "WriteArrayI64"
   471  			case rmeta.OffsetP + rmeta.Uint8:
   472  				wfunc = "WriteArrayU8"
   473  			case rmeta.OffsetP + rmeta.Uint16:
   474  				wfunc = "WriteArrayU16"
   475  			case rmeta.OffsetP + rmeta.Uint32:
   476  				wfunc = "WriteArrayU32"
   477  			case rmeta.OffsetP + rmeta.Uint64, rmeta.OffsetP + rmeta.ULong64:
   478  				wfunc = "WriteArrayU64"
   479  			case rmeta.OffsetP + rmeta.Float32:
   480  				wfunc = "WriteArrayF32"
   481  			case rmeta.OffsetP + rmeta.Float64:
   482  				wfunc = "WriteArrayF64"
   483  			default:
   484  				panic(fmt.Errorf("invalid element type: %v", se.Type()))
   485  			}
   486  			g.printf("w.%s(o.%s[:o.%s])\n", wfunc, se.Name(), n)
   487  		default:
   488  			panic("not implemented")
   489  		}
   490  
   491  	case *StreamerBasicType:
   492  		switch se.ArrayLen() {
   493  		case 0:
   494  			switch se.Type() {
   495  			case rmeta.Bool:
   496  				g.printf("w.WriteBool(o.%s)\n", se.Name())
   497  
   498  			case rmeta.Counter:
   499  				switch se.Size() {
   500  				case 4:
   501  					g.printf("w.WriteI32(int32(o.%s))\n", se.Name())
   502  				case 8:
   503  					g.printf("w.WriteI64(int64(o.%s))\n", se.Name())
   504  				default:
   505  					panic(fmt.Errorf("invalid counter size %d for %s.%s", se.Size(), si.Name(), se.Name()))
   506  				}
   507  
   508  			case rmeta.Bits:
   509  				g.printf("w.WriteI32(int32(o.%s))\n", se.Name())
   510  
   511  			case rmeta.Int8:
   512  				g.printf("w.WriteI8(o.%s)\n", se.Name())
   513  			case rmeta.Int16:
   514  				g.printf("w.WriteI16(o.%s)\n", se.Name())
   515  			case rmeta.Int32:
   516  				g.printf("w.WriteI32(o.%s)\n", se.Name())
   517  			case rmeta.Int64, rmeta.Long64:
   518  				g.printf("w.WriteI64(o.%s)\n", se.Name())
   519  
   520  			case rmeta.Uint8:
   521  				g.printf("w.WriteU8(o.%s)\n", se.Name())
   522  			case rmeta.Uint16:
   523  				g.printf("w.WriteU16(o.%s)\n", se.Name())
   524  			case rmeta.Uint32:
   525  				g.printf("w.WriteU32(o.%s)\n", se.Name())
   526  			case rmeta.Uint64, rmeta.ULong64:
   527  				g.printf("w.WriteU64(o.%s)\n", se.Name())
   528  
   529  			case rmeta.Float32:
   530  				g.printf("w.WriteF32(o.%s)\n", se.Name())
   531  			case rmeta.Float64:
   532  				g.printf("w.WriteF64(o.%s)\n", se.Name())
   533  
   534  			case rmeta.Float16:
   535  				g.printf("w.WriteF32(float32(o.%s)) // FIXME(sbinet)\n", se.Name()) // FIXME(sbinet): handle compression
   536  			case rmeta.Double32:
   537  				g.printf("w.WriteF32(float32(o.%s)) // FIXME(sbinet)\n", se.Name()) // FIXME(sbinet): handle compression
   538  
   539  			default:
   540  				panic(fmt.Errorf("invalid basic type %v (%d) for %s.%s", se.Type(), se.Type(), si.Name(), se.Name()))
   541  			}
   542  		default:
   543  			n := int(se.ArrayLen())
   544  			wfunc := ""
   545  			switch se.Type() {
   546  			case rmeta.OffsetL + rmeta.Bool:
   547  				wfunc = "WriteArrayBool"
   548  			case rmeta.OffsetL + rmeta.Int8:
   549  				wfunc = "WriteArrayI8"
   550  			case rmeta.OffsetL + rmeta.Int16:
   551  				wfunc = "WriteArrayI16"
   552  			case rmeta.OffsetL + rmeta.Int32:
   553  				wfunc = "WriteArrayI32"
   554  			case rmeta.OffsetL + rmeta.Int64, rmeta.OffsetL + rmeta.Long64:
   555  				wfunc = "WriteArrayI64"
   556  			case rmeta.OffsetL + rmeta.Uint8:
   557  				wfunc = "WriteArrayU8"
   558  			case rmeta.OffsetL + rmeta.Uint16:
   559  				wfunc = "WriteArrayU16"
   560  			case rmeta.OffsetL + rmeta.Uint32:
   561  				wfunc = "WriteArrayU32"
   562  			case rmeta.OffsetL + rmeta.Uint64, rmeta.OffsetL + rmeta.ULong64:
   563  				wfunc = "WriteArrayU64"
   564  			case rmeta.OffsetL + rmeta.Float32:
   565  				wfunc = "WriteArrayF32"
   566  			case rmeta.OffsetL + rmeta.Float64:
   567  				wfunc = "WriteArrayF64"
   568  			default:
   569  				panic(fmt.Errorf("invalid array element type: %v", se.Type()))
   570  			}
   571  			g.printf("w.%s(o.%s[:%d])\n", wfunc, se.Name(), n)
   572  		}
   573  
   574  	case *StreamerLoop:
   575  		// FIXME(sbinet): implement. handle mbr-wise
   576  		g.printf("panic(\"o.%s: not implemented (TStreamerLoop)\")\n", se.Name())
   577  
   578  	case *StreamerObject:
   579  		// FIXME(sbinet): check semantics
   580  		switch se.ArrayLen() {
   581  		case 0:
   582  			g.printf("w.WriteObject(&o.%s) // obj\n", se.Name())
   583  		default:
   584  			g.printf("for i := range o.%s {\n", se.Name())
   585  			g.printf("w.WriteObject(&o.%s[i]) // obj\n", se.Name())
   586  			g.printf("}\n")
   587  		}
   588  
   589  	case *StreamerObjectAny:
   590  		// FIXME(sbinet): check semantics
   591  		switch se.ArrayLen() {
   592  		case 0:
   593  			g.printf("w.WriteObject(&o.%s) // obj-any\n", se.Name())
   594  		default:
   595  			g.printf("for i := range o.%s {\n", se.Name())
   596  			g.printf("w.WriteObject(&o.%s[i]) // obj-any\n", se.Name())
   597  			g.printf("}\n")
   598  		}
   599  
   600  	case *StreamerObjectAnyPointer:
   601  		// FIXME(sbinet): check semantics
   602  		g.printf("w.WriteObjectAny(o.%s) // obj-any-ptr\n", se.Name())
   603  
   604  	case *StreamerObjectPointer:
   605  		// FIXME(sbinet): check semantics
   606  		g.printf("w.WriteObjectAny(o.%s) // obj-ptr\n", se.Name())
   607  
   608  	case *StreamerString:
   609  		g.printf("w.WriteString(o.%s)\n", se.Name())
   610  
   611  	case *StreamerSTLstring:
   612  		g.printf("w.WriteStdString(o.%s)\n", se.Name())
   613  
   614  	case *StreamerSTL:
   615  		switch se.STLType() {
   616  		case rmeta.STLvector, rmeta.STLend:
   617  			wfunc := ""
   618  			switch se.ContainedType() {
   619  			case rmeta.Bool:
   620  				wfunc = "WriteStdVectorBool"
   621  			case rmeta.Int8:
   622  				wfunc = "WriteStdVectorI8"
   623  			case rmeta.Int16:
   624  				wfunc = "WriteStdVectorI16"
   625  			case rmeta.Int32:
   626  				wfunc = "WriteStdVectorI32"
   627  			case rmeta.Int64, rmeta.Long64:
   628  				wfunc = "WriteStdVectorI64"
   629  			case rmeta.Uint8:
   630  				wfunc = "WriteStdVectorU8"
   631  			case rmeta.Uint16:
   632  				wfunc = "WriteStdVectorU16"
   633  			case rmeta.Uint32:
   634  				wfunc = "WriteStdVectorU32"
   635  			case rmeta.Uint64, rmeta.ULong64:
   636  				wfunc = "WriteStdVectorU64"
   637  			case rmeta.Float32:
   638  				wfunc = "WriteStdVectorF32"
   639  			case rmeta.Float64:
   640  				wfunc = "WriteStdVectorF64"
   641  			case rmeta.Object:
   642  				etn := se.ElemTypeName()
   643  				switch etn[0] {
   644  				case "string":
   645  					wfunc = "WriteStdVectorStrs"
   646  				default:
   647  					panic(fmt.Errorf("invalid stl-vector element type: %v", se.ContainedType()))
   648  				}
   649  			default:
   650  				panic(fmt.Errorf("invalid stl-vector element type: %v", se.ContainedType()))
   651  			}
   652  			g.printf("w.%s(o.%s)\n", wfunc, se.Name())
   653  
   654  		default:
   655  			panic(fmt.Errorf("STL-type not implemented %#v", se))
   656  		}
   657  
   658  	default:
   659  		g.printf("// %s -- %T\n", se.Name(), se)
   660  	}
   661  }
   662  
   663  func (g *genGoType) genUnmarshal(si rbytes.StreamerInfo) {
   664  	g.printf(`// UnmarshalROOT implements rbytes.Unmarshaler
   665  func (o *%[1]s) UnmarshalROOT(r *rbytes.RBuffer) error {
   666  	if r.Err() != nil {
   667  		return r.Err()
   668  	}
   669  	
   670  	hdr := r.ReadHeader(o.Class(), o.RVersion())
   671  
   672  `,
   673  		g.cxx2go(si.Name(), qualNone),
   674  	)
   675  
   676  	for i, se := range si.Elements() {
   677  		g.genUnmarshalField(si, i, se)
   678  	}
   679  
   680  	g.printf("\nr.CheckHeader(hdr)\nreturn r.Err()\n}\n\n")
   681  }
   682  
   683  func (g *genGoType) genUnmarshalField(si rbytes.StreamerInfo, i int, se rbytes.StreamerElement) {
   684  	switch se := se.(type) {
   685  	case *StreamerBase:
   686  		g.printf("r.ReadObject(&o.%s)\n", fmt.Sprintf("base%d", i))
   687  
   688  	case *StreamerBasicPointer:
   689  		title := se.Title()
   690  		switch {
   691  		case strings.HasPrefix(title, "["):
   692  			n := title[strings.Index(title, "[")+1 : strings.Index(title, "]")]
   693  			g.printf("_ = r.ReadI8() // is-array\n")
   694  			rfunc := ""
   695  			rsize := ""
   696  			switch se.Type() {
   697  			case rmeta.OffsetP + rmeta.Bool:
   698  				rfunc = "ReadArrayBool"
   699  				rsize = "ResizeBool"
   700  			case rmeta.OffsetP + rmeta.Int8:
   701  				rfunc = "ReadArrayI8"
   702  				rsize = "ResizeI8"
   703  			case rmeta.OffsetP + rmeta.Int16:
   704  				rfunc = "ReadArrayI16"
   705  				rsize = "ResizeI16"
   706  			case rmeta.OffsetP + rmeta.Int32:
   707  				rfunc = "ReadArrayI32"
   708  				rsize = "ResizeI32"
   709  			case rmeta.OffsetP + rmeta.Int64, rmeta.OffsetP + rmeta.Long64:
   710  				rfunc = "ReadArrayI64"
   711  				rsize = "ResizeI64"
   712  			case rmeta.OffsetP + rmeta.Uint8:
   713  				rfunc = "ReadArrayU8"
   714  				rsize = "ResizeU8"
   715  			case rmeta.OffsetP + rmeta.Uint16:
   716  				rfunc = "ReadArrayU16"
   717  				rsize = "ResizeU16"
   718  			case rmeta.OffsetP + rmeta.Uint32:
   719  				rfunc = "ReadArrayU32"
   720  				rsize = "ResizeU32"
   721  			case rmeta.OffsetP + rmeta.Uint64, rmeta.OffsetP + rmeta.ULong64:
   722  				rfunc = "ReadArrayU64"
   723  				rsize = "ResizeU64"
   724  			case rmeta.OffsetP + rmeta.Float32:
   725  				rfunc = "ReadArrayF32"
   726  				rsize = "ResizeF32"
   727  			case rmeta.OffsetP + rmeta.Float64:
   728  				rfunc = "ReadArrayF64"
   729  				rsize = "ResizeF64"
   730  			default:
   731  				panic(fmt.Errorf("invalid element type: %v", se.Type()))
   732  			}
   733  			g.printf("o.%s = rbytes.%s(nil, int(o.%s))\n", se.Name(), rsize, n)
   734  			g.printf("r.%s(o.%s)\n", rfunc, se.Name())
   735  		default:
   736  			panic("not implemented")
   737  		}
   738  
   739  	case *StreamerBasicType:
   740  		switch se.ArrayLen() {
   741  		case 0:
   742  			switch se.Type() {
   743  			case rmeta.Bool:
   744  				g.printf("o.%s = r.ReadBool()\n", se.Name())
   745  
   746  			case rmeta.Counter:
   747  				switch se.Size() {
   748  				case 4:
   749  					g.printf("o.%s = r.ReadI32()\n", se.Name())
   750  				case 8:
   751  					g.printf("o.%s = r.ReadI64()\n", se.Name())
   752  				default:
   753  					panic(fmt.Errorf("invalid counter size %d for %s.%s", se.Size(), si.Name(), se.Name()))
   754  				}
   755  
   756  			case rmeta.Bits:
   757  				g.printf("o.%s = r.ReadI32()\n", se.Name())
   758  
   759  			case rmeta.Int8:
   760  				g.printf("o.%s = r.ReadI8()\n", se.Name())
   761  			case rmeta.Int16:
   762  				g.printf("o.%s = r.ReadI16()\n", se.Name())
   763  			case rmeta.Int32:
   764  				g.printf("o.%s = r.ReadI32()\n", se.Name())
   765  			case rmeta.Int64, rmeta.Long64:
   766  				g.printf("o.%s = r.ReadI64()\n", se.Name())
   767  
   768  			case rmeta.Uint8:
   769  				g.printf("o.%s = r.ReadU8()\n", se.Name())
   770  			case rmeta.Uint16:
   771  				g.printf("o.%s = r.ReadU16()\n", se.Name())
   772  			case rmeta.Uint32:
   773  				g.printf("o.%s = r.ReadU32()\n", se.Name())
   774  			case rmeta.Uint64, rmeta.ULong64:
   775  				g.printf("o.%s = r.ReadU64()\n", se.Name())
   776  
   777  			case rmeta.Float32:
   778  				g.printf("o.%s = r.ReadF32()\n", se.Name())
   779  			case rmeta.Float64:
   780  				g.printf("o.%s = r.ReadF64()\n", se.Name())
   781  
   782  			case rmeta.Float16:
   783  				g.printf("o.%s = root.Float16(r.ReadF32()) // FIXME(sbinet)\n", se.Name()) // FIXME(sbinet): handle compression,factor
   784  			case rmeta.Double32:
   785  				g.printf("o.%s = root.Double32(r.ReadF32()) // FIXME(sbinet)\n", se.Name()) // FIXME(sbinet): handle compression,factor
   786  
   787  			default:
   788  				panic(fmt.Errorf("invalid basic type %v (%d) for %s.%s", se.Type(), se.Type(), si.Name(), se.Name()))
   789  			}
   790  		default:
   791  			rfunc := ""
   792  			switch se.Type() {
   793  			case rmeta.OffsetL + rmeta.Bool:
   794  				rfunc = "ReadArrayBool"
   795  			case rmeta.OffsetL + rmeta.Int8:
   796  				rfunc = "ReadArrayI8"
   797  			case rmeta.OffsetL + rmeta.Int16:
   798  				rfunc = "ReadArrayI16"
   799  			case rmeta.OffsetL + rmeta.Int32:
   800  				rfunc = "ReadArrayI32"
   801  			case rmeta.OffsetL + rmeta.Int64, rmeta.OffsetL + rmeta.Long64:
   802  				rfunc = "ReadArrayI64"
   803  			case rmeta.OffsetL + rmeta.Uint8:
   804  				rfunc = "ReadArrayU8"
   805  			case rmeta.OffsetL + rmeta.Uint16:
   806  				rfunc = "ReadArrayU16"
   807  			case rmeta.OffsetL + rmeta.Uint32:
   808  				rfunc = "ReadArrayU32"
   809  			case rmeta.OffsetL + rmeta.Uint64, rmeta.OffsetL + rmeta.ULong64:
   810  				rfunc = "ReadArrayU64"
   811  			case rmeta.OffsetL + rmeta.Float32:
   812  				rfunc = "ReadArrayF32"
   813  			case rmeta.OffsetL + rmeta.Float64:
   814  				rfunc = "ReadArrayF64"
   815  			default:
   816  				panic(fmt.Errorf("invalid array element type: %v", se.Type()))
   817  			}
   818  			g.printf("r.%s(o.%s[:])\n", rfunc, se.Name())
   819  		}
   820  
   821  	case *StreamerLoop:
   822  		// FIXME(sbinet): implement. handle mbr-wise
   823  		g.printf("panic(\"o.%s: not implemented (TStreamerLoop)\")\n", se.Name())
   824  
   825  	case *StreamerObject:
   826  		// FIXME(sbinet): check semantics
   827  		switch se.ArrayLen() {
   828  		case 0:
   829  			g.printf("r.ReadObject(&o.%s) // obj\n", se.Name())
   830  		default:
   831  			g.printf("for i := range o.%s {\n", se.Name())
   832  			g.printf("r.ReadObject(&o.%s[i]) // obj\n", se.Name())
   833  			g.printf("}\n")
   834  		}
   835  
   836  	case *StreamerObjectAny:
   837  		// FIXME(sbinet): check semantics
   838  		switch se.ArrayLen() {
   839  		case 0:
   840  			g.printf("r.ReadObject(&o.%s) // obj-any\n", se.Name())
   841  		default:
   842  			g.printf("for i := range o.%s {\n", se.Name())
   843  			g.printf("r.ReadObject(&o.%s[i]) // obj-any\n", se.Name())
   844  			g.printf("}\n")
   845  		}
   846  
   847  	case *StreamerObjectAnyPointer:
   848  		// FIXME(sbinet): check semantics
   849  		g.printf("{\n")
   850  		g.printf("o.%s = nil\n", se.Name())
   851  		g.printf("if oo := r.ReadObjectAny(); oo != nil {  // obj-any-ptr\n")
   852  		g.printf("o.%s = oo.(%s)\n", se.Name(), g.typename(se))
   853  		g.printf("}\n}\n")
   854  
   855  	case *StreamerObjectPointer:
   856  		// FIXME(sbinet): check semantics
   857  		g.printf("{\n")
   858  		g.printf("o.%s = nil\n", se.Name())
   859  		g.printf("if oo := r.ReadObjectAny(); oo != nil {  // obj-ptr\n")
   860  		g.printf("o.%s = oo.(%s)\n", se.Name(), g.typename(se))
   861  		g.printf("}\n}\n")
   862  
   863  	case *StreamerString:
   864  		g.printf("o.%s = r.ReadString()\n", se.Name())
   865  
   866  	case *StreamerSTLstring:
   867  		g.printf("o.%s = r.ReadStdString()\n", se.Name())
   868  
   869  	case *StreamerSTL:
   870  		switch se.STLType() {
   871  		case rmeta.STLvector, rmeta.STLend:
   872  			rfunc := ""
   873  			switch se.ContainedType() {
   874  			case rmeta.Bool:
   875  				rfunc = "ReadStdVectorBool"
   876  			case rmeta.Int8:
   877  				rfunc = "ReadStdVectorI8"
   878  			case rmeta.Int16:
   879  				rfunc = "ReadStdVectorI16"
   880  			case rmeta.Int32:
   881  				rfunc = "ReadStdVectorI32"
   882  			case rmeta.Int64, rmeta.Long64:
   883  				rfunc = "ReadStdVectorI64"
   884  			case rmeta.Uint8:
   885  				rfunc = "ReadStdVectorU8"
   886  			case rmeta.Uint16:
   887  				rfunc = "ReadStdVectorU16"
   888  			case rmeta.Uint32:
   889  				rfunc = "ReadStdVectorU32"
   890  			case rmeta.Uint64, rmeta.ULong64:
   891  				rfunc = "ReadStdVectorU64"
   892  			case rmeta.Float32:
   893  				rfunc = "ReadStdVectorF32"
   894  			case rmeta.Float64:
   895  				rfunc = "ReadStdVectorF64"
   896  			case rmeta.Object:
   897  				etn := se.ElemTypeName()
   898  				switch etn[0] {
   899  				case "string":
   900  					rfunc = "ReadStdVectorStrs"
   901  				default:
   902  					panic(fmt.Errorf("invalid stl-vector element type: %v", se.ContainedType()))
   903  				}
   904  			default:
   905  				panic(fmt.Errorf("invalid stl-vector element type: %v", se.ContainedType()))
   906  			}
   907  			g.printf("r.%s(&o.%s)\n", rfunc, se.Name())
   908  
   909  		default:
   910  			panic(fmt.Errorf("STL-type not implemented %#v", se))
   911  		}
   912  
   913  	default:
   914  		g.printf("// %s -- %T\n", se.Name(), se)
   915  	}
   916  }
   917  
   918  func (g *genGoType) genStreamerInfo(si rbytes.StreamerInfo) {
   919  	g.printf(`func init() {
   920  		// Streamer for %[1]s.
   921  		%[4]sStreamerInfos.Add(%[4]sNewCxxStreamerInfo(%[1]q, %[2]d, 0x%[3]x, []rbytes.StreamerElement{
   922  `,
   923  		si.Name(), si.ClassVersion(), si.CheckSum(),
   924  		g.rdict,
   925  	)
   926  
   927  	for i, se := range si.Elements() {
   928  		g.genStreamerType(si, i, se)
   929  	}
   930  
   931  	g.printf("}))\n}\n\n")
   932  }
   933  
   934  func (g *genGoType) genStreamerType(si rbytes.StreamerInfo, i int, se rbytes.StreamerElement) {
   935  	maxidx := func(v [5]int32) string {
   936  		return fmt.Sprintf("[5]int32{%d, %d, %d, %d, %d}", v[0], v[1], v[2], v[3], v[4])
   937  	}
   938  
   939  	g.imps["go-hep.org/x/hep/groot/rbase"] = 1
   940  	if g.rdict != "" {
   941  		g.imps["go-hep.org/x/hep/groot/rdict"] = 1
   942  	}
   943  	g.imps["go-hep.org/x/hep/groot/rmeta"] = 1
   944  
   945  	switch se := se.(type) {
   946  	case *StreamerBase:
   947  		g.printf(`%[13]sNewStreamerBase(%[13]sElement{
   948  			Name:   *rbase.NewNamed(%[1]q, %[2]q),
   949  			Type:   rmeta.Base,
   950  			Size:   %[3]d,
   951  			ArrLen: %[4]d,
   952  			ArrDim: %[5]d,
   953  			MaxIdx: %[6]s,
   954  			Offset: %[7]d,
   955  			EName:  %[8]q,
   956  			XMin:   %[9]f,
   957  			XMax:   %[10]f,
   958  			Factor: %[11]f,
   959  		}.New(), %[12]d),
   960  		`,
   961  			se.Name(), se.Title(),
   962  			se.esize,
   963  			se.arrlen,
   964  			se.arrdim,
   965  			maxidx(se.maxidx),
   966  			se.offset,
   967  			se.ename,
   968  			se.xmin, se.xmax, se.factor,
   969  			se.vbase,
   970  			g.rdict,
   971  		)
   972  
   973  	case *StreamerBasicType:
   974  		g.printf(`&%[13]sStreamerBasicType{StreamerElement: %[13]sElement{
   975  			Name:   *rbase.NewNamed(%[1]q, %[2]q),
   976  			Type:   rmeta.%[3]v,
   977  			Size:   %[4]d,
   978  			ArrLen: %[5]d,
   979  			ArrDim: %[6]d,
   980  			MaxIdx: %[7]s,
   981  			Offset: %[8]d,
   982  			EName:  %[9]q,
   983  			XMin:   %[10]f,
   984  			XMax:   %[11]f,
   985  			Factor: %[12]f,
   986  		}.New()},
   987  		`,
   988  			se.Name(), se.Title(),
   989  			se.etype,
   990  			se.esize,
   991  			se.arrlen,
   992  			se.arrdim,
   993  			maxidx(se.maxidx),
   994  			se.offset,
   995  			se.ename,
   996  			se.xmin, se.xmax, se.factor,
   997  			g.rdict,
   998  		)
   999  
  1000  	case *StreamerBasicPointer:
  1001  		g.printf(`%[16]sNewStreamerBasicPointer(%[16]sElement{
  1002  			Name:   *rbase.NewNamed(%[1]q, %[2]q),
  1003  			Type:   %[3]d,
  1004  			Size:   %[4]d,
  1005  			ArrLen: %[5]d,
  1006  			ArrDim: %[6]d,
  1007  			MaxIdx: %[7]s,
  1008  			Offset: %[8]d,
  1009  			EName:  %[9]q,
  1010  			XMin:   %[10]f,
  1011  			XMax:   %[11]f,
  1012  			Factor: %[12]f,
  1013  		}.New(), %[13]d, %[14]q, %[15]q),
  1014  		`,
  1015  			se.Name(), se.Title(),
  1016  			se.etype,
  1017  			se.esize,
  1018  			se.arrlen,
  1019  			se.arrdim,
  1020  			maxidx(se.maxidx),
  1021  			se.offset,
  1022  			se.ename,
  1023  			se.xmin, se.xmax, se.factor,
  1024  			se.cvers, se.cname, se.ccls,
  1025  			g.rdict,
  1026  		)
  1027  
  1028  	case *StreamerLoop:
  1029  		g.printf(`%[15]sNewStreamerLoop(%[15]sElement{
  1030  			Name:   *rbase.NewNamed(%[1]q, %[2]q),
  1031  			Type:   rmeta.StreamLoop,
  1032  			Size:   %[3]d,
  1033  			ArrLen: %[4]d,
  1034  			ArrDim: %[5]d,
  1035  			MaxIdx: %[6]s,
  1036  			Offset: %[7]d,
  1037  			EName:  %[8]q,
  1038  			XMin:   %[9]f,
  1039  			XMax:   %[10]f,
  1040  			Factor: %[11]f,
  1041  		}.New(), %[12]d, %[13]q, %[14]q),
  1042  		`,
  1043  			se.Name(), se.Title(),
  1044  			se.esize,
  1045  			se.arrlen,
  1046  			se.arrdim,
  1047  			maxidx(se.maxidx),
  1048  			se.offset,
  1049  			se.ename,
  1050  			se.xmin, se.xmax, se.factor,
  1051  			se.cvers, se.cname, se.cclass,
  1052  			g.rdict,
  1053  		)
  1054  
  1055  	case *StreamerObject:
  1056  		g.printf(`&%[13]sStreamerObject{StreamerElement: %[13]sElement{
  1057  			Name:   *rbase.NewNamed(%[1]q, %[2]q),
  1058  			Type:   rmeta.%[3]v,
  1059  			Size:   %[4]d,
  1060  			ArrLen: %[5]d,
  1061  			ArrDim: %[6]d,
  1062  			MaxIdx: %[7]s,
  1063  			Offset: %[8]d,
  1064  			EName:  %[9]q,
  1065  			XMin:   %[10]f,
  1066  			XMax:   %[11]f,
  1067  			Factor: %[12]f,
  1068  		}.New()},
  1069  		`,
  1070  			se.Name(), se.Title(),
  1071  			se.etype,
  1072  			se.esize,
  1073  			se.arrlen,
  1074  			se.arrdim,
  1075  			maxidx(se.maxidx),
  1076  			se.offset,
  1077  			se.ename,
  1078  			se.xmin, se.xmax, se.factor,
  1079  			g.rdict,
  1080  		)
  1081  
  1082  	case *StreamerObjectPointer:
  1083  		g.printf(`&%[13]sStreamerObjectPointer{StreamerElement: %[13]sElement{
  1084  			Name:   *rbase.NewNamed(%[1]q, %[2]q),
  1085  			Type:   rmeta.%[3]v,
  1086  			Size:   %[4]d,
  1087  			ArrLen: %[5]d,
  1088  			ArrDim: %[6]d,
  1089  			MaxIdx: %[7]s,
  1090  			Offset: %[8]d,
  1091  			EName:  %[9]q,
  1092  			XMin:   %[10]f,
  1093  			XMax:   %[11]f,
  1094  			Factor: %[12]f,
  1095  		}.New()},
  1096  		`,
  1097  			se.Name(), se.Title(),
  1098  			se.etype,
  1099  			se.esize,
  1100  			se.arrlen,
  1101  			se.arrdim,
  1102  			maxidx(se.maxidx),
  1103  			se.offset,
  1104  			se.ename,
  1105  			se.xmin, se.xmax, se.factor,
  1106  			g.rdict,
  1107  		)
  1108  
  1109  	case *StreamerObjectAny:
  1110  		g.printf(`&%[13]sStreamerObjectAny{StreamerElement: %[13]sElement{
  1111  			Name:   *rbase.NewNamed(%[1]q, %[2]q),
  1112  			Type:   rmeta.%[3]v,
  1113  			Size:   %[4]d,
  1114  			ArrLen: %[5]d,
  1115  			ArrDim: %[6]d,
  1116  			MaxIdx: %[7]s,
  1117  			Offset: %[8]d,
  1118  			EName:  %[9]q,
  1119  			XMin:   %[10]f,
  1120  			XMax:   %[11]f,
  1121  			Factor: %[12]f,
  1122  		}.New()},
  1123  		`,
  1124  			se.Name(), se.Title(),
  1125  			se.etype,
  1126  			se.esize,
  1127  			se.arrlen,
  1128  			se.arrdim,
  1129  			maxidx(se.maxidx),
  1130  			se.offset,
  1131  			se.ename,
  1132  			se.xmin, se.xmax, se.factor,
  1133  			g.rdict,
  1134  		)
  1135  
  1136  	case *StreamerObjectAnyPointer:
  1137  		g.printf(`&%[13]sStreamerObjectAnyPointer{StreamerElement: %[13]sElement{
  1138  			Name:   *rbase.NewNamed(%[1]q, %[2]q),
  1139  			Type:   rmeta.%[3]v,
  1140  			Size:   %[4]d,
  1141  			ArrLen: %[5]d,
  1142  			ArrDim: %[6]d,
  1143  			MaxIdx: %[7]s,
  1144  			Offset: %[8]d,
  1145  			EName:  %[9]q,
  1146  			XMin:   %[10]f,
  1147  			XMax:   %[11]f,
  1148  			Factor: %[12]f,
  1149  		}.New()},
  1150  		`,
  1151  			se.Name(), se.Title(),
  1152  			se.etype,
  1153  			se.esize,
  1154  			se.arrlen,
  1155  			se.arrdim,
  1156  			maxidx(se.maxidx),
  1157  			se.offset,
  1158  			se.ename,
  1159  			se.xmin, se.xmax, se.factor,
  1160  			g.rdict,
  1161  		)
  1162  
  1163  	case *StreamerString:
  1164  		g.printf(`&%[13]sStreamerString{StreamerElement: %[13]sElement{
  1165  			Name:   *rbase.NewNamed(%[1]q, %[2]q),
  1166  			Type:   rmeta.%[3]v,
  1167  			Size:   %[4]d,
  1168  			ArrLen: %[5]d,
  1169  			ArrDim: %[6]d,
  1170  			MaxIdx: %[7]s,
  1171  			Offset: %[8]d,
  1172  			EName:  %[9]q,
  1173  			XMin:   %[10]f,
  1174  			XMax:   %[11]f,
  1175  			Factor: %[12]f,
  1176  		}.New()},
  1177  		`,
  1178  			se.Name(), se.Title(),
  1179  			se.etype,
  1180  			se.esize,
  1181  			se.arrlen,
  1182  			se.arrdim,
  1183  			maxidx(se.maxidx),
  1184  			se.offset,
  1185  			se.ename,
  1186  			se.xmin, se.xmax, se.factor,
  1187  			g.rdict,
  1188  		)
  1189  
  1190  	case *StreamerSTL:
  1191  		g.printf(`%[15]sNewCxxStreamerSTL(%[15]sElement{
  1192  			Name:   *rbase.NewNamed(%[1]q, %[2]q),
  1193  			Type:   rmeta.%[3]v,
  1194  			Size:   %[4]d,
  1195  			ArrLen: %[5]d,
  1196  			ArrDim: %[6]d,
  1197  			MaxIdx: %[7]s,
  1198  			Offset: %[8]d,
  1199  			EName:  %[9]q,
  1200  			XMin:   %[10]f,
  1201  			XMax:   %[11]f,
  1202  			Factor: %[12]f,
  1203  		}.New(), %[13]d, %[14]d),
  1204  		`,
  1205  			se.Name(), se.Title(),
  1206  			se.etype,
  1207  			se.esize,
  1208  			se.arrlen,
  1209  			se.arrdim,
  1210  			maxidx(se.maxidx),
  1211  			se.offset,
  1212  			se.ename,
  1213  			se.xmin, se.xmax, se.factor,
  1214  			se.vtype, se.ctype,
  1215  			g.rdict,
  1216  		)
  1217  
  1218  	case *StreamerSTLstring:
  1219  		g.printf(`&%[15]sStreamerSTLstring{*%[15]sNewCxxStreamerSTL(%[15]sElement{
  1220  			Name:   *rbase.NewNamed(%[1]q, %[2]q),
  1221  			Type:   rmeta.%[3]v,
  1222  			Size:   %[4]d,
  1223  			ArrLen: %[5]d,
  1224  			ArrDim: %[6]d,
  1225  			MaxIdx: %[7]s,
  1226  			Offset: %[8]d,
  1227  			EName:  %[9]q,
  1228  			XMin:   %[10]f,
  1229  			XMax:   %[11]f,
  1230  			Factor: %[12]f,
  1231  		}.New(), %[13]d, %[14]d)},
  1232  		`,
  1233  			se.Name(), se.Title(),
  1234  			se.etype,
  1235  			se.esize,
  1236  			se.arrlen,
  1237  			se.arrdim,
  1238  			maxidx(se.maxidx),
  1239  			se.offset,
  1240  			se.ename,
  1241  			se.xmin, se.xmax, se.factor,
  1242  			se.vtype, se.ctype,
  1243  			g.rdict,
  1244  		)
  1245  
  1246  	case *StreamerArtificial:
  1247  		g.printf(`&%[13]sStreamerArtificial{StreamerElement: %[13]sElement{
  1248  			Name:   *rbase.NewNamed(%[1]q, %[2]q),
  1249  			Type:   rmeta.%[3]v,
  1250  			Size:   %[4]d,
  1251  			ArrLen: %[5]d,
  1252  			ArrDim: %[6]d,
  1253  			MaxIdx: %[7]s,
  1254  			Offset: %[8]d,
  1255  			EName:  %[9]q,
  1256  			XMin:   %[10]f,
  1257  			XMax:   %[11]f,
  1258  			Factor: %[12]f,
  1259  		}.New()},
  1260  		`,
  1261  			se.Name(), se.Title(),
  1262  			se.etype,
  1263  			se.esize,
  1264  			se.arrlen,
  1265  			se.arrdim,
  1266  			maxidx(se.maxidx),
  1267  			se.offset,
  1268  			se.ename,
  1269  			se.xmin, se.xmax, se.factor,
  1270  			g.rdict,
  1271  		)
  1272  
  1273  	default:
  1274  		g.printf("// %s -- %T\n", se.Name(), se)
  1275  		panic(fmt.Errorf("rdict: unknown streamer type %T (%#v)", se, se))
  1276  	}
  1277  }
  1278  
  1279  func (g *genGoType) printf(format string, args ...any) {
  1280  	fmt.Fprintf(g.buf, format, args...)
  1281  }
  1282  
  1283  // Generate implements rdict.Generator
  1284  func (g *genGoType) Format() ([]byte, error) {
  1285  	buf := new(bytes.Buffer)
  1286  
  1287  	buf.WriteString(fmt.Sprintf(`// DO NOT EDIT; automatically generated by %[1]s
  1288  
  1289  package %[2]s
  1290  
  1291  import (
  1292  `,
  1293  		"root-gen-type",
  1294  		g.pkg,
  1295  	))
  1296  
  1297  	var (
  1298  		stdlib []string
  1299  		imps   []string
  1300  	)
  1301  
  1302  	for k := range g.imps {
  1303  		switch {
  1304  		case !strings.Contains(k, "."): // stdlib
  1305  			stdlib = append(stdlib, k)
  1306  		default:
  1307  			imps = append(imps, k)
  1308  		}
  1309  	}
  1310  
  1311  	sort.Strings(stdlib)
  1312  	for _, pkg := range stdlib {
  1313  		fmt.Fprintf(buf, "%q\n", pkg)
  1314  	}
  1315  	fmt.Fprintf(buf, "\n")
  1316  
  1317  	sort.Strings(imps)
  1318  	for _, pkg := range imps {
  1319  		fmt.Fprintf(buf, "%q\n", pkg)
  1320  	}
  1321  	fmt.Fprintf(buf, ")\n\n")
  1322  
  1323  	buf.Write(g.buf.Bytes())
  1324  
  1325  	src, err := format.Source(buf.Bytes())
  1326  	if err != nil {
  1327  		log.Printf("=== error ===\n%s\n", buf.Bytes())
  1328  	}
  1329  	return src, err
  1330  }
  1331  
  1332  var (
  1333  	_ Generator = (*genGoType)(nil)
  1334  )