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(&timestamppb.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  }