feat(codec): Add collections value codec for interfaces. (#15898)
Co-authored-by: unknown unknown <unknown@unknown>
This commit is contained in:
co-authored by
unknown unknown
parent
294027cf2d
commit
295c261b18
@@ -1,6 +1,9 @@
|
||||
package codec
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
gogotypes "github.com/cosmos/gogoproto/types"
|
||||
|
||||
"cosmossdk.io/collections"
|
||||
@@ -79,3 +82,47 @@ func (c collValue[T, PT]) Stringify(value T) string {
|
||||
func (c collValue[T, PT]) ValueType() string {
|
||||
return "gogoproto/" + proto.MessageName(PT(new(T)))
|
||||
}
|
||||
|
||||
// CollInterfaceValue instantiates a new collections.ValueCodec for a generic
|
||||
// interface value. The codec must be able to marshal and unmarshal the
|
||||
// interface.
|
||||
func CollInterfaceValue[T proto.Message](codec BinaryCodec) collcodec.ValueCodec[T] {
|
||||
var x T // assertion
|
||||
if reflect.TypeOf(&x).Elem().Kind() != reflect.Interface {
|
||||
panic("CollInterfaceValue can only be used with interface types")
|
||||
}
|
||||
return collInterfaceValue[T]{codec.(Codec)}
|
||||
}
|
||||
|
||||
type collInterfaceValue[T proto.Message] struct {
|
||||
codec Codec
|
||||
}
|
||||
|
||||
func (c collInterfaceValue[T]) Encode(value T) ([]byte, error) {
|
||||
return c.codec.MarshalInterface(value)
|
||||
}
|
||||
|
||||
func (c collInterfaceValue[T]) Decode(b []byte) (T, error) {
|
||||
var value T
|
||||
err := c.codec.UnmarshalInterface(b, &value)
|
||||
return value, err
|
||||
}
|
||||
|
||||
func (c collInterfaceValue[T]) EncodeJSON(value T) ([]byte, error) {
|
||||
return c.codec.MarshalInterfaceJSON(value)
|
||||
}
|
||||
|
||||
func (c collInterfaceValue[T]) DecodeJSON(b []byte) (T, error) {
|
||||
var value T
|
||||
err := c.codec.UnmarshalInterfaceJSON(b, &value)
|
||||
return value, err
|
||||
}
|
||||
|
||||
func (c collInterfaceValue[T]) Stringify(value T) string {
|
||||
return value.String()
|
||||
}
|
||||
|
||||
func (c collInterfaceValue[T]) ValueType() string {
|
||||
var t T
|
||||
return fmt.Sprintf("%T", t)
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
package codec
|
||||
package codec_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/testutil/testdata"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"cosmossdk.io/collections/colltest"
|
||||
@@ -11,22 +14,22 @@ import (
|
||||
)
|
||||
|
||||
func TestCollectionsCorrectness(t *testing.T) {
|
||||
cdc := NewProtoCodec(codectypes.NewInterfaceRegistry())
|
||||
t.Run("CollValue", func(t *testing.T) {
|
||||
colltest.TestValueCodec(t, CollValue[gogotypes.UInt64Value](cdc), gogotypes.UInt64Value{
|
||||
cdc := codec.NewProtoCodec(codectypes.NewInterfaceRegistry())
|
||||
colltest.TestValueCodec(t, codec.CollValue[gogotypes.UInt64Value](cdc), gogotypes.UInt64Value{
|
||||
Value: 500,
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("BoolValue", func(t *testing.T) {
|
||||
colltest.TestValueCodec(t, BoolValue, true)
|
||||
colltest.TestValueCodec(t, BoolValue, false)
|
||||
colltest.TestValueCodec(t, codec.BoolValue, true)
|
||||
colltest.TestValueCodec(t, codec.BoolValue, false)
|
||||
|
||||
// asserts produced bytes are equal
|
||||
valueAssert := func(b bool) {
|
||||
wantBytes, err := (&gogotypes.BoolValue{Value: b}).Marshal()
|
||||
require.NoError(t, err)
|
||||
gotBytes, err := BoolValue.Encode(b)
|
||||
gotBytes, err := codec.BoolValue.Encode(b)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, wantBytes, gotBytes)
|
||||
}
|
||||
@@ -34,4 +37,18 @@ func TestCollectionsCorrectness(t *testing.T) {
|
||||
valueAssert(true)
|
||||
valueAssert(false)
|
||||
})
|
||||
|
||||
t.Run("CollInterfaceValue", func(t *testing.T) {
|
||||
cdc := codec.NewProtoCodec(codectypes.NewInterfaceRegistry())
|
||||
cdc.InterfaceRegistry().RegisterInterface("animal", (*testdata.Animal)(nil), &testdata.Dog{}, &testdata.Cat{})
|
||||
valueCodec := codec.CollInterfaceValue[testdata.Animal](cdc)
|
||||
|
||||
colltest.TestValueCodec[testdata.Animal](t, valueCodec, &testdata.Dog{Name: "Doggo"})
|
||||
colltest.TestValueCodec[testdata.Animal](t, valueCodec, &testdata.Cat{Moniker: "Kitty"})
|
||||
|
||||
// assert if used with a non interface type it yields a panic.
|
||||
require.Panics(t, func() {
|
||||
codec.CollInterfaceValue[*testdata.Dog](cdc)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user