Commit 552f5b26 authored by Felix Lange's avatar Felix Lange

rlp: add functions for encoding

I'm reasonably confident that the encoding matches the output of
ethutil.Encode for values that it supports. Some of the tests have been
adpated from the Ethereum testing repository.

There are still TODOs in the code.
parent bb55307a
...@@ -329,16 +329,10 @@ type field struct { ...@@ -329,16 +329,10 @@ 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 f := typ.Field(i); f.PkgPath == "" { // exported
info, err := cachedTypeInfo1(f.Type)
if err != nil { if err != nil {
return nil, err 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 {
return wrapStreamError(err, typ) return wrapStreamError(err, typ)
......
...@@ -509,7 +509,7 @@ func ExampleStream() { ...@@ -509,7 +509,7 @@ 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()
...@@ -524,7 +524,7 @@ func BenchmarkDecode(b *testing.B) { ...@@ -524,7 +524,7 @@ 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()
...@@ -538,7 +538,7 @@ func BenchmarkDecodeIntSliceReuse(b *testing.B) { ...@@ -538,7 +538,7 @@ func BenchmarkDecodeIntSliceReuse(b *testing.B) {
} }
} }
func encTest(n int) []byte { func encodeTestSlice(n int) []byte {
s := make([]interface{}, n) s := make([]interface{}, n)
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
s[i] = i s[i] = i
......
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