github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/codec/proto_codec.go (about)

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