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 }