diff --git a/go.mod b/go.mod index 32363b994..4d0cd6316 100644 --- a/go.mod +++ b/go.mod @@ -34,7 +34,7 @@ require ( github.com/stretchr/testify v1.11.1 github.com/tebeka/strftime v0.1.5 github.com/tevino/abool v1.2.0 - github.com/tinylib/msgp v1.4.0 + github.com/tinylib/msgp v1.5.0 github.com/valyala/fastjson v1.6.4 github.com/wangjohn/quickselect v0.0.0-20161129230411-ed8402a42d5f go.uber.org/zap v1.27.0 diff --git a/go.sum b/go.sum index d0445f0fa..533a2d4ee 100644 --- a/go.sum +++ b/go.sum @@ -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.4.0 h1:SYOeDRiydzOw9kSiwdYp9UcBgPFtLU2WDHaJXyHruf8= -github.com/tinylib/msgp v1.4.0/go.mod h1:cvjFkb4RiC8qSBOPMGPSzSAx47nAsfhLVTCZZNuHv5o= +github.com/tinylib/msgp v1.5.0 h1:GWnqAE54wmnlFazjq2+vgr736Akg58iiHImh+kPY2pc= +github.com/tinylib/msgp v1.5.0/go.mod h1:cvjFkb4RiC8qSBOPMGPSzSAx47nAsfhLVTCZZNuHv5o= 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/tinylib/msgp/msgp/defs.go b/vendor/github.com/tinylib/msgp/msgp/defs.go index 47a8c1834..f622bf1e1 100644 --- a/vendor/github.com/tinylib/msgp/msgp/defs.go +++ b/vendor/github.com/tinylib/msgp/msgp/defs.go @@ -26,6 +26,27 @@ // the wiki at http://github.com/tinylib/msgp package msgp +// RT is the runtime interface for all types that can be encoded and decoded. +type RT interface { + Decodable + Encodable + Sizer + Unmarshaler + Marshaler +} + +// PtrTo is the runtime interface for all types that can be encoded and decoded. +type PtrTo[T any] interface { + ~*T +} + +// RTFor is the runtime interface for all types that can be encoded and decoded. +// Use for generic types. +type RTFor[T any] interface { + PtrTo[T] + RT +} + const ( last4 = 0x0f first4 = 0xf0 diff --git a/vendor/github.com/tinylib/msgp/msgp/iter.go b/vendor/github.com/tinylib/msgp/msgp/iter.go new file mode 100644 index 000000000..3689649e8 --- /dev/null +++ b/vendor/github.com/tinylib/msgp/msgp/iter.go @@ -0,0 +1,387 @@ +//go:build go1.23 + +package msgp + +import ( + "cmp" + "fmt" + "iter" + "maps" + "math" + "slices" +) + +// ReadArray returns an iterator that can be used to iterate over the elements +// of an array in the MessagePack data while being read by the provided Reader. +// The type parameter V specifies the type of the elements in the array. +// The returned iterator implements the iter.Seq[V] interface, +// allowing for sequential access to the array elements. +func ReadArray[T any](m *Reader, readFn func() (T, error)) iter.Seq2[T, error] { + return func(yield func(T, error) bool) { + // Check if nil + if m.IsNil() { + m.ReadNil() + return + } + // Regular array. + var empty T + length, err := m.ReadArrayHeader() + if err != nil { + yield(empty, fmt.Errorf("cannot read array header: %w", err)) + return + } + for range length { + var v T + v, err = readFn() + if !yield(v, err) { + return + } + } + } +} + +// WriteArray writes an array to the provided Writer. +// The writeFn parameter specifies the function to use to write each element of the array. +func WriteArray[T any](w *Writer, a []T, writeFn func(T) error) error { + // Check if nil + if a == nil { + return w.WriteNil() + } + if uint64(len(a)) > math.MaxUint32 { + return fmt.Errorf("array too large to encode: %d elements", len(a)) + } + // Write array header + err := w.WriteArrayHeader(uint32(len(a))) + if err != nil { + return err + } + // Write elements + for _, v := range a { + err = writeFn(v) + if err != nil { + return err + } + } + return nil +} + +// ReadMap returns an iterator that can be used to iterate over the elements +// of a map in the MessagePack data while being read by the provided Reader. +// The type parameters K and V specify the types of the keys and values in the map. +// The returned iterator implements the iter.Seq2[K, V] interface, +// allowing for sequential access to the map elements. +// The returned function can be used to read any error that +// occurred during iteration when iteration is done. +func ReadMap[K, V any](m *Reader, readKey func() (K, error), readVal func() (V, error)) (iter.Seq2[K, V], func() error) { + var err error + return func(yield func(K, V) bool) { + var sz uint32 + if m.IsNil() { + err = m.ReadNil() + return + } + sz, err = m.ReadMapHeader() + if err != nil { + err = fmt.Errorf("cannot read map header: %w", err) + return + } + + for range sz { + var k K + k, err = readKey() + if err != nil { + err = fmt.Errorf("cannot read key: %w", err) + return + } + var v V + v, err = readVal() + if err != nil { + err = fmt.Errorf("cannot read value: %w", err) + return + } + if !yield(k, v) { + return + } + } + }, func() error { return err } +} + +// WriteMap writes a map to the provided Writer. +// The writeKey and writeVal parameters specify the functions +// to use to write each key and value of the map. +func WriteMap[K comparable, V any](w *Writer, m map[K]V, writeKey func(K) error, writeVal func(V) error) error { + if m == nil { + return w.WriteNil() + } + if uint64(len(m)) > math.MaxUint32 { + return fmt.Errorf("map too large to encode: %d elements", len(m)) + } + + // Write map header + err := w.WriteMapHeader(uint32(len(m))) + if err != nil { + return err + } + // Write elements + for k, v := range m { + err = writeKey(k) + if err != nil { + return err + } + err = writeVal(v) + if err != nil { + return err + } + } + return nil +} + +// WriteMapSorted writes a map to the provided Writer. +// The keys of the map are sorted before writing. +// This provides deterministic output, but will allocate to sort the keys. +// The writeKey and writeVal parameters specify the functions +// to use to write each key and value of the map. +func WriteMapSorted[K cmp.Ordered, V any](w *Writer, m map[K]V, writeKey func(K) error, writeVal func(V) error) error { + if m == nil { + return w.WriteNil() + } + if uint64(len(m)) > math.MaxUint32 { + return fmt.Errorf("map too large to encode: %d elements", len(m)) + } + + // Write map header + err := w.WriteMapHeader(uint32(len(m))) + if err != nil { + return err + } + // Write elements + for _, k := range slices.Sorted(maps.Keys(m)) { + err = writeKey(k) + if err != nil { + return err + } + err = writeVal(m[k]) + if err != nil { + return err + } + } + return nil +} + +// ReadArrayBytes returns an iterator that can be used to iterate over the elements +// of an array in the MessagePack data while being read by the provided Reader. +// The type parameter V specifies the type of the elements in the array. +// After the iterator is exhausted, the remaining bytes in the buffer +// and any error can be read by calling the returned function. +func ReadArrayBytes[T any](b []byte, readFn func([]byte) (T, []byte, error)) (iter.Seq[T], func() (remain []byte, err error)) { + if IsNil(b) { + b, err := ReadNilBytes(b) + return func(yield func(T) bool) {}, func() ([]byte, error) { return b, err } + } + sz, b, err := ReadArrayHeaderBytes(b) + if err != nil || sz == 0 { + return func(yield func(T) bool) {}, func() ([]byte, error) { return b, err } + } + return func(yield func(T) bool) { + for range sz { + var v T + v, b, err = readFn(b) + if err != nil || !yield(v) { + return + } + } + }, func() ([]byte, error) { + return b, err + } +} + +// AppendArray writes an array to the provided buffer. +// The writeFn parameter specifies the function to use to write each element of the array. +// The returned buffer contains the encoded array. +// The function panics if the array is larger than math.MaxUint32 elements. +func AppendArray[T any](b []byte, a []T, writeFn func(b []byte, v T) []byte) []byte { + if a == nil { + return AppendNil(b) + } + if uint64(len(a)) > math.MaxUint32 { + panic(fmt.Sprintf("array too large to encode: %d elements", len(a))) + } + b = AppendArrayHeader(b, uint32(len(a))) + for _, v := range a { + b = writeFn(b, v) + } + return b +} + +// ReadMapBytes returns an iterator over key/value +// pairs from a MessagePack map encoded in b. +// The iterator yields K,V pairs, and this function also returns +// a closure to get the remaining bytes and any error. +func ReadMapBytes[K any, V any](b []byte, + readK func([]byte) (K, []byte, error), + readV func([]byte) (V, []byte, error)) (iter.Seq2[K, V], func() (remain []byte, err error)) { + var err error + var sz uint32 + if IsNil(b) { + b, err = ReadNilBytes(b) + return func(yield func(K, V) bool) {}, func() ([]byte, error) { return b, err } + } + sz, b, err = ReadMapHeaderBytes(b) + if err != nil || sz == 0 { + return func(yield func(K, V) bool) {}, func() ([]byte, error) { return b, err } + } + + return func(yield func(K, V) bool) { + for range sz { + var k K + k, b, err = readK(b) + if err != nil { + err = fmt.Errorf("cannot read map key: %w", err) + return + } + var v V + v, b, err = readV(b) + if err != nil { + err = fmt.Errorf("cannot read map value: %w", err) + return + } + if !yield(k, v) { + return + } + } + }, func() ([]byte, error) { return b, err } +} + +// AppendMap writes a map to the provided buffer. +// The writeK and writeV parameters specify the functions to use to write each key and value of the map. +// The returned buffer contains the encoded map. +// The function panics if the map is larger than math.MaxUint32 elements. +func AppendMap[K comparable, V any](b []byte, m map[K]V, + writeK func(b []byte, k K) []byte, + writeV func(b []byte, v V) []byte) []byte { + if m == nil { + return AppendNil(b) + } + if uint64(len(m)) > math.MaxUint32 { + panic(fmt.Sprintf("map too large to encode: %d elements", len(m))) + } + b = AppendMapHeader(b, uint32(len(m))) + for k, v := range m { + b = writeK(b, k) + b = writeV(b, v) + } + return b +} + +// AppendMapSorted writes a map to the provided buffer. +// Keys are sorted before writing. +// This provides deterministic output, but will allocate to sort the keys. +// The writeK and writeV parameters specify the functions to use to write each key and value of the map. +// The returned buffer contains the encoded map. +// The function panics if the map is larger than math.MaxUint32 elements. +func AppendMapSorted[K cmp.Ordered, V any](b []byte, m map[K]V, + writeK func(b []byte, k K) []byte, + writeV func(b []byte, v V) []byte) []byte { + if m == nil { + return AppendNil(b) + } + if uint64(len(m)) > math.MaxUint32 { + panic(fmt.Sprintf("map too large to encode: %d elements", len(m))) + } + b = AppendMapHeader(b, uint32(len(m))) + for _, k := range slices.Sorted(maps.Keys(m)) { + b = writeK(b, k) + b = writeV(b, m[k]) + } + return b +} + +// DecodePtr is a convenience type for decoding into a pointer. +type DecodePtr[T any] interface { + *T + Decodable +} + +// DecoderFrom allows augmenting any type with a DecodeMsg method into a method +// that reads from Reader and returns a T. +// Provide an instance of T. This value isn't used. +// See ReadArray/ReadMap "struct" examples for usage. +func DecoderFrom[T any, PT DecodePtr[T]](r *Reader, _ T) func() (T, error) { + return func() (T, error) { + var t T + tPtr := PT(&t) + err := tPtr.DecodeMsg(r) + return t, err + } +} + +// FlexibleEncoder is a constraint for types where either T or *T implements Encodable +type FlexibleEncoder[T any] interface { + Encodable + *T +} + +// EncoderTo allows augmenting any type with an EncodeMsg +// method into a method that writes to Writer on each call. +// Provide an instance of T. This value isn't used. +// See ReadArray or ReadMap "struct" examples for usage. +func EncoderTo[T any, _ FlexibleEncoder[T]](w *Writer, _ T) func(T) error { + return func(t T) error { + // Check if T implements Marshaler + if marshaler, ok := any(t).(Encodable); ok { + return marshaler.EncodeMsg(w) + } + // Check if *T implements Marshaler + if ptrMarshaler, ok := any(&t).(Encodable); ok { + return ptrMarshaler.EncodeMsg(w) + } + // The compiler should have asserted this. + panic("type does not implement Marshaler") + } +} + +// UnmarshalPtr is a convenience type for unmarshaling into a pointer. +type UnmarshalPtr[T any] interface { + *T + Unmarshaler +} + +// DecoderFromBytes allows augmenting any type with an UnmarshalMsg +// method into a method that reads from []byte and returns a T. +// Provide an instance of T. This value isn't used. +// See ReadArrayBytes or ReadMapBytes "struct" examples for usage. +func DecoderFromBytes[T any, PT UnmarshalPtr[T]](_ T) func([]byte) (T, []byte, error) { + return func(b []byte) (T, []byte, error) { + var t T + tPtr := PT(&t) + b, err := tPtr.UnmarshalMsg(b) + return t, b, err + } +} + +// FlexibleMarshaler is a constraint for types where either T or *T implements Marshaler +type FlexibleMarshaler[T any] interface { + Marshaler + *T // Include *T in the interface +} + +// EncoderToBytes allows augmenting any type with a MarshalMsg method into a method +// that reads from T and returns a []byte. +// Provide an instance of T. This value isn't used. +// See ReadArrayBytes or ReadMapBytes "struct" examples for usage. +func EncoderToBytes[T any, _ FlexibleMarshaler[T]](_ T) func([]byte, T) []byte { + return func(b []byte, t T) []byte { + // Check if T implements Marshaler + if marshaler, ok := any(t).(Marshaler); ok { + b, _ = marshaler.MarshalMsg(b) + return b + } + // Check if *T implements Marshaler + if ptrMarshaler, ok := any(&t).(Marshaler); ok { + b, _ = ptrMarshaler.MarshalMsg(b) + return b + } + // The compiler should have asserted this. + panic("type does not implement Marshaler") + } +} diff --git a/vendor/github.com/tinylib/msgp/msgp/number.go b/vendor/github.com/tinylib/msgp/msgp/number.go index edfe328b4..3b6588fda 100644 --- a/vendor/github.com/tinylib/msgp/msgp/number.go +++ b/vendor/github.com/tinylib/msgp/msgp/number.go @@ -2,6 +2,7 @@ package msgp import ( "math" + "math/bits" "strconv" ) @@ -77,7 +78,7 @@ func (n *Number) Uint() (uint64, bool) { } // Float casts the number to a float64, and -// returns whether or not that was the underlying +// returns whether that was the underlying // type (either a float64 or a float32). func (n *Number) Float() (float64, bool) { switch n.typ { @@ -208,6 +209,129 @@ func (n *Number) EncodeMsg(w *Writer) error { } } +// CoerceInt attempts to coerce the value of +// the number into a signed integer and returns +// whether it was successful. +// "Success" implies that no precision in the value of +// the number was lost, which means that the number was an integer or +// a floating point that mapped exactly to an integer without rounding. +func (n *Number) CoerceInt() (int64, bool) { + switch n.typ { + case InvalidType, IntType: + // InvalidType just means un-initialized. + return int64(n.bits), true + case UintType: + return int64(n.bits), n.bits <= math.MaxInt64 + case Float32Type: + f := math.Float32frombits(uint32(n.bits)) + if n.isExactInt() && f <= math.MaxInt64 && f >= math.MinInt64 { + return int64(f), true + } + if n.bits == 0 || n.bits == 1<<31 { + return 0, true + } + case Float64Type: + f := math.Float64frombits(n.bits) + if n.isExactInt() && f <= math.MaxInt64 && f >= math.MinInt64 { + return int64(f), true + } + return 0, n.bits == 0 || n.bits == 1<<63 + } + return 0, false +} + +// CoerceUInt attempts to coerce the value of +// the number into an unsigned integer and returns +// whether it was successful. +// "Success" implies that no precision in the value of +// the number was lost, which means that the number was an integer or +// a floating point that mapped exactly to an integer without rounding. +func (n *Number) CoerceUInt() (uint64, bool) { + switch n.typ { + case InvalidType, IntType: + // InvalidType just means un-initialized. + if int64(n.bits) >= 0 { + return n.bits, true + } + case UintType: + return n.bits, true + case Float32Type: + f := math.Float32frombits(uint32(n.bits)) + if f >= 0 && f <= math.MaxUint64 && n.isExactInt() { + return uint64(f), true + } + if n.bits == 0 || n.bits == 1<<31 { + return 0, true + } + case Float64Type: + f := math.Float64frombits(n.bits) + if f >= 0 && f <= math.MaxUint64 && n.isExactInt() { + return uint64(f), true + } + return 0, n.bits == 0 || n.bits == 1<<63 + } + return 0, false +} + +// isExactInt will return true if the number represents an integer value. +// NaN, Inf returns false. +func (n *Number) isExactInt() bool { + var eBits int // Exponent bits + var mBits int // Mantissa bits + + switch n.typ { + case InvalidType, IntType, UintType: + return true + case Float32Type: + eBits = 8 + mBits = 23 + case Float64Type: + eBits = 11 + mBits = 52 + default: + return false + } + // Calculate float parts + exp := int(n.bits>>mBits) & ((1 << eBits) - 1) + mant := n.bits & ((1 << mBits) - 1) + if exp == 0 && mant == 0 { + // Handle zero value. + return true + } + + exp -= (1 << (eBits - 1)) - 1 + if exp < 0 || exp == 1<<(eBits-1) { + // Negative exponent is never integer (except zero handled above) + // Handles NaN (exp all 1s) + return false + } + + if exp >= mBits { + // If we have more exponent than mantissa bits it is always an integer. + return true + } + // Check if all bits below the exponent are zero. + return bits.TrailingZeros64(mant) >= mBits-exp +} + +// CoerceFloat returns the number as a float64. +// If the number is an integer, it will be +// converted to a float64 with the closest representation. +func (n *Number) CoerceFloat() float64 { + switch n.typ { + case IntType: + return float64(int64(n.bits)) + case UintType: + return float64(n.bits) + case Float32Type: + return float64(math.Float32frombits(uint32(n.bits))) + case Float64Type: + return math.Float64frombits(n.bits) + default: + return 0.0 + } +} + // Msgsize implements msgp.Sizer func (n *Number) Msgsize() int { switch n.typ { diff --git a/vendor/github.com/tinylib/msgp/msgp/read.go b/vendor/github.com/tinylib/msgp/msgp/read.go index 409dbcec5..4acfd78ff 100644 --- a/vendor/github.com/tinylib/msgp/msgp/read.go +++ b/vendor/github.com/tinylib/msgp/msgp/read.go @@ -175,7 +175,7 @@ func (m *Reader) CopyNext(w io.Writer) (int64, error) { // Opportunistic optimization: if we can fit the whole thing in the m.R // buffer, then just get a pointer to that, and pass it to w.Write, // avoiding an allocation. - if int(sz) <= m.R.BufferSize() { + if int(sz) >= 0 && int(sz) <= m.R.BufferSize() { var nn int var buf []byte buf, err = m.R.Next(int(sz)) @@ -582,7 +582,7 @@ func (m *Reader) ReadFloat64() (f float64, err error) { var p []byte p, err = m.R.Peek(9) if err != nil { - // we'll allow a coversion from float32 to float64, + // we'll allow a conversion from float32 to float64, // since we don't lose any precision if err == io.EOF && len(p) > 0 && p[0] == mfloat32 { ef, err := m.ReadFloat32() diff --git a/vendor/modules.txt b/vendor/modules.txt index aa6f0ffa0..1713639ad 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -181,7 +181,7 @@ github.com/tebeka/strftime # github.com/tevino/abool v1.2.0 ## explicit; go 1.14 github.com/tevino/abool -# github.com/tinylib/msgp v1.4.0 +# github.com/tinylib/msgp v1.5.0 ## explicit; go 1.22 github.com/tinylib/msgp/msgp # github.com/valyala/fastjson v1.6.4