github.com/Finschia/finschia-sdk@v0.48.1/codec/proto_codec.go (about)

     1  package codec
     2  
     3  import (
     4  	"encoding/binary"
     5  	"errors"
     6  	"fmt"
     7  	"strings"
     8  
     9  	"github.com/gogo/protobuf/jsonpb"
    10  	"github.com/gogo/protobuf/proto"
    11  
    12  	"github.com/Finschia/finschia-sdk/codec/types"
    13  )
    14  
    15  // ProtoCodecMarshaler defines an interface for codecs that utilize Protobuf for both
    16  // binary and JSON encoding.
    17  type ProtoCodecMarshaler interface {
    18  	Codec
    19  	InterfaceRegistry() types.InterfaceRegistry
    20  }
    21  
    22  // ProtoCodec defines a codec that utilizes Protobuf for both binary and JSON
    23  // encoding.
    24  type ProtoCodec struct {
    25  	interfaceRegistry types.InterfaceRegistry
    26  }
    27  
    28  var (
    29  	_ Codec               = &ProtoCodec{}
    30  	_ ProtoCodecMarshaler = &ProtoCodec{}
    31  )
    32  
    33  // NewProtoCodec returns a reference to a new ProtoCodec
    34  func NewProtoCodec(interfaceRegistry types.InterfaceRegistry) *ProtoCodec {
    35  	return &ProtoCodec{interfaceRegistry: interfaceRegistry}
    36  }
    37  
    38  // Marshal implements BinaryMarshaler.Marshal method.
    39  // NOTE: this function must be used with a concrete type which
    40  // implements proto.Message. For interface please use the codec.MarshalInterface
    41  func (pc *ProtoCodec) Marshal(o ProtoMarshaler) ([]byte, error) {
    42  	return o.Marshal()
    43  }
    44  
    45  // MustMarshal implements BinaryMarshaler.MustMarshal method.
    46  // NOTE: this function must be used with a concrete type which
    47  // implements proto.Message. For interface please use the codec.MarshalInterface
    48  func (pc *ProtoCodec) MustMarshal(o ProtoMarshaler) []byte {
    49  	bz, err := pc.Marshal(o)
    50  	if err != nil {
    51  		panic(err)
    52  	}
    53  
    54  	return bz
    55  }
    56  
    57  // MarshalLengthPrefixed implements BinaryMarshaler.MarshalLengthPrefixed method.
    58  func (pc *ProtoCodec) MarshalLengthPrefixed(o ProtoMarshaler) ([]byte, error) {
    59  	bz, err := pc.Marshal(o)
    60  	if err != nil {
    61  		return nil, err
    62  	}
    63  
    64  	var sizeBuf [binary.MaxVarintLen64]byte
    65  	n := binary.PutUvarint(sizeBuf[:], uint64(o.Size()))
    66  	return append(sizeBuf[:n], bz...), nil
    67  }
    68  
    69  // MustMarshalLengthPrefixed implements BinaryMarshaler.MustMarshalLengthPrefixed method.
    70  func (pc *ProtoCodec) MustMarshalLengthPrefixed(o ProtoMarshaler) []byte {
    71  	bz, err := pc.MarshalLengthPrefixed(o)
    72  	if err != nil {
    73  		panic(err)
    74  	}
    75  
    76  	return bz
    77  }
    78  
    79  // Unmarshal implements BinaryMarshaler.Unmarshal method.
    80  // NOTE: this function must be used with a concrete type which
    81  // implements proto.Message. For interface please use the codec.UnmarshalInterface
    82  func (pc *ProtoCodec) Unmarshal(bz []byte, ptr ProtoMarshaler) error {
    83  	err := ptr.Unmarshal(bz)
    84  	if err != nil {
    85  		return err
    86  	}
    87  	err = types.UnpackInterfaces(ptr, pc.interfaceRegistry)
    88  	if err != nil {
    89  		return err
    90  	}
    91  	return nil
    92  }
    93  
    94  // MustUnmarshal implements BinaryMarshaler.MustUnmarshal method.
    95  // NOTE: this function must be used with a concrete type which
    96  // implements proto.Message. For interface please use the codec.UnmarshalInterface
    97  func (pc *ProtoCodec) MustUnmarshal(bz []byte, ptr ProtoMarshaler) {
    98  	if err := pc.Unmarshal(bz, ptr); err != nil {
    99  		panic(err)
   100  	}
   101  }
   102  
   103  // UnmarshalLengthPrefixed implements BinaryMarshaler.UnmarshalLengthPrefixed method.
   104  func (pc *ProtoCodec) UnmarshalLengthPrefixed(bz []byte, ptr ProtoMarshaler) error {
   105  	size, n := binary.Uvarint(bz)
   106  	if n < 0 {
   107  		return fmt.Errorf("invalid number of bytes read from length-prefixed encoding: %d", n)
   108  	}
   109  
   110  	if size > uint64(len(bz)-n) {
   111  		return fmt.Errorf("not enough bytes to read; want: %v, got: %v", size, len(bz)-n)
   112  	} else if size < uint64(len(bz)-n) {
   113  		return fmt.Errorf("too many bytes to read; want: %v, got: %v", size, len(bz)-n)
   114  	}
   115  
   116  	bz = bz[n:]
   117  	return pc.Unmarshal(bz, ptr)
   118  }
   119  
   120  // MustUnmarshalLengthPrefixed implements BinaryMarshaler.MustUnmarshalLengthPrefixed method.
   121  func (pc *ProtoCodec) MustUnmarshalLengthPrefixed(bz []byte, ptr ProtoMarshaler) {
   122  	if err := pc.UnmarshalLengthPrefixed(bz, ptr); err != nil {
   123  		panic(err)
   124  	}
   125  }
   126  
   127  // MarshalJSON implements JSONCodec.MarshalJSON method,
   128  // it marshals to JSON using proto codec.
   129  // NOTE: this function must be used with a concrete type which
   130  // implements proto.Message. For interface please use the codec.MarshalInterfaceJSON
   131  func (pc *ProtoCodec) MarshalJSON(o proto.Message) ([]byte, error) {
   132  	m, ok := o.(ProtoMarshaler)
   133  	if !ok {
   134  		return nil, fmt.Errorf("cannot protobuf JSON encode unsupported type: %T", o)
   135  	}
   136  
   137  	return ProtoMarshalJSON(m, pc.interfaceRegistry)
   138  }
   139  
   140  // MustMarshalJSON implements JSONCodec.MustMarshalJSON method,
   141  // it executes MarshalJSON except it panics upon failure.
   142  // NOTE: this function must be used with a concrete type which
   143  // implements proto.Message. For interface please use the codec.MarshalInterfaceJSON
   144  func (pc *ProtoCodec) MustMarshalJSON(o proto.Message) []byte {
   145  	bz, err := pc.MarshalJSON(o)
   146  	if err != nil {
   147  		panic(err)
   148  	}
   149  
   150  	return bz
   151  }
   152  
   153  // UnmarshalJSON implements JSONCodec.UnmarshalJSON method,
   154  // it unmarshals from JSON using proto codec.
   155  // NOTE: this function must be used with a concrete type which
   156  // implements proto.Message. For interface please use the codec.UnmarshalInterfaceJSON
   157  func (pc *ProtoCodec) UnmarshalJSON(bz []byte, ptr proto.Message) error {
   158  	m, ok := ptr.(ProtoMarshaler)
   159  	if !ok {
   160  		return fmt.Errorf("cannot protobuf JSON decode unsupported type: %T", ptr)
   161  	}
   162  
   163  	unmarshaler := jsonpb.Unmarshaler{AnyResolver: pc.interfaceRegistry}
   164  	err := unmarshaler.Unmarshal(strings.NewReader(string(bz)), m)
   165  	if err != nil {
   166  		return err
   167  	}
   168  
   169  	return types.UnpackInterfaces(ptr, pc.interfaceRegistry)
   170  }
   171  
   172  // MustUnmarshalJSON implements JSONCodec.MustUnmarshalJSON method,
   173  // it executes UnmarshalJSON except it panics upon failure.
   174  // NOTE: this function must be used with a concrete type which
   175  // implements proto.Message. For interface please use the codec.UnmarshalInterfaceJSON
   176  func (pc *ProtoCodec) MustUnmarshalJSON(bz []byte, ptr proto.Message) {
   177  	if err := pc.UnmarshalJSON(bz, ptr); err != nil {
   178  		panic(err)
   179  	}
   180  }
   181  
   182  // MarshalInterface is a convenience function for proto marshalling interfaces. It packs
   183  // the provided value, which must be an interface, in an Any and then marshals it to bytes.
   184  // NOTE: to marshal a concrete type, you should use Marshal instead
   185  func (pc *ProtoCodec) MarshalInterface(i proto.Message) ([]byte, error) {
   186  	if err := assertNotNil(i); err != nil {
   187  		return nil, err
   188  	}
   189  	any, err := types.NewAnyWithValue(i)
   190  	if err != nil {
   191  		return nil, err
   192  	}
   193  
   194  	return pc.Marshal(any)
   195  }
   196  
   197  // UnmarshalInterface is a convenience function for proto unmarshaling interfaces. It
   198  // unmarshals an Any from bz bytes and then unpacks it to the `ptr`, which must
   199  // be a pointer to a non empty interface with registered implementations.
   200  // NOTE: to unmarshal a concrete type, you should use Unmarshal instead
   201  //
   202  // Example:
   203  //
   204  //	var x MyInterface
   205  //	err := cdc.UnmarshalInterface(bz, &x)
   206  func (pc *ProtoCodec) UnmarshalInterface(bz []byte, ptr interface{}) error {
   207  	any := &types.Any{}
   208  	err := pc.Unmarshal(bz, any)
   209  	if err != nil {
   210  		return err
   211  	}
   212  
   213  	return pc.UnpackAny(any, ptr)
   214  }
   215  
   216  // MarshalInterfaceJSON is a convenience function for proto marshalling interfaces. It
   217  // packs the provided value in an Any and then marshals it to bytes.
   218  // NOTE: to marshal a concrete type, you should use MarshalJSON instead
   219  func (pc *ProtoCodec) MarshalInterfaceJSON(x proto.Message) ([]byte, error) {
   220  	any, err := types.NewAnyWithValue(x)
   221  	if err != nil {
   222  		return nil, err
   223  	}
   224  	return pc.MarshalJSON(any)
   225  }
   226  
   227  // UnmarshalInterfaceJSON is a convenience function for proto unmarshaling interfaces.
   228  // It unmarshals an Any from bz bytes and then unpacks it to the `iface`, which must
   229  // be a pointer to a non empty interface, implementing proto.Message with registered implementations.
   230  // NOTE: to unmarshal a concrete type, you should use UnmarshalJSON instead
   231  //
   232  // Example:
   233  //
   234  //	var x MyInterface  // must implement proto.Message
   235  //	err := cdc.UnmarshalInterfaceJSON(&x, bz)
   236  func (pc *ProtoCodec) UnmarshalInterfaceJSON(bz []byte, iface interface{}) error {
   237  	any := &types.Any{}
   238  	err := pc.UnmarshalJSON(bz, any)
   239  	if err != nil {
   240  		return err
   241  	}
   242  	return pc.UnpackAny(any, iface)
   243  }
   244  
   245  // UnpackAny implements AnyUnpacker.UnpackAny method,
   246  // it unpacks the value in any to the interface pointer passed in as
   247  // iface.
   248  func (pc *ProtoCodec) UnpackAny(any *types.Any, iface interface{}) error {
   249  	return pc.interfaceRegistry.UnpackAny(any, iface)
   250  }
   251  
   252  // InterfaceRegistry returns InterfaceRegistry
   253  func (pc *ProtoCodec) InterfaceRegistry() types.InterfaceRegistry {
   254  	return pc.interfaceRegistry
   255  }
   256  
   257  func assertNotNil(i interface{}) error {
   258  	if i == nil {
   259  		return errors.New("can't marshal <nil> value")
   260  	}
   261  	return nil
   262  }