github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/tm2/pkg/amino/encoder.go (about)

     1  package amino
     2  
     3  import (
     4  	"encoding/binary"
     5  	"fmt"
     6  	"io"
     7  	"math"
     8  	"math/bits"
     9  	"time"
    10  )
    11  
    12  // ----------------------------------------
    13  // Signed
    14  
    15  func EncodeVarint8(w io.Writer, i int8) (err error) {
    16  	var buf [2]byte
    17  	n := binary.PutVarint(buf[:], int64(i))
    18  	_, err = w.Write(buf[0:n])
    19  	return
    20  }
    21  
    22  func EncodeVarint16(w io.Writer, i int16) (err error) {
    23  	var buf [3]byte
    24  	n := binary.PutVarint(buf[:], int64(i))
    25  	_, err = w.Write(buf[0:n])
    26  	return
    27  }
    28  
    29  func EncodeVarint32(w io.Writer, i int32) (err error) {
    30  	var buf [5]byte
    31  	n := binary.PutVarint(buf[:], int64(i))
    32  	_, err = w.Write(buf[0:n])
    33  	return
    34  }
    35  
    36  func EncodeVarint(w io.Writer, i int64) (err error) {
    37  	var buf [10]byte
    38  	n := binary.PutVarint(buf[:], i)
    39  	_, err = w.Write(buf[0:n])
    40  	return
    41  }
    42  
    43  func EncodeInt32(w io.Writer, i int32) (err error) {
    44  	var buf [4]byte
    45  	binary.LittleEndian.PutUint32(buf[:], uint32(i))
    46  	_, err = w.Write(buf[:])
    47  	return
    48  }
    49  
    50  func EncodeInt64(w io.Writer, i int64) (err error) {
    51  	var buf [8]byte
    52  	binary.LittleEndian.PutUint64(buf[:], uint64(i))
    53  	_, err = w.Write(buf[:])
    54  	return err
    55  }
    56  
    57  func VarintSize(i int64) int {
    58  	return UvarintSize((uint64(i) << 1) ^ uint64(i>>63))
    59  }
    60  
    61  // ----------------------------------------
    62  // Unsigned
    63  
    64  // Unlike EncodeUint8, writes a single byte.
    65  func EncodeByte(w io.Writer, b byte) (err error) {
    66  	_, err = w.Write([]byte{b})
    67  	return
    68  }
    69  
    70  func EncodeUvarint8(w io.Writer, i uint8) (err error) {
    71  	var buf [2]byte
    72  	n := binary.PutUvarint(buf[:], uint64(i))
    73  	_, err = w.Write(buf[0:n])
    74  	return
    75  }
    76  
    77  func EncodeUvarint16(w io.Writer, i uint16) (err error) {
    78  	var buf [3]byte
    79  	n := binary.PutUvarint(buf[:], uint64(i))
    80  	_, err = w.Write(buf[0:n])
    81  	return
    82  }
    83  
    84  func EncodeUvarint32(w io.Writer, i uint32) (err error) {
    85  	var buf [5]byte
    86  	n := binary.PutUvarint(buf[:], uint64(i))
    87  	_, err = w.Write(buf[0:n])
    88  	return
    89  }
    90  
    91  func EncodeUvarint(w io.Writer, u uint64) (err error) {
    92  	var buf [10]byte
    93  	n := binary.PutUvarint(buf[:], u)
    94  	_, err = w.Write(buf[0:n])
    95  	return
    96  }
    97  
    98  func EncodeUint32(w io.Writer, u uint32) (err error) {
    99  	var buf [4]byte
   100  	binary.LittleEndian.PutUint32(buf[:], u)
   101  	_, err = w.Write(buf[:])
   102  	return
   103  }
   104  
   105  func EncodeUint64(w io.Writer, u uint64) (err error) {
   106  	var buf [8]byte
   107  	binary.LittleEndian.PutUint64(buf[:], u)
   108  	_, err = w.Write(buf[:])
   109  	return
   110  }
   111  
   112  func UvarintSize(u uint64) int {
   113  	if u == 0 {
   114  		return 1
   115  	}
   116  	return (bits.Len64(u) + 6) / 7
   117  }
   118  
   119  // ----------------------------------------
   120  // Other Primitives
   121  
   122  func EncodeBool(w io.Writer, b bool) (err error) {
   123  	if b {
   124  		err = EncodeByte(w, 0x01)
   125  	} else {
   126  		err = EncodeByte(w, 0x00)
   127  	}
   128  	return
   129  }
   130  
   131  // NOTE: UNSAFE
   132  func EncodeFloat32(w io.Writer, f float32) (err error) {
   133  	return EncodeUint32(w, math.Float32bits(f))
   134  }
   135  
   136  // NOTE: UNSAFE
   137  func EncodeFloat64(w io.Writer, f float64) (err error) {
   138  	return EncodeUint64(w, math.Float64bits(f))
   139  }
   140  
   141  // ----------------------------------------
   142  // Time and Duration
   143  
   144  const (
   145  	// See https://github.com/protocolbuffers/protobuf/blob/d2980062c859649523d5fd51d6b55ab310e47482/src/google/protobuf/timestamp.proto#L123-L135
   146  	// seconds of 01-01-0001
   147  	minTimeSeconds int64 = -62135596800
   148  	// seconds of 10000-01-01
   149  	maxTimeSeconds int64 = 253402300800 // exclusive
   150  	// nanos have to be in interval: [0, 999999999]
   151  	maxTimeNanos = 999999999 // inclusive
   152  
   153  	// See https://github.com/protocolbuffers/protobuf/blob/d2980062c859649523d5fd51d6b55ab310e47482/src/google/protobuf/duration.proto#L105-L116
   154  	minDurationSeconds int64 = -315576000000
   155  	maxDurationSeconds int64 = 315576000000 // inclusive
   156  	minDurationNanos         = -999999999
   157  	maxDurationNanos         = 999999999 // inclusive
   158  )
   159  
   160  type InvalidTimeError string
   161  
   162  func (e InvalidTimeError) Error() string {
   163  	return "invalid time: " + string(e)
   164  }
   165  
   166  type InvalidDurationError string
   167  
   168  func (e InvalidDurationError) Error() string {
   169  	return "invalid duration: " + string(e)
   170  }
   171  
   172  // EncodeTimeValue writes the number of seconds (int64) and nanoseconds (int32),
   173  // with millisecond resolution since January 1, 1970 UTC to the Writer as an
   174  // UInt64.
   175  // Milliseconds are used to ease compatibility with Javascript,
   176  // which does not support finer resolution.
   177  /* See https://godoc.org/google.golang.org/protobuf/types/known/timestamppb#Timestamp
   178  type Timestamp struct {
   179  
   180      // Represents seconds of UTC time since Unix epoch
   181      // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to
   182      // 9999-12-31T23:59:59Z inclusive.
   183      Seconds int64 `protobuf:"varint,1,opt,name=seconds,proto3" json:"seconds,omitempty"`
   184      // Non-negative fractions of a second at nanosecond resolution. Negative
   185      // second values with fractions must still have non-negative nanos values
   186      // that count forward in time. Must be from 0 to 999,999,999
   187      // inclusive.
   188      Nanos int32 `protobuf:"varint,2,opt,name=nanos,proto3" json:"nanos,omitempty"`
   189      // contains filtered or unexported fields
   190  }
   191  */
   192  func EncodeTimeValue(w io.Writer, s int64, ns int32) (err error) {
   193  	// Validations
   194  	err = validateTimeValue(s, ns)
   195  	if err != nil {
   196  		return
   197  	}
   198  	// skip if default/zero value:
   199  	if s != 0 {
   200  		err = encodeFieldNumberAndTyp3(w, 1, Typ3Varint)
   201  		if err != nil {
   202  			return
   203  		}
   204  		err = EncodeUvarint(w, uint64(s))
   205  		if err != nil {
   206  			return
   207  		}
   208  	}
   209  	// skip if default/zero value:
   210  	if ns != 0 {
   211  		err = encodeFieldNumberAndTyp3(w, 2, Typ3Varint)
   212  		if err != nil {
   213  			return
   214  		}
   215  		err = EncodeUvarint(w, uint64(ns))
   216  		if err != nil {
   217  			return
   218  		}
   219  	}
   220  
   221  	return err
   222  }
   223  
   224  func EncodeTime(w io.Writer, t time.Time) (err error) {
   225  	return EncodeTimeValue(w, t.Unix(), int32(t.Nanosecond()))
   226  }
   227  
   228  func validateTimeValue(s int64, ns int32) (err error) {
   229  	if s < minTimeSeconds || s >= maxTimeSeconds {
   230  		return InvalidTimeError(fmt.Sprintf("seconds have to be >= %d and < %d, got: %d",
   231  			minTimeSeconds, maxTimeSeconds, s))
   232  	}
   233  	if ns < 0 || ns > maxTimeNanos {
   234  		// we could as well panic here:
   235  		// time.Time.Nanosecond() guarantees nanos to be in [0, 999,999,999]
   236  		return InvalidTimeError(fmt.Sprintf("nanoseconds have to be >= 0 and <= %v, got: %d",
   237  			maxTimeNanos, ns))
   238  	}
   239  	return nil
   240  }
   241  
   242  // The binary encoding of Duration is the same as Timestamp,
   243  // but the validation checks are different.
   244  /* See https://godoc.org/google.golang.org/protobuf/types/known/durationpb#Duration
   245  type Duration struct {
   246  
   247      // Signed seconds of the span of time. Must be from -315,576,000,000
   248      // to +315,576,000,000 inclusive. Note: these bounds are computed from:
   249      // 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years
   250      Seconds int64 `protobuf:"varint,1,opt,name=seconds,proto3" json:"seconds,omitempty"`
   251      // Signed fractions of a second at nanosecond resolution of the span
   252      // of time. Durations less than one second are represented with a 0
   253      // `seconds` field and a positive or negative `nanos` field. For durations
   254      // of one second or more, a non-zero value for the `nanos` field must be
   255      // of the same sign as the `seconds` field. Must be from -999,999,999
   256      // to +999,999,999 inclusive.
   257      Nanos int32 `protobuf:"varint,2,opt,name=nanos,proto3" json:"nanos,omitempty"`
   258      // contains filtered or unexported fields
   259  }
   260  */
   261  func EncodeDurationValue(w io.Writer, s int64, ns int32) (err error) {
   262  	// Validations
   263  	err = validateDurationValue(s, ns)
   264  	if err != nil {
   265  		return err
   266  	}
   267  	// skip if default/zero value:
   268  	if s != 0 {
   269  		err = encodeFieldNumberAndTyp3(w, 1, Typ3Varint)
   270  		if err != nil {
   271  			return
   272  		}
   273  		err = EncodeUvarint(w, uint64(s))
   274  		if err != nil {
   275  			return
   276  		}
   277  	}
   278  	// skip if default/zero value:
   279  	if ns != 0 {
   280  		err = encodeFieldNumberAndTyp3(w, 2, Typ3Varint)
   281  		if err != nil {
   282  			return
   283  		}
   284  		err = EncodeUvarint(w, uint64(ns))
   285  		if err != nil {
   286  			return
   287  		}
   288  	}
   289  
   290  	return err
   291  }
   292  
   293  func EncodeDuration(w io.Writer, d time.Duration) (err error) {
   294  	sns := d.Nanoseconds()
   295  	s, ns := sns/1e9, int32(sns%1e9)
   296  	err = validateDurationValue(s, ns)
   297  	if err != nil {
   298  		return err
   299  	}
   300  	return EncodeDurationValue(w, s, ns)
   301  }
   302  
   303  func validateDurationValue(s int64, ns int32) (err error) {
   304  	if (s > 0 && ns < 0) || (s < 0 && ns > 0) {
   305  		return InvalidDurationError(fmt.Sprintf("signs of seconds and nanos do not match: %v and %v",
   306  			s, ns))
   307  	}
   308  	if s < minDurationSeconds || s > maxDurationSeconds {
   309  		return InvalidDurationError(fmt.Sprintf("seconds have to be >= %d and < %d, got: %d",
   310  			minDurationSeconds, maxDurationSeconds, s))
   311  	}
   312  	if ns < minDurationNanos || ns > maxDurationNanos {
   313  		return InvalidDurationError(fmt.Sprintf("ns out of range [%v, %v], got: %v",
   314  			minDurationNanos, maxDurationNanos, ns))
   315  	}
   316  	return nil
   317  }
   318  
   319  const (
   320  	// On the other hand, Go's native duration only allows a smaller interval:
   321  	// https://golang.org/pkg/time/#Duration
   322  	minDurationSecondsGo = int64(math.MinInt64) / int64(1e9)
   323  	maxDurationSecondsGo = int64(math.MaxInt64) / int64(1e9)
   324  )
   325  
   326  // Go's time.Duration has a more limited range.
   327  // This is specific to Go and not Amino.
   328  func validateDurationValueGo(s int64, ns int32) (err error) {
   329  	err = validateDurationValue(s, ns)
   330  	if err != nil {
   331  		return err
   332  	}
   333  	if s < minDurationSecondsGo || s > maxDurationSecondsGo {
   334  		return InvalidDurationError(fmt.Sprintf("duration seconds exceeds bounds for Go's time.Duration type: %v",
   335  			s))
   336  	}
   337  	sns := s*1e9 + int64(ns)
   338  	if sns > 0 && s < 0 || sns < 0 && s > 0 {
   339  		return InvalidDurationError(fmt.Sprintf("duration seconds+nanoseconds exceeds bounds for Go's time.Duration type: %v and %v",
   340  			s, ns))
   341  	}
   342  	return nil
   343  }
   344  
   345  // ----------------------------------------
   346  // Byte Slices and Strings
   347  
   348  func EncodeByteSlice(w io.Writer, bz []byte) (err error) {
   349  	err = EncodeUvarint(w, uint64(len(bz)))
   350  	if err != nil {
   351  		return
   352  	}
   353  	_, err = w.Write(bz)
   354  	return
   355  }
   356  
   357  func ByteSliceSize(bz []byte) int {
   358  	return UvarintSize(uint64(len(bz))) + len(bz)
   359  }
   360  
   361  func EncodeString(w io.Writer, s string) (err error) {
   362  	return EncodeByteSlice(w, []byte(s))
   363  }