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  }