go-hep.org/x/hep@v0.38.1/hbook/ann.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 hbook
     6  
     7  import (
     8  	"bufio"
     9  	"bytes"
    10  	"encoding/gob"
    11  	"fmt"
    12  	"io"
    13  	"sort"
    14  	"strings"
    15  
    16  	"gopkg.in/yaml.v3"
    17  )
    18  
    19  // Annotation is a bag of attributes that are attached to a histogram.
    20  type Annotation map[string]any
    21  
    22  func (ann Annotation) clone() Annotation {
    23  	buf := new(bytes.Buffer)
    24  	err := gob.NewEncoder(buf).Encode(&ann)
    25  	if err != nil {
    26  		panic(err)
    27  	}
    28  	out := make(Annotation, len(ann))
    29  	err = gob.NewDecoder(buf).Decode(&out)
    30  	if err != nil {
    31  		panic(err)
    32  	}
    33  	return out
    34  }
    35  
    36  // MarshalYODA implements the YODAMarshaler interface.
    37  func (ann Annotation) MarshalYODA() ([]byte, error) {
    38  	return ann.marshalYODAv2()
    39  }
    40  
    41  // marshalYODAv1 implements the YODAMarshaler interface.
    42  func (ann Annotation) marshalYODAv1() ([]byte, error) {
    43  	keys := make([]string, 0, len(ann))
    44  	for k := range ann {
    45  		if k == "" {
    46  			continue
    47  		}
    48  		keys = append(keys, k)
    49  	}
    50  	sort.Strings(keys)
    51  	buf := new(bytes.Buffer)
    52  	for _, k := range keys {
    53  		fmt.Fprintf(buf, "%s=%v\n", k, ann[k])
    54  	}
    55  	return buf.Bytes(), nil
    56  }
    57  
    58  // marshalYODAv2 implements the YODAMarshaler interface.
    59  func (ann Annotation) marshalYODAv2() ([]byte, error) {
    60  	return yaml.Marshal(ann)
    61  }
    62  
    63  // UnmarshalYODA implements the YODAUnmarshaler interface.
    64  func (ann *Annotation) UnmarshalYODA(data []byte) error {
    65  	return ann.unmarshalYODAv2(data)
    66  }
    67  
    68  // unmarshalYODAv1 unmarshal YODA v1.
    69  func (ann *Annotation) unmarshalYODAv1(data []byte) error {
    70  	var err error
    71  	s := bufio.NewScanner(bytes.NewReader(data))
    72  	for s.Scan() {
    73  		txt := s.Text()
    74  		i := strings.Index(txt, "=")
    75  		k := txt[:i]
    76  		v := txt[i+1:]
    77  		(*ann)[k] = v
    78  	}
    79  	err = s.Err()
    80  	if err == io.EOF {
    81  		err = nil
    82  	}
    83  	return err
    84  }
    85  
    86  // unmarshalYODAv2 unmarshal YODA v2.
    87  func (ann *Annotation) unmarshalYODAv2(data []byte) error {
    88  	return yaml.Unmarshal(data, ann)
    89  }
    90  
    91  // MarshalBinary implements encoding.BinaryMarshaler
    92  func (ann *Annotation) MarshalBinary() ([]byte, error) {
    93  	var v map[string]any = *ann
    94  	buf := new(bytes.Buffer)
    95  	err := gob.NewEncoder(buf).Encode(v)
    96  	return buf.Bytes(), err
    97  }
    98  
    99  // UnmarshalBinary implements encoding.BinaryUnmarshaler
   100  func (ann *Annotation) UnmarshalBinary(data []byte) error {
   101  	var v = make(map[string]any)
   102  	buf := bytes.NewReader(data)
   103  	err := gob.NewDecoder(buf).Decode(&v)
   104  	if err != nil {
   105  		return err
   106  	}
   107  	*ann = Annotation(v)
   108  	return nil
   109  }