go-hep.org/x/hep@v0.38.1/groot/rdict/encoder.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  
    11  	"go-hep.org/x/hep/groot/rbytes"
    12  )
    13  
    14  type encoder struct {
    15  	w    *rbytes.WBuffer
    16  	si   *StreamerInfo
    17  	kind rbytes.StreamKind
    18  	wops []wstreamer
    19  }
    20  
    21  func newEncoder(w *rbytes.WBuffer, si *StreamerInfo, kind rbytes.StreamKind, ops []wstreamer) (*encoder, error) {
    22  	return &encoder{w, si, kind, ops}, nil
    23  }
    24  
    25  func (enc *encoder) EncodeROOT(ptr any) error {
    26  	rv := reflect.ValueOf(ptr)
    27  	if rv.Kind() != reflect.Ptr {
    28  		return fmt.Errorf("rdict: invalid kind (got=%T, want=pointer)", ptr)
    29  	}
    30  
    31  	var (
    32  		typename = enc.si.Name()
    33  		typevers = int16(enc.si.ClassVersion())
    34  		hdr      = enc.w.WriteHeader(typename, typevers)
    35  		err      error
    36  	)
    37  
    38  	for i, op := range enc.wops {
    39  		_, err = op.wstream(enc.w, ptr)
    40  		if err != nil {
    41  			return fmt.Errorf("rdict: could not write element %d from %q: %w", i, typename, err)
    42  		}
    43  	}
    44  
    45  	_, err = enc.w.SetHeader(hdr)
    46  	if err != nil {
    47  		return fmt.Errorf("rdict: could not set byte count for %q: %w", typename, err)
    48  	}
    49  	return nil
    50  }
    51  
    52  var (
    53  	_ rbytes.Encoder = (*encoder)(nil)
    54  )
    55  
    56  type wstreamerInfo struct {
    57  	recv any
    58  	wops []wstreamer
    59  	kind rbytes.StreamKind
    60  	si   *StreamerInfo
    61  }
    62  
    63  func newWStreamerInfo(si *StreamerInfo, kind rbytes.StreamKind, wops []wstreamer) (*wstreamerInfo, error) {
    64  	return &wstreamerInfo{
    65  		recv: nil,
    66  		wops: wops,
    67  		kind: kind,
    68  		si:   si,
    69  	}, nil
    70  }
    71  
    72  func (ww *wstreamerInfo) Bind(recv any) error {
    73  	rv := reflect.ValueOf(recv)
    74  	if rv.Kind() != reflect.Ptr {
    75  		return fmt.Errorf("rdict: invalid kind (got=%T, want=pointer)", recv)
    76  	}
    77  	ww.recv = recv
    78  	if recv, ok := recv.(rbytes.Marshaler); ok && ww.kind == rbytes.ObjectWise {
    79  		// FIXME(sbinet): handle mbr-/obj-wise
    80  		ww.wops = []wstreamer{{
    81  			op: func(w *rbytes.WBuffer, _ any, _ *streamerConfig) (int, error) {
    82  				return recv.MarshalROOT(w)
    83  			},
    84  			cfg: nil,
    85  		}}
    86  		return nil
    87  	}
    88  	if len(ww.wops) == 1 && ww.wops[0].cfg.descr.elem.Name() == "This" {
    89  		// binding directly to 'recv'. assume no offset is to be applied
    90  		ww.wops[0].cfg.offset = -1
    91  	}
    92  	return nil
    93  }
    94  
    95  func (ww *wstreamerInfo) WStreamROOT(w *rbytes.WBuffer) error {
    96  	for i, op := range ww.wops {
    97  		_, err := op.wstream(w, ww.recv)
    98  		if err != nil {
    99  			typename := ww.si.Name()
   100  			return fmt.Errorf("rdict: could not write element %d from %q: %w", i, typename, err)
   101  		}
   102  	}
   103  	return nil
   104  }
   105  
   106  var (
   107  	_ rbytes.WStreamer = (*wstreamerInfo)(nil)
   108  	_ rbytes.Binder    = (*wstreamerInfo)(nil)
   109  )