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  }