Skip to content

Commit

Permalink
Merge pull request #67 from dekarrin/ghi045-time-support
Browse files Browse the repository at this point in the history
Ghi045 underlying type detection support
  • Loading branch information
dekarrin committed Nov 23, 2023
2 parents e4e4d47 + 5f50200 commit b804ca6
Show file tree
Hide file tree
Showing 8 changed files with 1,232 additions and 89 deletions.
29 changes: 17 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
[![Go Reference](https://pkg.go.dev/badge/github.com/dekarrin/rezi/v2.svg)](https://pkg.go.dev/github.com/dekarrin/rezi/v2)

The Rarefied Encoding (Compressible) for Interchange (REZI) library performs
binary marshaling of data to REZI-format bytes. It can encode and decode several
built-in Go types to bytes, and handles decoding and encoding of user-defined
types that implement `encoding.BinaryMarshaler` or `encoding.TextMarshaler`.
binary marshaling of data to REZI-format bytes. It can encode and decode most
simple (non-struct) built-in Go types to bytes, and handles customization of
decoding and encoding of user-defined types that implement
`encoding.BinaryMarshaler` or `encoding.TextMarshaler`.

All data is encoded in a deterministic fashion, or as deterministically as
possible. Any non-determinism in the resulting encoded value will arise from
Expand Down Expand Up @@ -203,17 +204,21 @@ integer types, or one of the built-in float types.
REZI can also handle encoding and decoding pointers to any supported type, with
any level of indirection.

On top of all of the above, REZI supports any type whose underlying type is
supported.

#### User-Defined Types
REZI supports encoding any custom type that implements
`encoding.BinaryMarshaler`, and it supports decoding any custom type that
implements `encoding.BinaryUnmarshaler` with a pointer receiver. In fact, the
lack of built-in facilities in Go for binary encoding of user-defined types is
partially why REZI exists.

REZI does not perform any automatic inference of a user-defined type's encoding
such as what the `json` library is capable of. User-defined types that do not
implement BinaryMarshaler are not supported for encoding, and those that do not
implement BinaryUnmarshaler are not supported for decoding.
REZI does not perform any automatic inference of a user-defined struct type's
encoding such as what the `json` library is capable of. User-defined types that
do not implement BinaryMarshaler or TextMarshaler are only supported for
encoding if their underlying type is one supported by REZI, and vice-versa for
the corresponding unmarshal methods when decoding.

Within the `MarshalBinary` method, you can encode the data in whichever format
you wish, though these examples will have that function use REZI to encode the
Expand Down Expand Up @@ -273,11 +278,11 @@ func (p Person) MarshalBinary() ([]byte, error) {
}
```

Decoding of user-defined types is handled with the UnmarshalBinary method. The
bytes that were returned by MarshalBinary while decoding are picked up by REZI
and passed into UnmarshalBinary. Note that unlike the MarshalBinary method,
which must be defined with a value receiver for the type, REZI requires the
UnmarshalBinary to be defined with a pointer receiver.
Custom decoding of user-defined types is handled with the UnmarshalBinary
method. The bytes that were returned by MarshalBinary while decoding are picked
up by REZI and passed into UnmarshalBinary. Note that unlike the MarshalBinary
method, which must be defined with a value receiver for the type, REZI requires
the UnmarshalBinary to be defined with a pointer receiver.

```golang
// UnmarshalBinary takes in bytes and decodes them into a new Person object,
Expand Down
223 changes: 223 additions & 0 deletions arrays_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (
"github.com/stretchr/testify/assert"
)

type underlyingArray [5]bool

func Test_Enc_Array_NoIndirection(t *testing.T) {
// different types, can't rly be table driven easily

Expand Down Expand Up @@ -345,6 +347,28 @@ func Test_Enc_Array_NoIndirection(t *testing.T) {
assert.Equal(expect, actual)
})

t.Run("underlyingArray ([5]bool)", func(t *testing.T) {
// setup
assert := assert.New(t)
var (
input = underlyingArray{true, true, false, false, true}

expect = []byte{
0x01, 0x05,
0x01, 0x01, 0x00, 0x00, 0x01,
}
)

// execute
actual, err := Enc(input)
if !assert.NoError(err) {
return
}

// assert
assert.Equal(expect, actual)
})

t.Run("meta array [2][3]int", func(t *testing.T) {
// setup
assert := assert.New(t)
Expand Down Expand Up @@ -464,6 +488,84 @@ func Test_Enc_Array_SelfIndirection(t *testing.T) {

assert.Equal(expect, actual)
})

t.Run("*underlyingArray (*[5]bool) (nil)", func(t *testing.T) {
// setup
assert := assert.New(t)
var (
input *underlyingArray
expect = []byte{
0xa0,
}
)

actual, err := Enc(input)
if !assert.NoError(err) {
return
}

assert.Equal(expect, actual)
})

t.Run("*underlyingArray (*[5]bool)", func(t *testing.T) {
// setup
assert := assert.New(t)
var (
inputVal = underlyingArray{true, true, false, false, true}
input = &inputVal
expect = []byte{
0x01, 0x05,
0x01, 0x01, 0x00, 0x00, 0x01,
}
)

actual, err := Enc(input)
if !assert.NoError(err) {
return
}

assert.Equal(expect, actual)
})

t.Run("**underlyingArray (**[5]bool)", func(t *testing.T) {
assert := assert.New(t)

var (
inputVal = underlyingArray{true, true, false, false, true}
inputPtr = &inputVal
input = &inputPtr
expect = []byte{
0x01, 0x05,
0x01, 0x01, 0x00, 0x00, 0x01,
}
)

actual, err := Enc(input)
if !assert.NoError(err) {
return
}

assert.Equal(expect, actual)
})

t.Run("**underlyingArray, but nil underlyingArray part (**[5]bool)", func(t *testing.T) {
assert := assert.New(t)

var (
inputPtr *underlyingArray
input = &inputPtr
expect = []byte{
0xb0, 0x01, 0x01,
}
)

actual, err := Enc(input)
if !assert.NoError(err) {
return
}

assert.Equal(expect, actual)
})
}

func Test_Enc_Array_ValueIndirection(t *testing.T) {
Expand Down Expand Up @@ -1566,6 +1668,31 @@ func Test_Dec_Array_NoIndirection(t *testing.T) {
assert.Equal(expect, actual)
})

t.Run("underlyingArray ([5]bool)", func(t *testing.T) {
// setup
assert := assert.New(t)
var (
input = []byte{
0x01, 0x05,
0x01, 0x01, 0x00, 0x00, 0x01,
}
expect = underlyingArray{true, true, false, false, true}
expectConsumed = 7
)

// execute
var actual underlyingArray
consumed, err := Dec(input, &actual)

// assert
if !assert.NoError(err) {
return
}

assert.Equal(expectConsumed, consumed)
assert.Equal(expect, actual)
})

t.Run("meta array [2][3]int", func(t *testing.T) {
// setup
assert := assert.New(t)
Expand Down Expand Up @@ -1702,6 +1829,102 @@ func Test_Dec_Array_SelfIndirection(t *testing.T) {
assert.Equal(expectConsumed, consumed)
assert.Equal(expect, actual)
})

t.Run("*underlyingArray (*[5]bool) (nil)", func(t *testing.T) {
// setup
assert := assert.New(t)
var (
input = []byte{
0xa0,
}
expect *underlyingArray
expectConsumed = 1
)

// execute
var actual *underlyingArray
consumed, err := Dec(input, &actual)

// assert
if !assert.NoError(err) {
return
}

assert.Equal(expectConsumed, consumed)
assert.Equal(expect, actual)
})

t.Run("*underlyingArray (*[5]bool)", func(t *testing.T) {
// setup
assert := assert.New(t)
var (
input = []byte{
0x01, 0x05,
0x01, 0x01, 0x00, 0x00, 0x01,
}
expectVal = underlyingArray{true, true, false, false, true}
expect = &expectVal
expectConsumed = 7
)

// execute
var actual *underlyingArray
consumed, err := Dec(input, &actual)

// assert
if !assert.NoError(err) {
return
}

assert.Equal(expectConsumed, consumed)
assert.Equal(expect, actual)
})

t.Run("**underlyingArray (**[5]bool)", func(t *testing.T) {
assert := assert.New(t)

var (
input = []byte{
0x01, 0x05,
0x01, 0x01, 0x00, 0x00, 0x01,
}
expectVal = underlyingArray{true, true, false, false, true}
expectPtr = &expectVal
expect = &expectPtr
expectConsumed = 7
)

var actual **underlyingArray
consumed, err := Dec(input, &actual)
if !assert.NoError(err) {
return
}

assert.Equal(expectConsumed, consumed)
assert.Equal(expect, actual)
})

t.Run("**underlyingArray, but nil underlyingArray part (**[5]bool)", func(t *testing.T) {
assert := assert.New(t)

var (
input = []byte{
0xb0, 0x01, 0x01,
}
expectPtr *underlyingArray
expect = &expectPtr
expectConsumed = 3
)

var actual **underlyingArray = ref(&underlyingArray{true})
consumed, err := Dec(input, &actual)
if !assert.NoError(err) {
return
}

assert.Equal(expectConsumed, consumed)
assert.Equal(expect, actual)
})
}

func Test_Dec_Array_ValueIndirection(t *testing.T) {
Expand Down
Loading

0 comments on commit b804ca6

Please sign in to comment.