github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/tm2/pkg/amino/wellknown.go (about) 1 package amino 2 3 // NOTE: We must not depend on protubuf libraries for serialization. 4 5 import ( 6 "bytes" 7 "fmt" 8 "io" 9 "reflect" 10 "strings" 11 "time" 12 13 "google.golang.org/protobuf/proto" 14 "google.golang.org/protobuf/types/known/anypb" 15 "google.golang.org/protobuf/types/known/durationpb" 16 "google.golang.org/protobuf/types/known/emptypb" 17 18 //"google.golang.org/protobuf/types/known/structpb" 19 "google.golang.org/protobuf/types/known/timestamppb" 20 "google.golang.org/protobuf/types/known/wrapperspb" 21 ) 22 23 var ( 24 // native 25 timeType = reflect.TypeOf(time.Time{}) 26 durationType = reflect.TypeOf(time.Duration(0)) 27 // doubleType = reflect.TypeOf(float64(0)) 28 // floatType = reflect.TypeOf(float32(0)) 29 int64Type = reflect.TypeOf(int64(0)) 30 uint64Type = reflect.TypeOf(uint64(0)) 31 int32Type = reflect.TypeOf(int32(0)) 32 uint32Type = reflect.TypeOf(uint32(0)) 33 int16Type = reflect.TypeOf(int16(0)) 34 uint16Type = reflect.TypeOf(uint16(0)) 35 int8Type = reflect.TypeOf(int8(0)) 36 uint8Type = reflect.TypeOf(uint8(0)) 37 boolType = reflect.TypeOf(bool(false)) 38 stringType = reflect.TypeOf(string("")) 39 bytesType = reflect.TypeOf([]byte(nil)) 40 intType = reflect.TypeOf(int(0)) 41 uintType = reflect.TypeOf(uint(0)) 42 43 // google 44 gAnyType = reflect.TypeOf(anypb.Any{}) 45 gTimestampType = reflect.TypeOf(timestamppb.Timestamp{}) 46 gDurationType = reflect.TypeOf(durationpb.Duration{}) 47 gEmptyType = reflect.TypeOf(emptypb.Empty{}) 48 // gStructType = reflect.TypeOf(structpb.Struct{}) MAP not yet supported 49 // gValueType = reflect.TypeOf(structpb.Value{}) 50 // gListType = reflect.TypeOf(structpb.ListValue{}) 51 // gDoubleType = reflect.TypeOf(wrapperspb.DoubleValue{}) 52 // gFloatType = reflect.TypeOf(wrapperspb.FloatValue{}) 53 gInt64Type = reflect.TypeOf(wrapperspb.Int64Value{}) 54 gUInt64Type = reflect.TypeOf(wrapperspb.UInt64Value{}) 55 gInt32Type = reflect.TypeOf(wrapperspb.Int32Value{}) 56 gUInt32Type = reflect.TypeOf(wrapperspb.UInt32Value{}) 57 gBoolType = reflect.TypeOf(wrapperspb.BoolValue{}) 58 gStringType = reflect.TypeOf(wrapperspb.StringValue{}) 59 gBytesType = reflect.TypeOf(wrapperspb.BytesValue{}) 60 ) 61 62 var ( 63 nativePkg = NewPackage( 64 "", 65 "", 66 "", 67 ). 68 WithP3SchemaFile(""). 69 WithTypes( 70 int64(0), uint64(0), int32(0), uint32(0), bool(false), 71 string(""), []byte(nil), int(0), uint(0), 72 ) 73 74 timePkg = NewPackage( 75 "time", 76 "", 77 "", 78 ). 79 WithP3SchemaFile(""). 80 WithP3GoPkgPath(""). // since conflicting p3 pkg paths. 81 WithTypes( 82 time.Now(), 83 time.Duration(0), 84 ) 85 86 gAnyPkg = NewPackage( 87 "google.golang.org/protobuf/types/known/anypb", 88 "google.protobuf", 89 "", 90 ). 91 WithP3ImportPath("google/protobuf/any.proto"). 92 WithP3SchemaFile(""). 93 WithTypes(&anypb.Any{}) 94 95 gTimestampPkg = NewPackage( 96 "google.golang.org/protobuf/types/known/timestamppb", 97 "google.protobuf", 98 "", 99 ). 100 WithP3ImportPath("google/protobuf/timestamp.proto"). 101 WithP3SchemaFile(""). 102 WithTypes(×tamppb.Timestamp{}) 103 104 gDurationPkg = NewPackage( 105 "google.golang.org/protobuf/types/known/durationpb", 106 "google.protobuf", 107 "", 108 ). 109 WithP3ImportPath("google/protobuf/duration.proto"). 110 WithP3SchemaFile(""). 111 WithTypes(&durationpb.Duration{}) 112 113 gEmptyPkg = NewPackage( 114 "google.golang.org/protobuf/types/known/emptypb", 115 "google.protobuf", 116 "", 117 ). 118 WithP3ImportPath("google/protobuf/empty.proto"). 119 WithP3SchemaFile(""). 120 WithTypes(&emptypb.Empty{}) 121 122 gWrappersPkg = NewPackage( 123 "google.golang.org/protobuf/types/known/wrapperspb", 124 "google.protobuf", 125 "", 126 ). 127 WithP3ImportPath("google/protobuf/wrappers.proto"). 128 WithP3SchemaFile(""). 129 WithTypes( 130 &wrapperspb.BoolValue{}, 131 &wrapperspb.BytesValue{}, 132 &wrapperspb.DoubleValue{}, 133 &wrapperspb.FloatValue{}, 134 &wrapperspb.Int32Value{}, 135 &wrapperspb.Int64Value{}, 136 &wrapperspb.StringValue{}, 137 &wrapperspb.UInt32Value{}, 138 &wrapperspb.UInt64Value{}, 139 ) 140 ) 141 142 func (cdc *Codec) registerWellKnownTypes() { 143 register, preferNative := true, false 144 ptr, noPtr := true, false 145 // native not supported by protobuf 146 cdc.registerType(nativePkg, uint16Type, "/amino.UInt16", noPtr, register) // XXX create them, and consider switching other types over. 147 cdc.registerType(nativePkg, uint8Type, "/amino.UInt8", noPtr, register) 148 cdc.registerType(nativePkg, int16Type, "/amino.Int16", noPtr, register) 149 cdc.registerType(nativePkg, int8Type, "/amino.Int8", noPtr, register) 150 // native 151 cdc.registerType(timePkg, timeType, "/google.protobuf.Timestamp", noPtr, register) 152 cdc.registerType(timePkg, durationType, "/google.protobuf.Duration", noPtr, register) 153 cdc.registerType(nativePkg, int64Type, "/google.protobuf.Int64Value", noPtr, register) 154 cdc.registerType(nativePkg, uint64Type, "/google.protobuf.UInt64Value", noPtr, register) 155 cdc.registerType(nativePkg, int32Type, "/google.protobuf.Int32Value", noPtr, register) 156 cdc.registerType(nativePkg, uint32Type, "/google.protobuf.UInt32Value", noPtr, register) 157 cdc.registerType(nativePkg, boolType, "/google.protobuf.BoolValue", noPtr, register) 158 cdc.registerType(nativePkg, stringType, "/google.protobuf.StringValue", noPtr, register) 159 cdc.registerType(nativePkg, bytesType, "/google.protobuf.BytesValue", noPtr, register) 160 cdc.registerType(nativePkg, intType, "/google.protobuf.Int64Value", noPtr, preferNative) 161 cdc.registerType(nativePkg, uintType, "/google.protobuf.UInt64Value", noPtr, preferNative) 162 // google 163 cdc.registerType(gAnyPkg, gAnyType, "/google.protobuf.Any", ptr, register) 164 cdc.registerType(gDurationPkg, gDurationType, "/google.protobuf.Duration", ptr, preferNative) 165 cdc.registerType(gEmptyPkg, gEmptyType, "/google.protobuf.Empty", ptr, register) 166 cdc.registerType(gTimestampPkg, gTimestampType, "/google.protobuf.Timestamp", ptr, preferNative) 167 cdc.registerType(gWrappersPkg, gInt64Type, "/google.protobuf.Int64Value", ptr, preferNative) 168 cdc.registerType(gWrappersPkg, gUInt64Type, "/google.protobuf.UInt64Value", ptr, preferNative) 169 cdc.registerType(gWrappersPkg, gInt32Type, "/google.protobuf.Int32Value", ptr, preferNative) 170 cdc.registerType(gWrappersPkg, gUInt32Type, "/google.protobuf.UInt32Value", ptr, preferNative) 171 cdc.registerType(gWrappersPkg, gBoolType, "/google.protobuf.BoolValue", ptr, preferNative) 172 cdc.registerType(gWrappersPkg, gStringType, "/google.protobuf.StringValue", ptr, preferNative) 173 cdc.registerType(gWrappersPkg, gBytesType, "/google.protobuf.BytesValue", ptr, preferNative) 174 } 175 176 // These require special functions for encoding/decoding. 177 func isBinaryWellKnownType(rt reflect.Type) (wellKnown bool) { 178 switch rt { 179 // Native types. 180 case timeType, durationType: 181 return true 182 } 183 return false 184 } 185 186 // These require special functions for encoding/decoding. 187 func isJSONWellKnownType(rt reflect.Type) (wellKnown bool) { 188 // Special cases based on type. 189 switch rt { 190 // Native types. 191 case timeType, durationType: 192 return true 193 // Google "well known" types. 194 case 195 gAnyType, gTimestampType, gDurationType, gEmptyType, 196 /*gStructType, gValueType, gListType,*/ 197 /*gDoubleType, gFloatType,*/ 198 gInt64Type, gUInt64Type, gInt32Type, gUInt32Type, gBoolType, 199 gStringType, gBytesType: 200 return true 201 } 202 // General cases based on kind. 203 switch rt.Kind() { 204 case 205 reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, 206 reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, 207 reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64, 208 reflect.Array, reflect.Slice, reflect.String: 209 return true 210 default: 211 return false 212 } 213 return false 214 } 215 216 // Returns ok=false if nothing was done because the default behavior is fine (or if err). 217 // TODO: remove proto dependency. 218 func encodeReflectJSONWellKnown(w io.Writer, info *TypeInfo, rv reflect.Value, fopts FieldOptions) (ok bool, err error) { 219 switch info.Type { 220 // Native types. 221 case timeType: 222 // See https://github.com/golang/protobuf/blob/d04d7b157bb510b1e0c10132224b616ac0e26b17/jsonpb/encode.go#L308, 223 // "RFC 3339, where generated output will always be Z-normalized 224 // and uses 0, 3, 6 or 9 fractional digits." 225 t := rv.Interface().(time.Time) 226 err = EncodeJSONTime(w, t) 227 if err != nil { 228 return false, err 229 } 230 return true, nil 231 case durationType: 232 // "Generated output always contains 0, 3, 6, or 9 fractional digits, 233 // depending on required precision." 234 d := rv.Interface().(time.Duration) 235 err = EncodeJSONDuration(w, d) 236 if err != nil { 237 return false, err 238 } 239 return true, nil 240 // Google "well known" types. 241 case gTimestampType: 242 t := rv.Interface().(timestamppb.Timestamp) 243 err = EncodeJSONPBTimestamp(w, t) 244 if err != nil { 245 return false, err 246 } 247 return true, nil 248 case gDurationType: 249 d := rv.Interface().(durationpb.Duration) 250 err = EncodeJSONPBDuration(w, d) 251 if err != nil { 252 return false, err 253 } 254 return true, nil 255 // TODO: port each below to above without proto dependency 256 // for marshaling code, to minimize dependencies. 257 case 258 gAnyType, gEmptyType, 259 /*gStructType, gValueType, gListType,*/ 260 /*gDoubleType, gFloatType,*/ 261 gInt64Type, gUInt64Type, gInt32Type, gUInt32Type, gBoolType, 262 gStringType, gBytesType: 263 bz, err := proto.Marshal(rv.Interface().(proto.Message)) 264 if err != nil { 265 return false, err 266 } 267 _, err = w.Write(bz) 268 return true, err 269 } 270 return false, nil 271 } 272 273 // Returns ok=false if nothing was done because the default behavior is fine. 274 // CONTRACT: rv is a concrete type. 275 func decodeReflectJSONWellKnown(bz []byte, info *TypeInfo, rv reflect.Value, fopts FieldOptions) (ok bool, err error) { 276 if rv.Kind() == reflect.Interface { 277 panic("expected a concrete type to decode to") 278 } 279 switch info.Type { 280 // Native types. 281 case timeType: 282 var t time.Time 283 t, err = DecodeJSONTime(bz, fopts) 284 if err != nil { 285 return false, err 286 } 287 rv.Set(reflect.ValueOf(t)) 288 return true, nil 289 case durationType: 290 var d time.Duration 291 d, err = DecodeJSONDuration(bz, fopts) 292 if err != nil { 293 return false, err 294 } 295 rv.Set(reflect.ValueOf(d)) 296 return true, nil 297 // Google "well known" types. 298 case gTimestampType: 299 var t timestamppb.Timestamp 300 t, err = DecodeJSONPBTimestamp(bz, fopts) 301 if err != nil { 302 return false, err 303 } 304 rv.Set(reflect.ValueOf(t)) 305 return true, nil 306 case gDurationType: 307 var d durationpb.Duration 308 d, err = DecodeJSONPBDuration(bz, fopts) 309 if err != nil { 310 return false, err 311 } 312 rv.Set(reflect.ValueOf(d)) 313 return true, nil 314 // TODO: port each below to above without proto dependency 315 // for unmarshaling code, to minimize dependencies. 316 case 317 gAnyType, gEmptyType, 318 /*gStructType, gValueType, gListType,*/ 319 /*gDoubleType, gFloatType,*/ 320 gInt64Type, gUInt64Type, gInt32Type, gUInt32Type, gBoolType, 321 gStringType, gBytesType: 322 err := proto.Unmarshal(bz, rv.Addr().Interface().(proto.Message)) 323 if err != nil { 324 return false, err 325 } 326 return true, nil 327 } 328 return false, nil 329 } 330 331 // Returns ok=false if nothing was done because the default behavior is fine. 332 func encodeReflectBinaryWellKnown(w io.Writer, info *TypeInfo, rv reflect.Value, fopts FieldOptions, bare bool) (ok bool, err error) { 333 // Validations. 334 if rv.Kind() == reflect.Interface { 335 panic("expected a concrete type to decode to") 336 } 337 // Maybe recurse with length-prefixing. 338 if !bare { 339 buf := bytes.NewBuffer(nil) 340 ok, err = encodeReflectBinaryWellKnown(buf, info, rv, fopts, true) 341 if err != nil { 342 return false, err 343 } 344 err = EncodeByteSlice(w, buf.Bytes()) 345 if err != nil { 346 return false, err 347 } 348 return true, nil 349 } 350 switch info.Type { 351 // Native types. 352 case timeType: 353 var t time.Time 354 t = rv.Interface().(time.Time) 355 err = EncodeTime(w, t) 356 if err != nil { 357 return false, err 358 } 359 return true, nil 360 case durationType: 361 var d time.Duration 362 d = rv.Interface().(time.Duration) 363 err = EncodeDuration(w, d) 364 if err != nil { 365 return false, err 366 } 367 return true, nil 368 } 369 return false, nil 370 } 371 372 // Returns ok=false if nothing was done because the default behavior is fine. 373 func decodeReflectBinaryWellKnown(bz []byte, info *TypeInfo, rv reflect.Value, fopts FieldOptions, bare bool) (ok bool, n int, err error) { 374 // Validations. 375 if rv.Kind() == reflect.Interface { 376 panic("expected a concrete type to decode to") 377 } 378 // Strip if needed. 379 bz, err = decodeMaybeBare(bz, &n, bare) 380 if err != nil { 381 return false, n, err 382 } 383 switch info.Type { 384 // Native types. 385 case timeType: 386 var t time.Time 387 var n_ int 388 t, n_, err = DecodeTime(bz) 389 if slide(&bz, &n, n_) && err != nil { 390 return false, n, err 391 } 392 rv.Set(reflect.ValueOf(t)) 393 return true, n, nil 394 case durationType: 395 var d time.Duration 396 var n_ int 397 d, n_, err = DecodeDuration(bz) 398 if slide(&bz, &n, n_) && err != nil { 399 return false, n, err 400 } 401 rv.Set(reflect.ValueOf(d)) 402 return true, n, nil 403 } 404 return false, 0, nil 405 } 406 407 //---------------------------------------- 408 // Well known JSON encoders and decoders 409 410 func EncodeJSONTimeValue(w io.Writer, s int64, ns int32) (err error) { 411 err = validateTimeValue(s, ns) 412 if err != nil { 413 return err 414 } 415 // time.RFC3339Nano isn't exactly right (we need to get 3/6/9 fractional digits). 416 t := time.Unix(s, int64(ns)).Round(0).UTC() 417 x := t.Format("2006-01-02T15:04:05.000000000") 418 x = strings.TrimSuffix(x, "000") 419 x = strings.TrimSuffix(x, "000") 420 x = strings.TrimSuffix(x, ".000") 421 _, err = w.Write([]byte(fmt.Sprintf(`"%vZ"`, x))) 422 return err 423 } 424 425 func EncodeJSONTime(w io.Writer, t time.Time) (err error) { 426 t = t.Round(0).UTC() 427 return EncodeJSONTimeValue(w, t.Unix(), int32(t.Nanosecond())) 428 } 429 430 func EncodeJSONPBTimestamp(w io.Writer, t timestamppb.Timestamp) (err error) { 431 return EncodeJSONTimeValue(w, t.GetSeconds(), t.GetNanos()) 432 } 433 434 func EncodeJSONDurationValue(w io.Writer, s int64, ns int32) (err error) { 435 err = validateDurationValue(s, ns) 436 if err != nil { 437 return err 438 } 439 sign := "" 440 if s < 0 { 441 s = -s 442 sign = "-" 443 } 444 if ns < 0 { 445 ns = -ns 446 sign = "-" // could be true even if s == 0. 447 } 448 x := fmt.Sprintf("%s%d.%09d", sign, s, ns) 449 x = strings.TrimSuffix(x, "000") 450 x = strings.TrimSuffix(x, "000") 451 x = strings.TrimSuffix(x, ".000") 452 _, err = w.Write([]byte(fmt.Sprintf(`"%vs"`, x))) 453 return err 454 } 455 456 func EncodeJSONDuration(w io.Writer, d time.Duration) (err error) { 457 return EncodeJSONDurationValue(w, int64(d)/1e9, int32(int64(d)%1e9)) 458 } 459 460 func EncodeJSONPBDuration(w io.Writer, d durationpb.Duration) (err error) { 461 return EncodeJSONDurationValue(w, d.GetSeconds(), d.GetNanos()) 462 } 463 464 func DecodeJSONTime(bz []byte, fopts FieldOptions) (t time.Time, err error) { 465 t = emptyTime // defensive 466 v, err := unquoteString(string(bz)) 467 if err != nil { 468 return 469 } 470 t, err = time.Parse(time.RFC3339Nano, v) 471 if err != nil { 472 err = fmt.Errorf("bad time: %w", err) 473 return 474 } 475 return 476 } 477 478 // NOTE: probably not needed after protobuf v1.25 and after, replace with New(). 479 func newPBTimestamp(t time.Time) timestamppb.Timestamp { 480 return timestamppb.Timestamp{Seconds: t.Unix(), Nanos: int32(t.Nanosecond())} 481 } 482 483 func DecodeJSONPBTimestamp(bz []byte, fopts FieldOptions) (t timestamppb.Timestamp, err error) { 484 var t_ time.Time 485 t_, err = DecodeJSONTime(bz, fopts) 486 if err != nil { 487 return 488 } 489 return newPBTimestamp(t_), nil 490 } 491 492 func DecodeJSONDuration(bz []byte, fopts FieldOptions) (d time.Duration, err error) { 493 v, err := unquoteString(string(bz)) 494 if err != nil { 495 return 496 } 497 d, err = time.ParseDuration(v) 498 if err != nil { 499 err = fmt.Errorf("bad time: %w", err) 500 return 501 } 502 return 503 } 504 505 // NOTE: probably not needed after protobuf v1.25 and after, replace with New(). 506 func newPBDuration(d time.Duration) durationpb.Duration { 507 nanos := d.Nanoseconds() 508 secs := nanos / 1e9 509 nanos -= secs * 1e9 510 return durationpb.Duration{Seconds: secs, Nanos: int32(nanos)} 511 } 512 513 func DecodeJSONPBDuration(bz []byte, fopts FieldOptions) (d durationpb.Duration, err error) { 514 var d_ time.Duration 515 d_, err = DecodeJSONDuration(bz, fopts) 516 if err != nil { 517 return 518 } 519 return newPBDuration(d_), nil 520 } 521 522 func IsEmptyTime(t time.Time) bool { 523 t = t.Round(0).UTC() 524 return t.Unix() == 0 && t.Nanosecond() == 0 525 }