diff --git a/go.mod b/go.mod index 1f2f8ec85..35d015de1 100644 --- a/go.mod +++ b/go.mod @@ -36,7 +36,7 @@ require ( github.com/stretchr/testify v1.10.0 github.com/tebeka/strftime v0.1.5 github.com/tevino/abool v1.2.0 - github.com/tinylib/msgp v1.1.9 + github.com/tinylib/msgp v1.3.0 github.com/valyala/fastjson v1.6.4 github.com/wangjohn/quickselect v0.0.0-20161129230411-ed8402a42d5f go.uber.org/zap v1.27.0 @@ -56,7 +56,7 @@ require ( github.com/google/uuid v1.6.0 // indirect github.com/openhistogram/circonusllhist v0.4.0 // indirect github.com/pelletier/go-toml/v2 v2.2.3 // indirect - github.com/philhofer/fwd v1.1.2 // indirect + github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/sagikazarmark/locafero v0.7.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect diff --git a/go.sum b/go.sum index 5416b3da0..d9ba5360f 100644 --- a/go.sum +++ b/go.sum @@ -138,8 +138,8 @@ github.com/openhistogram/circonusllhist v0.4.0 h1:t77KqrahIG/iuJqTBNDBwyHu1dkvbC github.com/openhistogram/circonusllhist v0.4.0/go.mod h1:PfeYJ/RW2+Jfv3wTz0upbY2TRour/LLqIm2K2Kw5zg0= github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= -github.com/philhofer/fwd v1.1.2 h1:bnDivRJ1EWPjUIRXV5KfORO897HTbpFAQddBdE8t7Gw= -github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2tUTP0= +github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c h1:dAMKvw0MlJT1GshSTtih8C2gDs04w8dReiOGXrGLNoY= +github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM= github.com/pierrec/lz4 v2.6.0+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -180,8 +180,8 @@ github.com/tebeka/strftime v0.1.5 h1:1NQKN1NiQgkqd/2moD6ySP/5CoZQsKa1d3ZhJ44Jpmg github.com/tebeka/strftime v0.1.5/go.mod h1:29/OidkoWHdEKZqzyDLUyC+LmgDgdHo4WAFCDT7D/Ig= github.com/tevino/abool v1.2.0 h1:heAkClL8H6w+mK5md9dzsuohKeXHUpY7Vw0ZCKW+huA= github.com/tevino/abool v1.2.0/go.mod h1:qc66Pna1RiIsPa7O4Egxxs9OqkuxDX55zznh9K07Tzg= -github.com/tinylib/msgp v1.1.9 h1:SHf3yoO2sGA0veCJeCBYLHuttAVFHGm2RHgNodW7wQU= -github.com/tinylib/msgp v1.1.9/go.mod h1:BCXGB54lDD8qUEPmiG0cQQUANC4IUQyB2ItS2UDlO/k= +github.com/tinylib/msgp v1.3.0 h1:ULuf7GPooDaIlbyvgAxBV/FI7ynli6LZ1/nVUNu+0ww= +github.com/tinylib/msgp v1.3.0/go.mod h1:ykjzy2wzgrlvpDCRc4LA8UXy6D8bzMSuAF3WD57Gok0= github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ= github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= github.com/wangjohn/quickselect v0.0.0-20161129230411-ed8402a42d5f h1:9DDCDwOyEy/gId+IEMrFHLuQ5R/WV0KNxWLler8X2OY= diff --git a/vendor/github.com/philhofer/fwd/README.md b/vendor/github.com/philhofer/fwd/README.md index 62bd5c6d0..4e9952342 100644 --- a/vendor/github.com/philhofer/fwd/README.md +++ b/vendor/github.com/philhofer/fwd/README.md @@ -45,6 +45,15 @@ the write position by the length of the returned slice. This allows users to write directly to the end of the buffer. +## Portability + +Because it uses the unsafe package, there are theoretically +no promises about forward or backward portability. + +To stay compatible with tinygo 0.32, unsafestr() has been updated +to use unsafe.Slice() as suggested by +https://tinygo.org/docs/guides/compatibility, which also required +bumping go.mod to require at least go 1.20. ## Index diff --git a/vendor/github.com/philhofer/fwd/reader.go b/vendor/github.com/philhofer/fwd/reader.go index 7c21f8fb4..a24a896e2 100644 --- a/vendor/github.com/philhofer/fwd/reader.go +++ b/vendor/github.com/philhofer/fwd/reader.go @@ -82,9 +82,10 @@ type Reader struct { r io.Reader // underlying reader // data[n:len(data)] is buffered data; data[len(data):cap(data)] is free buffer space - data []byte // data - n int // read offset - state error // last read error + data []byte // data + n int // read offset + inputOffset int64 // offset in the input stream + state error // last read error // if the reader past to NewReader was // also an io.Seeker, this is non-nil @@ -97,6 +98,7 @@ func (r *Reader) Reset(rd io.Reader) { r.r = rd r.data = r.data[0:0] r.n = 0 + r.inputOffset = 0 r.state = nil if s, ok := rd.(io.Seeker); ok { r.rs = s @@ -158,6 +160,9 @@ func (r *Reader) Buffered() int { return len(r.data) - r.n } // BufferSize returns the total size of the buffer func (r *Reader) BufferSize() int { return cap(r.data) } +// InputOffset returns the input stream byte offset of the current reader position +func (r *Reader) InputOffset() int64 { return r.inputOffset } + // Peek returns the next 'n' buffered bytes, // reading from the underlying reader if necessary. // It will only return a slice shorter than 'n' bytes @@ -191,16 +196,50 @@ func (r *Reader) Peek(n int) ([]byte, error) { return r.data[r.n : r.n+n], nil } +func (r *Reader) PeekByte() (b byte, err error) { + if len(r.data)-r.n >= 1 { + b = r.data[r.n] + } else { + b, err = r.peekByte() + } + return +} + +func (r *Reader) peekByte() (byte, error) { + const n = 1 + if cap(r.data) < n { + old := r.data[r.n:] + r.data = make([]byte, n+r.buffered()) + r.data = r.data[:copy(r.data, old)] + r.n = 0 + } + + // keep filling until + // we hit an error or + // read enough bytes + for r.buffered() < n && r.state == nil { + r.more() + } + + // we must have hit an error + if r.buffered() < n { + return 0, r.err() + } + return r.data[r.n], nil +} + // discard(n) discards up to 'n' buffered bytes, and // and returns the number of bytes discarded func (r *Reader) discard(n int) int { inbuf := r.buffered() if inbuf <= n { r.n = 0 + r.inputOffset += int64(inbuf) r.data = r.data[:0] return inbuf } r.n += n + r.inputOffset += int64(n) return n } @@ -228,6 +267,7 @@ func (r *Reader) Skip(n int) (int, error) { // if we can Seek() through the remaining bytes, do that if n > skipped && r.rs != nil { nn, err := r.rs.Seek(int64(n-skipped), 1) + r.inputOffset += nn return int(nn) + skipped, err } // otherwise, keep filling the buffer @@ -248,7 +288,18 @@ func (r *Reader) Skip(n int) (int, error) { // If an the returned slice is less than the // length asked for, an error will be returned, // and the reader position will not be incremented. -func (r *Reader) Next(n int) ([]byte, error) { +func (r *Reader) Next(n int) (b []byte, err error) { + if r.state == nil && len(r.data)-r.n >= n { + b = r.data[r.n : r.n+n] + r.n += n + r.inputOffset += int64(n) + } else { + b, err = r.next(n) + } + return +} + +func (r *Reader) next(n int) ([]byte, error) { // in case the buffer is too small if cap(r.data) < n { old := r.data[r.n:] @@ -267,6 +318,7 @@ func (r *Reader) Next(n int) ([]byte, error) { } out := r.data[r.n : r.n+n] r.n += n + r.inputOffset += int64(n) return out, nil } @@ -277,6 +329,7 @@ func (r *Reader) Read(b []byte) (int, error) { if r.buffered() != 0 { x := copy(b, r.data[r.n:]) r.n += x + r.inputOffset += int64(x) return x, nil } var n int @@ -293,6 +346,9 @@ func (r *Reader) Read(b []byte) (int, error) { if n == 0 { return 0, r.err() } + + r.inputOffset += int64(n) + return n, nil } @@ -312,9 +368,11 @@ func (r *Reader) ReadFull(b []byte) (int, error) { nn = copy(b[n:], r.data[r.n:]) n += nn r.n += nn + r.inputOffset += int64(nn) } else if l-n > cap(r.data) { nn, r.state = r.r.Read(b[n:]) n += nn + r.inputOffset += int64(nn) } else { r.more() } @@ -335,6 +393,8 @@ func (r *Reader) ReadByte() (byte, error) { } b := r.data[r.n] r.n++ + r.inputOffset++ + return b, nil } @@ -354,6 +414,7 @@ func (r *Reader) WriteTo(w io.Writer) (int64, error) { } r.data = r.data[0:0] r.n = 0 + r.inputOffset += int64(ii) } for r.state == nil { // here we just do @@ -367,6 +428,7 @@ func (r *Reader) WriteTo(w io.Writer) (int64, error) { } r.data = r.data[0:0] r.n = 0 + r.inputOffset += int64(ii) } } if r.state != io.EOF { diff --git a/vendor/github.com/philhofer/fwd/writer_tinygo.go b/vendor/github.com/philhofer/fwd/writer_tinygo.go index b060faf7a..c98cd57f3 100644 --- a/vendor/github.com/philhofer/fwd/writer_tinygo.go +++ b/vendor/github.com/philhofer/fwd/writer_tinygo.go @@ -4,16 +4,10 @@ package fwd import ( - "reflect" "unsafe" ) // unsafe cast string as []byte func unsafestr(b string) []byte { - l := uintptr(len(b)) - return *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{ - Len: l, - Cap: l, - Data: (*reflect.StringHeader)(unsafe.Pointer(&b)).Data, - })) + return unsafe.Slice(unsafe.StringData(b), len(b)) } diff --git a/vendor/github.com/tinylib/msgp/msgp/circular.go b/vendor/github.com/tinylib/msgp/msgp/circular.go index a0434c7ea..6e6afd868 100644 --- a/vendor/github.com/tinylib/msgp/msgp/circular.go +++ b/vendor/github.com/tinylib/msgp/msgp/circular.go @@ -14,8 +14,16 @@ type EndlessReader struct { offset int } -// NewEndlessReader returns a new endless reader +// NewEndlessReader returns a new endless reader. +// Buffer b cannot be empty func NewEndlessReader(b []byte, tb timer) *EndlessReader { + if len(b) == 0 { + panic("EndlessReader cannot be of zero length") + } + // Double until we reach 4K. + for len(b) < 4<<10 { + b = append(b, b...) + } return &EndlessReader{tb: tb, data: b, offset: 0} } @@ -24,16 +32,14 @@ func NewEndlessReader(b []byte, tb timer) *EndlessReader { // fills the supplied slice while the benchmark // timer is stopped. func (c *EndlessReader) Read(p []byte) (int, error) { - c.tb.StopTimer() var n int l := len(p) m := len(c.data) + nn := copy(p[n:], c.data[c.offset:]) + n += nn for n < l { - nn := copy(p[n:], c.data[c.offset:]) - n += nn - c.offset += nn - c.offset %= m + n += copy(p[n:], c.data[:]) } - c.tb.StartTimer() + c.offset = (c.offset + l) % m return n, nil } diff --git a/vendor/github.com/tinylib/msgp/msgp/defs.go b/vendor/github.com/tinylib/msgp/msgp/defs.go index e265aa4f8..47a8c1834 100644 --- a/vendor/github.com/tinylib/msgp/msgp/defs.go +++ b/vendor/github.com/tinylib/msgp/msgp/defs.go @@ -32,6 +32,10 @@ const ( last5 = 0x1f first3 = 0xe0 last7 = 0x7f + + // recursionLimit is the limit of recursive calls. + // This limits the call depth of dynamic code, like Skip and interface conversions. + recursionLimit = 100000 ) func isfixint(b byte) bool { diff --git a/vendor/github.com/tinylib/msgp/msgp/errors.go b/vendor/github.com/tinylib/msgp/msgp/errors.go index 4f19359a2..e6b42b689 100644 --- a/vendor/github.com/tinylib/msgp/msgp/errors.go +++ b/vendor/github.com/tinylib/msgp/msgp/errors.go @@ -13,6 +13,10 @@ var ( // contain the contents of the message ErrShortBytes error = errShort{} + // ErrRecursion is returned when the maximum recursion limit is reached for an operation. + // This should only realistically be seen on adversarial data trying to exhaust the stack. + ErrRecursion error = errRecursion{} + // this error is only returned // if we reach code that should // be unreachable @@ -134,6 +138,11 @@ func (f errFatal) Resumable() bool { return false } func (f errFatal) withContext(ctx string) error { f.ctx = addCtx(f.ctx, ctx); return f } +type errRecursion struct{} + +func (e errRecursion) Error() string { return "msgp: recursion limit reached" } +func (e errRecursion) Resumable() bool { return false } + // ArrayError is an error returned // when decoding a fix-sized array // of the wrong size @@ -203,6 +212,31 @@ func (u UintOverflow) Resumable() bool { return true } func (u UintOverflow) withContext(ctx string) error { u.ctx = addCtx(u.ctx, ctx); return u } +// InvalidTimestamp is returned when an invalid timestamp is encountered +type InvalidTimestamp struct { + Nanos int64 // value of the nano, if invalid + FieldLength int // Unexpected field length. + ctx string +} + +// Error implements the error interface +func (u InvalidTimestamp) Error() (str string) { + if u.Nanos > 0 { + str = "msgp: timestamp nanosecond field value " + strconv.FormatInt(u.Nanos, 10) + " exceeds maximum allows of 999999999" + } else if u.FieldLength >= 0 { + str = "msgp: invalid timestamp field length " + strconv.FormatInt(int64(u.FieldLength), 10) + " - must be 4, 8 or 12" + } + if u.ctx != "" { + str += " at " + u.ctx + } + return str +} + +// Resumable is always 'true' for overflows +func (u InvalidTimestamp) Resumable() bool { return true } + +func (u InvalidTimestamp) withContext(ctx string) error { u.ctx = addCtx(u.ctx, ctx); return u } + // UintBelowZero is returned when a call // would cast a signed integer below zero // to an unsigned integer. diff --git a/vendor/github.com/tinylib/msgp/msgp/extension.go b/vendor/github.com/tinylib/msgp/msgp/extension.go index 5f7624730..cda71c984 100644 --- a/vendor/github.com/tinylib/msgp/msgp/extension.go +++ b/vendor/github.com/tinylib/msgp/msgp/extension.go @@ -15,8 +15,15 @@ const ( // TimeExtension is the extension number used for time.Time TimeExtension = 5 + + // MsgTimeExtension is the extension number for timestamps as defined in + // https://github.com/msgpack/msgpack/blob/master/spec.md#timestamp-extension-type + MsgTimeExtension = -1 ) +// msgTimeExtension is a painful workaround to avoid "constant -1 overflows byte". +var msgTimeExtension = int8(MsgTimeExtension) + // our extensions live here var extensionReg = make(map[int8]func() Extension) @@ -477,15 +484,27 @@ func AppendExtension(b []byte, e Extension) ([]byte, error) { // - InvalidPrefixError // - An umarshal error returned from e.UnmarshalBinary func ReadExtensionBytes(b []byte, e Extension) ([]byte, error) { + typ, remain, data, err := readExt(b) + if err != nil { + return b, err + } + if typ != e.ExtensionType() { + return b, errExt(typ, e.ExtensionType()) + } + return remain, e.UnmarshalBinary(data) +} + +// readExt will read the extension type, and return remaining bytes, +// as well as the data of the extension. +func readExt(b []byte) (typ int8, remain []byte, data []byte, err error) { l := len(b) if l < 3 { - return b, ErrShortBytes + return 0, b, nil, ErrShortBytes } lead := b[0] var ( sz int // size of 'data' off int // offset of 'data' - typ int8 ) switch lead { case mfixext1: @@ -513,35 +532,30 @@ func ReadExtensionBytes(b []byte, e Extension) ([]byte, error) { typ = int8(b[2]) off = 3 if sz == 0 { - return b[3:], e.UnmarshalBinary(b[3:3]) + return typ, b[3:], b[3:3], nil } case mext16: if l < 4 { - return b, ErrShortBytes + return 0, b, nil, ErrShortBytes } sz = int(big.Uint16(b[1:])) typ = int8(b[3]) off = 4 case mext32: if l < 6 { - return b, ErrShortBytes + return 0, b, nil, ErrShortBytes } sz = int(big.Uint32(b[1:])) typ = int8(b[5]) off = 6 default: - return b, badPrefix(ExtensionType, lead) - } - - if typ != e.ExtensionType() { - return b, errExt(typ, e.ExtensionType()) + return 0, b, nil, badPrefix(ExtensionType, lead) } - // the data of the extension starts // at 'off' and is 'sz' bytes long + tot := off + sz if len(b[off:]) < sz { - return b, ErrShortBytes + return 0, b, nil, ErrShortBytes } - tot := off + sz - return b[tot:], e.UnmarshalBinary(b[off:tot]) + return typ, b[tot:], b[off:tot:tot], nil } diff --git a/vendor/github.com/tinylib/msgp/msgp/file.go b/vendor/github.com/tinylib/msgp/msgp/file.go index 0f2c37520..a6d91ede1 100644 --- a/vendor/github.com/tinylib/msgp/msgp/file.go +++ b/vendor/github.com/tinylib/msgp/msgp/file.go @@ -1,5 +1,5 @@ -//go:build (linux || darwin || dragonfly || freebsd || netbsd || openbsd) && !appengine && !tinygo -// +build linux darwin dragonfly freebsd netbsd openbsd +//go:build (linux || darwin || dragonfly || freebsd || illumos || netbsd || openbsd) && !appengine && !tinygo +// +build linux darwin dragonfly freebsd illumos netbsd openbsd // +build !appengine // +build !tinygo diff --git a/vendor/github.com/tinylib/msgp/msgp/file_port.go b/vendor/github.com/tinylib/msgp/msgp/file_port.go index 2bbb3ad13..dac0dba3f 100644 --- a/vendor/github.com/tinylib/msgp/msgp/file_port.go +++ b/vendor/github.com/tinylib/msgp/msgp/file_port.go @@ -4,7 +4,7 @@ package msgp import ( - "io/ioutil" + "io" "os" ) @@ -21,7 +21,7 @@ func ReadFile(dst Unmarshaler, file *os.File) error { return u.DecodeMsg(NewReader(file)) } - data, err := ioutil.ReadAll(file) + data, err := io.ReadAll(file) if err != nil { return err } diff --git a/vendor/github.com/tinylib/msgp/msgp/integers.go b/vendor/github.com/tinylib/msgp/msgp/integers.go index f817d7759..d07a5fba7 100644 --- a/vendor/github.com/tinylib/msgp/msgp/integers.go +++ b/vendor/github.com/tinylib/msgp/msgp/integers.go @@ -1,5 +1,7 @@ package msgp +import "encoding/binary" + /* ---------------------------------- integer encoding utilities (inline-able) @@ -11,6 +13,8 @@ package msgp ---------------------------------- */ func putMint64(b []byte, i int64) { + _ = b[8] // bounds check elimination + b[0] = mint64 b[1] = byte(i >> 56) b[2] = byte(i >> 48) @@ -23,6 +27,8 @@ func putMint64(b []byte, i int64) { } func getMint64(b []byte) int64 { + _ = b[8] // bounds check elimination + return (int64(b[1]) << 56) | (int64(b[2]) << 48) | (int64(b[3]) << 40) | (int64(b[4]) << 32) | (int64(b[5]) << 24) | (int64(b[6]) << 16) | @@ -30,6 +36,8 @@ func getMint64(b []byte) int64 { } func putMint32(b []byte, i int32) { + _ = b[4] // bounds check elimination + b[0] = mint32 b[1] = byte(i >> 24) b[2] = byte(i >> 16) @@ -38,20 +46,28 @@ func putMint32(b []byte, i int32) { } func getMint32(b []byte) int32 { + _ = b[4] // bounds check elimination + return (int32(b[1]) << 24) | (int32(b[2]) << 16) | (int32(b[3]) << 8) | (int32(b[4])) } func putMint16(b []byte, i int16) { + _ = b[2] // bounds check elimination + b[0] = mint16 b[1] = byte(i >> 8) b[2] = byte(i) } func getMint16(b []byte) (i int16) { + _ = b[2] // bounds check elimination + return (int16(b[1]) << 8) | int16(b[2]) } func putMint8(b []byte, i int8) { + _ = b[1] // bounds check elimination + b[0] = mint8 b[1] = byte(i) } @@ -61,6 +77,8 @@ func getMint8(b []byte) (i int8) { } func putMuint64(b []byte, u uint64) { + _ = b[8] // bounds check elimination + b[0] = muint64 b[1] = byte(u >> 56) b[2] = byte(u >> 48) @@ -73,6 +91,8 @@ func putMuint64(b []byte, u uint64) { } func getMuint64(b []byte) uint64 { + _ = b[8] // bounds check elimination + return (uint64(b[1]) << 56) | (uint64(b[2]) << 48) | (uint64(b[3]) << 40) | (uint64(b[4]) << 32) | (uint64(b[5]) << 24) | (uint64(b[6]) << 16) | @@ -80,6 +100,8 @@ func getMuint64(b []byte) uint64 { } func putMuint32(b []byte, u uint32) { + _ = b[4] // bounds check elimination + b[0] = muint32 b[1] = byte(u >> 24) b[2] = byte(u >> 16) @@ -88,20 +110,28 @@ func putMuint32(b []byte, u uint32) { } func getMuint32(b []byte) uint32 { + _ = b[4] // bounds check elimination + return (uint32(b[1]) << 24) | (uint32(b[2]) << 16) | (uint32(b[3]) << 8) | (uint32(b[4])) } func putMuint16(b []byte, u uint16) { + _ = b[2] // bounds check elimination + b[0] = muint16 b[1] = byte(u >> 8) b[2] = byte(u) } func getMuint16(b []byte) uint16 { + _ = b[2] // bounds check elimination + return (uint16(b[1]) << 8) | uint16(b[2]) } func putMuint8(b []byte, u uint8) { + _ = b[1] // bounds check elimination + b[0] = muint8 b[1] = byte(u) } @@ -111,28 +141,15 @@ func getMuint8(b []byte) uint8 { } func getUnix(b []byte) (sec int64, nsec int32) { - sec = (int64(b[0]) << 56) | (int64(b[1]) << 48) | - (int64(b[2]) << 40) | (int64(b[3]) << 32) | - (int64(b[4]) << 24) | (int64(b[5]) << 16) | - (int64(b[6]) << 8) | (int64(b[7])) + sec = int64(binary.BigEndian.Uint64(b)) + nsec = int32(binary.BigEndian.Uint32(b[8:])) - nsec = (int32(b[8]) << 24) | (int32(b[9]) << 16) | (int32(b[10]) << 8) | (int32(b[11])) return } func putUnix(b []byte, sec int64, nsec int32) { - b[0] = byte(sec >> 56) - b[1] = byte(sec >> 48) - b[2] = byte(sec >> 40) - b[3] = byte(sec >> 32) - b[4] = byte(sec >> 24) - b[5] = byte(sec >> 16) - b[6] = byte(sec >> 8) - b[7] = byte(sec) - b[8] = byte(nsec >> 24) - b[9] = byte(nsec >> 16) - b[10] = byte(nsec >> 8) - b[11] = byte(nsec) + binary.BigEndian.PutUint64(b, uint64(sec)) + binary.BigEndian.PutUint32(b[8:], uint32(nsec)) } /* ----------------------------- @@ -141,12 +158,16 @@ func putUnix(b []byte, sec int64, nsec int32) { // write prefix and uint8 func prefixu8(b []byte, pre byte, sz uint8) { + _ = b[1] // bounds check elimination + b[0] = pre b[1] = byte(sz) } // write prefix and big-endian uint16 func prefixu16(b []byte, pre byte, sz uint16) { + _ = b[2] // bounds check elimination + b[0] = pre b[1] = byte(sz >> 8) b[2] = byte(sz) @@ -154,6 +175,8 @@ func prefixu16(b []byte, pre byte, sz uint16) { // write prefix and big-endian uint32 func prefixu32(b []byte, pre byte, sz uint32) { + _ = b[4] // bounds check elimination + b[0] = pre b[1] = byte(sz >> 24) b[2] = byte(sz >> 16) @@ -162,6 +185,8 @@ func prefixu32(b []byte, pre byte, sz uint32) { } func prefixu64(b []byte, pre byte, sz uint64) { + _ = b[8] // bounds check elimination + b[0] = pre b[1] = byte(sz >> 56) b[2] = byte(sz >> 48) diff --git a/vendor/github.com/tinylib/msgp/msgp/json.go b/vendor/github.com/tinylib/msgp/msgp/json.go index 0e11e603c..18593f64d 100644 --- a/vendor/github.com/tinylib/msgp/msgp/json.go +++ b/vendor/github.com/tinylib/msgp/msgp/json.go @@ -109,6 +109,13 @@ func rwMap(dst jsWriter, src *Reader) (n int, err error) { return dst.WriteString("{}") } + // This is potentially a recursive call. + if done, err := src.recursiveCall(); err != nil { + return 0, err + } else { + defer done() + } + err = dst.WriteByte('{') if err != nil { return @@ -162,6 +169,13 @@ func rwArray(dst jsWriter, src *Reader) (n int, err error) { if err != nil { return } + // This is potentially a recursive call. + if done, err := src.recursiveCall(); err != nil { + return 0, err + } else { + defer done() + } + var sz uint32 var nn int sz, err = src.ReadArrayHeader() @@ -296,7 +310,7 @@ func rwExtension(dst jsWriter, src *Reader) (n int, err error) { } n++ - nn, err = dst.WriteString(`"type:"`) + nn, err = dst.WriteString(`"type":`) n += nn if err != nil { return @@ -332,14 +346,12 @@ func rwExtension(dst jsWriter, src *Reader) (n int, err error) { } func rwString(dst jsWriter, src *Reader) (n int, err error) { - var p []byte - p, err = src.R.Peek(1) + lead, err := src.R.PeekByte() if err != nil { return } - lead := p[0] var read int - + var p []byte if isfixstr(lead) { read = int(rfixstr(lead)) src.R.Skip(1) diff --git a/vendor/github.com/tinylib/msgp/msgp/json_bytes.go b/vendor/github.com/tinylib/msgp/msgp/json_bytes.go index e6162d0a6..d4fbda631 100644 --- a/vendor/github.com/tinylib/msgp/msgp/json_bytes.go +++ b/vendor/github.com/tinylib/msgp/msgp/json_bytes.go @@ -9,12 +9,12 @@ import ( "time" ) -var unfuns [_maxtype]func(jsWriter, []byte, []byte) ([]byte, []byte, error) +var unfuns [_maxtype]func(jsWriter, []byte, []byte, int) ([]byte, []byte, error) func init() { // NOTE(pmh): this is best expressed as a jump table, // but gc doesn't do that yet. revisit post-go1.5. - unfuns = [_maxtype]func(jsWriter, []byte, []byte) ([]byte, []byte, error){ + unfuns = [_maxtype]func(jsWriter, []byte, []byte, int) ([]byte, []byte, error){ StrType: rwStringBytes, BinType: rwBytesBytes, MapType: rwMapBytes, @@ -51,7 +51,7 @@ func UnmarshalAsJSON(w io.Writer, msg []byte) ([]byte, error) { dst = bufio.NewWriterSize(w, 512) } for len(msg) > 0 && err == nil { - msg, scratch, err = writeNext(dst, msg, scratch) + msg, scratch, err = writeNext(dst, msg, scratch, 0) } if !cast && err == nil { err = dst.(*bufio.Writer).Flush() @@ -59,7 +59,7 @@ func UnmarshalAsJSON(w io.Writer, msg []byte) ([]byte, error) { return msg, err } -func writeNext(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) { +func writeNext(w jsWriter, msg []byte, scratch []byte, depth int) ([]byte, []byte, error) { if len(msg) < 1 { return msg, scratch, ErrShortBytes } @@ -72,14 +72,17 @@ func writeNext(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) { if err != nil { return nil, scratch, err } - if et == TimeExtension { + if et == TimeExtension || et == MsgTimeExtension { t = TimeType } } - return unfuns[t](w, msg, scratch) + return unfuns[t](w, msg, scratch, depth) } -func rwArrayBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) { +func rwArrayBytes(w jsWriter, msg []byte, scratch []byte, depth int) ([]byte, []byte, error) { + if depth >= recursionLimit { + return msg, scratch, ErrRecursion + } sz, msg, err := ReadArrayHeaderBytes(msg) if err != nil { return msg, scratch, err @@ -95,7 +98,7 @@ func rwArrayBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error return msg, scratch, err } } - msg, scratch, err = writeNext(w, msg, scratch) + msg, scratch, err = writeNext(w, msg, scratch, depth+1) if err != nil { return msg, scratch, err } @@ -104,7 +107,10 @@ func rwArrayBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error return msg, scratch, err } -func rwMapBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) { +func rwMapBytes(w jsWriter, msg []byte, scratch []byte, depth int) ([]byte, []byte, error) { + if depth >= recursionLimit { + return msg, scratch, ErrRecursion + } sz, msg, err := ReadMapHeaderBytes(msg) if err != nil { return msg, scratch, err @@ -120,7 +126,7 @@ func rwMapBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) return msg, scratch, err } } - msg, scratch, err = rwMapKeyBytes(w, msg, scratch) + msg, scratch, err = rwMapKeyBytes(w, msg, scratch, depth) if err != nil { return msg, scratch, err } @@ -128,7 +134,7 @@ func rwMapBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) if err != nil { return msg, scratch, err } - msg, scratch, err = writeNext(w, msg, scratch) + msg, scratch, err = writeNext(w, msg, scratch, depth+1) if err != nil { return msg, scratch, err } @@ -137,17 +143,17 @@ func rwMapBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) return msg, scratch, err } -func rwMapKeyBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) { - msg, scratch, err := rwStringBytes(w, msg, scratch) +func rwMapKeyBytes(w jsWriter, msg []byte, scratch []byte, depth int) ([]byte, []byte, error) { + msg, scratch, err := rwStringBytes(w, msg, scratch, depth) if err != nil { if tperr, ok := err.(TypeError); ok && tperr.Encoded == BinType { - return rwBytesBytes(w, msg, scratch) + return rwBytesBytes(w, msg, scratch, depth) } } return msg, scratch, err } -func rwStringBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) { +func rwStringBytes(w jsWriter, msg []byte, scratch []byte, depth int) ([]byte, []byte, error) { str, msg, err := ReadStringZC(msg) if err != nil { return msg, scratch, err @@ -156,7 +162,7 @@ func rwStringBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, erro return msg, scratch, err } -func rwBytesBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) { +func rwBytesBytes(w jsWriter, msg []byte, scratch []byte, depth int) ([]byte, []byte, error) { bts, msg, err := ReadBytesZC(msg) if err != nil { return msg, scratch, err @@ -180,7 +186,7 @@ func rwBytesBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error return msg, scratch, err } -func rwNullBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) { +func rwNullBytes(w jsWriter, msg []byte, scratch []byte, depth int) ([]byte, []byte, error) { msg, err := ReadNilBytes(msg) if err != nil { return msg, scratch, err @@ -189,7 +195,7 @@ func rwNullBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) return msg, scratch, err } -func rwBoolBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) { +func rwBoolBytes(w jsWriter, msg []byte, scratch []byte, depth int) ([]byte, []byte, error) { b, msg, err := ReadBoolBytes(msg) if err != nil { return msg, scratch, err @@ -202,7 +208,7 @@ func rwBoolBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) return msg, scratch, err } -func rwIntBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) { +func rwIntBytes(w jsWriter, msg []byte, scratch []byte, depth int) ([]byte, []byte, error) { i, msg, err := ReadInt64Bytes(msg) if err != nil { return msg, scratch, err @@ -212,7 +218,7 @@ func rwIntBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) return msg, scratch, err } -func rwUintBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) { +func rwUintBytes(w jsWriter, msg []byte, scratch []byte, depth int) ([]byte, []byte, error) { u, msg, err := ReadUint64Bytes(msg) if err != nil { return msg, scratch, err @@ -222,7 +228,7 @@ func rwUintBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) return msg, scratch, err } -func rwFloat32Bytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) { +func rwFloat32Bytes(w jsWriter, msg []byte, scratch []byte, depth int) ([]byte, []byte, error) { var f float32 var err error f, msg, err = ReadFloat32Bytes(msg) @@ -234,7 +240,7 @@ func rwFloat32Bytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, err return msg, scratch, err } -func rwFloat64Bytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) { +func rwFloat64Bytes(w jsWriter, msg []byte, scratch []byte, depth int) ([]byte, []byte, error) { var f float64 var err error f, msg, err = ReadFloat64Bytes(msg) @@ -246,7 +252,7 @@ func rwFloat64Bytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, err return msg, scratch, err } -func rwTimeBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) { +func rwTimeBytes(w jsWriter, msg []byte, scratch []byte, depth int) ([]byte, []byte, error) { var t time.Time var err error t, msg, err = ReadTimeBytes(msg) @@ -261,7 +267,7 @@ func rwTimeBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) return msg, scratch, err } -func rwExtensionBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) { +func rwExtensionBytes(w jsWriter, msg []byte, scratch []byte, depth int) ([]byte, []byte, error) { var err error var et int8 et, err = peekExtension(msg) @@ -270,7 +276,7 @@ func rwExtensionBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, e } // if it's time.Time - if et == TimeExtension { + if et == TimeExtension || et == MsgTimeExtension { var tm time.Time tm, msg, err = ReadTimeBytes(msg) if err != nil { diff --git a/vendor/github.com/tinylib/msgp/msgp/purego.go b/vendor/github.com/tinylib/msgp/msgp/purego.go index 2cd35c3e1..fe8723412 100644 --- a/vendor/github.com/tinylib/msgp/msgp/purego.go +++ b/vendor/github.com/tinylib/msgp/msgp/purego.go @@ -1,5 +1,5 @@ -//go:build purego || appengine -// +build purego appengine +//go:build (purego && !unsafe) || appengine +// +build purego,!unsafe appengine package msgp diff --git a/vendor/github.com/tinylib/msgp/msgp/read.go b/vendor/github.com/tinylib/msgp/msgp/read.go index e6d72f17d..20d3463bb 100644 --- a/vendor/github.com/tinylib/msgp/msgp/read.go +++ b/vendor/github.com/tinylib/msgp/msgp/read.go @@ -1,8 +1,11 @@ package msgp import ( + "encoding/binary" + "encoding/json" "io" "math" + "strconv" "sync" "time" @@ -45,6 +48,7 @@ const ( Complex64Type Complex128Type TimeType + NumberType _maxtype ) @@ -74,6 +78,8 @@ func (t Type) String() string { return "ext" case NilType: return "nil" + case NumberType: + return "number" default: return "" } @@ -143,8 +149,9 @@ type Reader struct { // is stateless; all the // buffering is done // within R. - R *fwd.Reader - scratch []byte + R *fwd.Reader + scratch []byte + recursionDepth int } // Read implements `io.Reader` @@ -190,6 +197,11 @@ func (m *Reader) CopyNext(w io.Writer) (int64, error) { return n, io.ErrShortWrite } + if done, err := m.recursiveCall(); err != nil { + return n, err + } else { + defer done() + } // for maps and slices, read elements for x := uintptr(0); x < o; x++ { var n2 int64 @@ -202,6 +214,18 @@ func (m *Reader) CopyNext(w io.Writer) (int64, error) { return n, nil } +// recursiveCall will increment the recursion depth and return an error if it is exceeded. +// If a nil error is returned, done must be called to decrement the counter. +func (m *Reader) recursiveCall() (done func(), err error) { + if m.recursionDepth >= recursionLimit { + return func() {}, ErrRecursion + } + m.recursionDepth++ + return func() { + m.recursionDepth-- + }, nil +} + // ReadFull implements `io.ReadFull` func (m *Reader) ReadFull(p []byte) (int, error) { return m.R.ReadFull(p) @@ -218,13 +242,13 @@ func (m *Reader) BufferSize() int { return m.R.BufferSize() } // NextType returns the next object type to be decoded. func (m *Reader) NextType() (Type, error) { - p, err := m.R.Peek(1) + next, err := m.R.PeekByte() if err != nil { return InvalidType, err } - t := getType(p[0]) + t := getType(next) if t == InvalidType { - return t, InvalidPrefixError(p[0]) + return t, InvalidPrefixError(next) } if t == ExtensionType { v, err := m.peekExtensionType() @@ -236,7 +260,7 @@ func (m *Reader) NextType() (Type, error) { return Complex64Type, nil case Complex128Extension: return Complex128Type, nil - case TimeExtension: + case TimeExtension, MsgTimeExtension: return TimeType, nil } } @@ -246,8 +270,8 @@ func (m *Reader) NextType() (Type, error) { // IsNil returns whether or not // the next byte is a null messagepack byte func (m *Reader) IsNil() bool { - p, err := m.R.Peek(1) - return err == nil && p[0] == mnil + p, err := m.R.PeekByte() + return err == nil && p == mnil } // getNextSize returns the size of the next object on the wire. @@ -258,11 +282,10 @@ func (m *Reader) IsNil() bool { // use uintptr b/c it's guaranteed to be large enough // to hold whatever we can fit in memory. func getNextSize(r *fwd.Reader) (uintptr, uintptr, error) { - b, err := r.Peek(1) + lead, err := r.PeekByte() if err != nil { return 0, 0, err } - lead := b[0] spec := getBytespec(lead) size, mode := spec.size, spec.extra if size == 0 { @@ -271,7 +294,7 @@ func getNextSize(r *fwd.Reader) (uintptr, uintptr, error) { if mode >= 0 { return uintptr(size), uintptr(mode), nil } - b, err = r.Peek(int(size)) + b, err := r.Peek(int(size)) if err != nil { return 0, 0, err } @@ -332,7 +355,12 @@ func (m *Reader) Skip() error { return err } - // for maps and slices, skip elements + // for maps and slices, skip elements with recursive call + if done, err := m.recursiveCall(); err != nil { + return err + } else { + defer done() + } for x := uintptr(0); x < o; x++ { err = m.Skip() if err != nil { @@ -350,11 +378,10 @@ func (m *Reader) Skip() error { func (m *Reader) ReadMapHeader() (sz uint32, err error) { var p []byte var lead byte - p, err = m.R.Peek(1) + lead, err = m.R.PeekByte() if err != nil { return } - lead = p[0] if isfixmap(lead) { sz = uint32(rfixmap(lead)) _, err = m.R.Skip(1) @@ -404,12 +431,12 @@ func (m *Reader) ReadMapKey(scratch []byte) ([]byte, error) { // method; writing into the returned slice may // corrupt future reads. func (m *Reader) ReadMapKeyPtr() ([]byte, error) { - p, err := m.R.Peek(1) + lead, err := m.R.PeekByte() if err != nil { return nil, err } - lead := p[0] var read int + var p []byte if isfixstr(lead) { read = int(rfixstr(lead)) m.R.Skip(1) @@ -448,18 +475,16 @@ fill: // array header and returns the size of the array // and the number of bytes read. func (m *Reader) ReadArrayHeader() (sz uint32, err error) { - var lead byte - var p []byte - p, err = m.R.Peek(1) + lead, err := m.R.PeekByte() if err != nil { return } - lead = p[0] if isfixarray(lead) { sz = uint32(rfixarray(lead)) _, err = m.R.Skip(1) return } + var p []byte switch lead { case marray16: p, err = m.R.Next(3) @@ -485,12 +510,12 @@ func (m *Reader) ReadArrayHeader() (sz uint32, err error) { // ReadNil reads a 'nil' MessagePack byte from the reader func (m *Reader) ReadNil() error { - p, err := m.R.Peek(1) + p, err := m.R.PeekByte() if err != nil { return err } - if p[0] != mnil { - return badPrefix(NilType, p[0]) + if p != mnil { + return badPrefix(NilType, p) } _, err = m.R.Skip(1) return err @@ -543,17 +568,17 @@ func (m *Reader) ReadFloat32() (f float32, err error) { // ReadBool reads a bool from the reader func (m *Reader) ReadBool() (b bool, err error) { - var p []byte - p, err = m.R.Peek(1) + var p byte + p, err = m.R.PeekByte() if err != nil { return } - switch p[0] { + switch p { case mtrue: b = true case mfalse: default: - err = badPrefix(BoolType, p[0]) + err = badPrefix(BoolType, p) return } _, err = m.R.Skip(1) @@ -569,12 +594,10 @@ func (m *Reader) ReadDuration() (d time.Duration, err error) { // ReadInt64 reads an int64 from the reader func (m *Reader) ReadInt64() (i int64, err error) { var p []byte - var lead byte - p, err = m.R.Peek(1) + lead, err := m.R.PeekByte() if err != nil { return } - lead = p[0] if isfixint(lead) { i = int64(rfixint(lead)) @@ -715,12 +738,10 @@ func (m *Reader) ReadInt() (i int, err error) { // ReadUint64 reads a uint64 from the reader func (m *Reader) ReadUint64() (u uint64, err error) { var p []byte - var lead byte - p, err = m.R.Peek(1) + lead, err := m.R.PeekByte() if err != nil { return } - lead = p[0] if isfixint(lead) { u = uint64(rfixint(lead)) _, err = m.R.Skip(1) @@ -935,11 +956,11 @@ func (m *Reader) ReadBytes(scratch []byte) (b []byte, err error) { // way. func (m *Reader) ReadBytesHeader() (sz uint32, err error) { var p []byte - p, err = m.R.Peek(1) + lead, err := m.R.PeekByte() if err != nil { return } - switch p[0] { + switch lead { case mbin8: p, err = m.R.Next(2) if err != nil { @@ -1013,12 +1034,10 @@ func (m *Reader) ReadExactBytes(into []byte) error { // if it is non-nil. func (m *Reader) ReadStringAsBytes(scratch []byte) (b []byte, err error) { var p []byte - var lead byte - p, err = m.R.Peek(1) + lead, err := m.R.PeekByte() if err != nil { return } - lead = p[0] var read int64 if isfixstr(lead) { @@ -1065,17 +1084,16 @@ fill: // for dealing with the next 'sz' bytes from // the reader in an application-specific manner. func (m *Reader) ReadStringHeader() (sz uint32, err error) { - var p []byte - p, err = m.R.Peek(1) + lead, err := m.R.PeekByte() if err != nil { return } - lead := p[0] if isfixstr(lead) { sz = uint32(rfixstr(lead)) m.R.Skip(1) return } + var p []byte switch lead { case mstr8: p, err = m.R.Next(2) @@ -1106,15 +1124,13 @@ func (m *Reader) ReadStringHeader() (sz uint32, err error) { // ReadString reads a utf-8 string from the reader func (m *Reader) ReadString() (s string, err error) { - var p []byte - var lead byte var read int64 - p, err = m.R.Peek(1) + lead, err := m.R.PeekByte() if err != nil { return } - lead = p[0] + var p []byte if isfixstr(lead) { read = int64(rfixstr(lead)) m.R.Skip(1) @@ -1244,29 +1260,119 @@ func (m *Reader) ReadMapStrIntf(mp map[string]interface{}) (err error) { return } +// ReadTimeUTC reads a time.Time object from the reader. +// The returned time's location will be set to UTC. +func (m *Reader) ReadTimeUTC() (t time.Time, err error) { + t, err = m.ReadTime() + return t.UTC(), err +} + // ReadTime reads a time.Time object from the reader. // The returned time's location will be set to time.Local. func (m *Reader) ReadTime() (t time.Time, err error) { - var p []byte - p, err = m.R.Peek(15) + offset, length, extType, err := m.peekExtensionHeader() if err != nil { - return + return t, err } - if p[0] != mext8 || p[1] != 12 { - err = badPrefix(TimeType, p[0]) - return + + switch extType { + case TimeExtension: + var p []byte + p, err = m.R.Peek(15) + if err != nil { + return + } + if p[0] != mext8 || p[1] != 12 { + err = badPrefix(TimeType, p[0]) + return + } + if int8(p[2]) != TimeExtension { + err = errExt(int8(p[2]), TimeExtension) + return + } + sec, nsec := getUnix(p[3:]) + t = time.Unix(sec, int64(nsec)).Local() + _, err = m.R.Skip(15) + return + case MsgTimeExtension: + switch length { + case 4, 8, 12: + var tmp [12]byte + _, err = m.R.Skip(offset) + if err != nil { + return + } + var n int + n, err = m.R.Read(tmp[:length]) + if err != nil { + return + } + if n != length { + err = ErrShortBytes + return + } + b := tmp[:length] + switch length { + case 4: + t = time.Unix(int64(binary.BigEndian.Uint32(b)), 0).Local() + case 8: + v := binary.BigEndian.Uint64(b) + nanos := int64(v >> 34) + if nanos > 999999999 { + // In timestamp 64 and timestamp 96 formats, nanoseconds must not be larger than 999999999. + err = InvalidTimestamp{Nanos: nanos} + return + } + t = time.Unix(int64(v&(1<<34-1)), nanos).Local() + case 12: + nanos := int64(binary.BigEndian.Uint32(b)) + if nanos > 999999999 { + // In timestamp 64 and timestamp 96 formats, nanoseconds must not be larger than 999999999. + err = InvalidTimestamp{Nanos: nanos} + return + } + ux := int64(binary.BigEndian.Uint64(b[4:])) + t = time.Unix(ux, nanos).Local() + } + default: + err = InvalidTimestamp{FieldLength: length} + } + default: + err = errExt(extType, TimeExtension) } - if int8(p[2]) != TimeExtension { - err = errExt(int8(p[2]), TimeExtension) + return +} + +// ReadJSONNumber reads an integer or a float value and return as json.Number +func (m *Reader) ReadJSONNumber() (n json.Number, err error) { + t, err := m.NextType() + if err != nil { return } - sec, nsec := getUnix(p[3:]) - t = time.Unix(sec, int64(nsec)).Local() - _, err = m.R.Skip(15) - return + switch t { + case IntType: + v, err := m.ReadInt64() + if err == nil { + return json.Number(strconv.FormatInt(v, 10)), nil + } + return "", err + case UintType: + v, err := m.ReadUint64() + if err == nil { + return json.Number(strconv.FormatUint(v, 10)), nil + } + return "", err + case Float32Type, Float64Type: + v, err := m.ReadFloat64() + if err == nil { + return json.Number(strconv.FormatFloat(v, 'f', -1, 64)), nil + } + return "", err + } + return "", TypeError{Method: NumberType, Encoded: t} } -// ReadIntf reads out the next object as a raw interface{}. +// ReadIntf reads out the next object as a raw interface{}/any. // Arrays are decoded as []interface{}, and maps are decoded // as map[string]interface{}. Integers are decoded as int64 // and unsigned integers are decoded as uint64. @@ -1333,6 +1439,13 @@ func (m *Reader) ReadIntf() (i interface{}, err error) { return case MapType: + // This can call back here, so treat as recursive call. + if done, err := m.recursiveCall(); err != nil { + return nil, err + } else { + defer done() + } + mp := make(map[string]interface{}) err = m.ReadMapStrIntf(mp) i = mp @@ -1358,6 +1471,13 @@ func (m *Reader) ReadIntf() (i interface{}, err error) { if err != nil { return } + + if done, err := m.recursiveCall(); err != nil { + return nil, err + } else { + defer done() + } + out := make([]interface{}, int(sz)) for j := range out { out[j], err = m.ReadIntf() diff --git a/vendor/github.com/tinylib/msgp/msgp/read_bytes.go b/vendor/github.com/tinylib/msgp/msgp/read_bytes.go index a204ac4b9..8ed15a968 100644 --- a/vendor/github.com/tinylib/msgp/msgp/read_bytes.go +++ b/vendor/github.com/tinylib/msgp/msgp/read_bytes.go @@ -3,7 +3,9 @@ package msgp import ( "bytes" "encoding/binary" + "encoding/json" "math" + "strconv" "time" ) @@ -27,7 +29,7 @@ func NextType(b []byte) Type { tp = int8(b[spec.size-1]) } switch tp { - case TimeExtension: + case TimeExtension, MsgTimeExtension: return TimeType case Complex128Extension: return Complex128Type @@ -166,29 +168,30 @@ func ReadMapHeaderBytes(b []byte) (sz uint32, o []byte, err error) { } lead := b[0] + b = b[1:] if isfixmap(lead) { sz = uint32(rfixmap(lead)) - o = b[1:] + o = b return } switch lead { case mmap16: - if l < 3 { + if len(b) < 2 { err = ErrShortBytes return } - sz = uint32(big.Uint16(b[1:])) - o = b[3:] + sz = uint32(big.Uint16(b)) + o = b[2:] return case mmap32: - if l < 5 { + if len(b) < 4 { err = ErrShortBytes return } - sz = big.Uint32(b[1:]) - o = b[5:] + sz = big.Uint32(b) + o = b[4:] return default: @@ -228,29 +231,30 @@ func ReadArrayHeaderBytes(b []byte) (sz uint32, o []byte, err error) { return 0, nil, ErrShortBytes } lead := b[0] + b = b[1:] if isfixarray(lead) { sz = uint32(rfixarray(lead)) - o = b[1:] + o = b return } switch lead { case marray16: - if len(b) < 3 { + if len(b) < 2 { err = ErrShortBytes return } - sz = uint32(big.Uint16(b[1:])) - o = b[3:] + sz = uint32(big.Uint16(b)) + o = b[2:] return case marray32: - if len(b) < 5 { + if len(b) < 4 { err = ErrShortBytes return } - sz = big.Uint32(b[1:]) - o = b[5:] + sz = big.Uint32(b) + o = b[4:] return default: @@ -354,7 +358,7 @@ func ReadFloat64Bytes(b []byte) (f float64, o []byte, err error) { return } -// ReadFloat32Bytes tries to read a float64 +// ReadFloat32Bytes tries to read a float32 // from 'b' and return the value and the remaining bytes. // // Possible errors: @@ -377,7 +381,7 @@ func ReadFloat32Bytes(b []byte) (f float32, o []byte, err error) { return } -// ReadBoolBytes tries to read a float64 +// ReadBoolBytes tries to read a bool // from 'b' and return the value and the remaining bytes. // // Possible errors: @@ -418,99 +422,99 @@ func ReadDurationBytes(b []byte) (d time.Duration, o []byte, err error) { // - [ErrShortBytes] (too few bytes) // - [TypeError] (not a int) func ReadInt64Bytes(b []byte) (i int64, o []byte, err error) { - l := len(b) - if l < 1 { + if len(b) < 1 { return 0, nil, ErrShortBytes } lead := b[0] + b = b[1:] if isfixint(lead) { i = int64(rfixint(lead)) - o = b[1:] + o = b return } if isnfixint(lead) { i = int64(rnfixint(lead)) - o = b[1:] + o = b return } switch lead { case mint8: - if l < 2 { + if len(b) < 1 { err = ErrShortBytes return } - i = int64(getMint8(b)) - o = b[2:] + i = int64(int8(b[0])) + o = b[1:] return case muint8: - if l < 2 { + if len(b) < 1 { err = ErrShortBytes return } - i = int64(getMuint8(b)) - o = b[2:] + i = int64(b[0]) + o = b[1:] return case mint16: - if l < 3 { + if len(b) < 2 { err = ErrShortBytes return } - i = int64(getMint16(b)) - o = b[3:] + i = int64(int16(big.Uint16(b))) + o = b[2:] return case muint16: - if l < 3 { + if len(b) < 2 { err = ErrShortBytes return } - i = int64(getMuint16(b)) - o = b[3:] + i = int64(big.Uint16(b)) + o = b[2:] return case mint32: - if l < 5 { + if len(b) < 4 { err = ErrShortBytes return } - i = int64(getMint32(b)) - o = b[5:] + i = int64(int32(big.Uint32(b))) + o = b[4:] return case muint32: - if l < 5 { + if len(b) < 4 { err = ErrShortBytes return } - i = int64(getMuint32(b)) - o = b[5:] + i = int64(big.Uint32(b)) + o = b[4:] return case mint64: - if l < 9 { + if len(b) < 8 { err = ErrShortBytes return } - i = int64(getMint64(b)) - o = b[9:] + i = int64(big.Uint64(b)) + o = b[8:] return case muint64: - if l < 9 { + if len(b) < 8 { err = ErrShortBytes return } - u := getMuint64(b) + u := big.Uint64(b) if u > math.MaxInt64 { err = UintOverflow{Value: u, FailedBitsize: 64} return } i = int64(u) - o = b[9:] + o = b[8:] return default: @@ -592,109 +596,109 @@ func ReadIntBytes(b []byte) (int, []byte, error) { // - [ErrShortBytes] (too few bytes) // - [TypeError] (not a uint) func ReadUint64Bytes(b []byte) (u uint64, o []byte, err error) { - l := len(b) - if l < 1 { + if len(b) < 1 { return 0, nil, ErrShortBytes } lead := b[0] + b = b[1:] if isfixint(lead) { u = uint64(rfixint(lead)) - o = b[1:] + o = b return } switch lead { case mint8: - if l < 2 { + if len(b) < 1 { err = ErrShortBytes return } - v := int64(getMint8(b)) + v := int64(int8(b[0])) if v < 0 { err = UintBelowZero{Value: v} return } u = uint64(v) - o = b[2:] + o = b[1:] return case muint8: - if l < 2 { + if len(b) < 1 { err = ErrShortBytes return } - u = uint64(getMuint8(b)) - o = b[2:] + u = uint64(b[0]) + o = b[1:] return case mint16: - if l < 3 { + if len(b) < 2 { err = ErrShortBytes return } - v := int64(getMint16(b)) + v := int64((int16(b[0]) << 8) | int16(b[1])) if v < 0 { err = UintBelowZero{Value: v} return } u = uint64(v) - o = b[3:] + o = b[2:] return case muint16: - if l < 3 { + if len(b) < 2 { err = ErrShortBytes return } - u = uint64(getMuint16(b)) - o = b[3:] + u = uint64(big.Uint16(b)) + o = b[2:] return case mint32: - if l < 5 { + if len(b) < 4 { err = ErrShortBytes return } - v := int64(getMint32(b)) + v := int64(int32(big.Uint32(b))) if v < 0 { err = UintBelowZero{Value: v} return } u = uint64(v) - o = b[5:] + o = b[4:] return case muint32: - if l < 5 { + if len(b) < 4 { err = ErrShortBytes return } - u = uint64(getMuint32(b)) - o = b[5:] + u = uint64(big.Uint32(b)) + o = b[4:] return case mint64: - if l < 9 { + if len(b) < 8 { err = ErrShortBytes return } - v := int64(getMint64(b)) + v := int64(big.Uint64(b)) if v < 0 { err = UintBelowZero{Value: v} return } u = uint64(v) - o = b[9:] + o = b[8:] return case muint64: - if l < 9 { + if len(b) < 8 { err = ErrShortBytes return } - u = getMuint64(b) - o = b[9:] + u = big.Uint64(b) + o = b[8:] return default: @@ -796,32 +800,33 @@ func readBytesBytes(b []byte, scratch []byte, zc bool) (v []byte, o []byte, err } lead := b[0] + b = b[1:] var read int switch lead { case mbin8: - if l < 2 { + if len(b) < 1 { err = ErrShortBytes return } - read = int(b[1]) - b = b[2:] + read = int(b[0]) + b = b[1:] case mbin16: - if l < 3 { + if len(b) < 2 { err = ErrShortBytes return } - read = int(big.Uint16(b[1:])) - b = b[3:] + read = int(big.Uint16(b)) + b = b[2:] case mbin32: - if l < 5 { + if len(b) < 4 { err = ErrShortBytes return } - read = int(big.Uint32(b[1:])) - b = b[5:] + read = int(big.Uint32(b)) + b = b[4:] default: err = badPrefix(BinType, lead) @@ -863,40 +868,39 @@ func ReadBytesZC(b []byte) (v []byte, o []byte, err error) { } func ReadExactBytes(b []byte, into []byte) (o []byte, err error) { - l := len(b) - if l < 1 { + if len(b) < 1 { err = ErrShortBytes return } lead := b[0] var read uint32 - var skip int + b = b[1:] switch lead { case mbin8: - if l < 2 { + if len(b) < 1 { err = ErrShortBytes return } - read = uint32(b[1]) - skip = 2 + read = uint32(b[0]) + b = b[1:] case mbin16: - if l < 3 { + if len(b) < 2 { err = ErrShortBytes return } - read = uint32(big.Uint16(b[1:])) - skip = 3 + read = uint32(big.Uint16(b)) + b = b[2:] case mbin32: - if l < 5 { + if len(b) < 4 { err = ErrShortBytes return } - read = uint32(big.Uint32(b[1:])) - skip = 5 + read = big.Uint32(b) + b = b[4:] default: err = badPrefix(BinType, lead) @@ -908,7 +912,7 @@ func ReadExactBytes(b []byte, into []byte) (o []byte, err error) { return } - o = b[skip+copy(into, b[skip:]):] + o = b[copy(into, b):] return } @@ -921,42 +925,41 @@ func ReadExactBytes(b []byte, into []byte) (o []byte, err error) { // - [ErrShortBytes] (b not long enough) // - [TypeError] (object not 'str') func ReadStringZC(b []byte) (v []byte, o []byte, err error) { - l := len(b) - if l < 1 { + if len(b) < 1 { return nil, nil, ErrShortBytes } lead := b[0] var read int + b = b[1:] if isfixstr(lead) { read = int(rfixstr(lead)) - b = b[1:] } else { switch lead { case mstr8: - if l < 2 { + if len(b) < 1 { err = ErrShortBytes return } - read = int(b[1]) - b = b[2:] + read = int(b[0]) + b = b[1:] case mstr16: - if l < 3 { + if len(b) < 2 { err = ErrShortBytes return } - read = int(big.Uint16(b[1:])) - b = b[3:] + read = int(big.Uint16(b)) + b = b[2:] case mstr32: - if l < 5 { + if len(b) < 4 { err = ErrShortBytes return } - read = int(big.Uint32(b[1:])) - b = b[5:] + read = int(big.Uint32(b)) + b = b[4:] default: err = TypeError{Method: StrType, Encoded: getType(lead)} @@ -1063,38 +1066,88 @@ func ReadComplex64Bytes(b []byte) (c complex64, o []byte, err error) { return } +// ReadTimeUTCBytes does the same as ReadTimeBytes, but returns the value as UTC. +func ReadTimeUTCBytes(b []byte) (t time.Time, o []byte, err error) { + t, o, err = ReadTimeBytes(b) + return t.UTC(), o, err +} + // ReadTimeBytes reads a time.Time // extension object from 'b' and returns the // remaining bytes. +// Both the official and the format in this package will be read. // // Possible errors: // // - [ErrShortBytes] (not enough bytes in 'b') -// - [TypeError] (object not a complex64) +// - [TypeError] (object not a time extension 5 or -1) // - [ExtensionTypeError] (object an extension of the correct size, but not a time.Time) func ReadTimeBytes(b []byte) (t time.Time, o []byte, err error) { - if len(b) < 15 { + if len(b) < 6 { err = ErrShortBytes return } - if b[0] != mext8 || b[1] != 12 { - err = badPrefix(TimeType, b[0]) + typ, o, b, err := readExt(b) + if err != nil { return } - if int8(b[2]) != TimeExtension { + switch typ { + case TimeExtension: + if len(b) != 12 { + err = ErrShortBytes + return + } + sec, nsec := getUnix(b) + t = time.Unix(sec, int64(nsec)).Local() + return + case MsgTimeExtension: + switch len(b) { + case 4: + t = time.Unix(int64(binary.BigEndian.Uint32(b)), 0).Local() + return + case 8: + v := binary.BigEndian.Uint64(b) + nanos := int64(v >> 34) + if nanos > 999999999 { + // In timestamp 64 and timestamp 96 formats, nanoseconds must not be larger than 999999999. + err = InvalidTimestamp{Nanos: nanos} + return + } + t = time.Unix(int64(v&(1<<34-1)), nanos).Local() + return + case 12: + nanos := int64(binary.BigEndian.Uint32(b)) + if nanos > 999999999 { + // In timestamp 64 and timestamp 96 formats, nanoseconds must not be larger than 999999999. + err = InvalidTimestamp{Nanos: nanos} + return + } + ux := int64(binary.BigEndian.Uint64(b[4:])) + t = time.Unix(ux, nanos).Local() + return + default: + err = InvalidTimestamp{FieldLength: len(b)} + return + } + default: err = errExt(int8(b[2]), TimeExtension) return } - sec, nsec := getUnix(b[3:]) - t = time.Unix(sec, int64(nsec)).Local() - o = b[15:] - return } // ReadMapStrIntfBytes reads a map[string]interface{} // out of 'b' and returns the map and remaining bytes. // If 'old' is non-nil, the values will be read into that map. func ReadMapStrIntfBytes(b []byte, old map[string]interface{}) (v map[string]interface{}, o []byte, err error) { + return readMapStrIntfBytesDepth(b, old, 0) +} + +func readMapStrIntfBytesDepth(b []byte, old map[string]interface{}, depth int) (v map[string]interface{}, o []byte, err error) { + if depth >= recursionLimit { + err = ErrRecursion + return + } + var sz uint32 o = b sz, o, err = ReadMapHeaderBytes(o) @@ -1123,7 +1176,7 @@ func ReadMapStrIntfBytes(b []byte, old map[string]interface{}) (v map[string]int return } var val interface{} - val, o, err = ReadIntfBytes(o) + val, o, err = readIntfBytesDepth(o, depth) if err != nil { return } @@ -1136,6 +1189,14 @@ func ReadMapStrIntfBytes(b []byte, old map[string]interface{}) (v map[string]int // the next object out of 'b' as a raw interface{} and // return the remaining bytes. func ReadIntfBytes(b []byte) (i interface{}, o []byte, err error) { + return readIntfBytesDepth(b, 0) +} + +func readIntfBytesDepth(b []byte, depth int) (i interface{}, o []byte, err error) { + if depth >= recursionLimit { + err = ErrRecursion + return + } if len(b) < 1 { err = ErrShortBytes return @@ -1145,7 +1206,7 @@ func ReadIntfBytes(b []byte) (i interface{}, o []byte, err error) { switch k { case MapType: - i, o, err = ReadMapStrIntfBytes(b, nil) + i, o, err = readMapStrIntfBytesDepth(b, nil, depth+1) return case ArrayType: @@ -1157,7 +1218,7 @@ func ReadIntfBytes(b []byte) (i interface{}, o []byte, err error) { j := make([]interface{}, int(sz)) i = j for d := range j { - j[d], o, err = ReadIntfBytes(o) + j[d], o, err = readIntfBytesDepth(o, depth+1) if err != nil { return } @@ -1245,7 +1306,15 @@ func ReadIntfBytes(b []byte) (i interface{}, o []byte, err error) { // // - [ErrShortBytes] (not enough bytes in b) // - [InvalidPrefixError] (bad encoding) +// - [ErrRecursion] (too deeply nested data) func Skip(b []byte) ([]byte, error) { + return skipDepth(b, 0) +} + +func skipDepth(b []byte, depth int) ([]byte, error) { + if depth >= recursionLimit { + return b, ErrRecursion + } sz, asz, err := getSize(b) if err != nil { return b, err @@ -1255,7 +1324,7 @@ func Skip(b []byte) ([]byte, error) { } b = b[sz:] for asz > 0 { - b, err = Skip(b) + b, err = skipDepth(b, depth+1) if err != nil { return b, err } @@ -1301,3 +1370,24 @@ func getSize(b []byte) (uintptr, uintptr, error) { return 0, 0, fatal } } + +// ReadJSONNumberBytes tries to read a number +// from 'b' and return the value and the remaining bytes. +// +// Possible errors: +// +// - [ErrShortBytes] (too few bytes) +// - TypeError (not a number (int/float)) +func ReadJSONNumberBytes(b []byte) (number json.Number, o []byte, err error) { + if len(b) < 1 { + return "", nil, ErrShortBytes + } + if i, o, err := ReadInt64Bytes(b); err == nil { + return json.Number(strconv.FormatInt(i, 10)), o, nil + } + f, o, err := ReadFloat64Bytes(b) + if err == nil { + return json.Number(strconv.FormatFloat(f, 'f', -1, 64)), o, nil + } + return "", nil, TypeError{Method: NumberType, Encoded: getType(b[0])} +} diff --git a/vendor/github.com/tinylib/msgp/msgp/size.go b/vendor/github.com/tinylib/msgp/msgp/size.go index e3a613b24..585a67fdb 100644 --- a/vendor/github.com/tinylib/msgp/msgp/size.go +++ b/vendor/github.com/tinylib/msgp/msgp/size.go @@ -25,10 +25,11 @@ const ( Complex64Size = 10 Complex128Size = 18 - DurationSize = Int64Size - TimeSize = 15 - BoolSize = 1 - NilSize = 1 + DurationSize = Int64Size + TimeSize = 15 + BoolSize = 1 + NilSize = 1 + JSONNumberSize = Int64Size // Same as Float64Size MapHeaderSize = 5 ArrayHeaderSize = 5 diff --git a/vendor/github.com/tinylib/msgp/msgp/unsafe.go b/vendor/github.com/tinylib/msgp/msgp/unsafe.go index 06e8d8437..7d36bfb1e 100644 --- a/vendor/github.com/tinylib/msgp/msgp/unsafe.go +++ b/vendor/github.com/tinylib/msgp/msgp/unsafe.go @@ -1,5 +1,5 @@ -//go:build !purego && !appengine -// +build !purego,!appengine +//go:build (!purego && !appengine) || (!appengine && purego && unsafe) +// +build !purego,!appengine !appengine,purego,unsafe package msgp diff --git a/vendor/github.com/tinylib/msgp/msgp/write.go b/vendor/github.com/tinylib/msgp/msgp/write.go index ec2f6f528..352350f90 100644 --- a/vendor/github.com/tinylib/msgp/msgp/write.go +++ b/vendor/github.com/tinylib/msgp/msgp/write.go @@ -1,6 +1,8 @@ package msgp import ( + "encoding/binary" + "encoding/json" "errors" "io" "math" @@ -346,6 +348,16 @@ func (mw *Writer) WriteNil() error { return mw.push(mnil) } +// WriteFloat writes a float to the writer as either float64 +// or float32 when it represents the exact same value +func (mw *Writer) WriteFloat(f float64) error { + f32 := float32(f) + if float64(f32) == f { + return mw.prefix32(mfloat32, math.Float32bits(f32)) + } + return mw.prefix64(mfloat64, math.Float64bits(f)) +} + // WriteFloat64 writes a float64 to the writer func (mw *Writer) WriteFloat64(f float64) error { return mw.prefix64(mfloat64, math.Float64bits(f)) @@ -624,6 +636,65 @@ func (mw *Writer) WriteTime(t time.Time) error { return nil } +// WriteTimeExt will write t using the official msgpack extension spec. +// https://github.com/msgpack/msgpack/blob/master/spec.md#timestamp-extension-type +func (mw *Writer) WriteTimeExt(t time.Time) error { + // Time rounded towards zero. + secPrec := t.Truncate(time.Second) + remain := t.Sub(secPrec).Nanoseconds() + asSecs := secPrec.Unix() + switch { + case remain == 0 && asSecs > 0 && asSecs <= math.MaxUint32: + // 4 bytes + o, err := mw.require(6) + if err != nil { + return err + } + mw.buf[o] = mfixext4 + mw.buf[o+1] = byte(msgTimeExtension) + binary.BigEndian.PutUint32(mw.buf[o+2:], uint32(asSecs)) + return nil + case asSecs < 0 || asSecs >= (1<<34): + // 12 bytes + o, err := mw.require(12 + 3) + if err != nil { + return err + } + mw.buf[o] = mext8 + mw.buf[o+1] = 12 + mw.buf[o+2] = byte(msgTimeExtension) + binary.BigEndian.PutUint32(mw.buf[o+3:], uint32(remain)) + binary.BigEndian.PutUint64(mw.buf[o+3+4:], uint64(asSecs)) + default: + // 8 bytes + o, err := mw.require(10) + if err != nil { + return err + } + mw.buf[o] = mfixext8 + mw.buf[o+1] = byte(msgTimeExtension) + binary.BigEndian.PutUint64(mw.buf[o+2:], uint64(asSecs)|(uint64(remain)<<34)) + } + return nil +} + +// WriteJSONNumber writes the json.Number to the stream as either integer or float. +func (mw *Writer) WriteJSONNumber(n json.Number) error { + if n == "" { + // The zero value outputs the 0 integer. + return mw.push(0) + } + ii, err := n.Int64() + if err == nil { + return mw.WriteInt64(ii) + } + ff, err := n.Float64() + if err == nil { + return mw.WriteFloat(ff) + } + return err +} + // WriteIntf writes the concrete type of 'v'. // WriteIntf will error if 'v' is not one of the following: // - A bool, float, string, []byte, int, uint, or complex @@ -689,6 +760,8 @@ func (mw *Writer) WriteIntf(v interface{}) error { return mw.WriteTime(v) case time.Duration: return mw.WriteDuration(v) + case json.Number: + return mw.WriteJSONNumber(v) } val := reflect.ValueOf(v) diff --git a/vendor/github.com/tinylib/msgp/msgp/write_bytes.go b/vendor/github.com/tinylib/msgp/msgp/write_bytes.go index 676a6efe1..704501746 100644 --- a/vendor/github.com/tinylib/msgp/msgp/write_bytes.go +++ b/vendor/github.com/tinylib/msgp/msgp/write_bytes.go @@ -1,6 +1,9 @@ package msgp import ( + "encoding/binary" + "encoding/json" + "errors" "math" "reflect" "time" @@ -59,6 +62,16 @@ func AppendArrayHeader(b []byte, sz uint32) []byte { // AppendNil appends a 'nil' byte to the slice func AppendNil(b []byte) []byte { return append(b, mnil) } +// AppendFloat appends a float to the slice as either float64 +// or float32 when it represents the exact same value +func AppendFloat(b []byte, f float64) []byte { + f32 := float32(f) + if float64(f32) == f { + return AppendFloat32(b, f32) + } + return AppendFloat64(b, f) +} + // AppendFloat64 appends a float64 to the slice func AppendFloat64(b []byte, f float64) []byte { o, n := ensure(b, Float64Size) @@ -310,6 +323,40 @@ func AppendTime(b []byte, t time.Time) []byte { return o } +// AppendTimeExt will write t using the official msgpack extension spec. +// https://github.com/msgpack/msgpack/blob/master/spec.md#timestamp-extension-type +func AppendTimeExt(b []byte, t time.Time) []byte { + // Time rounded towards zero. + secPrec := t.Truncate(time.Second) + remain := t.Sub(secPrec).Nanoseconds() + asSecs := secPrec.Unix() + switch { + case remain == 0 && asSecs > 0 && asSecs <= math.MaxUint32: + // 4 bytes + o, n := ensure(b, 2+4) + o[n+0] = mfixext4 + o[n+1] = byte(msgTimeExtension) + binary.BigEndian.PutUint32(o[n+2:], uint32(asSecs)) + return o + case asSecs < 0 || asSecs >= (1<<34): + // 12 bytes + o, n := ensure(b, 3+12) + o[n+0] = mext8 + o[n+1] = 12 + o[n+2] = byte(msgTimeExtension) + binary.BigEndian.PutUint32(o[n+3:], uint32(remain)) + binary.BigEndian.PutUint64(o[n+3+4:], uint64(asSecs)) + return o + default: + // 8 bytes + o, n := ensure(b, 2+8) + o[n+0] = mfixext8 + o[n+1] = byte(msgTimeExtension) + binary.BigEndian.PutUint64(o[n+2:], uint64(asSecs)|(uint64(remain)<<34)) + return o + } +} + // AppendMapStrStr appends a map[string]string to the slice // as a MessagePack map with 'str'-type keys and values func AppendMapStrStr(b []byte, m map[string]string) []byte { @@ -342,10 +389,10 @@ func AppendMapStrIntf(b []byte, m map[string]interface{}) ([]byte, error) { // provided []byte. 'i' must be one of the following: // - 'nil' // - A bool, float, string, []byte, int, uint, or complex -// - A map[string]interface{} or map[string]string +// - A map[string]T where T is another supported type // - A []T, where T is another supported type // - A *T, where T is another supported type -// - A type that satisfieds the msgp.Marshaler interface +// - A type that satisfies the msgp.Marshaler interface // - A type that satisfies the msgp.Extension interface func AppendIntf(b []byte, i interface{}) ([]byte, error) { if i == nil { @@ -395,10 +442,14 @@ func AppendIntf(b []byte, i interface{}) ([]byte, error) { return AppendUint64(b, i), nil case time.Time: return AppendTime(b, i), nil + case time.Duration: + return AppendDuration(b, i), nil case map[string]interface{}: return AppendMapStrIntf(b, i) case map[string]string: return AppendMapStrStr(b, i), nil + case json.Number: + return AppendJSONNumber(b, i) case []interface{}: b = AppendArrayHeader(b, uint32(len(i))) var err error @@ -414,6 +465,21 @@ func AppendIntf(b []byte, i interface{}) ([]byte, error) { var err error v := reflect.ValueOf(i) switch v.Kind() { + case reflect.Map: + if v.Type().Key().Kind() != reflect.String { + return b, errors.New("msgp: map keys must be strings") + } + ks := v.MapKeys() + b = AppendMapHeader(b, uint32(len(ks))) + for _, key := range ks { + val := v.MapIndex(key) + b = AppendString(b, key.String()) + b, err = AppendIntf(b, val.Interface()) + if err != nil { + return nil, err + } + } + return b, nil case reflect.Array, reflect.Slice: l := v.Len() b = AppendArrayHeader(b, uint32(l)) @@ -434,3 +500,21 @@ func AppendIntf(b []byte, i interface{}) ([]byte, error) { return b, &ErrUnsupportedType{T: v.Type()} } } + +// AppendJSONNumber appends a json.Number to the slice. +// An error will be returned if the json.Number returns error as both integer and float. +func AppendJSONNumber(b []byte, n json.Number) ([]byte, error) { + if n == "" { + // The zero value outputs the 0 integer. + return append(b, 0), nil + } + ii, err := n.Int64() + if err == nil { + return AppendInt64(b, ii), nil + } + ff, err := n.Float64() + if err == nil { + return AppendFloat(b, ff), nil + } + return b, err +} diff --git a/vendor/modules.txt b/vendor/modules.txt index eab2cf96a..3c2e9588a 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -128,8 +128,8 @@ github.com/pelletier/go-toml/v2/internal/characters github.com/pelletier/go-toml/v2/internal/danger github.com/pelletier/go-toml/v2/internal/tracker github.com/pelletier/go-toml/v2/unstable -# github.com/philhofer/fwd v1.1.2 -## explicit; go 1.15 +# github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c +## explicit; go 1.20 github.com/philhofer/fwd # github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 ## explicit @@ -181,8 +181,8 @@ github.com/tebeka/strftime # github.com/tevino/abool v1.2.0 ## explicit; go 1.14 github.com/tevino/abool -# github.com/tinylib/msgp v1.1.9 -## explicit; go 1.18 +# github.com/tinylib/msgp v1.3.0 +## explicit; go 1.20 github.com/tinylib/msgp/msgp # github.com/valyala/fastjson v1.6.4 ## explicit; go 1.12