go-hep.org/x/hep@v0.40.0/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  		k, v, _ := strings.Cut(txt, "=")
    75  		(*ann)[k] = v
    76  	}
    77  	err = s.Err()
    78  	if err == io.EOF {
    79  		err = nil
    80  	}
    81  	return err
    82  }
    83  
    84  // unmarshalYODAv2 unmarshal YODA v2.
    85  func (ann *Annotation) unmarshalYODAv2(data []byte) error {
    86  	return yaml.Unmarshal(data, ann)
    87  }
    88  
    89  // MarshalBinary implements encoding.BinaryMarshaler
    90  func (ann *Annotation) MarshalBinary() ([]byte, error) {
    91  	var v map[string]any = *ann
    92  	buf := new(bytes.Buffer)
    93  	err := gob.NewEncoder(buf).Encode(v)
    94  	return buf.Bytes(), err
    95  }
    96  
    97  // UnmarshalBinary implements encoding.BinaryUnmarshaler
    98  func (ann *Annotation) UnmarshalBinary(data []byte) error {
    99  	var v = make(map[string]any)
   100  	buf := bytes.NewReader(data)
   101  	err := gob.NewDecoder(buf).Decode(&v)
   102  	if err != nil {
   103  		return err
   104  	}
   105  	*ann = Annotation(v)
   106  	return nil
   107  }