diff --git a/utils/codec/zero_copy_reader.go b/utils/codec/zero_copy_reader.go new file mode 100644 index 0000000..f10fa3d --- /dev/null +++ b/utils/codec/zero_copy_reader.go @@ -0,0 +1,160 @@ +package codec + +import ( + "io" + + "github.com/laizy/web3" +) + +type ZeroCopyReader struct { + Source *ZeroCopySource + err error +} + +func (self *ZeroCopyReader) Error() error { + return self.err +} + +// Len returns the number of bytes of the unread portion of the +// slice. +func (self *ZeroCopyReader) Len() uint64 { + return self.Source.Len() +} + +func (self *ZeroCopyReader) Pos() uint64 { + return self.Source.Pos() +} + +// Size returns the original length of the underlying byte slice. +// Size is the number of bytes available for reading via ReadAt. +// The returned value is always the same and is not affected by calls +// to any other method. +func (self *ZeroCopyReader) Size() uint64 { return self.Source.Size() } + +// Read implements the io.ZeroCopyReader interface. +func (self *ZeroCopyReader) ReadBytes(n uint64) (data []byte) { + if self.err != nil { + return + } + data, self.err = self.Source.ReadBytes(n) + return +} + +func (self *ZeroCopyReader) Skip(n uint64) { + if self.err != nil { + return + } + eof := self.Source.Skip(n) + if eof { + self.err = io.ErrUnexpectedEOF + } + return +} + +func (self *ZeroCopyReader) ReadUint8() (data uint8) { + if self.err != nil { + return + } + data, self.err = self.Source.ReadByte() + return +} + +func (self *ZeroCopyReader) ReadBool() (data bool) { + if self.err != nil { + return + } + data, self.err = self.Source.ReadBool() + return +} + +// Backs up a number of bytes, so that the next call to NextXXX() returns data again +// that was already returned by the last call to NextXXX(). +func (self *ZeroCopyReader) BackUp(n uint64) { + self.Source.BackUp(n) +} + +func (self *ZeroCopyReader) ReadUint32() (data uint32) { + if self.err != nil { + return + } + data, self.err = self.Source.ReadUint32BE() + return +} + +func (self *ZeroCopyReader) ReadUint32BE() (data uint32) { + if self.err != nil { + return + } + data, self.err = self.Source.ReadUint32BE() + return +} + +func (self *ZeroCopyReader) ReadUint64() (data uint64) { + if self.err != nil { + return + } + data, self.err = self.Source.ReadUint64() + return +} + +func (self *ZeroCopyReader) ReadUint64BE() (data uint64) { + if self.err != nil { + return + } + data, self.err = self.Source.ReadUint64BE() + return +} + +func (self *ZeroCopyReader) ReadInt32() (data int32) { + return int32(self.ReadUint32()) +} + +func (self *ZeroCopyReader) ReadInt64() (data int64) { + return int64(self.ReadUint64()) +} + +func (self *ZeroCopyReader) ReadString() (data string) { + if self.err != nil { + return + } + data, self.err = self.Source.ReadString() + return +} + +func (self *ZeroCopyReader) ReadVarBytes() (data []byte) { + if self.err != nil { + return nil + } + data, self.err = self.Source.ReadVarBytes() + return data +} + +func (self *ZeroCopyReader) ReadAddress() (addr web3.Address) { + if self.err != nil { + return + } + addr, self.err = self.Source.ReadAddress() + return +} + +func (self *ZeroCopyReader) ReadHash() (hash web3.Hash) { + if self.err != nil { + return + } + hash, self.err = self.Source.ReadHash() + return +} + +func (self *ZeroCopyReader) ReadVarUint() (data uint64) { + if self.err != nil { + return + } + data, self.err = self.Source.ReadVarUint() + return +} + +func NewZeroCopyReader(b []byte) *ZeroCopyReader { + return &ZeroCopyReader{ + Source: NewZeroCopySource(b), + } +} diff --git a/utils/codec/zero_copy_source.go b/utils/codec/zero_copy_source.go index 6cba265..6743d2c 100644 --- a/utils/codec/zero_copy_source.go +++ b/utils/codec/zero_copy_source.go @@ -96,10 +96,23 @@ func (self *ZeroCopySource) NextByte() (data byte, eof bool) { return b, false } +func (self *ZeroCopySource) ReadByte() (data byte, err error) { + d, eof := self.NextByte() + if eof { + err = io.ErrUnexpectedEOF + return + } + return d, nil +} + +func (self *ZeroCopySource) ReadUint8() (data uint8, err error) { + return self.ReadByte() +} + func (self *ZeroCopySource) NextUint8() (data uint8, eof bool) { var val byte val, eof = self.NextByte() - return uint8(val), eof + return val, eof } func (self *ZeroCopySource) NextBool() (data bool, irregular bool, eof bool) { @@ -116,9 +129,24 @@ func (self *ZeroCopySource) NextBool() (data bool, irregular bool, eof bool) { return } +func (self *ZeroCopySource) ReadBool() (data bool, err error) { + d, irr, eof := self.NextBool() + if eof { + err = io.ErrUnexpectedEOF + return + } else if irr { + err = ErrIrregularData + return + } + return d, nil +} + // Backs up a number of bytes, so that the next call to NextXXX() returns data again // that was already returned by the last call to NextXXX(). func (self *ZeroCopySource) BackUp(n uint64) { + if n > self.off { + panic("backup too large") + } self.off -= n } @@ -224,6 +252,16 @@ func (self *ZeroCopySource) ReadString() (string, error) { return string(d), err } +func (self *ZeroCopySource) ReadBytes(n uint64) (data []byte, err error) { + d, eof := self.NextBytes(n) + if eof { + err = io.ErrUnexpectedEOF + return + } + + return d, nil +} + func (self *ZeroCopySource) ReadVarBytes() (data []byte, err error) { data, _, irr, eof := self.NextVarBytes() if irr { @@ -283,6 +321,18 @@ func (self *ZeroCopySource) NextString() (data string, size uint64, irregular bo return } +func (self *ZeroCopySource) ReadVarUint() (data uint64, err error) { + d, _, irr, eof := self.NextVarUint() + if eof { + err = io.ErrUnexpectedEOF + return + } else if irr { + err = ErrIrregularData + return + } + return d, nil +} + func (self *ZeroCopySource) NextVarUint() (data uint64, size uint64, irregular bool, eof bool) { var fb byte fb, eof = self.NextByte() @@ -345,3 +395,7 @@ func NewZeroCopySource(b []byte) *ZeroCopySource { byteOrder: binary.LittleEndian, } } + +func (self *ZeroCopySource) Reader() *ZeroCopyReader { + return &ZeroCopyReader{Source: self} +}