Go-HEP/groot: write support of (flat, simple) TTrees (v0.21.0)

hi there,

a new release of Go-HEP, v0.21.0, is out:

this one is the best release ever. (to date).

it provides reading support back to ROOT-4 (ie: TTrees and TH{1,2}x created by Geant4 applications)
and it provides write support for flat, simple TTrees (that C++/ROOT can read back).

type Data struct {
    I32    int32
    F64    float64
    Str    string
    ArrF64 [5]float64
    N      int32
    SliF64 []float64 `groot:"SliF64[N]"` // tell ROOT/C++ the leaf name and the leaf holding the count
}

const (
    fname = "struct.root"
    nevts = 5
)

f, err := groot.Create(fname)
if err != nil {
    log.Fatalf("%+v", err)
}
defer f.Close()

var evt Data

tree, err := rtree.NewWriter(f, "mytree", rtree.WriteVarsFromStruct(&evt))
if err != nil {
    log.Fatalf("could not create tree writer: %+v", err)
}

fmt.Printf("-- created tree %q:\n", tree.Name())
for i, b := range tree.Branches() {
    fmt.Printf("branch[%d]: name=%q, title=%q\n", i, b.Name(), b.Title())
}

for i := 0; i < nevts; i++ {
    evt.I32 = int32(i)
    evt.F64 = float64(i)
    evt.Str = fmt.Sprintf("evt-%0d", i)
    evt.ArrF64 = [5]float64{float64(i), float64(i + 1), float64(i + 2), float64(i + 3), float64(i + 4)}
    evt.N = int32(i)
    evt.SliF64 = []float64{float64(i), float64(i + 1), float64(i + 2), float64(i + 3), float64(i + 4)}[:i]
    _, err = tree.Write()
    if err != nil {
        log.Fatalf("could not write event %d: %+v", i, err)
    }
}
fmt.Printf("-- filled tree with %d entries\n", tree.Entries())

err = tree.Close()
if err != nil {
    log.Fatalf("could not write tree: %+v", err)
}

err = f.Close()
if err != nil {
    log.Fatalf("could not close tree: %+v", err)
}

// Output:
// -- created tree "mytree":
// branch[0]: name="I32", title="I32/I"
// branch[1]: name="F64", title="F64/D"
// branch[2]: name="Str", title="Str/C"
// branch[3]: name="ArrF64", title="ArrF64[5]/D"
// branch[4]: name="N", title="N/I"
// branch[5]: name="SliF64", title="SliF64[N]/D"
// -- filled tree with 5 entries
// -- read back ROOT file
// entry[0]: {I32:0 F64:0 Str:evt-0 ArrF64:[0 1 2 3 4] N:0 SliF64:[]}
// entry[1]: {I32:1 F64:1 Str:evt-1 ArrF64:[1 2 3 4 5] N:1 SliF64:[1]}
// entry[2]: {I32:2 F64:2 Str:evt-2 ArrF64:[2 3 4 5 6] N:2 SliF64:[2 3]}
// entry[3]: {I32:3 F64:3 Str:evt-3 ArrF64:[3 4 5 6 7] N:3 SliF64:[3 4 5]}
// entry[4]: {I32:4 F64:4 Str:evt-4 ArrF64:[4 5 6 7 8] N:4 SliF64:[4 5 6 7]}

Reading that file struct.root (5.3 KB) :

$> root ./struct.root
root [0] 
Attaching file ./struct.root as _file0...
(TFile *) 0x557bb6e071d0
root [1] ((TTree*)_file0->Get("mytree"))->Scan()
***********************************************************************************************
*    Row   * Instance *       I32 *       F64 *       Str *    ArrF64 *         N *    SliF64 *
***********************************************************************************************
*        0 *        0 *         0 *         0 *     evt-0 *         0 *         0 *           *
*        0 *        1 *         0 *         0 *           *         1 *         0 *           *
*        0 *        2 *         0 *         0 *           *         2 *         0 *           *
*        0 *        3 *         0 *         0 *           *         3 *         0 *           *
*        0 *        4 *         0 *         0 *           *         4 *         0 *           *
*        1 *        0 *         1 *         1 *     evt-1 *         1 *         1 *         1 *
*        1 *        1 *         1 *         1 *           *         2 *         1 *           *
*        1 *        2 *         1 *         1 *           *         3 *         1 *           *
*        1 *        3 *         1 *         1 *           *         4 *         1 *           *
*        1 *        4 *         1 *         1 *           *         5 *         1 *           *
*        2 *        0 *         2 *         2 *     evt-2 *         2 *         2 *         2 *
*        2 *        1 *         2 *         2 *           *         3 *         2 *         3 *
*        2 *        2 *         2 *         2 *           *         4 *         2 *           *
*        2 *        3 *         2 *         2 *           *         5 *         2 *           *
*        2 *        4 *         2 *         2 *           *         6 *         2 *           *
*        3 *        0 *         3 *         3 *     evt-3 *         3 *         3 *         3 *
*        3 *        1 *         3 *         3 *           *         4 *         3 *         4 *
*        3 *        2 *         3 *         3 *           *         5 *         3 *         5 *
*        3 *        3 *         3 *         3 *           *         6 *         3 *           *
*        3 *        4 *         3 *         3 *           *         7 *         3 *           *
*        4 *        0 *         4 *         4 *     evt-4 *         4 *         4 *         4 *
*        4 *        1 *         4 *         4 *           *         5 *         4 *         5 *
*        4 *        2 *         4 *         4 *           *         6 *         4 *         6 *
*        4 *        3 *         4 *         4 *           *         7 *         4 *         7 *
*        4 *        4 *         4 *         4 *           *         8 *         4 *           *
***********************************************************************************************
(long long) 25

Binaries are available for testing (w/o any Go SDK installed whatsoever) here: