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 }