Commit a19d2c22 authored by obscuren's avatar obscuren

Merge branch 'develop' into refactor

parents ca74bcc4 cad770c7
This diff is collapsed.
This diff is collapsed.
/*
Package rlp implements the RLP serialization format.
The purpose of RLP (Recursive Linear Prefix) qis to encode arbitrarily
nested arrays of binary data, and RLP is the main encoding method used
to serialize objects in Ethereum. The only purpose of RLP is to encode
structure; encoding specific atomic data types (eg. strings, ints,
floats) is left up to higher-order protocols; in Ethereum integers
must be represented in big endian binary form with no leading zeroes
(thus making the integer value zero be equivalent to the empty byte
array).
RLP values are distinguished by a type tag. The type tag precedes the
value in the input stream and defines the size and kind of the bytes
that follow.
*/
package rlp
package rlp
import (
"fmt"
"math/big"
"reflect"
"sync"
)
type decoder func(*Stream, reflect.Value) error
type typeinfo struct {
decoder
}
var (
typeCacheMutex sync.RWMutex
typeCache = make(map[reflect.Type]*typeinfo)
)
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
}
var (
decoderInterface = reflect.TypeOf(new(Decoder)).Elem()
bigInt = reflect.TypeOf(big.Int{})
)
func genTypeInfo(typ reflect.Type) (info *typeinfo, err error) {
info = new(typeinfo)
kind := typ.Kind()
switch {
case typ.Implements(decoderInterface):
info.decoder = decodeDecoder
case kind != reflect.Ptr && reflect.PtrTo(typ).Implements(decoderInterface):
info.decoder = decodeDecoderNoPtr
case typ.AssignableTo(reflect.PtrTo(bigInt)):
info.decoder = decodeBigInt
case typ.AssignableTo(bigInt):
info.decoder = decodeBigIntNoPtr
case isInteger(kind):
info.decoder = makeNumDecoder(typ)
case kind == reflect.String:
info.decoder = decodeString
case kind == reflect.Slice || kind == reflect.Array:
info.decoder, err = makeListDecoder(typ)
case kind == reflect.Struct:
info.decoder, err = makeStructDecoder(typ)
case kind == reflect.Ptr:
info.decoder, err = makePtrDecoder(typ)
case kind == reflect.Interface && typ.NumMethod() == 0:
info.decoder = decodeInterface
default:
err = fmt.Errorf("rlp: type %v is not RLP-serializable", typ)
}
return info, err
}
func isInteger(k reflect.Kind) bool {
return k >= reflect.Int && k <= reflect.Uintptr
}
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