github.com/grailbio/base@v0.0.11/recordio/deprecated/range.go (about) 1 // Copyright 2017 GRAIL, Inc. All rights reserved. 2 // Use of this source code is governed by the Apache-2.0 3 // license that can be found in the LICENSE file. 4 5 package deprecated 6 7 import "io" 8 9 // RangeReader represents an io.ReadSeeker that operates over a restricted 10 // range of the supplied ReadSeeker. Reading and Seeking are consequently 11 // relative to the start of the range used to create the RangeReader. 12 type RangeReader struct { 13 rs io.ReadSeeker 14 start, pos, end int64 15 } 16 17 // NewRangeReader returns a new RangedReader. 18 func NewRangeReader(rs io.ReadSeeker, offset, length int64) (io.ReadSeeker, error) { 19 _, err := rs.Seek(offset, io.SeekStart) 20 if err != nil { 21 return nil, err 22 } 23 return &RangeReader{ 24 rs: rs, 25 start: offset, 26 pos: offset, 27 end: offset + length, 28 }, nil 29 } 30 31 // Read implements io.Read. 32 func (rr *RangeReader) Read(buf []byte) (int, error) { 33 var eof error 34 size := int64(len(buf)) 35 if rr.pos+size >= rr.end { 36 size = rr.end - rr.pos 37 eof = io.EOF 38 } 39 n, err := rr.rs.Read(buf[:size]) 40 if err == nil { 41 err = eof 42 } 43 rr.pos += int64(n) 44 return n, err 45 } 46 47 // Seek implements io.Seek. 48 func (rr *RangeReader) Seek(offset int64, whence int) (int64, error) { 49 pos := rr.start 50 switch whence { 51 case io.SeekStart: 52 pos += offset 53 case io.SeekCurrent: 54 pos = rr.pos + offset 55 case io.SeekEnd: 56 if offset > 0 { 57 offset = 0 58 } 59 pos = rr.end + offset 60 } 61 if pos > rr.end { 62 rr.pos = rr.end 63 return pos, nil 64 } 65 n, err := rr.rs.Seek(pos, io.SeekStart) 66 if err == nil { 67 rr.pos = n 68 } 69 return n - rr.start, err 70 }