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 )