go-hep.org/x/hep@v0.38.1/groot/rdict/decoder.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  	"strings"
    11  
    12  	"go-hep.org/x/hep/groot/rbytes"
    13  )
    14  
    15  type decoder struct {
    16  	r    *rbytes.RBuffer
    17  	si   *StreamerInfo
    18  	kind rbytes.StreamKind
    19  	rops []rstreamer
    20  }
    21  
    22  func newDecoder(r *rbytes.RBuffer, si *StreamerInfo, kind rbytes.StreamKind, ops []rstreamer) (*decoder, error) {
    23  	return &decoder{r, si, kind, ops}, nil
    24  }
    25  
    26  func (dec *decoder) DecodeROOT(ptr any) error {
    27  	rv := reflect.ValueOf(ptr)
    28  	if rv.Kind() != reflect.Ptr {
    29  		return fmt.Errorf("rdict: invalid kind (got=%T, want=pointer)", ptr)
    30  	}
    31  
    32  	var (
    33  		typename = dec.si.Name()
    34  		typevers = int16(dec.si.ClassVersion())
    35  		hdr      = dec.r.ReadHeader(typename, typevers)
    36  	)
    37  
    38  	if hdr.Vers != typevers {
    39  		dec.r.SetErr(fmt.Errorf("rdict: inconsistent ROOT version type=%q (got=%d, want=%d)",
    40  			typename, hdr.Vers, typevers,
    41  		))
    42  		return dec.r.Err()
    43  	}
    44  
    45  	for i, op := range dec.rops {
    46  		err := op.rstream(dec.r, ptr)
    47  		if err != nil {
    48  			return fmt.Errorf("rdict: could not read element %d from %q: %w", i, typename, err)
    49  		}
    50  	}
    51  
    52  	dec.r.CheckHeader(hdr)
    53  	if err := dec.r.Err(); err != nil {
    54  		return fmt.Errorf("rdict: invalid bytecount for %q: %w", typename, err)
    55  	}
    56  
    57  	return nil
    58  }
    59  
    60  var (
    61  	_ rbytes.Decoder = (*decoder)(nil)
    62  )
    63  
    64  type rstreamerInfo struct {
    65  	recv any
    66  	rops []rstreamer
    67  	kind rbytes.StreamKind
    68  	si   *StreamerInfo
    69  }
    70  
    71  func newRStreamerInfo(si *StreamerInfo, kind rbytes.StreamKind, rops []rstreamer) (*rstreamerInfo, error) {
    72  	return &rstreamerInfo{
    73  		recv: nil,
    74  		rops: rops,
    75  		kind: kind,
    76  		si:   si,
    77  	}, nil
    78  }
    79  
    80  func (rr *rstreamerInfo) Bind(recv any) error {
    81  	rv := reflect.ValueOf(recv)
    82  	if rv.Kind() != reflect.Ptr {
    83  		return fmt.Errorf("rdict: invalid kind (got=%T, want=pointer)", recv)
    84  	}
    85  	rr.recv = recv
    86  	if recv, ok := recv.(rbytes.Unmarshaler); ok && rr.kind == rbytes.ObjectWise {
    87  		// FIXME(sbinet): handle mbr-/obj-wise
    88  		rr.rops = []rstreamer{{
    89  			op: func(r *rbytes.RBuffer, _ any, _ *streamerConfig) error {
    90  				return recv.UnmarshalROOT(r)
    91  			},
    92  			cfg: nil,
    93  		}}
    94  		return nil
    95  	}
    96  	if len(rr.rops) == 1 {
    97  		se := rr.rops[0].cfg.descr.elem
    98  		if se.Name() == "This" ||
    99  			strings.HasPrefix(se.TypeName(), "vector<") {
   100  			// binding directly to 'recv'. assume no offset is to be applied
   101  			rr.rops[0].cfg.offset = -1
   102  		}
   103  	}
   104  	return nil
   105  }
   106  
   107  func (rr *rstreamerInfo) RStreamROOT(r *rbytes.RBuffer) error {
   108  	for i, op := range rr.rops {
   109  		err := op.rstream(r, rr.recv)
   110  		if err != nil {
   111  			typename := rr.si.Name()
   112  			return fmt.Errorf("rdict: could not read element %d from %q: %w", i, typename, err)
   113  		}
   114  	}
   115  	return nil
   116  }
   117  
   118  var (
   119  	_ rbytes.RStreamer = (*rstreamerInfo)(nil)
   120  	_ rbytes.Binder    = (*rstreamerInfo)(nil)
   121  )