Skip to content

Commit

Permalink
groot/rjson: first import
Browse files Browse the repository at this point in the history
Fixes #991.

Signed-off-by: Sebastien Binet <binet@cern.ch>
  • Loading branch information
sbinet committed Sep 7, 2023
1 parent d280b3c commit 301b96c
Show file tree
Hide file tree
Showing 5 changed files with 437 additions and 0 deletions.
122 changes: 122 additions & 0 deletions groot/rjson/rjson.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
// Copyright ©2023 The go-hep Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package rjson contains tools to marshal ROOT objects to JSON.
package rjson // import "go-hep.org/x/hep/groot/rjson"

import (
"bytes"
"encoding/json"
"fmt"
"io"
"log"
"reflect"

"go-hep.org/x/hep/groot/rbytes"
"go-hep.org/x/hep/groot/rdict"
"go-hep.org/x/hep/groot/root"
)

func Marshal(o root.Object) ([]byte, error) {
if o, ok := o.(rbytes.RSlicer); ok {
buf := new(bytes.Buffer)
enc := newEncoder(buf)
err := enc.Encode(o)
return buf.Bytes(), err
}

panic(fmt.Errorf("not implemented for %T", o))

vers := -1
if o, ok := o.(interface{ RVersion() int }); ok {
vers = o.RVersion()
}
log.Printf("--> marshal %T", o)
si, err := rdict.StreamerInfos.StreamerInfo(o.Class(), vers)
if err != nil {
return nil, fmt.Errorf("could not find streamer info for %T: %w", o, err)
}

w := new(bytes.Buffer)
w.WriteByte('{')
for i, elt := range si.Elements() {
log.Printf("elt: %+v", elt)
switch elt := elt.(type) {
case *rdict.StreamerBase:
log.Printf(">>> %+v", elt)
}
if i > 0 {
w.WriteByte(',')
}
fmt.Fprintf(w, "%q: %q", "_typename", elt.Name())
}
w.WriteByte('}')

rv := reflect.Indirect(reflect.ValueOf(o))
for i := 0; i < rv.NumField(); i++ {
rf := rv.Field(i)
ft := rv.Type().Field(i)
var (
vv any
name = ft.Name
)
if ft.IsExported() {
vv = rf.Interface()
}
log.Printf("field[%d]: %q %+v (%s)", i, name, vv, ft.Type.Name())
}

return w.Bytes(), nil
}

type encoder struct {
w io.Writer
}

func newEncoder(w io.Writer) *encoder {
return &encoder{w: w}
}

func (enc *encoder) Encode(v rbytes.RSlicer) error {
mbrs := v.RMembers()
name := v.(root.Object).Class()
w := enc.w
_, err := fmt.Fprintf(w, "{%q: %q", "_typename", name)
if err != nil {
return err
}
for _, m := range mbrs {
_, err := fmt.Fprintf(w, ", %q: ", m.Name)
if err != nil {
return err
}
if v, ok := m.Value.(rbytes.RSlicer); ok {
err := enc.Encode(v)
if err != nil {
return err
}
continue
}
if v := reflect.Indirect(reflect.ValueOf(m.Value)); v.Kind() == reflect.Slice && v.Len() == 0 {
_, err = w.Write([]byte("[]"))
if err != nil {
return err
}
continue
}
v, err := json.Marshal(m.Value)
if err != nil {
return err
}
_, err = w.Write(v)
if err != nil {
return err
}
}
_, err = fmt.Fprintf(w, "}")
if err != nil {
return err
}
return nil
}
189 changes: 189 additions & 0 deletions groot/rjson/rjson_example_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
// Copyright ©2023 The go-hep Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package rjson_test

import (
"bytes"
"encoding/json"
"fmt"
"log"

"go-hep.org/x/hep/groot/rhist"
"go-hep.org/x/hep/groot/rjson"
"go-hep.org/x/hep/hbook"
)

func ExampleMarshal() {
h := hbook.NewH1D(5, 0, 5)
h.Fill(1, 1)
h.Fill(-1, 1)
h.Ann["name"] = "h1"
h.Ann["title"] = "my title"

raw, err := rjson.Marshal(rhist.NewH1FFrom(h))
if err != nil {
log.Fatalf("could not marshal to ROOT JSON: %+v", err)
}

buf := new(bytes.Buffer)
err = json.Indent(buf, raw, "", " ")
if err != nil {
log.Fatalf("could not indent JSON: %+v", err)
}

fmt.Printf("json: %s\n", buf.String())

// Output:
// json: {
// "_typename": "TH1F",
// "fUniqueID": 0,
// "fBits": 50331648,
// "fName": "h1",
// "fTitle": "my title",
// "fLineColor": 602,
// "fLineStyle": 1,
// "fLineWidth": 1,
// "fFillColor": 0,
// "fFillStyle": 1001,
// "fMarkerColor": 1,
// "fMarkerStyle": 1,
// "fMarkerSize": 1,
// "fNcells": 7,
// "fXaxis": {
// "_typename": "TAxis",
// "fUniqueID": 0,
// "fBits": 50331648,
// "fName": "xaxis",
// "fTitle": "",
// "fNdivisions": 510,
// "fAxisColor": 1,
// "fLabelColor": 1,
// "fLabelFont": 42,
// "fLabelOffset": 0.005,
// "fLabelSize": 0.035,
// "fTickLength": 0.03,
// "fTitleOffset": 1,
// "fTitleSize": 0.035,
// "fTitleColor": 1,
// "fTitleFont": 42,
// "fNbins": 5,
// "fXmin": 0,
// "fXmax": 5,
// "fXbins": [
// 0,
// 1,
// 2,
// 3,
// 4,
// 5
// ],
// "fFirst": 0,
// "fLast": 0,
// "fBits2": 0,
// "fTimeDisplay": false,
// "fTimeFormat": "",
// "fLabels": null,
// "fModLabs": null
// },
// "fYaxis": {
// "_typename": "TAxis",
// "fUniqueID": 0,
// "fBits": 50331648,
// "fName": "yaxis",
// "fTitle": "",
// "fNdivisions": 510,
// "fAxisColor": 1,
// "fLabelColor": 1,
// "fLabelFont": 42,
// "fLabelOffset": 0.005,
// "fLabelSize": 0.035,
// "fTickLength": 0.03,
// "fTitleOffset": 1,
// "fTitleSize": 0.035,
// "fTitleColor": 1,
// "fTitleFont": 42,
// "fNbins": 1,
// "fXmin": 0,
// "fXmax": 1,
// "fXbins": [],
// "fFirst": 0,
// "fLast": 0,
// "fBits2": 0,
// "fTimeDisplay": false,
// "fTimeFormat": "",
// "fLabels": null,
// "fModLabs": null
// },
// "fZaxis": {
// "_typename": "TAxis",
// "fUniqueID": 0,
// "fBits": 50331648,
// "fName": "zaxis",
// "fTitle": "",
// "fNdivisions": 510,
// "fAxisColor": 1,
// "fLabelColor": 1,
// "fLabelFont": 42,
// "fLabelOffset": 0.005,
// "fLabelSize": 0.035,
// "fTickLength": 0.03,
// "fTitleOffset": 1,
// "fTitleSize": 0.035,
// "fTitleColor": 1,
// "fTitleFont": 42,
// "fNbins": 1,
// "fXmin": 0,
// "fXmax": 1,
// "fXbins": [],
// "fFirst": 0,
// "fLast": 0,
// "fBits2": 0,
// "fTimeDisplay": false,
// "fTimeFormat": "",
// "fLabels": null,
// "fModLabs": null
// },
// "fBarOffset": 0,
// "fBarWidth": 1000,
// "fEntries": 2,
// "fTsumw": 2,
// "fTsumw2": 2,
// "fTsumwx": 0,
// "fTsumwx2": 2,
// "fMaximum": -1111,
// "fMinimum": -1111,
// "fNormFactor": 0,
// "fContour": [],
// "fSumw2": [
// 1,
// 0,
// 1,
// 0,
// 0,
// 0,
// 0
// ],
// "fOption": "",
// "fFunctions": {
// "_typename": "TList",
// "name": "",
// "arr": [],
// "opt": []
// },
// "fBufferSize": 0,
// "fBuffer": [],
// "fBinStatErrOpt": 0,
// "fStatOverflows": 2,
// "fArray": [
// 1,
// 0,
// 1,
// 0,
// 0,
// 0,
// 0
// ]
// }
}

0 comments on commit 301b96c

Please sign in to comment.