go-ethereum/rlp/typecache.go
Felix Lange 552f5b2693 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.
2015-01-15 11:00:19 +01:00

82 lines
1.8 KiB
Go

package rlp
import (
"reflect"
"sync"
)
var (
typeCacheMutex sync.RWMutex
typeCache = make(map[reflect.Type]*typeinfo)
)
type typeinfo struct {
decoder
writer
}
type decoder func(*Stream, reflect.Value) error
type writer func(reflect.Value, *encbuf) error
func cachedTypeInfo(typ reflect.Type) (*typeinfo, error) {
typeCacheMutex.RLock()
info := typeCache[typ]
typeCacheMutex.RUnlock()
if info != nil {
return info, nil
}
// not in the cache, need to generate info for this type.
typeCacheMutex.Lock()
defer typeCacheMutex.Unlock()
return cachedTypeInfo1(typ)
}
func cachedTypeInfo1(typ reflect.Type) (*typeinfo, error) {
info := typeCache[typ]
if info != nil {
// another goroutine got the write lock first
return info, nil
}
// put a dummmy value into the cache before generating.
// if the generator tries to lookup itself, it will get
// the dummy value and won't call itself recursively.
typeCache[typ] = new(typeinfo)
info, err := genTypeInfo(typ)
if err != nil {
// remove the dummy value if the generator fails
delete(typeCache, typ)
return nil, err
}
*typeCache[typ] = *info
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) {
info = new(typeinfo)
if info.decoder, err = makeDecoder(typ); err != nil {
return nil, err
}
if info.writer, err = makeWriter(typ); err != nil {
return nil, err
}
return info, nil
}
func isUint(k reflect.Kind) bool {
return k >= reflect.Uint && k <= reflect.Uintptr
}