go-hep.org/x/hep@v0.38.1/sio/decoder.go (about) 1 // Copyright ©2017 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 sio 6 7 import ( 8 "encoding/binary" 9 "reflect" 10 ) 11 12 // Decoder decodes SIO streams. 13 // Decoder provides a nice API to deal with errors that may occur during decoding. 14 type Decoder struct { 15 r Reader 16 err error 17 } 18 19 // NewDecoder creates a new Decoder reading from the provided sio.Reader. 20 func NewDecoder(r Reader) *Decoder { 21 return &Decoder{r: r} 22 } 23 24 // Decode reads the next value from the input sio stream and stores it in 25 // the data, an empty interface value wrapping a pointer to a concrete value. 26 func (dec *Decoder) Decode(ptr any) { 27 if dec.err != nil { 28 return 29 } 30 31 dec.err = unmarshal(dec.r, ptr) 32 } 33 34 // Tag tags a pointer, assigning it a unique identifier, so links between values 35 // (inside a given SIO record) can be rebuilt. 36 func (dec *Decoder) Tag(ptr any) { 37 if dec.err != nil { 38 return 39 } 40 dec.err = dec.r.Tag(ptr) 41 } 42 43 // Pointer marks a (pointer to a) pointer, assigning it a unique identifier, 44 // so links between values (inside a given SIO record) can be rebuilt. 45 func (dec *Decoder) Pointer(ptr any) { 46 if dec.err != nil { 47 return 48 } 49 dec.err = dec.r.Pointer(ptr) 50 } 51 52 // Err returns the first encountered error while decoding, if any. 53 func (dec *Decoder) Err() error { 54 return dec.err 55 } 56 57 // unmarshal unmarshals a stream of bytes into ptr. 58 // If ptr implements Codec, use it. 59 func unmarshal(r Reader, ptr any) error { 60 if ptr, ok := ptr.(Unmarshaler); ok { 61 return ptr.UnmarshalSio(r) 62 } 63 return bread(r, ptr) 64 } 65 66 func bread(r Reader, data any) error { 67 bo := binary.BigEndian 68 rv := reflect.ValueOf(data) 69 //fmt.Printf("::: [%v] :::...\n", rv.Type()) 70 //defer fmt.Printf("### [%v] [done]\n", rv.Type()) 71 72 switch rv.Type().Kind() { 73 case reflect.Ptr: 74 rv = rv.Elem() 75 } 76 switch rv.Type().Kind() { 77 case reflect.Struct: 78 //fmt.Printf(">>> struct: [%v]...\n", rv.Type()) 79 for i, n := 0, rv.NumField(); i < n; i++ { 80 //fmt.Printf(">>> i=%d [%v] (%v)...\n", i, rv.Field(i).Type(), rv.Type().Name()+"."+rv.Type().Field(i).Name) 81 err := unmarshal(r, rv.Field(i).Addr().Interface()) 82 if err != nil { 83 return err 84 } 85 //fmt.Printf(">>> i=%d [%v] (%v)...[done=>%v]\n", i, rv.Field(i).Type(), rv.Type().Name(), rv.Field(i).Interface()) 86 } 87 //fmt.Printf(">>> struct: [%v]...[done]\n", rv.Type()) 88 return nil 89 case reflect.String: 90 //fmt.Printf("++++> string...\n") 91 sz := uint32(0) 92 err := bread(r, &sz) 93 if err != nil { 94 return err 95 } 96 strlen := align4U32(sz) 97 //fmt.Printf("string [%d=>%d]...\n", sz, strlen) 98 str := make([]byte, strlen) 99 _, err = r.Read(str) 100 if err != nil { 101 return err 102 } 103 rv.SetString(string(str[:sz])) 104 //fmt.Printf("<++++ [%s]\n", string(str)) 105 return nil 106 107 case reflect.Slice: 108 //fmt.Printf("<<< slice: [%v|%v]...\n", rv.Type(), rv.Type().Elem().Kind()) 109 sz := uint32(0) 110 err := bread(r, &sz) 111 if err != nil { 112 return err 113 } 114 //fmt.Printf("<<< slice: %d [%v]\n", sz, rv.Type()) 115 slice := reflect.MakeSlice(rv.Type(), int(sz), int(sz)) 116 for i := range int(sz) { 117 err = unmarshal(r, slice.Index(i).Addr().Interface()) 118 if err != nil { 119 return err 120 } 121 } 122 rv.Set(slice) 123 //fmt.Printf("<<< slice: [%v]... [done] (%#v)\n", rv.Type(), rv.Interface()) 124 return err 125 126 case reflect.Map: 127 //fmt.Printf(">>> map: [%v]...\n", rv.Type()) 128 sz := uint32(0) 129 err := bread(r, &sz) 130 if err != nil { 131 return err 132 } 133 //fmt.Printf(">>> map: %d [%v]\n", sz, rv.Type()) 134 m := reflect.MakeMap(rv.Type()) 135 kt := rv.Type().Key() 136 vt := rv.Type().Elem() 137 for i, n := 0, int(sz); i < n; i++ { 138 kv := reflect.New(kt) 139 err = unmarshal(r, kv.Interface()) 140 if err != nil { 141 return err 142 } 143 vv := reflect.New(vt) 144 err = unmarshal(r, vv.Interface()) 145 if err != nil { 146 return err 147 } 148 //fmt.Printf("m - %d: {%v} - {%v}\n", i, kv.Elem().Interface(), vv.Elem().Interface()) 149 m.SetMapIndex(kv.Elem(), vv.Elem()) 150 } 151 rv.Set(m) 152 return nil 153 154 default: 155 //fmt.Printf(">>> binary - [%v]...\n", rv.Type()) 156 err := binary.Read(r, bo, data) 157 //fmt.Printf(">>> binary - [%v]... [done]\n", rv.Type()) 158 return err 159 } 160 }