Skip to content

Commit

Permalink
Fixed encoding of optional primitive types as well as *Uint64 types
Browse files Browse the repository at this point in the history
Fixes #140
  • Loading branch information
Matthieu Vachon committed May 7, 2020
1 parent 271bfac commit 24c0eb7
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 5 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Expand Up @@ -15,6 +15,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added `ActionTrace.ContextFree` field of type `bool` that was previously missing from the struct definition.

### Fixed
- Optional encoding of primitive types.

A struct with a non-pointer type tagged with `eos:"optional"` is now properly encoded at the binary level. **Important** that means that for non-pointer type, when the value of the type is the "emtpy" value according to Golang rules, it will be written as not-present at the binary level. If it's something that you do want want, use a pointer to a primitive type. It's actually a good habit to use a pointer type for "optional" element anyway, to increase awarness.

- Fix json tags for delegatebw action data.
- Unpacking binary `Except` now correctly works.
- Unpacking binary `Action` and `ActionTrace` now correctly works.
Expand Down
8 changes: 3 additions & 5 deletions encoder.go
Expand Up @@ -20,7 +20,7 @@ import (
//
// **Warning** This is experimental, exposed only for internal usage for now.
type MarshalerBinary interface {
MarshalerBinary(encoder *Encoder) error
MarshalBinary(encoder *Encoder) error
}

func MarshalBinary(v interface{}) ([]byte, error) {
Expand Down Expand Up @@ -58,7 +58,7 @@ func (e *Encoder) writeName(name Name) error {
func (e *Encoder) Encode(v interface{}) (err error) {
switch cv := v.(type) {
case MarshalerBinary:
return cv.MarshalerBinary(e)
return cv.MarshalBinary(e)
case BaseVariant:
err = e.writeUVarInt(int(cv.TypeID))
if err != nil {
Expand Down Expand Up @@ -108,8 +108,6 @@ func (e *Encoder) Encode(v interface{}) (err error) {
return e.writeUint64(cv)
case Int64:
return e.writeUint64(uint64(cv))
case Uint64:
return e.writeUint64(uint64(cv))
case int64:
return e.writeInt64(cv)
case float32:
Expand Down Expand Up @@ -236,7 +234,7 @@ func (e *Encoder) Encode(v interface{}) (err error) {
if v.CanInterface() {
isPresent := true
if tag == "optional" {
isPresent = !v.IsNil()
isPresent = !v.IsZero()
e.writeBool(isPresent)
}

Expand Down
38 changes: 38 additions & 0 deletions encoder_test.go
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/hex"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

Expand All @@ -29,3 +30,40 @@ func TestEncoder_MapStringString(t *testing.T) {
require.Fail(t, "encoded map is invalid", "must be either %q or %q, got %q", expected1, expected2, out)
}
}

func Test_OptionalPrimitiveType(t *testing.T) {
type test struct {
ID uint64 `eos:"optional"`
}

out, err := MarshalBinary(test{ID: 0})
require.NoError(t, err)

assert.Equal(t, []byte{0x0}, out)

out, err = MarshalBinary(test{ID: 10})
require.NoError(t, err)

assert.Equal(t, []byte{0x1, 0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, out)
}

func Test_OptionalPointerToPrimitiveType(t *testing.T) {
type test struct {
ID *Uint64 `eos:"optional"`
}

out, err := MarshalBinary(test{ID: nil})
require.NoError(t, err)
assert.Equal(t, []byte{0x0}, out)

id := Uint64(0)
out, err = MarshalBinary(test{ID: &id})
require.NoError(t, err)
assert.Equal(t, []byte{0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, out)

id = Uint64(10)
out, err = MarshalBinary(test{ID: &id})
require.NoError(t, err)

assert.Equal(t, []byte{0x1, 0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, out)
}
4 changes: 4 additions & 0 deletions types.go
Expand Up @@ -963,6 +963,10 @@ func (i *Uint64) UnmarshalJSON(data []byte) error {
return nil
}

func (i Uint64) MarshalBinary(encoder *Encoder) error {
return encoder.writeUint64(uint64(i))
}

// uint128
type Uint128 struct {
Lo uint64
Expand Down

0 comments on commit 24c0eb7

Please sign in to comment.