go-hep.org/x/hep@v0.38.1/fwk/hbooksvc/stream.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 hbooksvc
     6  
     7  import (
     8  	"fmt"
     9  	"io"
    10  	"os"
    11  
    12  	"go-hep.org/x/hep/fwk"
    13  	"go-hep.org/x/hep/rio"
    14  )
    15  
    16  // Mode describes the open-mode of a stream
    17  type Mode int
    18  
    19  const (
    20  	Read  Mode = Mode(os.O_RDONLY)
    21  	Write Mode = Mode(os.O_WRONLY)
    22  )
    23  
    24  // Stream defines an input or output hbook stream
    25  type Stream struct {
    26  	Name string // input|output file name
    27  	Mode Mode   // read|write
    28  }
    29  
    30  type istream struct {
    31  	name  string // stream name
    32  	fname string // file name
    33  	f     io.ReadCloser
    34  	r     *rio.Reader
    35  	objs  []fwk.Hist
    36  }
    37  
    38  func (stream *istream) close() error {
    39  	defer stream.f.Close() // do not leak file descriptors
    40  	err := stream.r.Close()
    41  	if err != nil {
    42  		return err
    43  	}
    44  
    45  	err = stream.f.Close()
    46  	if err != nil {
    47  		return err
    48  	}
    49  
    50  	return err
    51  }
    52  
    53  func (stream *istream) read(name string, ptr any) error {
    54  	var err error
    55  
    56  	seekr, ok := stream.f.(io.Seeker)
    57  	if !ok {
    58  		return fmt.Errorf("hbooksvc: input stream [%s] is not seek-able", stream.name)
    59  	}
    60  
    61  	pos, err := seekr.Seek(0, 1)
    62  	if err != nil {
    63  		return err
    64  	}
    65  	defer func() {
    66  		_, _ = seekr.Seek(pos, 0)
    67  	}()
    68  
    69  	_, err = seekr.Seek(0, 0)
    70  	if err != nil {
    71  		return err
    72  	}
    73  
    74  	r := seekr.(io.Reader)
    75  	rr, err := rio.NewReader(r)
    76  	if err != nil {
    77  		return err
    78  	}
    79  	defer rr.Close()
    80  
    81  	scan := rio.NewScanner(rr)
    82  	scan.Select([]rio.Selector{{Name: name, Unpack: true}})
    83  	if !scan.Scan() {
    84  		return scan.Err()
    85  	}
    86  	rec := scan.Record()
    87  	if rec == nil {
    88  		return fmt.Errorf("hbooksvc: could not find record [%s] in stream [%s]", name, stream.name)
    89  	}
    90  	blk := rec.Block(name)
    91  	if blk == nil {
    92  		return fmt.Errorf(
    93  			"hbooksvc: could not get block [%s] from record [%s] in stream [%s]",
    94  			name, name, stream.name,
    95  		)
    96  	}
    97  	err = blk.Read(ptr)
    98  	if err != nil {
    99  		return fmt.Errorf(
   100  			"hbooksvc: could not read data from block [%s] from record [%s] in stream [%s]: %w",
   101  			name, name, stream.name, err,
   102  		)
   103  	}
   104  	return err
   105  }
   106  
   107  type ostream struct {
   108  	name  string // stream name
   109  	fname string // file name
   110  	f     io.WriteCloser
   111  	w     *rio.Writer
   112  	objs  []fwk.Hist
   113  }
   114  
   115  func (stream *ostream) write() error {
   116  	for i := range stream.objs {
   117  		obj := stream.objs[i]
   118  		name := string(obj.Name())
   119  		rec := stream.w.Record(name)
   120  		err := rec.Connect(name, obj.Value())
   121  		if err != nil {
   122  			return fmt.Errorf(
   123  				"error writing object [%s] to stream [%s]: %w",
   124  				name, stream.name, err,
   125  			)
   126  		}
   127  
   128  		blk := rec.Block(name)
   129  		err = blk.Write(obj.Value())
   130  		if err != nil {
   131  			return fmt.Errorf(
   132  				"error writing object [%s] to stream [%s]: %w",
   133  				name, stream.name, err,
   134  			)
   135  		}
   136  
   137  		err = rec.Write()
   138  		if err != nil {
   139  			return fmt.Errorf(
   140  				"error writing object [%s] to stream [%s]: %w",
   141  				name, stream.name, err,
   142  			)
   143  		}
   144  	}
   145  
   146  	return nil
   147  }
   148  
   149  func (stream *ostream) close() error {
   150  	defer stream.f.Close() // do not leak file descriptors
   151  	err := stream.w.Close()
   152  	if err != nil {
   153  		return err
   154  	}
   155  
   156  	err = stream.f.Close()
   157  	if err != nil {
   158  		return err
   159  	}
   160  
   161  	return err
   162  }