mission accomplished 
given the following Go type definition:
package redm
//go:generate root-gen-streamers -p go-hep.org/x/hep/groot/redm -t Event,HLV -o pkg_gen.go
// Event is a simple type to exercize streamers generation.
type Event struct {
name string `groot:"Name"`
run int64
evt int64
u8 uint8
u16 uint16
u32 uint32
u64 uint64
i8 int8
i16 int16
i32 int32
i64 int64
f32 float32
f64 float64
b bool
HLV HLV
ArrU8 [10]uint8
ArrU16 [10]uint16
ArrU32 [10]uint32
ArrU64 [10]uint64
ArrI8 [10]int8
ArrI16 [10]int16
ArrI32 [10]int32
ArrI64 [10]int64
ArrF32 [10]float32
ArrF64 [10]float64
ArrBs [4]bool
}
func (*Event) RVersion() int16 { return 1 }
func (*Event) Class() string { return "go-hep.org/x/hep/groot/redm.Event" }
// HLV is a simple type to exercize streamers generation.
type HLV struct {
px, py, pz, e float64
}
func (*HLV) RVersion() int16 { return 1 }
func (*HLV) Class() string { return "go-hep.org/x/hep/groot/redm.HLV" }
and the following equivalent C++ definition event.h
:
#include "TString.h"
namespace go_hep_org { namespace x {
namespace hep { namespace groot { namespace redm {
class HLV {
public:
double px,py,pz,e;
};
class Event {
public:
TString Name;
long run;
long evt;
unsigned char u8;
unsigned short u16;
unsigned int u32;
unsigned long u64;
char i8;
short i16;
int i32;
long i64;
float f32;
double f64;
bool b;
go_hep_org::x::hep::groot::redm::HLV HLV;
unsigned char ArrU8[10];
unsigned short ArrU16[10];
unsigned int ArrU32[10];
unsigned long ArrU64[10];
char ArrI8[10];
short ArrI16[10];
int ArrI32[10];
long ArrI64 [10];
float ArrF32[10];
double ArrF64[10];
bool ArrBs[4];
};
}}}}}
streamers are automatically generated, either at runtime or at buildtime, like so (for the latter):
$> go generate ./redm
$> go get ./redm
then, running the following Go program:
package main
import (
"log"
"go-hep.org/x/hep/groot"
"go-hep.org/x/hep/groot/redm"
)
func main() {
f, err := groot.Create("out.root")
if err != nil {
log.Fatal(err)
}
defer f.Close()
evt := redm.New("hello", 42, 666)
err = f.Put("my-evt", evt)
if err != nil {
log.Fatal(err)
}
err = f.Close()
if err != nil {
log.Fatal(err)
}
}
produces the following:
$> go run ./test-streamers.go
$> root-ls -sinfos ./out.root
=== [./out.root] ===
version: 61404
streamer-infos:
StreamerInfo for "go_hep_org::x::hep::groot::redm::Event" version=1 title="Go;go-hep.org/x/hep/groot/redm.Event"
TString Name offset= 0 type= 65 size= 24
long run offset= 0 type= 4 size= 8
long evt offset= 0 type= 4 size= 8
unsigned char u8 offset= 0 type= 11 size= 1
unsigned short u16 offset= 0 type= 12 size= 2
unsigned int u32 offset= 0 type= 13 size= 4
unsigned long u64 offset= 0 type= 14 size= 8
char i8 offset= 0 type= 1 size= 1
short i16 offset= 0 type= 2 size= 2
int i32 offset= 0 type= 3 size= 4
long i64 offset= 0 type= 4 size= 8
float f32 offset= 0 type= 5 size= 4
double f64 offset= 0 type= 8 size= 8
bool b offset= 0 type= 18 size= 1
go_hep_org::x::hep::groot::redm::HLV HLV offset= 0 type= 62 size= 32
unsigned char ArrU8 offset= 0 type= 31 size= 10
unsigned short ArrU16 offset= 0 type= 32 size= 20
unsigned int ArrU32 offset= 0 type= 33 size= 40
unsigned long ArrU64 offset= 0 type= 34 size= 80
char ArrI8 offset= 0 type= 21 size= 10
short ArrI16 offset= 0 type= 22 size= 20
int ArrI32 offset= 0 type= 23 size= 40
long ArrI64 offset= 0 type= 24 size= 80
float ArrF32 offset= 0 type= 25 size= 40
double ArrF64 offset= 0 type= 28 size= 80
bool ArrBs offset= 0 type= 38 size= 4
StreamerInfo for "TString" version=2 title=""
StreamerInfo for "go_hep_org::x::hep::groot::redm::HLV" version=1 title="Go;go-hep.org/x/hep/groot/redm.HLV"
double px offset= 0 type= 8 size= 8
double py offset= 0 type= 8 size= 8
double pz offset= 0 type= 8 size= 8
double e offset= 0 type= 8 size= 8
---
go_hep_org::x::hep::groot::redm::Event my-evt (cycle=1)
with the following content:
$> root-dump ./out.root
>>> file[./out.root]
key[000]: my-evt;1 "" (go_hep_org::x::hep::groot::redm::Event) => &{hello 42 666 8 16 32 64 -8 -16 -32 -64 32.32 64.64 true {1 2 3 4} [1 2 3 4 5 6 7 8 9 0] [1 2 3 4 5 6 7 8 9 0] [1 2 3 4 5 6 7 8 9 0] [1 2 3 4 5 6 7 8 9 0] [-1 -2 -3 -4 -5 -6 -7 -8 -9 0] [-1 -2 -3 -4 -5 -6 -7 -8 -9 0] [-1 -2 -3 -4 -5 -6 -7 -8 -9 0] [-1 -2 -3 -4 -5 -6 -7 -8 -9 0] [-1.1 -2.2 -3.3 -4.4 -5.5 -6.6 -7.7 -8.8 -9.9 0] [-1.1 -2.2 -3.3 -4.4 -5.5 -6.6 -7.7 -8.8 -9.9 0] [true false false true]}
which can be read from ROOT/C++ like so:
$> root
root [0] .L ./testdata/event.h++
Info in <TUnixSystem::ACLiC>: creating shared library /home/binet/work/gonum/src/go-hep.org/x/hep/groot/././testdata/event_h.so
Warning in cling::IncrementalParser::CheckABICompatibility():
Possible C++ standard library mismatch, compiled with __GLIBCXX__ '20180831'
Extraction of runtime standard library version was: '20181127'
root [1] auto f = TFile::Open("./out.root");
root [2] auto k = f->GetKey("my-evt");
root [3] auto ee = k->ReadObject<go_hep_org::x::hep::groot::redm::Event>()
(go_hep_org::x::hep::groot::redm::Event *) @0x7ffd104d0e10
root [4] ee->Name
(TString &) "hello"[5]
root [5] ee->evt
(long) 666
root [6] ee->run
(long) 42
root [7] ee->ArrF64
(double [10]) { -1.1000000, -2.2000000, -3.3000000, -4.4000000, -5.5000000, -6.6000000, -7.7000000, -8.8000000, -9.9000000, 0.0000000 }
root [8] ee->HLV.px
(double) 1.0000000
root [9] ee->HLV.py
(double) 2.0000000
root [10] ee->HLV.pz
(double) 3.0000000
root [11] ee->HLV.e
(double) 4.0000000
how cool is that?!
there are still a few interesting things to handle:
- Go slices
- Go types that “inherit” from
TObject
s
- STL containers
- polymorphic containers
but hey… I can basically write almost any kind of Go values in a ROOT file (at the top level.)