github.com/scottcagno/storage@v1.8.0/pkg/bio/reader.go (about) 1 package bio 2 3 import ( 4 "bufio" 5 "fmt" 6 "io" 7 ) 8 9 // Reader is a bio reader that implements the 10 // io.Reader and io.ReaderAt interfaces 11 type Reader struct { 12 br *bufio.Reader 13 } 14 15 // NewReader returns a new *Reader whose buffer has 16 // an underlying size of chunkSize. A Reader reads 17 // fixed size blocks of data into fixed size chunks, 18 // also sometimes called spans. 19 func NewReader(r io.Reader) *Reader { 20 // create and return a new *Reader 21 return &Reader{ 22 br: bufio.NewReaderSize(r, chunkSize), 23 } 24 } 25 26 // ReadRecord read and returns the next record sequentially 27 func (r *Reader) ReadRecord() ([]byte, error) { 28 // implement... 29 return nil, nil 30 } 31 32 // ReadRecordAt reads and returns the record located at the provided offset 33 func (r *Reader) ReadRecordAt(offset int64) ([]byte, error) { 34 // implement... 35 return nil, nil 36 } 37 38 // Read reads data into p. It returns the number of bytes read 39 // into p. At EOF, the count will be zero and err will be io.EOF. 40 func (r *Reader) Read(p []byte) (int, error) { 41 // perform error checking 42 if p == nil { 43 return -1, ErrDataIsEmpty 44 } 45 if len(p) > maxDataPerChunk { 46 return -1, ErrSliceTooLarge 47 } 48 if len(p) < blockSize { 49 return -1, ErrSliceTooSmall 50 } 51 // init error var for later 52 var err error 53 // start reading blocks sequentially 54 for i := 0; i < len(p); i += blockSize { 55 // setup j to be the slice ending boundary 56 j := i + blockSize 57 // necessary check to avoid slicing beyond p's capacity 58 if j > len(p) { 59 j = len(p) 60 } 61 // read block (a slice of p, from i to j) 62 _, err = r.readBlock(p[i:j]) 63 if err != nil { 64 return -1, err 65 } 66 } 67 // return 68 return 0, nil 69 } 70 71 func (r *Reader) readBlock(p []byte) (int, error) { 72 // error check p 73 if len(p) != blockSize { 74 return -1, ErrInvalidSize 75 } 76 // read block 77 n, err := r.br.Read(p) 78 if err != nil { 79 return -1, err 80 } 81 // return 82 return n, nil 83 } 84 85 func (r *Reader) readRecord() ([]byte, error) { 86 // init vars 87 var parts uint8 88 var length uint16 89 // peek into header bytes, to find block count 90 hdr, err := r.br.Peek(headerSize) 91 if err != nil { 92 return nil, err 93 } 94 // store block count for this record 95 parts = hdr[3] 96 // make slice large enough to hold record 97 record := make([]byte, parts*maxDataPerBlock) 98 // start the iteration 99 for i := 0; i < int(parts); i++ { 100 // peek into header bytes, to find block count 101 hdr, err := r.br.Peek(headerSize) 102 if err != nil { 103 return nil, err 104 } 105 // get record length 106 rlength := uint16(hdr[4]) | uint16(hdr[5])<<8 107 // skip past header 108 _, err = r.br.Discard(headerSize) 109 if err != nil { 110 return nil, err 111 } 112 // calculate offset 113 off := i * blockSize 114 // read into record and return 115 _, err = r.br.Read(record[off : off+int(rlength)]) 116 if err != nil { 117 return nil, err 118 } 119 // discard any padding 120 if rlength != maxDataPerBlock { 121 skip := maxDataPerBlock - int(rlength) 122 _, err = r.br.Discard(skip) 123 if err != nil { 124 return nil, err 125 } 126 } 127 // add to length 128 length += rlength 129 } 130 // return record 131 return record[:], nil 132 } 133 134 // ReadAt reads len(p) bytes into p starting at offset off in the 135 // underlying input source. It returns the number of bytes 136 // read (0 <= n <= len(p)) and any error encountered. 137 func (r *Reader) ReadAt(p []byte) (int, error) { 138 139 // implement me 140 return 0, nil 141 } 142 143 // String is *Reader's stringer method 144 func (r *Reader) String() string { 145 ss := fmt.Sprintf("%#+v", r.br) 146 return ss 147 }