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

     1  // Copyright ©2018 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  	"fmt"
     9  	"reflect"
    10  	"strings"
    11  
    12  	"go-hep.org/x/hep/groot/rbase"
    13  	"go-hep.org/x/hep/groot/rbytes"
    14  	"go-hep.org/x/hep/groot/rcont"
    15  	"go-hep.org/x/hep/groot/rmeta"
    16  	"go-hep.org/x/hep/groot/root"
    17  	"go-hep.org/x/hep/groot/rvers"
    18  )
    19  
    20  // StreamerOf generates a StreamerInfo from a reflect.Type.
    21  //
    22  // StreamerOf panics if the provided type contains non-ROOT compatible types
    23  // such as chan, int, uint or func.
    24  func StreamerOf(ctx rbytes.StreamerInfoContext, typ reflect.Type) rbytes.StreamerInfo {
    25  	if isTObject(typ) {
    26  		name := reflect.New(typ).Elem().Interface().(root.Object).Class()
    27  		si, err := ctx.StreamerInfo(name, -1)
    28  		if err == nil {
    29  			return si
    30  		}
    31  	}
    32  
    33  	bldr := newStreamerBuilder(ctx, typ)
    34  	return bldr.genStreamer(typ)
    35  }
    36  
    37  type streamerStore interface {
    38  	rbytes.StreamerInfoContext
    39  	addStreamer(si rbytes.StreamerInfo)
    40  }
    41  
    42  type streamerBuilder struct {
    43  	ctx streamerStore
    44  	typ reflect.Type
    45  }
    46  
    47  func newStreamerBuilder(ctx rbytes.StreamerInfoContext, typ reflect.Type) *streamerBuilder {
    48  	return &streamerBuilder{ctx: newStreamerStore(ctx), typ: typ}
    49  }
    50  
    51  func (bld *streamerBuilder) genStreamer(typ reflect.Type) rbytes.StreamerInfo {
    52  	name := typenameOf(typ)
    53  	si := &StreamerInfo{
    54  		named:  *rbase.NewNamed(name, name),
    55  		objarr: rcont.NewObjArray(),
    56  		clsver: 1,
    57  	}
    58  	switch typ.Kind() {
    59  	case reflect.Struct:
    60  		si.elems = make([]rbytes.StreamerElement, 0, typ.NumField())
    61  		for i := range typ.NumField() {
    62  			ft := typ.Field(i)
    63  			si.elems = append(si.elems, bld.genField(typ, ft))
    64  		}
    65  	case reflect.Slice:
    66  		si.clsver = rvers.StreamerBaseSTL
    67  		si.elems = []rbytes.StreamerElement{
    68  			bld.genStdVectorOf(typ.Elem(), "This", 0),
    69  		}
    70  	}
    71  	return si
    72  }
    73  
    74  func (bld *streamerBuilder) genStdVectorOf(typ reflect.Type, name string, offset int32) rbytes.StreamerElement {
    75  	const esize = 3 * diskPtrSize
    76  	var (
    77  		ename = ""
    78  		etype rmeta.Enum
    79  	)
    80  	switch typ.Kind() {
    81  	case reflect.Bool:
    82  		ename = "vector<bool>"
    83  		etype = rmeta.Bool
    84  	case reflect.Int8:
    85  		ename = "vector<int8_t>"
    86  		etype = rmeta.Int8
    87  	case reflect.Int16:
    88  		ename = "vector<int16_t>"
    89  		etype = rmeta.Int16
    90  	case reflect.Int32:
    91  		ename = "vector<int32_t>"
    92  		etype = rmeta.Int32
    93  	case reflect.Int64:
    94  		ename = "vector<int64_t>"
    95  		etype = rmeta.Int64
    96  	case reflect.Uint8:
    97  		ename = "vector<uint8_t>"
    98  		etype = rmeta.Uint8
    99  	case reflect.Uint16:
   100  		ename = "vector<uint16_t>"
   101  		etype = rmeta.Uint16
   102  	case reflect.Uint32:
   103  		ename = "vector<uint32_t>"
   104  		etype = rmeta.Uint32
   105  	case reflect.Uint64:
   106  		ename = "vector<uint64_t>"
   107  		etype = rmeta.Uint64
   108  	case reflect.Float32:
   109  		switch typ {
   110  		case reflect.TypeOf(root.Float16(0)):
   111  			ename = "vector<Float16_t>"
   112  			etype = rmeta.Float16
   113  		default:
   114  			ename = "vector<float>"
   115  			etype = rmeta.Float32
   116  		}
   117  	case reflect.Float64:
   118  		switch typ {
   119  		case reflect.TypeOf(root.Double32(0)):
   120  			ename = "vector<Double32_t>"
   121  			etype = rmeta.Double32
   122  		default:
   123  			ename = "vector<double>"
   124  			etype = rmeta.Float64
   125  		}
   126  	case reflect.String:
   127  		ename = "vector<string>"
   128  		etype = rmeta.STLstring
   129  	case reflect.Struct:
   130  		ename = fmt.Sprintf("vector<%s>", typenameOf(typ))
   131  		etype = rmeta.Any
   132  		if isTObject(typ) || isTObject(reflect.PointerTo(typ)) {
   133  			etype = rmeta.Object
   134  		}
   135  	case reflect.Slice:
   136  		ename = typenameOf(typ)
   137  		if strings.HasSuffix(ename, ">") {
   138  			ename += " "
   139  		}
   140  		ename = fmt.Sprintf("vector<%s>", ename)
   141  		etype = rmeta.Any
   142  	default:
   143  		panic(fmt.Errorf("rdict: invalid slice type %v", typ))
   144  	}
   145  
   146  	return NewCxxStreamerSTL(
   147  		StreamerElement{
   148  			named:  *rbase.NewNamed(name, ""),
   149  			etype:  rmeta.Streamer,
   150  			esize:  esize,
   151  			offset: offset,
   152  			ename:  ename,
   153  		}, rmeta.STLvector, etype,
   154  	)
   155  }
   156  
   157  func (bld *streamerBuilder) genPtr(typ reflect.Type, name string, offset int32) rbytes.StreamerElement {
   158  	// FIXME(sbinet): is typ always a struct?
   159  	//	switch typ.Kind() {
   160  	//	case reflect.Struct:
   161  	//	default:
   162  	//		panic(fmt.Errorf("rdict: invalid ptr-to type %v", typ))
   163  	//	}
   164  
   165  	ptr := reflect.PointerTo(typ)
   166  	se := StreamerElement{
   167  		named:  *rbase.NewNamed(name, ""),
   168  		etype:  rmeta.AnyP,
   169  		esize:  int32(ptrSize),
   170  		offset: offset,
   171  		ename:  typenameOf(ptr),
   172  	}
   173  
   174  	if isTObject(ptr) {
   175  		se.etype = rmeta.ObjectP
   176  		return &StreamerObjectPointer{se}
   177  	}
   178  
   179  	return &StreamerObjectAnyPointer{se}
   180  }
   181  
   182  func (bld *streamerBuilder) genArrayOf(n int, typ reflect.Type, name string, offset int32) rbytes.StreamerElement {
   183  	var (
   184  		arrlen = int32(n)
   185  		dims   = []int32{arrlen}
   186  		maxidx [5]int32
   187  		esize  = arrlen
   188  		etype  rmeta.Enum
   189  		ename  = ""
   190  	)
   191  
   192  	for typ.Kind() == reflect.Array && len(dims) < 5 {
   193  		dim := int32(typ.Len())
   194  		dims = append(dims, dim)
   195  		typ = typ.Elem()
   196  		esize *= dim
   197  	}
   198  	copy(maxidx[:], dims)
   199  	arrdim := int32(len(dims))
   200  
   201  	switch typ.Kind() {
   202  	case reflect.Bool:
   203  		esize *= 1
   204  		ename = "bool"
   205  		etype = rmeta.Bool
   206  
   207  	case reflect.Int8:
   208  		esize *= 1
   209  		ename = "int8_t"
   210  		etype = rmeta.Int8
   211  
   212  	case reflect.Int16:
   213  		esize *= 2
   214  		ename = "int16_t"
   215  		etype = rmeta.Int16
   216  
   217  	case reflect.Int32:
   218  		esize *= 4
   219  		ename = "int32_t"
   220  		etype = rmeta.Int32
   221  
   222  	case reflect.Int64:
   223  		esize *= 8
   224  		ename = "int64_t"
   225  		etype = rmeta.Int64
   226  
   227  	case reflect.Uint8:
   228  		esize *= 1
   229  		ename = "uint8_t"
   230  		etype = rmeta.Uint8
   231  
   232  	case reflect.Uint16:
   233  		esize *= 2
   234  		ename = "uint16_t"
   235  		etype = rmeta.Uint16
   236  
   237  	case reflect.Uint32:
   238  		esize *= 4
   239  		ename = "uint32_t"
   240  		etype = rmeta.Uint32
   241  
   242  	case reflect.Uint64:
   243  		esize *= 8
   244  		ename = "uint64_t"
   245  		etype = rmeta.Uint64
   246  
   247  	case reflect.Float32:
   248  		switch typ {
   249  		case reflect.TypeOf(root.Float16(0)):
   250  			esize *= 4
   251  			ename = "Float16_t"
   252  			etype = rmeta.Float16
   253  		default:
   254  			esize *= 4
   255  			ename = "float"
   256  			etype = rmeta.Float32
   257  		}
   258  
   259  	case reflect.Float64:
   260  		switch typ {
   261  		case reflect.TypeOf(root.Double32(0)):
   262  			esize *= 8
   263  			ename = "Double32_t"
   264  			etype = rmeta.Double32
   265  		default:
   266  			esize *= 8
   267  			ename = "double"
   268  			etype = rmeta.Float64
   269  		}
   270  
   271  	case reflect.String:
   272  		return &StreamerString{
   273  			StreamerElement{
   274  				named:  *rbase.NewNamed(name, ""),
   275  				etype:  rmeta.OffsetL + rmeta.TString,
   276  				esize:  esize * sizeOfTString,
   277  				arrlen: arrlen,
   278  				arrdim: arrdim,
   279  				maxidx: maxidx,
   280  				offset: offset,
   281  				ename:  "TString",
   282  			},
   283  		}
   284  	case reflect.Struct:
   285  		if isTObject(typ) || isTObject(reflect.PointerTo(typ)) {
   286  			return &StreamerObject{
   287  				StreamerElement{
   288  					named:  *rbase.NewNamed(name, ""),
   289  					etype:  rmeta.OffsetL + rmeta.Object,
   290  					esize:  esize * bld.sizeOf(typ),
   291  					arrlen: arrlen,
   292  					arrdim: arrdim,
   293  					maxidx: maxidx,
   294  					offset: offset,
   295  					ename:  typenameOf(typ),
   296  				},
   297  			}
   298  		}
   299  		return &StreamerObjectAny{
   300  			StreamerElement{
   301  				named:  *rbase.NewNamed(name, ""),
   302  				etype:  rmeta.OffsetL + rmeta.Any,
   303  				esize:  esize * bld.sizeOf(typ),
   304  				arrlen: arrlen,
   305  				arrdim: arrdim,
   306  				maxidx: maxidx,
   307  				offset: offset,
   308  				ename:  typenameOf(typ),
   309  			},
   310  		}
   311  	default:
   312  		panic(fmt.Errorf("rdict: invalid array element type %v", typ))
   313  	}
   314  
   315  	return &StreamerBasicType{
   316  		StreamerElement{
   317  			named:  *rbase.NewNamed(name, ""),
   318  			etype:  rmeta.OffsetL + etype,
   319  			esize:  esize,
   320  			offset: offset,
   321  			arrlen: arrlen,
   322  			arrdim: arrdim,
   323  			maxidx: maxidx,
   324  			ename:  ename,
   325  		},
   326  	}
   327  }
   328  
   329  func (bld *streamerBuilder) genVarLenArrayOf(typ reflect.Type, class, count, name string, offset int32) rbytes.StreamerElement {
   330  	var (
   331  		esize = 0
   332  		ename = ""
   333  		etype rmeta.Enum
   334  	)
   335  	switch typ.Kind() {
   336  	case reflect.Bool:
   337  		esize = 1
   338  		ename = "bool"
   339  		etype = rmeta.Bool
   340  	case reflect.Int8:
   341  		esize = 1
   342  		ename = "int8_t"
   343  		etype = rmeta.Int8
   344  	case reflect.Int16:
   345  		esize = 2
   346  		ename = "int16_t"
   347  		etype = rmeta.Int16
   348  	case reflect.Int32:
   349  		esize = 4
   350  		ename = "int32_t"
   351  		etype = rmeta.Int32
   352  	case reflect.Int64:
   353  		esize = 8
   354  		ename = "int64_t"
   355  		etype = rmeta.Int64
   356  	case reflect.Uint8:
   357  		esize = 1
   358  		ename = "uint8_t"
   359  		etype = rmeta.Uint8
   360  	case reflect.Uint16:
   361  		esize = 2
   362  		ename = "uint16_t"
   363  		etype = rmeta.Uint16
   364  	case reflect.Uint32:
   365  		esize = 4
   366  		ename = "uint32_t"
   367  		etype = rmeta.Uint32
   368  	case reflect.Uint64:
   369  		esize = 8
   370  		ename = "uint64_t"
   371  		etype = rmeta.Uint64
   372  	case reflect.Float32:
   373  		esize = 4
   374  		switch typ {
   375  		case reflect.TypeOf(root.Float16(0)):
   376  			ename = "Float16_t"
   377  			etype = rmeta.Float16
   378  		default:
   379  			ename = "float"
   380  			etype = rmeta.Float32
   381  		}
   382  	case reflect.Float64:
   383  		esize = 8
   384  		switch typ {
   385  		case reflect.TypeOf(root.Double32(0)):
   386  			ename = "Double32_t"
   387  			etype = rmeta.Double32
   388  		default:
   389  			ename = "double"
   390  			etype = rmeta.Float64
   391  		}
   392  	case reflect.String:
   393  		return NewStreamerLoop(
   394  			StreamerElement{
   395  				named:  *rbase.NewNamed(name, "["+count+"]"),
   396  				esize:  4,
   397  				offset: offset,
   398  				ename:  "TString*",
   399  			},
   400  			1, count, class,
   401  		)
   402  	case reflect.Struct:
   403  		ename = typenameOf(typ)
   404  		return NewStreamerLoop(
   405  			StreamerElement{
   406  				named:  *rbase.NewNamed(name, "["+count+"]"),
   407  				esize:  diskPtrSize,
   408  				offset: offset,
   409  				ename:  ename + "*",
   410  			},
   411  			1, count, class,
   412  		)
   413  	default:
   414  		panic(fmt.Errorf("rdict: invalid c-var-len-array type %v", typ))
   415  	}
   416  
   417  	return NewStreamerBasicPointer(
   418  		StreamerElement{
   419  			named:  *rbase.NewNamed(name, "["+count+"]"),
   420  			etype:  rmeta.OffsetP + etype,
   421  			esize:  int32(esize),
   422  			offset: offset,
   423  			ename:  ename + "*",
   424  		}, 1, count, class,
   425  	)
   426  }
   427  
   428  func (bld *streamerBuilder) genField(typ reflect.Type, field reflect.StructField) rbytes.StreamerElement {
   429  
   430  	offset := offsetOf(field)
   431  
   432  	switch field.Type.Kind() {
   433  	case reflect.Bool:
   434  		return &StreamerBasicType{
   435  			StreamerElement{
   436  				named:  *rbase.NewNamed(nameOf(field), ""),
   437  				etype:  rmeta.GoType2ROOTEnum[field.Type],
   438  				esize:  1,
   439  				offset: offset,
   440  				ename:  "bool",
   441  			},
   442  		}
   443  	case reflect.Int8:
   444  		return &StreamerBasicType{
   445  			StreamerElement{
   446  				named:  *rbase.NewNamed(nameOf(field), ""),
   447  				etype:  rmeta.GoType2ROOTEnum[field.Type],
   448  				esize:  1,
   449  				offset: offset,
   450  				ename:  "int8_t",
   451  			},
   452  		}
   453  	case reflect.Int16:
   454  		return &StreamerBasicType{
   455  			StreamerElement{
   456  				named:  *rbase.NewNamed(nameOf(field), ""),
   457  				etype:  rmeta.GoType2ROOTEnum[field.Type],
   458  				esize:  2,
   459  				offset: offset,
   460  				ename:  "int16_t",
   461  			},
   462  		}
   463  	case reflect.Int32:
   464  		return &StreamerBasicType{
   465  			StreamerElement{
   466  				named:  *rbase.NewNamed(nameOf(field), ""),
   467  				etype:  rmeta.GoType2ROOTEnum[field.Type],
   468  				esize:  4,
   469  				offset: offset,
   470  				ename:  "int32_t",
   471  			},
   472  		}
   473  	case reflect.Int64:
   474  		return &StreamerBasicType{
   475  			StreamerElement{
   476  				named:  *rbase.NewNamed(nameOf(field), ""),
   477  				etype:  rmeta.GoType2ROOTEnum[field.Type],
   478  				esize:  8,
   479  				offset: offset,
   480  				ename:  "int64_t",
   481  			},
   482  		}
   483  	case reflect.Uint8:
   484  		return &StreamerBasicType{
   485  			StreamerElement{
   486  				named:  *rbase.NewNamed(nameOf(field), ""),
   487  				etype:  rmeta.GoType2ROOTEnum[field.Type],
   488  				esize:  1,
   489  				offset: offset,
   490  				ename:  "uint8_t",
   491  			},
   492  		}
   493  	case reflect.Uint16:
   494  		return &StreamerBasicType{
   495  			StreamerElement{
   496  				named:  *rbase.NewNamed(nameOf(field), ""),
   497  				etype:  rmeta.GoType2ROOTEnum[field.Type],
   498  				esize:  2,
   499  				offset: offset,
   500  				ename:  "uint16_t",
   501  			},
   502  		}
   503  	case reflect.Uint32:
   504  		return &StreamerBasicType{
   505  			StreamerElement{
   506  				named:  *rbase.NewNamed(nameOf(field), ""),
   507  				etype:  rmeta.GoType2ROOTEnum[field.Type],
   508  				esize:  4,
   509  				offset: offset,
   510  				ename:  "uint32_t",
   511  			},
   512  		}
   513  	case reflect.Uint64:
   514  		return &StreamerBasicType{
   515  			StreamerElement{
   516  				named:  *rbase.NewNamed(nameOf(field), ""),
   517  				etype:  rmeta.GoType2ROOTEnum[field.Type],
   518  				esize:  8,
   519  				offset: offset,
   520  				ename:  "uint64_t",
   521  			},
   522  		}
   523  	case reflect.Float32:
   524  		switch field.Type {
   525  		case reflect.TypeOf(root.Float16(0)):
   526  			return &StreamerBasicType{
   527  				StreamerElement{
   528  					named:  *rbase.NewNamed(nameOf(field), ""),
   529  					etype:  rmeta.Float16,
   530  					esize:  4,
   531  					offset: offset,
   532  					ename:  "Float16_t",
   533  				},
   534  			}
   535  		default:
   536  			return &StreamerBasicType{
   537  				StreamerElement{
   538  					named:  *rbase.NewNamed(nameOf(field), ""),
   539  					etype:  rmeta.GoType2ROOTEnum[field.Type],
   540  					esize:  4,
   541  					offset: offset,
   542  					ename:  "float",
   543  				},
   544  			}
   545  		}
   546  	case reflect.Float64:
   547  		switch field.Type {
   548  		case reflect.TypeOf(root.Double32(0)):
   549  			return &StreamerBasicType{
   550  				StreamerElement{
   551  					named:  *rbase.NewNamed(nameOf(field), ""),
   552  					etype:  rmeta.Double32,
   553  					esize:  8,
   554  					offset: offset,
   555  					ename:  "Double32_t",
   556  				},
   557  			}
   558  		default:
   559  			return &StreamerBasicType{
   560  				StreamerElement{
   561  					named:  *rbase.NewNamed(nameOf(field), ""),
   562  					etype:  rmeta.GoType2ROOTEnum[field.Type],
   563  					esize:  8,
   564  					offset: offset,
   565  					ename:  "double",
   566  				},
   567  			}
   568  		}
   569  	case reflect.String:
   570  		return &StreamerSTLstring{
   571  			StreamerSTL: StreamerSTL{
   572  				StreamerElement: StreamerElement{
   573  					named:  *rbase.NewNamed(nameOf(field), ""),
   574  					etype:  rmeta.Streamer,
   575  					esize:  sizeOfStdString,
   576  					offset: offset,
   577  					ename:  "string",
   578  				},
   579  			},
   580  		}
   581  	case reflect.Struct:
   582  		return &StreamerObjectAny{
   583  			StreamerElement{
   584  				named:  *rbase.NewNamed(nameOf(field), ""),
   585  				etype:  rmeta.Any,
   586  				esize:  bld.sizeOf(field.Type),
   587  				offset: offset,
   588  				ename:  typenameOf(field.Type),
   589  			},
   590  		}
   591  
   592  	case reflect.Array:
   593  		var (
   594  			et   = field.Type.Elem()
   595  			n    = field.Type.Len()
   596  			name = nameOf(field)
   597  		)
   598  		return bld.genArrayOf(n, et, name, offsetOf(field))
   599  
   600  	case reflect.Slice:
   601  		et := field.Type.Elem()
   602  		count, ok := hasCount(field)
   603  		if ok {
   604  			class := typenameOf(typ)
   605  			return bld.genVarLenArrayOf(et, class, count, nameOf(field), offsetOf(field))
   606  		}
   607  		return bld.genStdVectorOf(et, nameOf(field), offsetOf(field))
   608  
   609  	case reflect.Ptr:
   610  		et := field.Type.Elem()
   611  		return bld.genPtr(et, nameOf(field), offsetOf(field))
   612  
   613  	default:
   614  		panic(fmt.Errorf(
   615  			"rdict: invalid struct field (name=%v, type=%v, kind=%v)",
   616  			field.Name, field.Type, field.Type.Kind(),
   617  		))
   618  	}
   619  }
   620  
   621  type streamerStoreImpl struct {
   622  	ctx rbytes.StreamerInfoContext
   623  	db  map[string]rbytes.StreamerInfo
   624  }
   625  
   626  func newStreamerStore(ctx rbytes.StreamerInfoContext) streamerStore {
   627  	if ctx, ok := ctx.(streamerStore); ok {
   628  		return ctx
   629  	}
   630  
   631  	return &streamerStoreImpl{
   632  		ctx: ctx,
   633  		db:  make(map[string]rbytes.StreamerInfo),
   634  	}
   635  }
   636  
   637  // StreamerInfo returns the named StreamerInfo.
   638  // If version is negative, the latest version should be returned.
   639  func (store *streamerStoreImpl) StreamerInfo(name string, version int) (rbytes.StreamerInfo, error) {
   640  	return store.ctx.StreamerInfo(name, version)
   641  }
   642  
   643  func (store *streamerStoreImpl) addStreamer(si rbytes.StreamerInfo) {
   644  	store.db[si.Name()] = si
   645  }
   646  
   647  func nameOf(field reflect.StructField) string {
   648  	tag, ok := field.Tag.Lookup("groot")
   649  	if ok {
   650  		i := strings.Index(tag, "[")
   651  		if i < 0 {
   652  			return tag
   653  		}
   654  		return tag[:i]
   655  	}
   656  	return field.Name
   657  }
   658  
   659  func hasCount(field reflect.StructField) (string, bool) {
   660  	tag, ok := field.Tag.Lookup("groot")
   661  	if !ok || !strings.Contains(tag, "[") {
   662  		return "", false
   663  	}
   664  	var (
   665  		count = new(strings.Builder)
   666  		brack bool
   667  	)
   668  	for _, v := range tag {
   669  		switch v {
   670  		case '[':
   671  			brack = true
   672  		case ']':
   673  			name := strings.TrimSpace(count.String())
   674  			if !isIdent(name) {
   675  				return "", false
   676  			}
   677  			return name, true
   678  		default:
   679  			if brack {
   680  				_, _ = count.WriteString(string(v))
   681  			}
   682  		}
   683  	}
   684  	return "", false
   685  }
   686  
   687  func isIdent(name string) bool {
   688  	if len(name) == 0 {
   689  		return false
   690  	}
   691  
   692  	ok := func(c rune) bool {
   693  		return 'A' <= c && c <= 'Z' ||
   694  			'a' <= c && c <= 'z' ||
   695  			'0' <= c && c <= '9' ||
   696  			c == '_'
   697  	}
   698  
   699  	for i, c := range name {
   700  		if i == 0 && ('0' <= c && c <= '9') {
   701  			return false
   702  		}
   703  		if !ok(c) {
   704  			return false
   705  		}
   706  	}
   707  	return true
   708  }
   709  
   710  func offsetOf(field reflect.StructField) int32 {
   711  	// return int32(field.Offset)
   712  	// FIXME(sbinet): it seems ROOT expects 0 here...
   713  	return 0
   714  }
   715  
   716  func (bld *streamerBuilder) sizeOf(typ reflect.Type) int32 {
   717  	// FIXME(sbinet): compute ROOT-compatible size.
   718  	if ptr := reflect.PointerTo(typ); isTObject(ptr) || isTObject(typ) {
   719  		name := typenameOf(typ)
   720  		switch name {
   721  		case "TObjString":
   722  			return sizeOfTObjString
   723  		}
   724  	}
   725  	return int32(typ.Size())
   726  }
   727  
   728  func isTObject(typ reflect.Type) bool {
   729  	return typ.Implements(rootObjectIface)
   730  }
   731  
   732  func typenameOf(typ reflect.Type) string {
   733  	if isTObject(typ) {
   734  		switch typ.Kind() {
   735  		case reflect.Ptr:
   736  			name := reflect.New(typ.Elem()).Interface().(root.Object).Class()
   737  			return name + "*"
   738  		default:
   739  			name := reflect.New(typ).Elem().Interface().(root.Object).Class()
   740  			return name
   741  		}
   742  	}
   743  	if ptr := reflect.PointerTo(typ); isTObject(ptr) {
   744  		name := reflect.New(typ).Interface().(root.Object).Class()
   745  		return name
   746  	}
   747  
   748  	switch typ.Kind() {
   749  	case reflect.Slice:
   750  		ename := typenameOf(typ.Elem())
   751  		if strings.HasSuffix(ename, ">") {
   752  			ename += " "
   753  		}
   754  		return "vector<" + ename + ">"
   755  	case reflect.Array:
   756  		var (
   757  			dims []int
   758  			et   = typ
   759  		)
   760  		for range 10 {
   761  			dims = append(dims, et.Len())
   762  			et = et.Elem()
   763  			if et.Kind() != reflect.Array {
   764  				break
   765  			}
   766  
   767  		}
   768  		o := new(strings.Builder)
   769  		ename := typenameOf(et)
   770  		_, _ = o.WriteString(ename)
   771  		for _, v := range dims {
   772  			fmt.Fprintf(o, "[%d]", v)
   773  		}
   774  		return o.String()
   775  	case reflect.Bool:
   776  		return "bool"
   777  	case reflect.Int8:
   778  		return "int8_t"
   779  	case reflect.Int16:
   780  		return "int16_t"
   781  	case reflect.Int32:
   782  		return "int32_t"
   783  	case reflect.Int64:
   784  		return "int64_t"
   785  	case reflect.Uint8:
   786  		return "uint8_t"
   787  	case reflect.Uint16:
   788  		return "uint16_t"
   789  	case reflect.Uint32:
   790  		return "uint32_t"
   791  	case reflect.Uint64:
   792  		return "uint64_t"
   793  	case reflect.Float32:
   794  		switch typ {
   795  		case reflect.TypeOf(root.Float16(0)):
   796  			return "Float16_t"
   797  		default:
   798  			return "float"
   799  		}
   800  	case reflect.Float64:
   801  		switch typ {
   802  		case reflect.TypeOf(root.Double32(0)):
   803  			return "Double32_t"
   804  		default:
   805  			return "double"
   806  		}
   807  	case reflect.String:
   808  		return "string"
   809  	case reflect.Ptr:
   810  		return typenameOf(typ.Elem()) + "*"
   811  
   812  	default:
   813  		name := typ.Name()
   814  		if name == "" {
   815  			panic(fmt.Errorf("rdict: invalid reflect type %v", typ))
   816  		}
   817  		return name
   818  	}
   819  }
   820  
   821  const (
   822  	diskPtrSize      = 8
   823  	sizeOfTObjString = 40
   824  	sizeOfTString    = 3 * diskPtrSize
   825  	sizeOfStdString  = 4 * diskPtrSize
   826  )
   827  
   828  var (
   829  	rootObjectIface = reflect.TypeOf((*root.Object)(nil)).Elem()
   830  )
   831  
   832  var (
   833  	_ streamerStore              = (*streamerStoreImpl)(nil)
   834  	_ rbytes.StreamerInfoContext = (*streamerStoreImpl)(nil)
   835  )