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 }