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 }