github.com/bazelbuild/remote-apis-sdks@v0.0.0-20240425170053-8a36686a6350/go/pkg/cas/ioutil.go (about)

     1  package cas
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"fmt"
     7  	"io"
     8  	"os"
     9  	"sync"
    10  )
    11  
    12  // This file contains various IO utility types and functions.
    13  
    14  // uploadSource is a common interface to in-memory blobs and files.
    15  // SeekStart is like io.Seeker.Seek, but only supports io.SeekStart.
    16  type uploadSource interface {
    17  	io.Reader
    18  	io.Closer
    19  	SeekStart(offset int64) error
    20  }
    21  
    22  // byteSliceSource implements uploadSource on top of []byte.
    23  type byteSliceSource struct {
    24  	io.Reader
    25  	content []byte
    26  }
    27  
    28  func newByteSliceSource(content []byte) *byteSliceSource {
    29  	return &byteSliceSource{Reader: bytes.NewReader(content), content: content}
    30  }
    31  
    32  func (s *byteSliceSource) SeekStart(offset int64) error {
    33  	if offset < 0 || offset >= int64(len(s.content)) {
    34  		return fmt.Errorf("offset out of range")
    35  	}
    36  	s.Reader = bytes.NewReader(s.content[offset:])
    37  	return nil
    38  }
    39  
    40  func (s *byteSliceSource) Close() error {
    41  	return nil
    42  }
    43  
    44  // fileSource implements uploadSource on top of *os.File, with buffering.
    45  //
    46  // Buffering is done using a reusable bufio.Reader.
    47  // When the fileSource is closed, the bufio.Reader is placed back to a pool.
    48  type fileSource struct {
    49  	f     *os.File
    50  	r     *bufio.Reader
    51  	rPool *sync.Pool
    52  }
    53  
    54  func newFileSource(f *os.File, bufReaders *sync.Pool) *fileSource {
    55  	r := bufReaders.Get().(*bufio.Reader)
    56  	r.Reset(f)
    57  	return &fileSource{
    58  		f:     f,
    59  		r:     r,
    60  		rPool: bufReaders,
    61  	}
    62  }
    63  
    64  func (f *fileSource) Read(p []byte) (int, error) {
    65  	return f.r.Read(p)
    66  }
    67  
    68  func (f *fileSource) SeekStart(offset int64) error {
    69  	if _, err := f.f.Seek(offset, io.SeekStart); err != nil {
    70  		return err
    71  	}
    72  	f.r.Reset(f.f)
    73  	return nil
    74  }
    75  
    76  func (f *fileSource) Close() error {
    77  	if err := f.f.Close(); err != nil {
    78  		return err
    79  	}
    80  
    81  	// Put it back to the pool only after closing the file, so that we don't try
    82  	// to put it back twice in case Close() is called again.
    83  	f.rPool.Put(f.r)
    84  	return nil
    85  }