wasmd/x/wasm/client/codec/marshaller.go

80 lines
2.4 KiB
Go

package codec
import (
"bytes"
"fmt"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/codec/types"
"github.com/gogo/protobuf/jsonpb"
"github.com/gogo/protobuf/proto"
)
var _ codec.Codec = (*ProtoCodec)(nil)
// ProtoCodec that omits empty values.
// This Marshaler can be used globally when setting up the client context or individually
// for each command via `clientCtx.WithJSONMarshaler(myMarshaler)`.
type ProtoCodec struct {
codec.Codec
interfaceRegistry types.InterfaceRegistry
}
func NewProtoCodec(marshaler codec.Codec, registry types.InterfaceRegistry) *ProtoCodec {
return &ProtoCodec{Codec: marshaler, interfaceRegistry: registry}
}
// MarshalJSON implements JSONMarshaler.MarshalJSON method,
// it marshals to JSON using proto codec.
func (pc *ProtoCodec) MarshalJSON(o proto.Message) ([]byte, error) {
m, ok := o.(codec.ProtoMarshaler)
if !ok {
return nil, fmt.Errorf("cannot protobuf JSON encode unsupported type: %T", o)
}
return ProtoMarshalJSON(m, pc.interfaceRegistry)
}
// MustMarshalJSON implements JSONMarshaler.MustMarshalJSON method,
// it executes MarshalJSON except it panics upon failure.
func (pc *ProtoCodec) MustMarshalJSON(o proto.Message) []byte {
bz, err := pc.MarshalJSON(o)
if err != nil {
panic(err)
}
return bz
}
// MarshalInterfaceJSON is a convenience function for proto marshalling interfaces. It
// packs the provided value in an Any and then marshals it to bytes.
// NOTE: to marshal a concrete type, you should use MarshalJSON instead
func (pc *ProtoCodec) MarshalInterfaceJSON(x proto.Message) ([]byte, error) {
any, err := types.NewAnyWithValue(x)
if err != nil {
return nil, err
}
return pc.MarshalJSON(any)
}
// ProtoMarshalJSON provides an auxiliary function to return Proto3 JSON encoded
// bytes of a message.
func ProtoMarshalJSON(msg proto.Message, resolver jsonpb.AnyResolver) ([]byte, error) {
// method copied from sdk codec/json.go with EmitDefaults set to `false`
// so that empty fields are not rendered
// We use the OrigName because camel casing fields just doesn't make sense.
// EmitDefaults is also often the more expected behavior for CLI users
jm := &jsonpb.Marshaler{OrigName: true, EmitDefaults: false, AnyResolver: resolver}
err := types.UnpackInterfaces(msg, types.ProtoJSONPacker{JSONPBMarshaler: jm})
if err != nil {
return nil, err
}
buf := new(bytes.Buffer)
if err := jm.Marshal(buf, msg); err != nil {
return nil, err
}
return buf.Bytes(), nil
}