github.com/hamba/avro@v1.8.0/reader.go (about)

     1  package avro
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"io"
     7  	"unsafe"
     8  )
     9  
    10  const (
    11  	maxIntBufSize  = 5
    12  	maxLongBufSize = 10
    13  )
    14  
    15  // ReaderFunc is a function used to customize the Reader.
    16  type ReaderFunc func(r *Reader)
    17  
    18  // WithReaderConfig specifies the configuration to use with a reader.
    19  func WithReaderConfig(cfg API) ReaderFunc {
    20  	return func(r *Reader) {
    21  		r.cfg = cfg.(*frozenConfig)
    22  	}
    23  }
    24  
    25  // Reader is an Avro specific io.Reader.
    26  type Reader struct {
    27  	cfg    *frozenConfig
    28  	reader io.Reader
    29  	buf    []byte
    30  	head   int
    31  	tail   int
    32  	Error  error
    33  }
    34  
    35  // NewReader creates a new Reader.
    36  func NewReader(r io.Reader, bufSize int, opts ...ReaderFunc) *Reader {
    37  	reader := &Reader{
    38  		cfg:    DefaultConfig.(*frozenConfig),
    39  		reader: r,
    40  		buf:    make([]byte, bufSize),
    41  		head:   0,
    42  		tail:   0,
    43  	}
    44  
    45  	for _, opt := range opts {
    46  		opt(reader)
    47  	}
    48  
    49  	return reader
    50  }
    51  
    52  // Reset resets a Reader with a new byte array attached.
    53  func (r *Reader) Reset(b []byte) *Reader {
    54  	r.reader = nil
    55  	r.buf = b
    56  	r.head = 0
    57  	r.tail = len(b)
    58  
    59  	return r
    60  }
    61  
    62  // ReportError record a error in iterator instance with current position.
    63  func (r *Reader) ReportError(operation, msg string) {
    64  	if r.Error != nil && !errors.Is(r.Error, io.EOF) {
    65  		return
    66  	}
    67  
    68  	r.Error = fmt.Errorf("avro: %s: %s", operation, msg)
    69  }
    70  
    71  func (r *Reader) loadMore() bool {
    72  	if r.reader == nil {
    73  		if r.Error == nil {
    74  			r.head = r.tail
    75  			r.Error = io.EOF
    76  		}
    77  
    78  		return false
    79  	}
    80  
    81  	for {
    82  		n, err := r.reader.Read(r.buf)
    83  		if n == 0 {
    84  			if err != nil {
    85  				if r.Error == nil {
    86  					r.Error = err
    87  				}
    88  
    89  				return false
    90  			}
    91  
    92  			continue
    93  		}
    94  
    95  		r.head = 0
    96  		r.tail = n
    97  		return true
    98  	}
    99  }
   100  
   101  func (r *Reader) readByte() byte {
   102  	if r.head == r.tail {
   103  		if !r.loadMore() {
   104  			return 0
   105  		}
   106  	}
   107  
   108  	b := r.buf[r.head]
   109  	r.head++
   110  
   111  	return b
   112  }
   113  
   114  // Read reads data into the given bytes.
   115  func (r *Reader) Read(b []byte) {
   116  	size := len(b)
   117  	read := 0
   118  
   119  	for read < size {
   120  		if r.head == r.tail {
   121  			if !r.loadMore() {
   122  				return
   123  			}
   124  		}
   125  
   126  		n := copy(b[read:], r.buf[r.head:r.tail])
   127  		r.head += n
   128  		read += n
   129  	}
   130  }
   131  
   132  // ReadBool reads a Bool from the Reader.
   133  func (r *Reader) ReadBool() bool {
   134  	b := r.readByte()
   135  
   136  	if b != 0 && b != 1 {
   137  		r.ReportError("ReadBool", "invalid bool")
   138  	}
   139  
   140  	return b == 1
   141  }
   142  
   143  // ReadInt reads an Int from the Reader.
   144  func (r *Reader) ReadInt() int32 {
   145  	var val uint32
   146  	var offset int8
   147  
   148  	for r.Error == nil {
   149  		if offset == maxIntBufSize {
   150  			r.ReportError("ReadInt", "int overflow")
   151  			return 0
   152  		}
   153  
   154  		b := r.readByte()
   155  		val |= uint32(b&0x7F) << uint(7*offset)
   156  		if b&0x80 == 0 {
   157  			break
   158  		}
   159  
   160  		offset++
   161  	}
   162  
   163  	return int32((val >> 1) ^ -(val & 1))
   164  }
   165  
   166  // ReadLong reads a Long from the Reader.
   167  func (r *Reader) ReadLong() int64 {
   168  	var val uint64
   169  	var offset int8
   170  
   171  	for r.Error == nil {
   172  		if offset == maxLongBufSize {
   173  			r.ReportError("ReadLong", "long overflow")
   174  			return 0
   175  		}
   176  
   177  		b := r.readByte()
   178  		val |= uint64(b&0x7F) << uint(7*offset)
   179  		if b&0x80 == 0 {
   180  			break
   181  		}
   182  
   183  		offset++
   184  	}
   185  
   186  	return int64((val >> 1) ^ -(val & 1))
   187  }
   188  
   189  // ReadFloat reads a Float from the Reader.
   190  func (r *Reader) ReadFloat() float32 {
   191  	var buf [4]byte
   192  	r.Read(buf[:])
   193  
   194  	float := *(*float32)(unsafe.Pointer(&buf[0]))
   195  
   196  	return float
   197  }
   198  
   199  // ReadDouble reads a Double from the Reader.
   200  func (r *Reader) ReadDouble() float64 {
   201  	var buf [8]byte
   202  	r.Read(buf[:])
   203  
   204  	float := *(*float64)(unsafe.Pointer(&buf[0]))
   205  
   206  	return float
   207  }
   208  
   209  // ReadBytes reads Bytes from the Reader.
   210  func (r *Reader) ReadBytes() []byte {
   211  	size := r.ReadLong()
   212  	if size < 0 {
   213  		r.ReportError("ReadBytes", "invalid bytes length")
   214  		return nil
   215  	}
   216  
   217  	buf := make([]byte, size)
   218  	r.Read(buf)
   219  
   220  	return buf
   221  }
   222  
   223  // ReadString reads a String from the Reader.
   224  func (r *Reader) ReadString() string {
   225  	size := int(r.ReadLong())
   226  	if size < 0 {
   227  		r.ReportError("ReadString", "invalid string length")
   228  		return ""
   229  	}
   230  
   231  	// The string is entirely in the current buffer, fast path.
   232  	if r.head+size <= r.tail {
   233  		ret := string(r.buf[r.head : r.head+size])
   234  		r.head += size
   235  		return ret
   236  	}
   237  
   238  	buf := make([]byte, size)
   239  	r.Read(buf)
   240  
   241  	return *(*string)(unsafe.Pointer(&buf))
   242  }
   243  
   244  // ReadBlockHeader reads a Block Header from the Reader.
   245  func (r *Reader) ReadBlockHeader() (int64, int64) {
   246  	length := r.ReadLong()
   247  	if length < 0 {
   248  		size := r.ReadLong()
   249  
   250  		return -length, size
   251  	}
   252  
   253  	return length, 0
   254  }