@ -91,13 +91,6 @@ func EncodeToReader(val interface{}) (size int, r io.Reader, err error) {
return eb . size ( ) , & encReader { buf : eb } , nil
}
type encbuf struct {
str [ ] byte // string data, contains everything except list headers
lheads [ ] listhead // all list headers
lhsize int // sum of sizes of all encoded list headers
sizebuf [ ] byte // 9-byte auxiliary buffer for uint encoding
}
type listhead struct {
offset int // index of this header in string data
size int // total size of encoded data (including list headers)
@ -130,9 +123,20 @@ func puthead(buf []byte, smalltag, largetag byte, size uint64) int {
return sizesize + 1
}
type encbuf struct {
str [ ] byte // string data, contains everything except list headers
lheads [ ] listhead // all list headers
lhsize int // sum of sizes of all encoded list headers
sizebuf [ 9 ] byte // auxiliary buffer for uint encoding
bufvalue reflect . Value // used in writeByteArrayCopy
}
// encbufs are pooled.
var encbufPool = sync . Pool {
New : func ( ) interface { } { return & encbuf { sizebuf : make ( [ ] byte , 9 ) } } ,
New : func ( ) interface { } {
var bytes [ ] byte
return & encbuf { bufvalue : reflect . ValueOf ( & bytes ) . Elem ( ) }
} ,
}
func ( w * encbuf ) reset ( ) {
@ -160,7 +164,6 @@ func (w *encbuf) encodeStringHeader(size int) {
if size < 56 {
w . str = append ( w . str , 0x80 + byte ( size ) )
} else {
// TODO: encode to w.str directly
sizesize := putint ( w . sizebuf [ 1 : ] , uint64 ( size ) )
w . sizebuf [ 0 ] = 0xB7 + byte ( sizesize )
w . str = append ( w . str , w . sizebuf [ : sizesize + 1 ] ... )
@ -177,6 +180,19 @@ func (w *encbuf) encodeString(b []byte) {
}
}
func ( w * encbuf ) encodeUint ( i uint64 ) {
if i == 0 {
w . str = append ( w . str , 0x80 )
} else if i < 128 {
// fits single byte
w . str = append ( w . str , byte ( i ) )
} else {
s := putint ( w . sizebuf [ 1 : ] , i )
w . sizebuf [ 0 ] = 0x80 + byte ( s )
w . str = append ( w . str , w . sizebuf [ : s + 1 ] ... )
}
}
// list adds a new list header to the header stack. It returns the index
// of the header. The caller must call listEnd with this index after encoding
// the content of the list.
@ -229,7 +245,7 @@ func (w *encbuf) toWriter(out io.Writer) (err error) {
}
}
// write the header
enc := head . encode ( w . sizebuf )
enc := head . encode ( w . sizebuf [ : ] )
if _ , err = out . Write ( enc ) ; err != nil {
return err
}
@ -295,7 +311,7 @@ func (r *encReader) next() []byte {
return p
}
r . lhpos ++
return head . encode ( r . buf . sizebuf )
return head . encode ( r . buf . sizebuf [ : ] )
case r . strpos < len ( r . buf . str ) :
// String data at the end, after all list headers.
@ -308,10 +324,7 @@ func (r *encReader) next() []byte {
}
}
var (
encoderInterface = reflect . TypeOf ( new ( Encoder ) ) . Elem ( )
big0 = big . NewInt ( 0 )
)
var encoderInterface = reflect . TypeOf ( new ( Encoder ) ) . Elem ( )
// makeWriter creates a writer function for the given type.
func makeWriter ( typ reflect . Type , ts tags ) ( writer , error ) {
@ -336,7 +349,7 @@ func makeWriter(typ reflect.Type, ts tags) (writer, error) {
case kind == reflect . Slice && isByte ( typ . Elem ( ) ) :
return writeBytes , nil
case kind == reflect . Array && isByte ( typ . Elem ( ) ) :
return writeByteArray , nil
return makeByteArrayWriter ( typ ) , nil
case kind == reflect . Slice || kind == reflect . Array :
return makeSliceWriter ( typ , ts )
case kind == reflect . Struct :
@ -348,28 +361,13 @@ func makeWriter(typ reflect.Type, ts tags) (writer, error) {
}
}
func isByte ( typ reflect . Type ) bool {
return typ . Kind ( ) == reflect . Uint8 && ! typ . Implements ( encoderInterface )
}
func writeRawValue ( val reflect . Value , w * encbuf ) error {
w . str = append ( w . str , val . Bytes ( ) ... )
return nil
}
func writeUint ( val reflect . Value , w * encbuf ) error {
i := val . Uint ( )
if i == 0 {
w . str = append ( w . str , 0x80 )
} else if i < 128 {
// fits single byte
w . str = append ( w . str , byte ( i ) )
} else {
// TODO: encode int to w.str directly
s := putint ( w . sizebuf [ 1 : ] , i )
w . sizebuf [ 0 ] = 0x80 + byte ( s )
w . str = append ( w . str , w . sizebuf [ : s + 1 ] ... )
}
w . encodeUint ( val . Uint ( ) )
return nil
}
@ -396,13 +394,32 @@ func writeBigIntNoPtr(val reflect.Value, w *encbuf) error {
return writeBigInt ( & i , w )
}
// wordBytes is the number of bytes in a big.Word
const wordBytes = ( 32 << ( uint64 ( ^ big . Word ( 0 ) ) >> 63 ) ) / 8
func writeBigInt ( i * big . Int , w * encbuf ) error {
if cmp := i . Cmp ( big0 ) ; cmp == - 1 {
if i . Sign ( ) == - 1 {
return fmt . Errorf ( "rlp: cannot encode negative *big.Int" )
} else if cmp == 0 {
w . str = append ( w . str , 0x80 )
} else {
w . encodeString ( i . Bytes ( ) )
}
bitlen := i . BitLen ( )
if bitlen <= 64 {
w . encodeUint ( i . Uint64 ( ) )
return nil
}
// Integer is larger than 64 bits, encode from i.Bits().
// The minimal byte length is bitlen rounded up to the next
// multiple of 8, divided by 8.
length := ( ( bitlen + 7 ) & - 8 ) >> 3
w . encodeStringHeader ( length )
w . str = append ( w . str , make ( [ ] byte , length ) ... )
index := length
buf := w . str [ len ( w . str ) - length : ]
for _ , d := range i . Bits ( ) {
for j := 0 ; j < wordBytes && index > 0 ; j ++ {
index --
buf [ index ] = byte ( d )
d >>= 8
}
}
return nil
}
@ -412,7 +429,52 @@ func writeBytes(val reflect.Value, w *encbuf) error {
return nil
}
func writeByteArray ( val reflect . Value , w * encbuf ) error {
var byteType = reflect . TypeOf ( byte ( 0 ) )
func makeByteArrayWriter ( typ reflect . Type ) writer {
length := typ . Len ( )
if length == 0 {
return writeLengthZeroByteArray
} else if length == 1 {
return writeLengthOneByteArray
}
if typ . Elem ( ) != byteType {
return writeNamedByteArray
}
return func ( val reflect . Value , w * encbuf ) error {
writeByteArrayCopy ( length , val , w )
return nil
}
}
func writeLengthZeroByteArray ( val reflect . Value , w * encbuf ) error {
w . str = append ( w . str , 0x80 )
return nil
}
func writeLengthOneByteArray ( val reflect . Value , w * encbuf ) error {
b := byte ( val . Index ( 0 ) . Uint ( ) )
if b <= 0x7f {
w . str = append ( w . str , b )
} else {
w . str = append ( w . str , 0x81 , b )
}
return nil
}
// writeByteArrayCopy encodes byte arrays using reflect.Copy. This is
// the fast path for [N]byte where N > 1.
func writeByteArrayCopy ( length int , val reflect . Value , w * encbuf ) {
w . encodeStringHeader ( length )
offset := len ( w . str )
w . str = append ( w . str , make ( [ ] byte , length ) ... )
w . bufvalue . SetBytes ( w . str [ offset : ] )
reflect . Copy ( w . bufvalue , val )
}
// writeNamedByteArray encodes byte arrays with named element type.
// This exists because reflect.Copy can't be used with such types.
func writeNamedByteArray ( val reflect . Value , w * encbuf ) error {
if ! val . CanAddr ( ) {
// Slice requires the value to be addressable.
// Make it addressable by copying.