mirror of https://github.com/ethereum/go-ethereum
In order to make this happen, kill all remaining trivial uses of common/{rlp,value}.go. The non-trivial ones have been updated earlier.pull/2064/head
parent
1b89bd5d26
commit
e6fb69296e
@ -1,139 +0,0 @@ |
||||
// Copyright 2014 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package common |
||||
|
||||
import ( |
||||
"archive/zip" |
||||
"encoding/json" |
||||
"fmt" |
||||
"io" |
||||
"io/ioutil" |
||||
"strings" |
||||
) |
||||
|
||||
// Manifest object
|
||||
//
|
||||
// The manifest object holds all the relevant information supplied with the
|
||||
// the manifest specified in the package
|
||||
type Manifest struct { |
||||
Entry string |
||||
Height, Width int |
||||
} |
||||
|
||||
// External package
|
||||
//
|
||||
// External package contains the main html file and manifest
|
||||
type ExtPackage struct { |
||||
EntryHtml string |
||||
Manifest *Manifest |
||||
} |
||||
|
||||
// Read file
|
||||
//
|
||||
// Read a given compressed file and returns the read bytes.
|
||||
// Returns an error otherwise
|
||||
func ReadFile(f *zip.File) ([]byte, error) { |
||||
rc, err := f.Open() |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
defer rc.Close() |
||||
|
||||
content, err := ioutil.ReadAll(rc) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return content, nil |
||||
} |
||||
|
||||
// Reads manifest
|
||||
//
|
||||
// Reads and returns a manifest object. Returns error otherwise
|
||||
func ReadManifest(m []byte) (*Manifest, error) { |
||||
var manifest Manifest |
||||
|
||||
dec := json.NewDecoder(strings.NewReader(string(m))) |
||||
if err := dec.Decode(&manifest); err == io.EOF { |
||||
} else if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return &manifest, nil |
||||
} |
||||
|
||||
// Find file in archive
|
||||
//
|
||||
// Returns the index of the given file name if it exists. -1 if file not found
|
||||
func FindFileInArchive(fn string, files []*zip.File) (index int) { |
||||
index = -1 |
||||
// Find the manifest first
|
||||
for i, f := range files { |
||||
if f.Name == fn { |
||||
index = i |
||||
} |
||||
} |
||||
|
||||
return |
||||
} |
||||
|
||||
// Open package
|
||||
//
|
||||
// Opens a prepared ethereum package
|
||||
// Reads the manifest file and determines file contents and returns and
|
||||
// the external package.
|
||||
func OpenPackage(fn string) (*ExtPackage, error) { |
||||
r, err := zip.OpenReader(fn) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
defer r.Close() |
||||
|
||||
manifestIndex := FindFileInArchive("manifest.json", r.File) |
||||
|
||||
if manifestIndex < 0 { |
||||
return nil, fmt.Errorf("No manifest file found in archive") |
||||
} |
||||
|
||||
f, err := ReadFile(r.File[manifestIndex]) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
manifest, err := ReadManifest(f) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
if manifest.Entry == "" { |
||||
return nil, fmt.Errorf("Entry file specified but appears to be empty: %s", manifest.Entry) |
||||
} |
||||
|
||||
entryIndex := FindFileInArchive(manifest.Entry, r.File) |
||||
if entryIndex < 0 { |
||||
return nil, fmt.Errorf("Entry file not found: '%s'", manifest.Entry) |
||||
} |
||||
|
||||
f, err = ReadFile(r.File[entryIndex]) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
extPackage := &ExtPackage{string(f), manifest} |
||||
|
||||
return extPackage, nil |
||||
} |
@ -1,292 +0,0 @@ |
||||
// Copyright 2014 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package common |
||||
|
||||
import ( |
||||
"bytes" |
||||
"fmt" |
||||
"math/big" |
||||
"reflect" |
||||
) |
||||
|
||||
type RlpEncode interface { |
||||
RlpEncode() []byte |
||||
} |
||||
|
||||
type RlpEncodeDecode interface { |
||||
RlpEncode |
||||
RlpValue() []interface{} |
||||
} |
||||
|
||||
type RlpEncodable interface { |
||||
RlpData() interface{} |
||||
} |
||||
|
||||
func Rlp(encoder RlpEncode) []byte { |
||||
return encoder.RlpEncode() |
||||
} |
||||
|
||||
type RlpEncoder struct { |
||||
rlpData []byte |
||||
} |
||||
|
||||
func NewRlpEncoder() *RlpEncoder { |
||||
encoder := &RlpEncoder{} |
||||
|
||||
return encoder |
||||
} |
||||
func (coder *RlpEncoder) EncodeData(rlpData interface{}) []byte { |
||||
return Encode(rlpData) |
||||
} |
||||
|
||||
const ( |
||||
RlpEmptyList = 0x80 |
||||
RlpEmptyStr = 0x40 |
||||
) |
||||
|
||||
const rlpEof = -1 |
||||
|
||||
func Char(c []byte) int { |
||||
if len(c) > 0 { |
||||
return int(c[0]) |
||||
} |
||||
|
||||
return rlpEof |
||||
} |
||||
|
||||
func DecodeWithReader(reader *bytes.Buffer) interface{} { |
||||
var slice []interface{} |
||||
|
||||
// Read the next byte
|
||||
char := Char(reader.Next(1)) |
||||
switch { |
||||
case char <= 0x7f: |
||||
return char |
||||
|
||||
case char <= 0xb7: |
||||
return reader.Next(int(char - 0x80)) |
||||
|
||||
case char <= 0xbf: |
||||
length := ReadVarInt(reader.Next(int(char - 0xb7))) |
||||
|
||||
return reader.Next(int(length)) |
||||
|
||||
case char <= 0xf7: |
||||
length := int(char - 0xc0) |
||||
for i := 0; i < length; i++ { |
||||
obj := DecodeWithReader(reader) |
||||
slice = append(slice, obj) |
||||
} |
||||
|
||||
return slice |
||||
case char <= 0xff: |
||||
length := ReadVarInt(reader.Next(int(char - 0xf7))) |
||||
for i := uint64(0); i < length; i++ { |
||||
obj := DecodeWithReader(reader) |
||||
slice = append(slice, obj) |
||||
} |
||||
|
||||
return slice |
||||
default: |
||||
panic(fmt.Sprintf("byte not supported: %q", char)) |
||||
} |
||||
|
||||
return slice |
||||
} |
||||
|
||||
var ( |
||||
directRlp = big.NewInt(0x7f) |
||||
numberRlp = big.NewInt(0xb7) |
||||
zeroRlp = big.NewInt(0x0) |
||||
) |
||||
|
||||
func intlen(i int64) (length int) { |
||||
for i > 0 { |
||||
i = i >> 8 |
||||
length++ |
||||
} |
||||
return |
||||
} |
||||
|
||||
func Encode(object interface{}) []byte { |
||||
var buff bytes.Buffer |
||||
|
||||
if object != nil { |
||||
switch t := object.(type) { |
||||
case *Value: |
||||
buff.Write(Encode(t.Val)) |
||||
case RlpEncodable: |
||||
buff.Write(Encode(t.RlpData())) |
||||
// Code dup :-/
|
||||
case int: |
||||
buff.Write(Encode(big.NewInt(int64(t)))) |
||||
case uint: |
||||
buff.Write(Encode(big.NewInt(int64(t)))) |
||||
case int8: |
||||
buff.Write(Encode(big.NewInt(int64(t)))) |
||||
case int16: |
||||
buff.Write(Encode(big.NewInt(int64(t)))) |
||||
case int32: |
||||
buff.Write(Encode(big.NewInt(int64(t)))) |
||||
case int64: |
||||
buff.Write(Encode(big.NewInt(t))) |
||||
case uint16: |
||||
buff.Write(Encode(big.NewInt(int64(t)))) |
||||
case uint32: |
||||
buff.Write(Encode(big.NewInt(int64(t)))) |
||||
case uint64: |
||||
buff.Write(Encode(big.NewInt(int64(t)))) |
||||
case byte: |
||||
buff.Write(Encode(big.NewInt(int64(t)))) |
||||
case *big.Int: |
||||
// Not sure how this is possible while we check for nil
|
||||
if t == nil { |
||||
buff.WriteByte(0xc0) |
||||
} else { |
||||
buff.Write(Encode(t.Bytes())) |
||||
} |
||||
case Bytes: |
||||
buff.Write(Encode([]byte(t))) |
||||
case []byte: |
||||
if len(t) == 1 && t[0] <= 0x7f { |
||||
buff.Write(t) |
||||
} else if len(t) < 56 { |
||||
buff.WriteByte(byte(len(t) + 0x80)) |
||||
buff.Write(t) |
||||
} else { |
||||
b := big.NewInt(int64(len(t))) |
||||
buff.WriteByte(byte(len(b.Bytes()) + 0xb7)) |
||||
buff.Write(b.Bytes()) |
||||
buff.Write(t) |
||||
} |
||||
case string: |
||||
buff.Write(Encode([]byte(t))) |
||||
case []interface{}: |
||||
// Inline function for writing the slice header
|
||||
WriteSliceHeader := func(length int) { |
||||
if length < 56 { |
||||
buff.WriteByte(byte(length + 0xc0)) |
||||
} else { |
||||
b := big.NewInt(int64(length)) |
||||
buff.WriteByte(byte(len(b.Bytes()) + 0xf7)) |
||||
buff.Write(b.Bytes()) |
||||
} |
||||
} |
||||
|
||||
var b bytes.Buffer |
||||
for _, val := range t { |
||||
b.Write(Encode(val)) |
||||
} |
||||
WriteSliceHeader(len(b.Bytes())) |
||||
buff.Write(b.Bytes()) |
||||
default: |
||||
// This is how it should have been from the start
|
||||
// needs refactoring (@fjl)
|
||||
v := reflect.ValueOf(t) |
||||
switch v.Kind() { |
||||
case reflect.Slice: |
||||
var b bytes.Buffer |
||||
for i := 0; i < v.Len(); i++ { |
||||
b.Write(Encode(v.Index(i).Interface())) |
||||
} |
||||
|
||||
blen := b.Len() |
||||
if blen < 56 { |
||||
buff.WriteByte(byte(blen) + 0xc0) |
||||
} else { |
||||
ilen := byte(intlen(int64(blen))) |
||||
buff.WriteByte(ilen + 0xf7) |
||||
t := make([]byte, ilen) |
||||
for i := byte(0); i < ilen; i++ { |
||||
t[ilen-i-1] = byte(blen >> (i * 8)) |
||||
} |
||||
buff.Write(t) |
||||
} |
||||
buff.ReadFrom(&b) |
||||
} |
||||
} |
||||
} else { |
||||
// Empty list for nil
|
||||
buff.WriteByte(0xc0) |
||||
} |
||||
|
||||
return buff.Bytes() |
||||
} |
||||
|
||||
// TODO Use a bytes.Buffer instead of a raw byte slice.
|
||||
// Cleaner code, and use draining instead of seeking the next bytes to read
|
||||
func Decode(data []byte, pos uint64) (interface{}, uint64) { |
||||
var slice []interface{} |
||||
char := int(data[pos]) |
||||
switch { |
||||
case char <= 0x7f: |
||||
return data[pos], pos + 1 |
||||
|
||||
case char <= 0xb7: |
||||
b := uint64(data[pos]) - 0x80 |
||||
|
||||
return data[pos+1 : pos+1+b], pos + 1 + b |
||||
|
||||
case char <= 0xbf: |
||||
b := uint64(data[pos]) - 0xb7 |
||||
|
||||
b2 := ReadVarInt(data[pos+1 : pos+1+b]) |
||||
|
||||
return data[pos+1+b : pos+1+b+b2], pos + 1 + b + b2 |
||||
|
||||
case char <= 0xf7: |
||||
b := uint64(data[pos]) - 0xc0 |
||||
prevPos := pos |
||||
pos++ |
||||
for i := uint64(0); i < b; { |
||||
var obj interface{} |
||||
|
||||
// Get the next item in the data list and append it
|
||||
obj, prevPos = Decode(data, pos) |
||||
slice = append(slice, obj) |
||||
|
||||
// Increment i by the amount bytes read in the previous
|
||||
// read
|
||||
i += (prevPos - pos) |
||||
pos = prevPos |
||||
} |
||||
return slice, pos |
||||
|
||||
case char <= 0xff: |
||||
l := uint64(data[pos]) - 0xf7 |
||||
b := ReadVarInt(data[pos+1 : pos+1+l]) |
||||
|
||||
pos = pos + l + 1 |
||||
|
||||
prevPos := b |
||||
for i := uint64(0); i < uint64(b); { |
||||
var obj interface{} |
||||
|
||||
obj, prevPos = Decode(data, pos) |
||||
slice = append(slice, obj) |
||||
|
||||
i += (prevPos - pos) |
||||
pos = prevPos |
||||
} |
||||
return slice, pos |
||||
|
||||
default: |
||||
panic(fmt.Sprintf("byte not supported: %q", char)) |
||||
} |
||||
|
||||
return slice, 0 |
||||
} |
@ -1,176 +0,0 @@ |
||||
// Copyright 2014 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package common |
||||
|
||||
import ( |
||||
"bytes" |
||||
"math/big" |
||||
"reflect" |
||||
"testing" |
||||
|
||||
"github.com/ethereum/go-ethereum/rlp" |
||||
) |
||||
|
||||
func TestNonInterfaceSlice(t *testing.T) { |
||||
vala := []string{"value1", "value2", "value3"} |
||||
valb := []interface{}{"value1", "value2", "value3"} |
||||
resa := Encode(vala) |
||||
resb := Encode(valb) |
||||
if !bytes.Equal(resa, resb) { |
||||
t.Errorf("expected []string & []interface{} to be equal") |
||||
} |
||||
} |
||||
|
||||
func TestRlpValueEncoding(t *testing.T) { |
||||
val := EmptyValue() |
||||
val.AppendList().Append(byte(1)).Append(byte(2)).Append(byte(3)) |
||||
val.Append("4").AppendList().Append(byte(5)) |
||||
|
||||
res, err := rlp.EncodeToBytes(val) |
||||
if err != nil { |
||||
t.Fatalf("encode error: %v", err) |
||||
} |
||||
exp := Encode([]interface{}{[]interface{}{1, 2, 3}, "4", []interface{}{5}}) |
||||
if bytes.Compare(res, exp) != 0 { |
||||
t.Errorf("expected %x, got %x", exp, res) |
||||
} |
||||
} |
||||
|
||||
func TestValueSlice(t *testing.T) { |
||||
val := []interface{}{ |
||||
"value1", |
||||
"valeu2", |
||||
"value3", |
||||
} |
||||
|
||||
value := NewValue(val) |
||||
splitVal := value.SliceFrom(1) |
||||
|
||||
if splitVal.Len() != 2 { |
||||
t.Error("SliceFrom: Expected len", 2, "got", splitVal.Len()) |
||||
} |
||||
|
||||
splitVal = value.SliceTo(2) |
||||
if splitVal.Len() != 2 { |
||||
t.Error("SliceTo: Expected len", 2, "got", splitVal.Len()) |
||||
} |
||||
|
||||
splitVal = value.SliceFromTo(1, 3) |
||||
if splitVal.Len() != 2 { |
||||
t.Error("SliceFromTo: Expected len", 2, "got", splitVal.Len()) |
||||
} |
||||
} |
||||
|
||||
func TestLargeData(t *testing.T) { |
||||
data := make([]byte, 100000) |
||||
enc := Encode(data) |
||||
value := NewValueFromBytes(enc) |
||||
if value.Len() != len(data) { |
||||
t.Error("Expected data to be", len(data), "got", value.Len()) |
||||
} |
||||
} |
||||
|
||||
func TestValue(t *testing.T) { |
||||
value := NewValueFromBytes([]byte("\xcd\x83dog\x83god\x83cat\x01")) |
||||
if value.Get(0).Str() != "dog" { |
||||
t.Errorf("expected '%v', got '%v'", value.Get(0).Str(), "dog") |
||||
} |
||||
|
||||
if value.Get(3).Uint() != 1 { |
||||
t.Errorf("expected '%v', got '%v'", value.Get(3).Uint(), 1) |
||||
} |
||||
} |
||||
|
||||
func TestEncode(t *testing.T) { |
||||
strRes := "\x83dog" |
||||
bytes := Encode("dog") |
||||
|
||||
str := string(bytes) |
||||
if str != strRes { |
||||
t.Errorf("Expected %q, got %q", strRes, str) |
||||
} |
||||
|
||||
sliceRes := "\xcc\x83dog\x83god\x83cat" |
||||
strs := []interface{}{"dog", "god", "cat"} |
||||
bytes = Encode(strs) |
||||
slice := string(bytes) |
||||
if slice != sliceRes { |
||||
t.Error("Expected %q, got %q", sliceRes, slice) |
||||
} |
||||
|
||||
intRes := "\x82\x04\x00" |
||||
bytes = Encode(1024) |
||||
if string(bytes) != intRes { |
||||
t.Errorf("Expected %q, got %q", intRes, bytes) |
||||
} |
||||
} |
||||
|
||||
func TestDecode(t *testing.T) { |
||||
single := []byte("\x01") |
||||
b, _ := Decode(single, 0) |
||||
|
||||
if b.(uint8) != 1 { |
||||
t.Errorf("Expected 1, got %q", b) |
||||
} |
||||
|
||||
str := []byte("\x83dog") |
||||
b, _ = Decode(str, 0) |
||||
if bytes.Compare(b.([]byte), []byte("dog")) != 0 { |
||||
t.Errorf("Expected dog, got %q", b) |
||||
} |
||||
|
||||
slice := []byte("\xcc\x83dog\x83god\x83cat") |
||||
res := []interface{}{"dog", "god", "cat"} |
||||
b, _ = Decode(slice, 0) |
||||
if reflect.DeepEqual(b, res) { |
||||
t.Errorf("Expected %q, got %q", res, b) |
||||
} |
||||
} |
||||
|
||||
func TestEncodeDecodeBigInt(t *testing.T) { |
||||
bigInt := big.NewInt(1391787038) |
||||
encoded := Encode(bigInt) |
||||
|
||||
value := NewValueFromBytes(encoded) |
||||
if value.BigInt().Cmp(bigInt) != 0 { |
||||
t.Errorf("Expected %v, got %v", bigInt, value.BigInt()) |
||||
} |
||||
} |
||||
|
||||
func TestEncodeDecodeBytes(t *testing.T) { |
||||
bv := NewValue([]interface{}{[]byte{1, 2, 3, 4, 5}, []byte{6}}) |
||||
b, _ := rlp.EncodeToBytes(bv) |
||||
val := NewValueFromBytes(b) |
||||
if !bv.Cmp(val) { |
||||
t.Errorf("Expected %#v, got %#v", bv, val) |
||||
} |
||||
} |
||||
|
||||
func TestEncodeZero(t *testing.T) { |
||||
b, _ := rlp.EncodeToBytes(NewValue(0)) |
||||
exp := []byte{0xc0} |
||||
if bytes.Compare(b, exp) == 0 { |
||||
t.Error("Expected", exp, "got", b) |
||||
} |
||||
} |
||||
|
||||
func BenchmarkEncodeDecode(b *testing.B) { |
||||
for i := 0; i < b.N; i++ { |
||||
bytes := Encode([]interface{}{"dog", "god", "cat"}) |
||||
Decode(bytes, 0) |
||||
} |
||||
} |
@ -1,428 +0,0 @@ |
||||
// Copyright 2014 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package common |
||||
|
||||
import ( |
||||
"bytes" |
||||
"fmt" |
||||
"io" |
||||
"math/big" |
||||
"reflect" |
||||
"strconv" |
||||
|
||||
"github.com/ethereum/go-ethereum/rlp" |
||||
) |
||||
|
||||
// Value can hold values of certain basic types and provides ways to
|
||||
// convert between types without bothering to check whether the
|
||||
// conversion is actually meaningful.
|
||||
//
|
||||
// It currently supports the following types:
|
||||
//
|
||||
// - int{,8,16,32,64}
|
||||
// - uint{,8,16,32,64}
|
||||
// - *big.Int
|
||||
// - []byte, string
|
||||
// - []interface{}
|
||||
//
|
||||
// Value is useful whenever you feel that Go's types limit your
|
||||
// ability to express yourself. In these situations, use Value and
|
||||
// forget about this strong typing nonsense.
|
||||
type Value struct{ Val interface{} } |
||||
|
||||
func (val *Value) String() string { |
||||
return fmt.Sprintf("%x", val.Val) |
||||
} |
||||
|
||||
func NewValue(val interface{}) *Value { |
||||
t := val |
||||
if v, ok := val.(*Value); ok { |
||||
t = v.Val |
||||
} |
||||
|
||||
return &Value{Val: t} |
||||
} |
||||
|
||||
func (val *Value) Type() reflect.Kind { |
||||
return reflect.TypeOf(val.Val).Kind() |
||||
} |
||||
|
||||
func (val *Value) IsNil() bool { |
||||
return val.Val == nil |
||||
} |
||||
|
||||
func (val *Value) Len() int { |
||||
if data, ok := val.Val.([]interface{}); ok { |
||||
return len(data) |
||||
} |
||||
|
||||
return len(val.Bytes()) |
||||
} |
||||
|
||||
func (val *Value) Uint() uint64 { |
||||
if Val, ok := val.Val.(uint8); ok { |
||||
return uint64(Val) |
||||
} else if Val, ok := val.Val.(uint16); ok { |
||||
return uint64(Val) |
||||
} else if Val, ok := val.Val.(uint32); ok { |
||||
return uint64(Val) |
||||
} else if Val, ok := val.Val.(uint64); ok { |
||||
return Val |
||||
} else if Val, ok := val.Val.(float32); ok { |
||||
return uint64(Val) |
||||
} else if Val, ok := val.Val.(float64); ok { |
||||
return uint64(Val) |
||||
} else if Val, ok := val.Val.(int); ok { |
||||
return uint64(Val) |
||||
} else if Val, ok := val.Val.(uint); ok { |
||||
return uint64(Val) |
||||
} else if Val, ok := val.Val.([]byte); ok { |
||||
return new(big.Int).SetBytes(Val).Uint64() |
||||
} else if Val, ok := val.Val.(*big.Int); ok { |
||||
return Val.Uint64() |
||||
} |
||||
|
||||
return 0 |
||||
} |
||||
|
||||
func (val *Value) Int() int64 { |
||||
if Val, ok := val.Val.(int8); ok { |
||||
return int64(Val) |
||||
} else if Val, ok := val.Val.(int16); ok { |
||||
return int64(Val) |
||||
} else if Val, ok := val.Val.(int32); ok { |
||||
return int64(Val) |
||||
} else if Val, ok := val.Val.(int64); ok { |
||||
return Val |
||||
} else if Val, ok := val.Val.(int); ok { |
||||
return int64(Val) |
||||
} else if Val, ok := val.Val.(float32); ok { |
||||
return int64(Val) |
||||
} else if Val, ok := val.Val.(float64); ok { |
||||
return int64(Val) |
||||
} else if Val, ok := val.Val.([]byte); ok { |
||||
return new(big.Int).SetBytes(Val).Int64() |
||||
} else if Val, ok := val.Val.(*big.Int); ok { |
||||
return Val.Int64() |
||||
} else if Val, ok := val.Val.(string); ok { |
||||
n, _ := strconv.Atoi(Val) |
||||
return int64(n) |
||||
} |
||||
|
||||
return 0 |
||||
} |
||||
|
||||
func (val *Value) Byte() byte { |
||||
if Val, ok := val.Val.(byte); ok { |
||||
return Val |
||||
} |
||||
|
||||
return 0x0 |
||||
} |
||||
|
||||
func (val *Value) BigInt() *big.Int { |
||||
if a, ok := val.Val.([]byte); ok { |
||||
b := new(big.Int).SetBytes(a) |
||||
|
||||
return b |
||||
} else if a, ok := val.Val.(*big.Int); ok { |
||||
return a |
||||
} else if a, ok := val.Val.(string); ok { |
||||
return Big(a) |
||||
} else { |
||||
return big.NewInt(int64(val.Uint())) |
||||
} |
||||
|
||||
return big.NewInt(0) |
||||
} |
||||
|
||||
func (val *Value) Str() string { |
||||
if a, ok := val.Val.([]byte); ok { |
||||
return string(a) |
||||
} else if a, ok := val.Val.(string); ok { |
||||
return a |
||||
} else if a, ok := val.Val.(byte); ok { |
||||
return string(a) |
||||
} |
||||
|
||||
return "" |
||||
} |
||||
|
||||
func (val *Value) Bytes() []byte { |
||||
if a, ok := val.Val.([]byte); ok { |
||||
return a |
||||
} else if s, ok := val.Val.(byte); ok { |
||||
return []byte{s} |
||||
} else if s, ok := val.Val.(string); ok { |
||||
return []byte(s) |
||||
} else if s, ok := val.Val.(*big.Int); ok { |
||||
return s.Bytes() |
||||
} else { |
||||
return big.NewInt(val.Int()).Bytes() |
||||
} |
||||
|
||||
return []byte{} |
||||
} |
||||
|
||||
func (val *Value) Err() error { |
||||
if err, ok := val.Val.(error); ok { |
||||
return err |
||||
} |
||||
|
||||
return nil |
||||
} |
||||
|
||||
func (val *Value) Slice() []interface{} { |
||||
if d, ok := val.Val.([]interface{}); ok { |
||||
return d |
||||
} |
||||
|
||||
return []interface{}{} |
||||
} |
||||
|
||||
func (val *Value) SliceFrom(from int) *Value { |
||||
slice := val.Slice() |
||||
|
||||
return NewValue(slice[from:]) |
||||
} |
||||
|
||||
func (val *Value) SliceTo(to int) *Value { |
||||
slice := val.Slice() |
||||
|
||||
return NewValue(slice[:to]) |
||||
} |
||||
|
||||
func (val *Value) SliceFromTo(from, to int) *Value { |
||||
slice := val.Slice() |
||||
|
||||
return NewValue(slice[from:to]) |
||||
} |
||||
|
||||
// TODO More type checking methods
|
||||
func (val *Value) IsSlice() bool { |
||||
return val.Type() == reflect.Slice |
||||
} |
||||
|
||||
func (val *Value) IsStr() bool { |
||||
return val.Type() == reflect.String |
||||
} |
||||
|
||||
func (self *Value) IsErr() bool { |
||||
_, ok := self.Val.(error) |
||||
return ok |
||||
} |
||||
|
||||
// Special list checking function. Something is considered
|
||||
// a list if it's of type []interface{}. The list is usually
|
||||
// used in conjunction with rlp decoded streams.
|
||||
func (val *Value) IsList() bool { |
||||
_, ok := val.Val.([]interface{}) |
||||
|
||||
return ok |
||||
} |
||||
|
||||
func (val *Value) IsEmpty() bool { |
||||
return val.Val == nil || ((val.IsSlice() || val.IsStr()) && val.Len() == 0) |
||||
} |
||||
|
||||
// Threat the value as a slice
|
||||
func (val *Value) Get(idx int) *Value { |
||||
if d, ok := val.Val.([]interface{}); ok { |
||||
// Guard for oob
|
||||
if len(d) <= idx { |
||||
return NewValue(nil) |
||||
} |
||||
|
||||
if idx < 0 { |
||||
return NewValue(nil) |
||||
} |
||||
|
||||
return NewValue(d[idx]) |
||||
} |
||||
|
||||
// If this wasn't a slice you probably shouldn't be using this function
|
||||
return NewValue(nil) |
||||
} |
||||
|
||||
func (self *Value) Copy() *Value { |
||||
switch val := self.Val.(type) { |
||||
case *big.Int: |
||||
return NewValue(new(big.Int).Set(val)) |
||||
case []byte: |
||||
return NewValue(CopyBytes(val)) |
||||
default: |
||||
return NewValue(self.Val) |
||||
} |
||||
|
||||
return nil |
||||
} |
||||
|
||||
func (val *Value) Cmp(o *Value) bool { |
||||
return reflect.DeepEqual(val.Val, o.Val) |
||||
} |
||||
|
||||
func (self *Value) DeepCmp(o *Value) bool { |
||||
return bytes.Compare(self.Bytes(), o.Bytes()) == 0 |
||||
} |
||||
|
||||
func (self *Value) DecodeRLP(s *rlp.Stream) error { |
||||
var v interface{} |
||||
if err := s.Decode(&v); err != nil { |
||||
return err |
||||
} |
||||
self.Val = v |
||||
return nil |
||||
} |
||||
|
||||
func (self *Value) EncodeRLP(w io.Writer) error { |
||||
if self == nil { |
||||
w.Write(rlp.EmptyList) |
||||
return nil |
||||
} else { |
||||
return rlp.Encode(w, self.Val) |
||||
} |
||||
} |
||||
|
||||
// NewValueFromBytes decodes RLP data.
|
||||
// The contained value will be nil if data contains invalid RLP.
|
||||
func NewValueFromBytes(data []byte) *Value { |
||||
v := new(Value) |
||||
if len(data) != 0 { |
||||
if err := rlp.DecodeBytes(data, v); err != nil { |
||||
v.Val = nil |
||||
} |
||||
} |
||||
return v |
||||
} |
||||
|
||||
// Value setters
|
||||
func NewSliceValue(s interface{}) *Value { |
||||
list := EmptyValue() |
||||
|
||||
if s != nil { |
||||
if slice, ok := s.([]interface{}); ok { |
||||
for _, val := range slice { |
||||
list.Append(val) |
||||
} |
||||
} else if slice, ok := s.([]string); ok { |
||||
for _, val := range slice { |
||||
list.Append(val) |
||||
} |
||||
} |
||||
} |
||||
|
||||
return list |
||||
} |
||||
|
||||
func EmptyValue() *Value { |
||||
return NewValue([]interface{}{}) |
||||
} |
||||
|
||||
func (val *Value) AppendList() *Value { |
||||
list := EmptyValue() |
||||
val.Val = append(val.Slice(), list) |
||||
|
||||
return list |
||||
} |
||||
|
||||
func (val *Value) Append(v interface{}) *Value { |
||||
val.Val = append(val.Slice(), v) |
||||
|
||||
return val |
||||
} |
||||
|
||||
const ( |
||||
valOpAdd = iota |
||||
valOpDiv |
||||
valOpMul |
||||
valOpPow |
||||
valOpSub |
||||
) |
||||
|
||||
// Math stuff
|
||||
func (self *Value) doOp(op int, other interface{}) *Value { |
||||
left := self.BigInt() |
||||
right := NewValue(other).BigInt() |
||||
|
||||
switch op { |
||||
case valOpAdd: |
||||
self.Val = left.Add(left, right) |
||||
case valOpDiv: |
||||
self.Val = left.Div(left, right) |
||||
case valOpMul: |
||||
self.Val = left.Mul(left, right) |
||||
case valOpPow: |
||||
self.Val = left.Exp(left, right, Big0) |
||||
case valOpSub: |
||||
self.Val = left.Sub(left, right) |
||||
} |
||||
|
||||
return self |
||||
} |
||||
|
||||
func (self *Value) Add(other interface{}) *Value { |
||||
return self.doOp(valOpAdd, other) |
||||
} |
||||
|
||||
func (self *Value) Sub(other interface{}) *Value { |
||||
return self.doOp(valOpSub, other) |
||||
} |
||||
|
||||
func (self *Value) Div(other interface{}) *Value { |
||||
return self.doOp(valOpDiv, other) |
||||
} |
||||
|
||||
func (self *Value) Mul(other interface{}) *Value { |
||||
return self.doOp(valOpMul, other) |
||||
} |
||||
|
||||
func (self *Value) Pow(other interface{}) *Value { |
||||
return self.doOp(valOpPow, other) |
||||
} |
||||
|
||||
type ValueIterator struct { |
||||
value *Value |
||||
currentValue *Value |
||||
idx int |
||||
} |
||||
|
||||
func (val *Value) NewIterator() *ValueIterator { |
||||
return &ValueIterator{value: val} |
||||
} |
||||
|
||||
func (it *ValueIterator) Len() int { |
||||
return it.value.Len() |
||||
} |
||||
|
||||
func (it *ValueIterator) Next() bool { |
||||
if it.idx >= it.value.Len() { |
||||
return false |
||||
} |
||||
|
||||
it.currentValue = it.value.Get(it.idx) |
||||
it.idx++ |
||||
|
||||
return true |
||||
} |
||||
|
||||
func (it *ValueIterator) Value() *Value { |
||||
return it.currentValue |
||||
} |
||||
|
||||
func (it *ValueIterator) Idx() int { |
||||
return it.idx - 1 |
||||
} |
@ -1,86 +0,0 @@ |
||||
// Copyright 2014 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package common |
||||
|
||||
import ( |
||||
"math/big" |
||||
|
||||
checker "gopkg.in/check.v1" |
||||
) |
||||
|
||||
type ValueSuite struct{} |
||||
|
||||
var _ = checker.Suite(&ValueSuite{}) |
||||
|
||||
func (s *ValueSuite) TestValueCmp(c *checker.C) { |
||||
val1 := NewValue("hello") |
||||
val2 := NewValue("world") |
||||
c.Assert(val1.Cmp(val2), checker.Equals, false) |
||||
|
||||
val3 := NewValue("hello") |
||||
val4 := NewValue("hello") |
||||
c.Assert(val3.Cmp(val4), checker.Equals, true) |
||||
} |
||||
|
||||
func (s *ValueSuite) TestValueTypes(c *checker.C) { |
||||
str := NewValue("str") |
||||
num := NewValue(1) |
||||
inter := NewValue([]interface{}{1}) |
||||
byt := NewValue([]byte{1, 2, 3, 4}) |
||||
bigInt := NewValue(big.NewInt(10)) |
||||
|
||||
strExp := "str" |
||||
numExp := uint64(1) |
||||
interExp := []interface{}{1} |
||||
bytExp := []byte{1, 2, 3, 4} |
||||
bigExp := big.NewInt(10) |
||||
|
||||
c.Assert(str.Str(), checker.Equals, strExp) |
||||
c.Assert(num.Uint(), checker.Equals, numExp) |
||||
c.Assert(NewValue(inter.Val).Cmp(NewValue(interExp)), checker.Equals, true) |
||||
c.Assert(byt.Bytes(), checker.DeepEquals, bytExp) |
||||
c.Assert(bigInt.BigInt(), checker.DeepEquals, bigExp) |
||||
} |
||||
|
||||
func (s *ValueSuite) TestIterator(c *checker.C) { |
||||
value := NewValue([]interface{}{1, 2, 3}) |
||||
iter := value.NewIterator() |
||||
values := []uint64{1, 2, 3} |
||||
i := 0 |
||||
for iter.Next() { |
||||
c.Assert(values[i], checker.Equals, iter.Value().Uint()) |
||||
i++ |
||||
} |
||||
} |
||||
|
||||
func (s *ValueSuite) TestMath(c *checker.C) { |
||||
data1 := NewValue(1) |
||||
data1.Add(1).Add(1) |
||||
exp1 := NewValue(3) |
||||
data2 := NewValue(2) |
||||
data2.Sub(1).Sub(1) |
||||
exp2 := NewValue(0) |
||||
|
||||
c.Assert(data1.DeepCmp(exp1), checker.Equals, true) |
||||
c.Assert(data2.DeepCmp(exp2), checker.Equals, true) |
||||
} |
||||
|
||||
func (s *ValueSuite) TestString(c *checker.C) { |
||||
data := "10" |
||||
exp := int64(10) |
||||
c.Assert(NewValue(data).Int(), checker.DeepEquals, exp) |
||||
} |
Loading…
Reference in new issue