Commit 52bb1495 authored by Jeffrey Wilcke's avatar Jeffrey Wilcke

Merge pull request #257 from fjl/rlp-encoder

rlp: add functions for encoding
parents bb55307a 29c46cdf
...@@ -329,15 +329,9 @@ type field struct { ...@@ -329,15 +329,9 @@ type field struct {
} }
func makeStructDecoder(typ reflect.Type) (decoder, error) { func makeStructDecoder(typ reflect.Type) (decoder, error) {
var fields []field fields, err := structFields(typ)
for i := 0; i < typ.NumField(); i++ { if err != nil {
if f := typ.Field(i); f.PkgPath == "" { // exported return nil, err
info, err := cachedTypeInfo1(f.Type)
if err != nil {
return nil, err
}
fields = append(fields, field{i, info})
}
} }
dec := func(s *Stream, val reflect.Value) (err error) { dec := func(s *Stream, val reflect.Value) (err error) {
if _, err = s.List(); err != nil { if _, err = s.List(); err != nil {
......
...@@ -8,8 +8,6 @@ import ( ...@@ -8,8 +8,6 @@ import (
"math/big" "math/big"
"reflect" "reflect"
"testing" "testing"
"github.com/ethereum/go-ethereum/ethutil"
) )
func TestStreamKind(t *testing.T) { func TestStreamKind(t *testing.T) {
...@@ -509,13 +507,13 @@ func ExampleStream() { ...@@ -509,13 +507,13 @@ func ExampleStream() {
} }
func BenchmarkDecode(b *testing.B) { func BenchmarkDecode(b *testing.B) {
enc := encTest(90000) enc := encodeTestSlice(90000)
b.SetBytes(int64(len(enc))) b.SetBytes(int64(len(enc)))
b.ReportAllocs() b.ReportAllocs()
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
var s []int var s []uint
r := bytes.NewReader(enc) r := bytes.NewReader(enc)
if err := Decode(r, &s); err != nil { if err := Decode(r, &s); err != nil {
b.Fatalf("Decode error: %v", err) b.Fatalf("Decode error: %v", err)
...@@ -524,12 +522,12 @@ func BenchmarkDecode(b *testing.B) { ...@@ -524,12 +522,12 @@ func BenchmarkDecode(b *testing.B) {
} }
func BenchmarkDecodeIntSliceReuse(b *testing.B) { func BenchmarkDecodeIntSliceReuse(b *testing.B) {
enc := encTest(100000) enc := encodeTestSlice(100000)
b.SetBytes(int64(len(enc))) b.SetBytes(int64(len(enc)))
b.ReportAllocs() b.ReportAllocs()
b.ResetTimer() b.ResetTimer()
var s []int var s []uint
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
r := bytes.NewReader(enc) r := bytes.NewReader(enc)
if err := Decode(r, &s); err != nil { if err := Decode(r, &s); err != nil {
...@@ -538,12 +536,16 @@ func BenchmarkDecodeIntSliceReuse(b *testing.B) { ...@@ -538,12 +536,16 @@ func BenchmarkDecodeIntSliceReuse(b *testing.B) {
} }
} }
func encTest(n int) []byte { func encodeTestSlice(n uint) []byte {
s := make([]interface{}, n) s := make([]uint, n)
for i := 0; i < n; i++ { for i := uint(0); i < n; i++ {
s[i] = i s[i] = i
} }
return ethutil.Encode(s) b, err := EncodeToBytes(s)
if err != nil {
panic(fmt.Sprintf("encode error: %v", err))
}
return b
} }
func unhex(str string) []byte { func unhex(str string) []byte {
......
This diff is collapsed.
This diff is collapsed.
package rlp
import (
"fmt"
"io"
)
type MyCoolType struct {
Name string
a, b uint
}
// EncodeRLP writes x as RLP list [a, b] that omits the Name field.
func (x *MyCoolType) EncodeRLP(w io.Writer) (err error) {
// Note: the receiver can be a nil pointer. This allows you to
// control the encoding of nil, but it also means that you have to
// check for a nil receiver.
if x == nil {
err = Encode(w, []uint{0, 0})
} else {
err = Encode(w, []uint{x.a, x.b})
}
return err
}
func ExampleEncoder() {
var t *MyCoolType // t is nil pointer to MyCoolType
bytes, _ := EncodeToBytes(t)
fmt.Printf("%v → %X\n", t, bytes)
t = &MyCoolType{Name: "foobar", a: 5, b: 6}
bytes, _ = EncodeToBytes(t)
fmt.Printf("%v → %X\n", t, bytes)
// Output:
// <nil> → C28080
// &{foobar 5 6} → C20506
}
...@@ -5,16 +5,19 @@ import ( ...@@ -5,16 +5,19 @@ import (
"sync" "sync"
) )
type decoder func(*Stream, reflect.Value) error var (
typeCacheMutex sync.RWMutex
typeCache = make(map[reflect.Type]*typeinfo)
)
type typeinfo struct { type typeinfo struct {
decoder decoder
writer
} }
var ( type decoder func(*Stream, reflect.Value) error
typeCacheMutex sync.RWMutex
typeCache = make(map[reflect.Type]*typeinfo) type writer func(reflect.Value, *encbuf) error
)
func cachedTypeInfo(typ reflect.Type) (*typeinfo, error) { func cachedTypeInfo(typ reflect.Type) (*typeinfo, error) {
typeCacheMutex.RLock() typeCacheMutex.RLock()
...@@ -49,11 +52,27 @@ func cachedTypeInfo1(typ reflect.Type) (*typeinfo, error) { ...@@ -49,11 +52,27 @@ func cachedTypeInfo1(typ reflect.Type) (*typeinfo, error) {
return typeCache[typ], err return typeCache[typ], err
} }
func structFields(typ reflect.Type) (fields []field, err error) {
for i := 0; i < typ.NumField(); i++ {
if f := typ.Field(i); f.PkgPath == "" { // exported
info, err := cachedTypeInfo1(f.Type)
if err != nil {
return nil, err
}
fields = append(fields, field{i, info})
}
}
return fields, nil
}
func genTypeInfo(typ reflect.Type) (info *typeinfo, err error) { func genTypeInfo(typ reflect.Type) (info *typeinfo, err error) {
info = new(typeinfo) info = new(typeinfo)
if info.decoder, err = makeDecoder(typ); err != nil { if info.decoder, err = makeDecoder(typ); err != nil {
return nil, err return nil, err
} }
if info.writer, err = makeWriter(typ); err != nil {
return nil, err
}
return info, nil return info, nil
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment