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

     1  // Copyright 2020 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  	"strconv"
    11  	"strings"
    12  
    13  	"go-hep.org/x/hep/groot/rbase"
    14  	"go-hep.org/x/hep/groot/rbytes"
    15  	"go-hep.org/x/hep/groot/rmeta"
    16  	"go-hep.org/x/hep/groot/root"
    17  	"go-hep.org/x/hep/groot/rtypes"
    18  	"go-hep.org/x/hep/groot/rvers"
    19  )
    20  
    21  // WStreamerOf returns a write-streamer for the i-th element of the provided
    22  // streamer info and stream kind.
    23  func WStreamerOf(sinfo rbytes.StreamerInfo, i int, kind rbytes.StreamKind) (rbytes.WStreamer, error) {
    24  	si, ok := sinfo.(*StreamerInfo)
    25  	if !ok {
    26  		return nil, fmt.Errorf("rdict: not a rdict.StreamerInfo (got=%T)", sinfo)
    27  	}
    28  
    29  	err := si.BuildStreamers()
    30  	if err != nil {
    31  		return nil, fmt.Errorf("rdict: could not build streamers: %w", err)
    32  	}
    33  
    34  	switch kind {
    35  	case rbytes.ObjectWise:
    36  		return newWStreamer(i, si, kind, si.woops)
    37  	case rbytes.MemberWise:
    38  		return newWStreamer(i, si, kind, si.wmops)
    39  	default:
    40  		return nil, fmt.Errorf("rdict: invalid stream kind %v", kind)
    41  	}
    42  }
    43  
    44  type wstreamerElem struct {
    45  	recv any
    46  	wop  *wstreamer
    47  	i    int // streamer-element index (or -1 for the whole StreamerInfo)
    48  	kind rbytes.StreamKind
    49  	si   *StreamerInfo
    50  	se   rbytes.StreamerElement
    51  }
    52  
    53  func newWStreamer(i int, si *StreamerInfo, kind rbytes.StreamKind, wops []wstreamer) (*wstreamerElem, error) {
    54  	return &wstreamerElem{
    55  		recv: nil,
    56  		wop:  &wops[i],
    57  		i:    i,
    58  		kind: kind,
    59  		si:   si,
    60  		se:   si.elems[i],
    61  	}, nil
    62  }
    63  
    64  func (ww *wstreamerElem) Bind(recv any) error {
    65  	rv := reflect.ValueOf(recv)
    66  	if rv.Kind() != reflect.Ptr {
    67  		return fmt.Errorf("rdict: invalid kind (got=%T, want=pointer)", recv)
    68  	}
    69  	ww.recv = recv
    70  	ww.wop.cfg.offset = -1 // binding directly to 'recv'. assume no offset is to be applied
    71  	return nil
    72  }
    73  
    74  func (ww *wstreamerElem) WStreamROOT(w *rbytes.WBuffer) error {
    75  	_, err := ww.wop.wstream(w, ww.recv)
    76  	if err != nil {
    77  		var (
    78  			name  = ww.si.Name()
    79  			ename = ww.se.TypeName()
    80  		)
    81  		return fmt.Errorf("rdict: could not write element %d (type=%q) from %q: %w",
    82  			ww.i, ename, name, err,
    83  		)
    84  	}
    85  
    86  	return nil
    87  }
    88  
    89  var (
    90  	_ rbytes.WStreamer = (*wstreamerElem)(nil)
    91  	_ rbytes.Binder    = (*wstreamerElem)(nil)
    92  )
    93  
    94  type wstreamOp interface {
    95  	wstream(w *rbytes.WBuffer, recv any) (int, error)
    96  }
    97  
    98  // type wstreamBufOp interface {
    99  // 	wstreamBuf(w *rbytes.WBuffer, recv reflect.Value, descr *elemDescr, beg, end int, n int, offset int, arrmode arrayMode) (int, error)
   100  // }
   101  
   102  type wopFunc func(w *rbytes.WBuffer, recv any, cfg *streamerConfig) (int, error)
   103  
   104  type wstreamer struct {
   105  	op  wopFunc
   106  	cfg *streamerConfig
   107  }
   108  
   109  func (ww wstreamer) wstream(w *rbytes.WBuffer, recv any) (int, error) {
   110  	return ww.op(w, recv, ww.cfg)
   111  }
   112  
   113  var (
   114  	_ wstreamOp = (*wstreamer)(nil)
   115  )
   116  
   117  func (si *StreamerInfo) makeWOp(sictx rbytes.StreamerInfoContext, i int, descr elemDescr) wstreamer {
   118  	cfg := &streamerConfig{si, i, &descr, descr.offset, 0, nil}
   119  	switch descr.otype {
   120  	case rmeta.Base:
   121  		var (
   122  			se       = descr.elem.(*StreamerBase)
   123  			typename = se.Name()
   124  			typevers = se.vbase
   125  			wop, _   = wopFrom(sictx, typename, int16(typevers), 0, nil)
   126  		)
   127  		return wstreamer{wop, cfg}
   128  
   129  	case rmeta.Bool:
   130  		return wstreamer{wstreamBool, cfg}
   131  	case rmeta.Char:
   132  		return wstreamer{wstreamI8, cfg}
   133  	case rmeta.Short:
   134  		return wstreamer{wstreamI16, cfg}
   135  	case rmeta.Int:
   136  		return wstreamer{wstreamI32, cfg}
   137  	case rmeta.Long, rmeta.Long64:
   138  		return wstreamer{wstreamI64, cfg}
   139  	case rmeta.UChar:
   140  		return wstreamer{wstreamU8, cfg}
   141  	case rmeta.UShort:
   142  		return wstreamer{wstreamU16, cfg}
   143  	case rmeta.UInt:
   144  		return wstreamer{wstreamU32, cfg}
   145  	case rmeta.ULong, rmeta.ULong64:
   146  		return wstreamer{wstreamU64, cfg}
   147  	case rmeta.Float32:
   148  		return wstreamer{wstreamF32, cfg}
   149  	case rmeta.Float64:
   150  		return wstreamer{wstreamF64, cfg}
   151  	case rmeta.Bits:
   152  		return wstreamer{wstreamBits, cfg}
   153  	case rmeta.Float16:
   154  		return wstreamer{wstreamF16(descr.elem), cfg}
   155  	case rmeta.Double32:
   156  		return wstreamer{wstreamD32(descr.elem), cfg}
   157  
   158  	case rmeta.Counter:
   159  		se := descr.elem.(*StreamerBasicType)
   160  		switch se.esize {
   161  		case 4:
   162  			return wstreamer{wstreamI32, cfg}
   163  		case 8:
   164  			return wstreamer{wstreamI64, cfg}
   165  		default:
   166  			panic(fmt.Errorf("rdict: invalid counter size (%d) in %#v", se.esize, se))
   167  		}
   168  
   169  	case rmeta.CharStar:
   170  		return wstreamer{wstreamTString, cfg}
   171  
   172  	case rmeta.TNamed:
   173  		return wstreamer{wstreamTNamed, cfg}
   174  	case rmeta.TObject:
   175  		return wstreamer{wstreamTObject, cfg}
   176  	case rmeta.TString, rmeta.STLstring:
   177  		return wstreamer{wstreamTString, cfg}
   178  
   179  	case rmeta.STL:
   180  		var (
   181  			se       = descr.elem
   182  			newClass = descr.nclass
   183  			oldClass = descr.oclass
   184  			// _, isSTLbase = se.(*StreamerBase) // FIXME(sbinet)
   185  		)
   186  
   187  		switch {
   188  		case se.ArrayLen() <= 1:
   189  			switch {
   190  			case newClass != oldClass:
   191  				panic("rdict: rmeta.STL (w/ old-class != new-class) not implemented")
   192  			default:
   193  				switch se := se.(type) {
   194  				default:
   195  					panic(fmt.Errorf("rdict: invalid streamer element: %#v", se))
   196  
   197  				case *StreamerSTLstring:
   198  					return wstreamer{
   199  						wstreamType("string", wstreamStdString),
   200  						cfg,
   201  					}
   202  
   203  				case *StreamerSTL:
   204  					switch se.STLType() {
   205  					case rmeta.STLvector, rmeta.STLlist, rmeta.STLdeque, rmeta.STLend:
   206  						var (
   207  							ct       = se.ContainedType()
   208  							typename = se.TypeName()
   209  							enames   = rmeta.CxxTemplateFrom(typename).Args
   210  							wop, _   = wopFrom(sictx, enames[0], -1, ct, &descr)
   211  						)
   212  						return wstreamer{
   213  							wstreamType(typename, wstreamStdSlice(typename, wop)),
   214  							cfg,
   215  						}
   216  
   217  					case rmeta.STLset, rmeta.STLmultiset, rmeta.STLunorderedset, rmeta.STLunorderedmultiset:
   218  						var (
   219  							ct       = se.ContainedType()
   220  							typename = se.TypeName()
   221  							enames   = rmeta.CxxTemplateFrom(typename).Args
   222  							wop, _   = wopFrom(sictx, enames[0], -1, ct, &descr)
   223  						)
   224  						return wstreamer{
   225  							wstreamType(typename, wstreamStdSet(typename, wop)),
   226  							cfg,
   227  						}
   228  
   229  					case rmeta.STLmap, rmeta.STLmultimap, rmeta.STLunorderedmap, rmeta.STLunorderedmultimap:
   230  						var (
   231  							ct     = se.ContainedType()
   232  							enames = rmeta.CxxTemplateFrom(se.TypeName()).Args
   233  							kname  = enames[0]
   234  							vname  = enames[1]
   235  						)
   236  
   237  						kwop, kvers := wopFrom(sictx, kname, -1, ct, &descr)
   238  						vwop, vvers := wopFrom(sictx, vname, -1, ct, &descr)
   239  						return wstreamer{
   240  							wstreamStdMap(
   241  								kname, vname,
   242  								kwop, vwop,
   243  								kvers, vvers,
   244  							),
   245  							cfg,
   246  						}
   247  
   248  					case rmeta.STLbitset:
   249  						var (
   250  							typename = se.TypeName()
   251  							enames   = rmeta.CxxTemplateFrom(typename).Args
   252  							n, err   = strconv.Atoi(enames[0])
   253  						)
   254  
   255  						if err != nil {
   256  							panic(fmt.Errorf("rdict: invalid STL bitset argument (type=%q): %+v", typename, err))
   257  						}
   258  						return wstreamer{
   259  							wstreamType(typename, wstreamStdBitset(typename, n)),
   260  							cfg,
   261  						}
   262  
   263  					default:
   264  						panic(fmt.Errorf("rdict: STL container type=%v not handled", se.STLType()))
   265  					}
   266  				}
   267  			}
   268  		default:
   269  			panic("rdict: rmeta.STL (w/ array-len > 1) not implemented")
   270  			//			switch {
   271  			//			case newClass != oldClass:
   272  			//				panic("not implemented")
   273  			//			default:
   274  			//				return wstreamer{
   275  			//					wstreamSTL(wstreamSTLArrayMbrWise, wstreamSTLObjWise, descr.oclass),
   276  			//					&wtreamerConfig{si, i, &descr, descr.offset, se.ArrayLen()},
   277  			//				}
   278  			//			}
   279  		}
   280  
   281  	// FIXME(sbinet): add rmeta.Conv handling.
   282  
   283  	// fixed-size arrays of basic types: [32]int
   284  
   285  	case rmeta.OffsetL + rmeta.Bool:
   286  		cfg.length = descr.elem.ArrayLen()
   287  		return wstreamer{wstreamBasicArray(cfg.length, wstreamBool), cfg}
   288  
   289  	case rmeta.OffsetL + rmeta.Char:
   290  		cfg.length = descr.elem.ArrayLen()
   291  		return wstreamer{wstreamBasicArray(cfg.length, wstreamI8), cfg}
   292  
   293  	case rmeta.OffsetL + rmeta.Short:
   294  		cfg.length = descr.elem.ArrayLen()
   295  		return wstreamer{wstreamBasicArray(cfg.length, wstreamI16), cfg}
   296  
   297  	case rmeta.OffsetL + rmeta.Int:
   298  		cfg.length = descr.elem.ArrayLen()
   299  		return wstreamer{wstreamBasicArray(cfg.length, wstreamI32), cfg}
   300  
   301  	case rmeta.OffsetL + rmeta.Long, rmeta.OffsetL + rmeta.Long64:
   302  		cfg.length = descr.elem.ArrayLen()
   303  		return wstreamer{wstreamBasicArray(cfg.length, wstreamI64), cfg}
   304  
   305  	case rmeta.OffsetL + rmeta.UChar:
   306  		cfg.length = descr.elem.ArrayLen()
   307  		return wstreamer{wstreamBasicArray(cfg.length, wstreamU8), cfg}
   308  
   309  	case rmeta.OffsetL + rmeta.UShort:
   310  		cfg.length = descr.elem.ArrayLen()
   311  		return wstreamer{wstreamBasicArray(cfg.length, wstreamU16), cfg}
   312  
   313  	case rmeta.OffsetL + rmeta.UInt:
   314  		cfg.length = descr.elem.ArrayLen()
   315  		return wstreamer{wstreamBasicArray(cfg.length, wstreamU32), cfg}
   316  
   317  	case rmeta.OffsetL + rmeta.ULong, rmeta.OffsetL + rmeta.ULong64:
   318  		cfg.length = descr.elem.ArrayLen()
   319  		return wstreamer{wstreamBasicArray(cfg.length, wstreamU64), cfg}
   320  
   321  	case rmeta.OffsetL + rmeta.Float32:
   322  		cfg.length = descr.elem.ArrayLen()
   323  		return wstreamer{wstreamBasicArray(cfg.length, wstreamF32), cfg}
   324  
   325  	case rmeta.OffsetL + rmeta.Float64:
   326  		cfg.length = descr.elem.ArrayLen()
   327  		return wstreamer{wstreamBasicArray(cfg.length, wstreamF64), cfg}
   328  
   329  	case rmeta.OffsetL + rmeta.Float16:
   330  		cfg.length = descr.elem.ArrayLen()
   331  		return wstreamer{
   332  			wstreamBasicArray(cfg.length, wstreamF16(descr.elem)), // FIXME(sbinet): ROOT uses wstreamCnv here.
   333  			cfg,
   334  		}
   335  
   336  	case rmeta.OffsetL + rmeta.Double32:
   337  		cfg.length = descr.elem.ArrayLen()
   338  		return wstreamer{
   339  			wstreamBasicArray(cfg.length, wstreamD32(descr.elem)), // FIXME(sbinet): ROOT uses wstreamCnv here.
   340  			cfg,
   341  		}
   342  
   343  	case rmeta.OffsetL + rmeta.CharStar:
   344  		cfg.length = descr.elem.ArrayLen()
   345  		return wstreamer{wstreamBasicArray(cfg.length, wstreamTString), cfg}
   346  
   347  	case rmeta.OffsetL + rmeta.TString:
   348  		cfg.length = descr.elem.ArrayLen()
   349  		return wstreamer{wstreamBasicArray(cfg.length, wstreamTString), cfg}
   350  
   351  	case rmeta.OffsetL + rmeta.TObject:
   352  		cfg.length = descr.elem.ArrayLen()
   353  		return wstreamer{wstreamBasicArray(cfg.length, wstreamTObject), cfg}
   354  
   355  	case rmeta.OffsetL + rmeta.TNamed:
   356  		cfg.length = descr.elem.ArrayLen()
   357  		return wstreamer{wstreamBasicArray(cfg.length, wstreamTNamed), cfg}
   358  
   359  	case rmeta.OffsetL + rmeta.Any,
   360  		rmeta.OffsetL + rmeta.Object:
   361  		var (
   362  			se       = descr.elem
   363  			typename = se.TypeName()
   364  			wop, _   = wopFrom(sictx, typename, -1, 0, nil)
   365  		)
   366  		cfg.length = se.ArrayLen()
   367  		return wstreamer{wstreamBasicArray(cfg.length, wop), cfg}
   368  
   369  	// var-size arrays of basic types: [n]int
   370  
   371  	case rmeta.OffsetP + rmeta.Bool:
   372  		return wstreamer{wstreamBools, cfg}
   373  
   374  	case rmeta.OffsetP + rmeta.Char:
   375  		return wstreamer{wstreamI8s, cfg}
   376  
   377  	case rmeta.OffsetP + rmeta.Short:
   378  		return wstreamer{wstreamI16s, cfg}
   379  
   380  	case rmeta.OffsetP + rmeta.Int:
   381  		return wstreamer{wstreamI32s, cfg}
   382  
   383  	case rmeta.OffsetP + rmeta.Long, rmeta.OffsetP + rmeta.Long64:
   384  		return wstreamer{wstreamI64s, cfg}
   385  
   386  	case rmeta.OffsetP + rmeta.UChar:
   387  		return wstreamer{wstreamU8s, cfg}
   388  
   389  	case rmeta.OffsetP + rmeta.UShort:
   390  		return wstreamer{wstreamU16s, cfg}
   391  
   392  	case rmeta.OffsetP + rmeta.UInt:
   393  		return wstreamer{wstreamU32s, cfg}
   394  
   395  	case rmeta.OffsetP + rmeta.ULong, rmeta.OffsetP + rmeta.ULong64:
   396  		return wstreamer{wstreamU64s, cfg}
   397  
   398  	case rmeta.OffsetP + rmeta.Float32:
   399  		return wstreamer{wstreamF32s, cfg}
   400  
   401  	case rmeta.OffsetP + rmeta.Float64:
   402  		return wstreamer{wstreamF64s, cfg}
   403  
   404  	case rmeta.OffsetP + rmeta.Float16:
   405  		return wstreamer{wstreamF16s, cfg}
   406  
   407  	case rmeta.OffsetP + rmeta.Double32:
   408  		return wstreamer{wstreamD32s, cfg}
   409  
   410  	case rmeta.OffsetP + rmeta.CharStar:
   411  		return wstreamer{wstreamStrs, cfg}
   412  
   413  	case rmeta.Streamer:
   414  		switch se := descr.elem.(type) {
   415  		default:
   416  			panic(fmt.Errorf("rdict: invalid streamer element: %#v", se))
   417  
   418  		case *StreamerSTLstring:
   419  			return wstreamer{
   420  				wstreamType("string", wstreamStdString),
   421  				cfg,
   422  			}
   423  
   424  		case *StreamerSTL:
   425  			switch se.STLType() {
   426  			case rmeta.STLvector, rmeta.STLlist, rmeta.STLdeque, rmeta.STLend:
   427  				var (
   428  					ct       = se.ContainedType()
   429  					typename = se.TypeName()
   430  					enames   = rmeta.CxxTemplateFrom(typename).Args
   431  					vname    = enames[0]
   432  					wop, _   = wopFrom(sictx, vname, -1, ct, &descr)
   433  				)
   434  				return wstreamer{
   435  					wstreamType(typename, wstreamStdSlice(typename, wop)),
   436  					cfg,
   437  				}
   438  
   439  			case rmeta.STLset, rmeta.STLmultiset, rmeta.STLunorderedset, rmeta.STLunorderedmultiset:
   440  				var (
   441  					ct       = se.ContainedType()
   442  					typename = se.TypeName()
   443  					enames   = rmeta.CxxTemplateFrom(typename).Args
   444  					vname    = enames[0]
   445  					wop, _   = wopFrom(sictx, vname, -1, ct, &descr)
   446  				)
   447  				return wstreamer{
   448  					wstreamType(typename, wstreamStdSet(typename, wop)),
   449  					cfg,
   450  				}
   451  
   452  			case rmeta.STLmap, rmeta.STLmultimap, rmeta.STLunorderedmap, rmeta.STLunorderedmultimap:
   453  				var (
   454  					ct     = se.ContainedType()
   455  					enames = rmeta.CxxTemplateFrom(se.TypeName()).Args
   456  					kname  = enames[0]
   457  					vname  = enames[1]
   458  				)
   459  
   460  				kwop, kvers := wopFrom(sictx, kname, -1, ct, &descr)
   461  				vwop, vvers := wopFrom(sictx, vname, -1, ct, &descr)
   462  				return wstreamer{
   463  					wstreamStdMap(
   464  						kname, vname,
   465  						kwop,
   466  						vwop,
   467  						kvers,
   468  						vvers,
   469  					),
   470  					cfg,
   471  				}
   472  
   473  			case rmeta.STLbitset:
   474  				var (
   475  					typename = se.TypeName()
   476  					enames   = rmeta.CxxTemplateFrom(typename).Args
   477  					n, err   = strconv.Atoi(enames[0])
   478  				)
   479  
   480  				if err != nil {
   481  					panic(fmt.Errorf("rdict: invalid STL bitset argument (type=%q): %+v", typename, err))
   482  				}
   483  				return wstreamer{
   484  					wstreamType(typename, wstreamStdBitset(typename, n)),
   485  					cfg,
   486  				}
   487  
   488  			default:
   489  				panic(fmt.Errorf("rdict: STL container type=%v not handled", se.STLType()))
   490  			}
   491  		}
   492  
   493  	case rmeta.Any, rmeta.Object:
   494  		var (
   495  			se       = descr.elem
   496  			typename = se.TypeName()
   497  			wop, _   = wopFrom(sictx, typename, -1, 0, nil)
   498  		)
   499  		return wstreamer{wop, cfg}
   500  
   501  	case rmeta.AnyP, rmeta.Anyp:
   502  		var (
   503  			se       = descr.elem
   504  			typename = strings.TrimRight(se.TypeName(), "*") // FIXME(sbinet): handle T** ?
   505  			wop, _   = wopFrom(sictx, typename, -1, 0, nil)
   506  		)
   507  		return wstreamer{
   508  			wstreamAnyPtr(wop),
   509  			cfg,
   510  		}
   511  
   512  	case rmeta.ObjectP, rmeta.Objectp:
   513  		var (
   514  			se       = descr.elem
   515  			typename = strings.TrimRight(se.TypeName(), "*") // FIXME(sbinet): handle T** ?
   516  			wop, _   = wopFrom(sictx, typename, -1, 0, nil)
   517  		)
   518  		return wstreamer{
   519  			wstreamObjPtr(wop),
   520  			cfg,
   521  		}
   522  
   523  	case rmeta.StreamLoop:
   524  		var (
   525  			se       = descr.elem.(*StreamerLoop)
   526  			typename = strings.TrimRight(se.TypeName(), "*") // FIXME(sbinet): handle T** ?
   527  			wop, _   = wopFrom(sictx, typename, -1, 0, nil)
   528  		)
   529  		return wstreamer{
   530  			wstreamBasicSlice(wop),
   531  			cfg,
   532  		}
   533  
   534  	default:
   535  		panic(fmt.Errorf("not implemented k=%d (%v)", descr.otype, descr.otype))
   536  		// return wstreamer{wstreamGeneric, &streamerConfig{si, i, &descr, descr.offset, 0}}
   537  	}
   538  }
   539  
   540  func wstreamSI(si *StreamerInfo) wopFunc {
   541  	typename := si.Name()
   542  	switch {
   543  	case typename == "TObject":
   544  		return wstreamTObject
   545  	case typename == "TNamed":
   546  		return wstreamTNamed
   547  	case typename == "TString":
   548  		return wstreamTString
   549  	case rtypes.Factory.HasKey(typename):
   550  		obj := rtypes.Factory.Get(typename)().Interface()
   551  		_, ok := obj.(rbytes.Marshaler)
   552  		if ok {
   553  			return func(w *rbytes.WBuffer, recv any, cfg *streamerConfig) (int, error) {
   554  				obj := cfg.adjust(recv).(rbytes.Marshaler)
   555  				return obj.MarshalROOT(w)
   556  			}
   557  		}
   558  	}
   559  	return wstreamCat(typename, int16(si.ClassVersion()), si.woops)
   560  }
   561  
   562  func wstreamObjPtr(wop wopFunc) wopFunc {
   563  	return func(w *rbytes.WBuffer, recv any, cfg *streamerConfig) (int, error) {
   564  		var (
   565  			pos = w.Pos()
   566  			rv  = reflect.ValueOf(cfg.adjust(recv)).Elem()
   567  			ptr root.Object
   568  		)
   569  		if !((rv == reflect.Value{}) || rv.IsNil()) {
   570  			ptr = rv.Interface().(root.Object)
   571  		}
   572  
   573  		w.WriteObjectAny(ptr)
   574  		return int(w.Pos() - pos), w.Err()
   575  	}
   576  }
   577  
   578  func wstreamAnyPtr(wop wopFunc) wopFunc {
   579  	return func(w *rbytes.WBuffer, recv any, cfg *streamerConfig) (int, error) {
   580  		var (
   581  			pos = w.Pos()
   582  			rv  = reflect.ValueOf(cfg.adjust(recv)).Elem()
   583  			ptr root.Object
   584  		)
   585  		if !((rv == reflect.Value{}) || rv.IsNil()) {
   586  			ptr = rv.Interface().(root.Object)
   587  		}
   588  
   589  		w.WriteObjectAny(ptr)
   590  		return int(w.Pos() - pos), w.Err()
   591  	}
   592  }
   593  
   594  func wstreamBool(w *rbytes.WBuffer, recv any, cfg *streamerConfig) (int, error) {
   595  	w.WriteBool(*cfg.adjust(recv).(*bool))
   596  	if err := w.Err(); err != nil {
   597  		return 0, err
   598  	}
   599  	return 1, nil
   600  }
   601  
   602  func wstreamU8(w *rbytes.WBuffer, recv any, cfg *streamerConfig) (int, error) {
   603  	w.WriteU8(*cfg.adjust(recv).(*uint8))
   604  	if err := w.Err(); err != nil {
   605  		return 0, err
   606  	}
   607  	return 1, nil
   608  }
   609  
   610  func wstreamU16(w *rbytes.WBuffer, recv any, cfg *streamerConfig) (int, error) {
   611  	w.WriteU16(*cfg.adjust(recv).(*uint16))
   612  	if err := w.Err(); err != nil {
   613  		return 0, err
   614  	}
   615  	return 2, nil
   616  }
   617  
   618  func wstreamU32(w *rbytes.WBuffer, recv any, cfg *streamerConfig) (int, error) {
   619  	w.WriteU32(*cfg.adjust(recv).(*uint32))
   620  	if err := w.Err(); err != nil {
   621  		return 0, err
   622  	}
   623  	return 4, nil
   624  }
   625  
   626  func wstreamU64(w *rbytes.WBuffer, recv any, cfg *streamerConfig) (int, error) {
   627  	w.WriteU64(*cfg.adjust(recv).(*uint64))
   628  	if err := w.Err(); err != nil {
   629  		return 0, err
   630  	}
   631  	return 8, nil
   632  }
   633  
   634  func wstreamI8(w *rbytes.WBuffer, recv any, cfg *streamerConfig) (int, error) {
   635  	w.WriteI8(*cfg.adjust(recv).(*int8))
   636  	if err := w.Err(); err != nil {
   637  		return 0, err
   638  	}
   639  	return 1, nil
   640  }
   641  
   642  func wstreamI16(w *rbytes.WBuffer, recv any, cfg *streamerConfig) (int, error) {
   643  	w.WriteI16(*cfg.adjust(recv).(*int16))
   644  	if err := w.Err(); err != nil {
   645  		return 0, err
   646  	}
   647  	return 2, nil
   648  }
   649  
   650  func wstreamI32(w *rbytes.WBuffer, recv any, cfg *streamerConfig) (int, error) {
   651  	w.WriteI32(*cfg.adjust(recv).(*int32))
   652  	if err := w.Err(); err != nil {
   653  		return 0, err
   654  	}
   655  	return 4, nil
   656  }
   657  
   658  func wstreamI64(w *rbytes.WBuffer, recv any, cfg *streamerConfig) (int, error) {
   659  	w.WriteI64(*cfg.adjust(recv).(*int64))
   660  	if err := w.Err(); err != nil {
   661  		return 0, err
   662  	}
   663  	return 8, nil
   664  }
   665  
   666  func wstreamF32(w *rbytes.WBuffer, recv any, cfg *streamerConfig) (int, error) {
   667  	w.WriteF32(*cfg.adjust(recv).(*float32))
   668  	if err := w.Err(); err != nil {
   669  		return 0, err
   670  	}
   671  	return 4, nil
   672  }
   673  
   674  func wstreamF64(w *rbytes.WBuffer, recv any, cfg *streamerConfig) (int, error) {
   675  	w.WriteF64(*cfg.adjust(recv).(*float64))
   676  	if err := w.Err(); err != nil {
   677  		return 0, err
   678  	}
   679  	return 8, nil
   680  }
   681  
   682  func wstreamBits(w *rbytes.WBuffer, recv any, cfg *streamerConfig) (int, error) {
   683  	// FIXME(sbinet) handle TObject reference
   684  	// if (bits&kIsReferenced) != 0 { ... }
   685  	w.WriteU32(*cfg.adjust(recv).(*uint32))
   686  	if err := w.Err(); err != nil {
   687  		return 0, err
   688  	}
   689  	return 4, nil
   690  }
   691  
   692  func wstreamF16(se rbytes.StreamerElement) wopFunc {
   693  	return func(w *rbytes.WBuffer, recv any, cfg *streamerConfig) (int, error) {
   694  		beg := w.Pos()
   695  		w.WriteF16(*cfg.adjust(recv).(*root.Float16), se)
   696  		if err := w.Err(); err != nil {
   697  			return 0, err
   698  		}
   699  		return int(w.Pos() - beg), w.Err()
   700  	}
   701  }
   702  
   703  func wstreamD32(se rbytes.StreamerElement) wopFunc {
   704  	return func(w *rbytes.WBuffer, recv any, cfg *streamerConfig) (int, error) {
   705  		beg := w.Pos()
   706  		w.WriteD32(*cfg.adjust(recv).(*root.Double32), se)
   707  		if err := w.Err(); err != nil {
   708  			return 0, err
   709  		}
   710  		return int(w.Pos() - beg), w.Err()
   711  	}
   712  }
   713  
   714  func wstreamTString(w *rbytes.WBuffer, recv any, cfg *streamerConfig) (int, error) {
   715  	beg := w.Pos()
   716  	w.WriteString(*cfg.adjust(recv).(*string))
   717  	return int(w.Pos() - beg), w.Err()
   718  }
   719  
   720  func wstreamTObject(w *rbytes.WBuffer, recv any, cfg *streamerConfig) (int, error) {
   721  	obj := cfg.adjust(recv).(*rbase.Object)
   722  	return obj.MarshalROOT(w)
   723  }
   724  
   725  func wstreamTNamed(w *rbytes.WBuffer, recv any, cfg *streamerConfig) (int, error) {
   726  	named := cfg.adjust(recv).(*rbase.Named)
   727  	return named.MarshalROOT(w)
   728  }
   729  
   730  func wstreamBasicArray(n int, arr wopFunc) wopFunc {
   731  	return func(w *rbytes.WBuffer, recv any, cfg *streamerConfig) (int, error) {
   732  		var (
   733  			nn = 0
   734  			rv = reflect.ValueOf(cfg.adjust(recv)).Elem()
   735  		)
   736  		for i := range n {
   737  			nb, err := arr(w, rv.Index(i).Addr().Interface(), nil)
   738  			if err != nil {
   739  				return 0, fmt.Errorf(
   740  					"rdict: could not wstream array element %s[%d] of %s: %w",
   741  					cfg.descr.elem.Name(), i, cfg.si.Name(), err,
   742  				)
   743  			}
   744  			nn += nb
   745  		}
   746  		return nn, nil
   747  	}
   748  }
   749  
   750  func wstreamBasicSlice(sli wopFunc) wopFunc {
   751  	return func(w *rbytes.WBuffer, recv any, cfg *streamerConfig) (int, error) {
   752  		w.WriteI8(1) // is-array
   753  		var (
   754  			nn = 1
   755  			n  = int(reflect.ValueOf(recv).Elem().FieldByIndex(cfg.descr.method).Int())
   756  			rv = reflect.ValueOf(cfg.adjust(recv)).Elem()
   757  		)
   758  		for i := range n {
   759  			nb, err := sli(w, rv.Index(i).Addr().Interface(), nil)
   760  			if err != nil {
   761  				return nn, fmt.Errorf(
   762  					"rdict: could not wstream slice element %s[%d] of %s: %w",
   763  					cfg.descr.elem.Name(), i, cfg.si.Name(), err,
   764  				)
   765  			}
   766  			nn += nb
   767  		}
   768  		return nn, nil
   769  	}
   770  }
   771  
   772  func wstreamHeader(w *rbytes.WBuffer, typename string, typevers int16) rbytes.Header {
   773  	if _, ok := rmeta.CxxBuiltins[typename]; ok && typename != "string" {
   774  		return rbytes.Header{Pos: -1}
   775  	}
   776  	if typename == "TString" {
   777  		return rbytes.Header{Pos: -1}
   778  	}
   779  	return w.WriteHeader(typename, typevers)
   780  }
   781  
   782  func wsetHeader(w *rbytes.WBuffer, hdr rbytes.Header) (int, error) {
   783  	if hdr.Pos < 0 {
   784  		return 0, nil
   785  	}
   786  	return w.SetHeader(hdr)
   787  }
   788  
   789  func wstreamType(typename string, wop wopFunc) wopFunc {
   790  	const typevers = rvers.StreamerBaseSTL
   791  	return func(w *rbytes.WBuffer, recv any, cfg *streamerConfig) (int, error) {
   792  		hdr := w.WriteHeader(typename, int16(typevers))
   793  		n, err := wop(w, recv, cfg)
   794  		if err != nil {
   795  			return n, err
   796  		}
   797  		return w.SetHeader(hdr)
   798  	}
   799  }
   800  
   801  func wstreamStdSlice(typename string, wop wopFunc) wopFunc {
   802  	return func(w *rbytes.WBuffer, recv any, cfg *streamerConfig) (int, error) {
   803  		var (
   804  			rv = reflect.ValueOf(cfg.adjust(recv)).Elem()
   805  			n  = rv.Len()
   806  			nn = 0
   807  		)
   808  		w.WriteI32(int32(n))
   809  		for i := range n {
   810  			nb, err := wop(w, rv.Index(i).Addr().Interface(), nil)
   811  			if err != nil {
   812  				return nn, fmt.Errorf(
   813  					"rdict: could not wstream element %s[%d] of %s: %w",
   814  					cfg.descr.elem.Name(), i, typename, err,
   815  				)
   816  			}
   817  			nn += nb
   818  		}
   819  		return nn, w.Err()
   820  	}
   821  }
   822  
   823  func wstreamStdSet(typename string, wop wopFunc) wopFunc {
   824  	// FIXME(sbinet): add special handling for std::set-like types
   825  	// the correct equivalent Go-type of std::set<T> is map[T]struct{}
   826  	// (or, when availaible, std.Set[T])
   827  	return wstreamStdSlice(typename, wop)
   828  }
   829  
   830  func wstreamStdMap(kname, vname string, kwop, vwop wopFunc, kvers, vvers int16) wopFunc {
   831  	typename := fmt.Sprintf("map<%s,%s>", kname, vname)
   832  	if strings.HasSuffix(vname, ">") {
   833  		typename = fmt.Sprintf("map<%s,%s >", kname, vname)
   834  	}
   835  	const typevers = rvers.StreamerBaseSTL
   836  	return func(w *rbytes.WBuffer, recv any, cfg *streamerConfig) (int, error) {
   837  		var (
   838  			rv = reflect.ValueOf(cfg.adjust(recv)).Elem()
   839  			n  = rv.Len()
   840  			nn = 0
   841  		)
   842  		hdr := w.WriteHeader(typename, int16(typevers))
   843  		w.WriteI32(int32(n))
   844  		keyT := reflect.SliceOf(rv.Type().Key())
   845  		valT := reflect.SliceOf(rv.Type().Elem())
   846  		keys := reflect.New(keyT).Elem()
   847  		vals := reflect.New(valT).Elem()
   848  		keys.Set(reflect.AppendSlice(keys, reflect.MakeSlice(keyT, n, n)))
   849  		vals.Set(reflect.AppendSlice(vals, reflect.MakeSlice(valT, n, n)))
   850  
   851  		iter := rv.MapRange()
   852  		for i := 0; iter.Next(); i++ {
   853  			key := iter.Key()
   854  			val := iter.Value()
   855  			keys.Index(i).Set(key)
   856  			vals.Index(i).Set(val)
   857  		}
   858  		if n > 0 {
   859  			hdr := wstreamHeader(w, kname, kvers)
   860  			for i := range n {
   861  				nb, err := kwop(w, keys.Index(i).Addr().Interface(), nil)
   862  				if err != nil {
   863  					return nn, fmt.Errorf(
   864  						"rdict: could not wstream key-element %s[%d] of %s: %w",
   865  						kname, i, cfg.si.Name(), err,
   866  					)
   867  				}
   868  				nn += nb
   869  			}
   870  			nb, err := wsetHeader(w, hdr)
   871  			if err != nil {
   872  				return nn, err
   873  			}
   874  			nn += nb
   875  		}
   876  
   877  		if n > 0 {
   878  			hdr := wstreamHeader(w, vname, vvers)
   879  			for i := range n {
   880  				nb, err := vwop(w, vals.Index(i).Addr().Interface(), nil)
   881  				if err != nil {
   882  					return nn, fmt.Errorf(
   883  						"rdict: could not rstream val-element %s[%d] of %s: %w",
   884  						vname, i, cfg.si.Name(), err,
   885  					)
   886  				}
   887  				nn += nb
   888  			}
   889  			_, err := wsetHeader(w, hdr)
   890  			if err != nil {
   891  				return nn, err
   892  			}
   893  		}
   894  
   895  		return w.SetHeader(hdr)
   896  	}
   897  }
   898  
   899  func wstreamStdBitset(typename string, n int) wopFunc {
   900  	return func(w *rbytes.WBuffer, recv any, cfg *streamerConfig) (int, error) {
   901  		sli := *cfg.adjust(recv).(*[]uint8)
   902  		sli = sli[:n]
   903  
   904  		w.WriteI32(int32(n))
   905  		w.WriteStdBitset(sli)
   906  		return n + 4, w.Err()
   907  	}
   908  }
   909  
   910  func wstreamBools(w *rbytes.WBuffer, recv any, cfg *streamerConfig) (int, error) {
   911  	var (
   912  		n   = cfg.counter(recv)
   913  		sli = *cfg.adjust(recv).(*[]bool)
   914  	)
   915  	sli = sli[:n]
   916  	w.WriteI8(1) // is-array
   917  	w.WriteArrayBool(sli)
   918  	return 1 + n, w.Err()
   919  }
   920  
   921  func wstreamI8s(w *rbytes.WBuffer, recv any, cfg *streamerConfig) (int, error) {
   922  	var (
   923  		n   = cfg.counter(recv)
   924  		sli = *cfg.adjust(recv).(*[]int8)
   925  	)
   926  	sli = (sli)[:n]
   927  	w.WriteI8(1) // is-array
   928  	w.WriteArrayI8(sli)
   929  	return 1 + n, w.Err()
   930  }
   931  
   932  func wstreamI16s(w *rbytes.WBuffer, recv any, cfg *streamerConfig) (int, error) {
   933  	var (
   934  		n   = cfg.counter(recv)
   935  		sli = *cfg.adjust(recv).(*[]int16)
   936  	)
   937  	sli = (sli)[:n]
   938  	w.WriteI8(1) // is-array
   939  	w.WriteArrayI16(sli)
   940  	return 1 + n*2, w.Err()
   941  }
   942  
   943  func wstreamI32s(w *rbytes.WBuffer, recv any, cfg *streamerConfig) (int, error) {
   944  	var (
   945  		n   = cfg.counter(recv)
   946  		sli = *cfg.adjust(recv).(*[]int32)
   947  	)
   948  	sli = (sli)[:n]
   949  	w.WriteI8(1) // is-array
   950  	w.WriteArrayI32(sli)
   951  	return 1 + n*4, w.Err()
   952  }
   953  
   954  func wstreamI64s(w *rbytes.WBuffer, recv any, cfg *streamerConfig) (int, error) {
   955  	var (
   956  		n   = cfg.counter(recv)
   957  		sli = *cfg.adjust(recv).(*[]int64)
   958  	)
   959  	sli = (sli)[:n]
   960  	w.WriteI8(1) // is-array
   961  	w.WriteArrayI64(sli)
   962  	return 1 + n*8, w.Err()
   963  }
   964  
   965  func wstreamU8s(w *rbytes.WBuffer, recv any, cfg *streamerConfig) (int, error) {
   966  	var (
   967  		n   = cfg.counter(recv)
   968  		sli = *cfg.adjust(recv).(*[]uint8)
   969  	)
   970  	sli = (sli)[:n]
   971  	w.WriteI8(1) // is-array
   972  	w.WriteArrayU8(sli)
   973  	return 1 + n, w.Err()
   974  }
   975  
   976  func wstreamU16s(w *rbytes.WBuffer, recv any, cfg *streamerConfig) (int, error) {
   977  	var (
   978  		n   = cfg.counter(recv)
   979  		sli = *cfg.adjust(recv).(*[]uint16)
   980  	)
   981  	sli = (sli)[:n]
   982  	w.WriteI8(1) // is-array
   983  	w.WriteArrayU16(sli)
   984  	return 1 + n*2, w.Err()
   985  }
   986  
   987  func wstreamU32s(w *rbytes.WBuffer, recv any, cfg *streamerConfig) (int, error) {
   988  	var (
   989  		n   = cfg.counter(recv)
   990  		sli = *cfg.adjust(recv).(*[]uint32)
   991  	)
   992  	sli = (sli)[:n]
   993  	w.WriteI8(1) // is-array
   994  	w.WriteArrayU32(sli)
   995  	return 1 + n*4, w.Err()
   996  }
   997  
   998  func wstreamU64s(w *rbytes.WBuffer, recv any, cfg *streamerConfig) (int, error) {
   999  	var (
  1000  		n   = cfg.counter(recv)
  1001  		sli = *cfg.adjust(recv).(*[]uint64)
  1002  	)
  1003  	sli = (sli)[:n]
  1004  	w.WriteI8(1) // is-array
  1005  	w.WriteArrayU64(sli)
  1006  	return 1 + n*8, w.Err()
  1007  }
  1008  
  1009  func wstreamF32s(w *rbytes.WBuffer, recv any, cfg *streamerConfig) (int, error) {
  1010  	var (
  1011  		n   = cfg.counter(recv)
  1012  		sli = *cfg.adjust(recv).(*[]float32)
  1013  	)
  1014  	sli = (sli)[:n]
  1015  	w.WriteI8(1) // is-array
  1016  	w.WriteArrayF32(sli)
  1017  	return 1 + n*4, w.Err()
  1018  }
  1019  
  1020  func wstreamF64s(w *rbytes.WBuffer, recv any, cfg *streamerConfig) (int, error) {
  1021  	var (
  1022  		n   = cfg.counter(recv)
  1023  		sli = *cfg.adjust(recv).(*[]float64)
  1024  	)
  1025  	sli = (sli)[:n]
  1026  	w.WriteI8(1) // is-array
  1027  	w.WriteArrayF64(sli)
  1028  	return 1 + n*8, w.Err()
  1029  }
  1030  
  1031  func wstreamF16s(w *rbytes.WBuffer, recv any, cfg *streamerConfig) (int, error) {
  1032  	var (
  1033  		n   = cfg.counter(recv)
  1034  		sli = *cfg.adjust(recv).(*[]root.Float16)
  1035  		beg = w.Pos()
  1036  	)
  1037  	sli = sli[:n]
  1038  	w.WriteI8(1) // is-array
  1039  	w.WriteArrayF16(sli, cfg.descr.elem)
  1040  	return int(w.Pos() - beg), w.Err()
  1041  }
  1042  
  1043  func wstreamD32s(w *rbytes.WBuffer, recv any, cfg *streamerConfig) (int, error) {
  1044  	var (
  1045  		n   = cfg.counter(recv)
  1046  		sli = *cfg.adjust(recv).(*[]root.Double32)
  1047  		beg = w.Pos()
  1048  	)
  1049  	sli = sli[:n]
  1050  	w.WriteI8(1) // is-array
  1051  	w.WriteArrayD32(sli, cfg.descr.elem)
  1052  	return int(w.Pos() - beg), w.Err()
  1053  }
  1054  
  1055  func wstreamStrs(w *rbytes.WBuffer, recv any, cfg *streamerConfig) (int, error) {
  1056  	var (
  1057  		n   = cfg.counter(recv)
  1058  		sli = *cfg.adjust(recv).(*[]string)
  1059  		beg = w.Pos()
  1060  	)
  1061  	sli = (sli)[:n]
  1062  	w.WriteI8(1) // is-array
  1063  	w.WriteArrayString(sli)
  1064  	return int(w.Pos() - beg), w.Err()
  1065  }
  1066  
  1067  func wstreamCat(typename string, typevers int16, wops []wstreamer) wopFunc {
  1068  	return func(w *rbytes.WBuffer, recv any, cfg *streamerConfig) (int, error) {
  1069  		hdr := w.WriteHeader(typename, typevers)
  1070  		recv = cfg.adjust(recv)
  1071  		for i, wop := range wops {
  1072  			_, err := wop.wstream(w, recv)
  1073  			if err != nil {
  1074  				return 0, fmt.Errorf(
  1075  					"rdict: could not wstream element %d (%s) of %s: %w",
  1076  					i, wop.cfg.descr.elem.Name(), cfg.si.Name(), err,
  1077  				)
  1078  			}
  1079  		}
  1080  		return w.SetHeader(hdr)
  1081  	}
  1082  }
  1083  
  1084  func wstreamStdString(w *rbytes.WBuffer, recv any, cfg *streamerConfig) (int, error) {
  1085  	beg := w.Pos()
  1086  	w.WriteString(*cfg.adjust(recv).(*string))
  1087  	return int(w.Pos() - beg), w.Err()
  1088  
  1089  }
  1090  
  1091  func wopFuncFor(e rmeta.Enum, descr *elemDescr) wopFunc {
  1092  	switch e {
  1093  	case rmeta.Bool:
  1094  		return wstreamBool
  1095  	case rmeta.Bits:
  1096  		return wstreamBits
  1097  	case rmeta.Int8:
  1098  		return wstreamI8
  1099  	case rmeta.Int16:
  1100  		return wstreamI16
  1101  	case rmeta.Int32:
  1102  		return wstreamI32
  1103  	case rmeta.Int64, rmeta.Long64:
  1104  		return wstreamI64
  1105  	case rmeta.Uint8:
  1106  		return wstreamU8
  1107  	case rmeta.Uint16:
  1108  		return wstreamU16
  1109  	case rmeta.Uint32:
  1110  		return wstreamU32
  1111  	case rmeta.Uint64, rmeta.ULong64:
  1112  		return wstreamU64
  1113  	case rmeta.Float32:
  1114  		return wstreamF32
  1115  	case rmeta.Float64:
  1116  		return wstreamF64
  1117  	case rmeta.Float16:
  1118  		return wstreamF16(descr.elem)
  1119  	case rmeta.Double32:
  1120  		return wstreamD32(descr.elem)
  1121  	case rmeta.TString, rmeta.CharStar:
  1122  		return wstreamTString
  1123  	case rmeta.STLstring:
  1124  		return wstreamStdString
  1125  	case rmeta.TObject:
  1126  		return wstreamTObject
  1127  	case rmeta.TNamed:
  1128  		return wstreamTNamed
  1129  	default:
  1130  		return nil
  1131  	}
  1132  }
  1133  
  1134  func wopFrom(sictx rbytes.StreamerInfoContext, typename string, typevers int16, enum rmeta.Enum, descr *elemDescr) (wopFunc, int16) {
  1135  	e, ok := rmeta.TypeName2Enum(typename)
  1136  	if ok {
  1137  		wop := wopFuncFor(e, descr)
  1138  		if wop != nil {
  1139  			return wop, -1
  1140  		}
  1141  	}
  1142  
  1143  	wop := wopFuncFor(enum, descr)
  1144  	if wop != nil {
  1145  		return wop, -1
  1146  	}
  1147  
  1148  	switch {
  1149  	case hasStdPrefix(typename, "vector", "list", "deque"):
  1150  		enames := rmeta.CxxTemplateFrom(typename).Args
  1151  		wop, _ := wopFrom(sictx, enames[0], -1, 0, nil)
  1152  		return wstreamStdSlice(typename, wop), rvers.StreamerBaseSTL
  1153  
  1154  	case hasStdPrefix(typename, "set", "multiset", "unordered_set", "unordered_multiset"):
  1155  		enames := rmeta.CxxTemplateFrom(typename).Args
  1156  		wop, _ := wopFrom(sictx, enames[0], -1, 0, nil)
  1157  		return wstreamStdSet(typename, wop), rvers.StreamerBaseSTL
  1158  
  1159  	case hasStdPrefix(typename, "map", "multimap", "unordered_map", "unordered_multimap"):
  1160  		enames := rmeta.CxxTemplateFrom(typename).Args
  1161  		kname := enames[0]
  1162  		vname := enames[1]
  1163  
  1164  		kwop, kvers := wopFrom(sictx, kname, -1, 0, nil)
  1165  		vwop, vvers := wopFrom(sictx, vname, -1, 0, nil)
  1166  		return wstreamStdMap(kname, vname, kwop, vwop, kvers, vvers), rvers.StreamerBaseSTL
  1167  
  1168  	case hasStdPrefix(typename, "bitset"):
  1169  		enames := rmeta.CxxTemplateFrom(typename).Args
  1170  		n, err := strconv.Atoi(enames[0])
  1171  		if err != nil {
  1172  			panic(fmt.Errorf("rdict: invalid STL bitset argument (type=%q): %+v", typename, err))
  1173  		}
  1174  		return wstreamStdBitset(typename, n), rvers.StreamerBaseSTL
  1175  	}
  1176  
  1177  	osi, err := sictx.StreamerInfo(typename, int(typevers))
  1178  	if err != nil {
  1179  		panic(fmt.Errorf("rdict: could not find streamer info for %q (version=%d): %w", typename, typevers, err))
  1180  	}
  1181  	esi := osi.(*StreamerInfo)
  1182  
  1183  	err = esi.BuildStreamers()
  1184  	if err != nil {
  1185  		panic(fmt.Errorf("rdict: could not build streamers for %q (version=%d): %w", typename, typevers, err))
  1186  	}
  1187  
  1188  	wop = wstreamSI(esi)
  1189  	return wop, int16(esi.ClassVersion())
  1190  }