diff options
author | Ethan Buchman <ethan@coinculture.info> | 2015-02-18 08:25:18 +0800 |
---|---|---|
committer | Ethan Buchman <ethan@coinculture.info> | 2015-02-18 08:25:18 +0800 |
commit | 2ba65f4fbaea49c1e0d99959b0331e09b153f931 (patch) | |
tree | add8cabb05cd7fbf0ba4b4bbaf9460dacfc2082d /rlp/encode.go | |
parent | 2da367a2bee84d74d1bb0ea1b42d4c22fae486dd (diff) | |
parent | 60318c96d03bcaaf731802b1080a3d87cb482124 (diff) | |
download | dexon-2ba65f4fbaea49c1e0d99959b0331e09b153f931.tar dexon-2ba65f4fbaea49c1e0d99959b0331e09b153f931.tar.gz dexon-2ba65f4fbaea49c1e0d99959b0331e09b153f931.tar.bz2 dexon-2ba65f4fbaea49c1e0d99959b0331e09b153f931.tar.lz dexon-2ba65f4fbaea49c1e0d99959b0331e09b153f931.tar.xz dexon-2ba65f4fbaea49c1e0d99959b0331e09b153f931.tar.zst dexon-2ba65f4fbaea49c1e0d99959b0331e09b153f931.zip |
Merge branch 'develop' of https://github.com/ethereum/go-ethereum into develop
Diffstat (limited to 'rlp/encode.go')
-rw-r--r-- | rlp/encode.go | 71 |
1 files changed, 70 insertions, 1 deletions
diff --git a/rlp/encode.go b/rlp/encode.go index d80b66315..9d11d66bf 100644 --- a/rlp/encode.go +++ b/rlp/encode.go @@ -32,6 +32,48 @@ type Encoder interface { EncodeRLP(io.Writer) error } +// Flat wraps a value (which must encode as a list) so +// it encodes as the list's elements. +// +// Example: suppose you have defined a type +// +// type foo struct { A, B uint } +// +// Under normal encoding rules, +// +// rlp.Encode(foo{1, 2}) --> 0xC20102 +// +// This function can help you achieve the following encoding: +// +// rlp.Encode(rlp.Flat(foo{1, 2})) --> 0x0102 +func Flat(val interface{}) Encoder { + return flatenc{val} +} + +type flatenc struct{ val interface{} } + +func (e flatenc) EncodeRLP(out io.Writer) error { + // record current output position + var ( + eb = out.(*encbuf) + prevstrsize = len(eb.str) + prevnheads = len(eb.lheads) + ) + if err := eb.encode(e.val); err != nil { + return err + } + // check that a new list header has appeared + if len(eb.lheads) == prevnheads || eb.lheads[prevnheads].offset == prevstrsize-1 { + return fmt.Errorf("rlp.Flat: %T did not encode as list", e.val) + } + // remove the new list header + newhead := eb.lheads[prevnheads] + copy(eb.lheads[prevnheads:], eb.lheads[prevnheads+1:]) + eb.lheads = eb.lheads[:len(eb.lheads)-1] + eb.lhsize -= newhead.tagsize() + return nil +} + // Encode writes the RLP encoding of val to w. Note that Encode may // perform many small writes in some cases. Consider making w // buffered. @@ -123,6 +165,13 @@ func (head *listhead) encode(buf []byte) []byte { } } +func (head *listhead) tagsize() int { + if head.size < 56 { + return 1 + } + return 1 + intsize(uint64(head.size)) +} + func newencbuf() *encbuf { return &encbuf{sizebuf: make([]byte, 9)} } @@ -301,8 +350,10 @@ func makeWriter(typ reflect.Type) (writer, error) { return writeUint, nil case kind == reflect.String: return writeString, nil - case kind == reflect.Slice && typ.Elem().Kind() == reflect.Uint8 && !typ.Elem().Implements(encoderInterface): + case kind == reflect.Slice && isByte(typ.Elem()): return writeBytes, nil + case kind == reflect.Array && isByte(typ.Elem()): + return writeByteArray, nil case kind == reflect.Slice || kind == reflect.Array: return makeSliceWriter(typ) case kind == reflect.Struct: @@ -314,6 +365,10 @@ func makeWriter(typ reflect.Type) (writer, error) { } } +func isByte(typ reflect.Type) bool { + return typ.Kind() == reflect.Uint8 && !typ.Implements(encoderInterface) +} + func writeUint(val reflect.Value, w *encbuf) error { i := val.Uint() if i == 0 { @@ -358,6 +413,20 @@ func writeBytes(val reflect.Value, w *encbuf) error { return nil } +func writeByteArray(val reflect.Value, w *encbuf) error { + if !val.CanAddr() { + // Slice requires the value to be addressable. + // Make it addressable by copying. + copy := reflect.New(val.Type()).Elem() + copy.Set(val) + val = copy + } + size := val.Len() + slice := val.Slice(0, size).Bytes() + w.encodeString(slice) + return nil +} + func writeString(val reflect.Value, w *encbuf) error { s := val.String() w.encodeStringHeader(len(s)) |