From 7d776c57e59b9d1474eef1192e9256c0f7c4ef5e Mon Sep 17 00:00:00 2001 From: Klaus Post Date: Mon, 11 May 2026 11:10:33 +0200 Subject: [PATCH 1/3] Add JSON Marshal/Unmarshal to setof Each type not also support JSON serializers so sets are stored as JSON. Sorted/Unsorted also applies here. Mildly breaking. Open for suggestions. --- msgp/setof/_gen/main.go | 413 +++- msgp/setof/generated.go | 1281 +++++++++- msgp/setof/generated_test.go | 4333 +++++++++++++++++++++++++++++++--- msgp/setof/json.go | 152 ++ msgp/setof/setof.go | 6 +- 5 files changed, 5782 insertions(+), 403 deletions(-) create mode 100644 msgp/setof/json.go diff --git a/msgp/setof/_gen/main.go b/msgp/setof/_gen/main.go index 369fcc50..655e0ada 100644 --- a/msgp/setof/_gen/main.go +++ b/msgp/setof/_gen/main.go @@ -75,6 +75,33 @@ func (s Foo) Msgsize() int { return size } +// UnmarshalJSON implements json.Unmarshaler. +func (s *Foo) UnmarshalJSON(data []byte) error { + if isJSONNull(data) { + *s = nil + return nil + } + dst := *s + if dst != nil { + clear(dst) + } else { + dst = make(Foo) + } + err := jsonArrayIter(data, func(raw []byte) error { + k, parseErr := jsonParseQuoted(raw) + if parseErr != nil { + return parseErr + } + dst[k] = struct{}{} + return nil + }) + if err != nil { + return err + } + *s = dst + return nil +} + // FooFromSlice creates a Foo from a slice. func FooFromSlice(s []string) Foo { if s == nil { @@ -138,6 +165,25 @@ func (s Foo) AsSlice() []string { } return dst } + +// MarshalJSON implements json.Marshaler. +func (s Foo) MarshalJSON() ([]byte, error) { + if s == nil { + return []byte("null"), nil + } + dst := make([]byte, 0, 2+len(s)*10) + dst = append(dst, '[') + first := true + for k := range s { + if !first { + dst = append(dst, ',') + } + first = false + dst = jsonAppendQuote(dst, k) + } + dst = append(dst, ']') + return dst, nil +} ` const sorted = ` @@ -217,6 +263,24 @@ func (s Foo) AsSlice() []string { }) return keys } + +// MarshalJSON implements json.Marshaler. +func (s Foo) MarshalJSON() ([]byte, error) { + if s == nil { + return []byte("null"), nil + } + keys := s.AsSlice() + dst := make([]byte, 0, 2+len(keys)*10) + dst = append(dst, '[') + for i, k := range keys { + if i > 0 { + dst = append(dst, ',') + } + dst = jsonAppendQuote(dst, k) + } + dst = append(dst, ']') + return dst, nil +} ` const testTemplate = ` @@ -404,6 +468,88 @@ func Test{{.TypeName}}_EmptySet(t *testing.T) { t.Fatalf("expected empty set, got length %d", len(unmarshaled)) } } + +func Test{{.TypeName}}_JSONRoundTrip(t *testing.T) { + set := make({{.TypeName}}) + {{.PopulateSet}} + + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON failed: %v", err) + } + + // Verify JSON is an array + if len(data) == 0 || data[0] != '[' || data[len(data)-1] != ']' { + t.Fatalf("expected JSON array, got: %s", data) + } + + // Verify it unmarshals as a generic JSON array + var arr []json.RawMessage + if err := json.Unmarshal(data, &arr); err != nil { + t.Fatalf("JSON is not a valid array: %v", err) + } + if len(arr) != len(set) { + t.Fatalf("JSON array length mismatch: expected %d, got %d", len(set), len(arr)) + } + + var decoded {{.TypeName}} + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON failed: %v", err) + } + + if len(set) != len(decoded) { + t.Fatalf("length mismatch: expected %d, got %d", len(set), len(decoded)) + } + + for k := range set { + if _, ok := decoded[k]; !ok { + t.Fatalf("missing key: %v", k) + } + } +} + +func Test{{.TypeName}}_JSONNil(t *testing.T) { + var nilSet {{.TypeName}} + + data, err := json.Marshal(nilSet) + if err != nil { + t.Fatalf("MarshalJSON nil failed: %v", err) + } + if string(data) != "null" { + t.Fatalf("expected null, got %s", data) + } + + var decoded {{.TypeName}} + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON nil failed: %v", err) + } + if decoded != nil { + t.Fatal("expected nil, got non-nil") + } +} + +func Test{{.TypeName}}_JSONEmpty(t *testing.T) { + set := make({{.TypeName}}) + + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON empty failed: %v", err) + } + if string(data) != "[]" { + t.Fatalf("expected [], got %s", data) + } + + var decoded {{.TypeName}} + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON empty failed: %v", err) + } + if len(decoded) != 0 { + t.Fatalf("expected empty set, got length %d", len(decoded)) + } +} ` const benchTemplate = ` @@ -530,6 +676,49 @@ func Benchmark{{.TypeName}}_FromSlice(b *testing.B) { }) } } + +func Benchmark{{.TypeName}}_MarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make({{.TypeName}}) + {{.GeneratePopulateCode}} + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := json.Marshal(set) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + +func Benchmark{{.TypeName}}_UnmarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make({{.TypeName}}) + {{.GeneratePopulateCode}} + + data, _ := json.Marshal(set) + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + var decoded {{.TypeName}} + err := json.Unmarshal(data, &decoded) + if err != nil { + b.Fatal(err) + } + } + }) + } +} ` type replacer struct { @@ -540,6 +729,9 @@ type replacer struct { AppendValue string // 'AppendString' KeyLen string // 'size += msgp.StringPrefixSize' Sorter string // 'sort.Slice(keys, func(i, j int) bool { return keys[i] < keys[j] })' + + JSONAppendKey string // 'jsonAppendQuote(dst, k)' + JSONParseKey string // 'jsonParseQuoted(raw)' } type testGen struct { @@ -750,127 +942,156 @@ func generateTests(out *os.File, r replacer) { var replacers = []replacer{ { - GoType: "string", - PackageName: "Foo", - DecodeValue: "ReadString", - EncodeValue: "WriteString", - AppendValue: "AppendString", - KeyLen: "size += len(s) * msgp.StringPrefixSize", - Sorter: "slices.SortFunc(keys, func(a, b string) int {\n\t\tif a < b {\n\t\t\treturn -1\n\t\t}\n\t\treturn 1\n\t})", + GoType: "string", + PackageName: "Foo", + DecodeValue: "ReadString", + EncodeValue: "WriteString", + AppendValue: "AppendString", + KeyLen: "size += len(s) * msgp.StringPrefixSize", + Sorter: "slices.SortFunc(keys, func(a, b string) int {\n\t\tif a < b {\n\t\t\treturn -1\n\t\t}\n\t\treturn 1\n\t})", + JSONAppendKey: "jsonAppendQuote(dst, k)", + JSONParseKey: "jsonParseQuoted(raw)", }, { - GoType: "string", - PackageName: "String", - DecodeValue: "ReadString", - EncodeValue: "WriteString", - AppendValue: "AppendString", - KeyLen: "for key := range s {\n\t\t\tsize += msgp.StringPrefixSize + len(key)\n\t\t}", - // Using slices.SortFunc is slower than sort.Strings - Sorter: "sort.Strings(keys)", + GoType: "string", + PackageName: "String", + DecodeValue: "ReadString", + EncodeValue: "WriteString", + AppendValue: "AppendString", + KeyLen: "for key := range s {\n\t\t\tsize += msgp.StringPrefixSize + len(key)\n\t\t}", + Sorter: "sort.Strings(keys)", + JSONAppendKey: "jsonAppendQuote(dst, k)", + JSONParseKey: "jsonParseQuoted(raw)", }, { - GoType: "int", - PackageName: "Int", - DecodeValue: "ReadInt", - EncodeValue: "WriteInt", - AppendValue: "AppendInt", - KeyLen: "size += len(s) * msgp.IntSize", + GoType: "int", + PackageName: "Int", + DecodeValue: "ReadInt", + EncodeValue: "WriteInt", + AppendValue: "AppendInt", + KeyLen: "size += len(s) * msgp.IntSize", + JSONAppendKey: "strconv.AppendInt(dst, int64(k), 10)", + JSONParseKey: "jsonParseSigned[int](raw, 0)", }, { - GoType: "uint", - PackageName: "Uint", - DecodeValue: "ReadUint", - EncodeValue: "WriteUint", - AppendValue: "AppendUint", - KeyLen: "size += len(s) * msgp.UintSize", + GoType: "uint", + PackageName: "Uint", + DecodeValue: "ReadUint", + EncodeValue: "WriteUint", + AppendValue: "AppendUint", + KeyLen: "size += len(s) * msgp.UintSize", + JSONAppendKey: "strconv.AppendUint(dst, uint64(k), 10)", + JSONParseKey: "jsonParseUnsigned[uint](raw, 0)", }, { - GoType: "byte", - PackageName: "Byte", - DecodeValue: "ReadByte", - EncodeValue: "WriteByte", - AppendValue: "AppendByte", - KeyLen: "size += len(s) * msgp.ByteSize", + GoType: "byte", + PackageName: "Byte", + DecodeValue: "ReadByte", + EncodeValue: "WriteByte", + AppendValue: "AppendByte", + KeyLen: "size += len(s) * msgp.ByteSize", + JSONAppendKey: "strconv.AppendUint(dst, uint64(k), 10)", + JSONParseKey: "jsonParseUnsigned[byte](raw, 8)", }, { - GoType: "int8", - PackageName: "Int8", - DecodeValue: "ReadInt8", - EncodeValue: "WriteInt8", - AppendValue: "AppendInt8", - KeyLen: "size += len(s) * msgp.Int8Size", + GoType: "int8", + PackageName: "Int8", + DecodeValue: "ReadInt8", + EncodeValue: "WriteInt8", + AppendValue: "AppendInt8", + KeyLen: "size += len(s) * msgp.Int8Size", + JSONAppendKey: "strconv.AppendInt(dst, int64(k), 10)", + JSONParseKey: "jsonParseSigned[int8](raw, 8)", }, { - GoType: "uint8", - PackageName: "Uint8", - DecodeValue: "ReadUint8", - EncodeValue: "WriteUint8", - AppendValue: "AppendUint8", - KeyLen: "size += len(s) * msgp.Uint8Size", + GoType: "uint8", + PackageName: "Uint8", + DecodeValue: "ReadUint8", + EncodeValue: "WriteUint8", + AppendValue: "AppendUint8", + KeyLen: "size += len(s) * msgp.Uint8Size", + JSONAppendKey: "strconv.AppendUint(dst, uint64(k), 10)", + JSONParseKey: "jsonParseUnsigned[uint8](raw, 8)", }, { - GoType: "int16", - PackageName: "Int16", - DecodeValue: "ReadInt16", - EncodeValue: "WriteInt16", - AppendValue: "AppendInt16", - KeyLen: "size += len(s) * msgp.Int16Size", + GoType: "int16", + PackageName: "Int16", + DecodeValue: "ReadInt16", + EncodeValue: "WriteInt16", + AppendValue: "AppendInt16", + KeyLen: "size += len(s) * msgp.Int16Size", + JSONAppendKey: "strconv.AppendInt(dst, int64(k), 10)", + JSONParseKey: "jsonParseSigned[int16](raw, 16)", }, { - GoType: "uint16", - PackageName: "Uint16", - DecodeValue: "ReadUint16", - EncodeValue: "WriteUint16", - AppendValue: "AppendUint16", - KeyLen: "size += len(s) * msgp.Uint16Size", + GoType: "uint16", + PackageName: "Uint16", + DecodeValue: "ReadUint16", + EncodeValue: "WriteUint16", + AppendValue: "AppendUint16", + KeyLen: "size += len(s) * msgp.Uint16Size", + JSONAppendKey: "strconv.AppendUint(dst, uint64(k), 10)", + JSONParseKey: "jsonParseUnsigned[uint16](raw, 16)", }, { - GoType: "int32", - PackageName: "Int32", - DecodeValue: "ReadInt32", - EncodeValue: "WriteInt32", - AppendValue: "AppendInt32", - KeyLen: "size += len(s) * msgp.Int32Size", + GoType: "int32", + PackageName: "Int32", + DecodeValue: "ReadInt32", + EncodeValue: "WriteInt32", + AppendValue: "AppendInt32", + KeyLen: "size += len(s) * msgp.Int32Size", + JSONAppendKey: "strconv.AppendInt(dst, int64(k), 10)", + JSONParseKey: "jsonParseSigned[int32](raw, 32)", }, { - GoType: "uint32", - PackageName: "Uint32", - DecodeValue: "ReadUint32", - EncodeValue: "WriteUint32", - AppendValue: "AppendUint32", - KeyLen: "size += len(s) * msgp.Uint32Size", + GoType: "uint32", + PackageName: "Uint32", + DecodeValue: "ReadUint32", + EncodeValue: "WriteUint32", + AppendValue: "AppendUint32", + KeyLen: "size += len(s) * msgp.Uint32Size", + JSONAppendKey: "strconv.AppendUint(dst, uint64(k), 10)", + JSONParseKey: "jsonParseUnsigned[uint32](raw, 32)", }, { - GoType: "int64", - PackageName: "Int64", - DecodeValue: "ReadInt64", - EncodeValue: "WriteInt64", - AppendValue: "AppendInt64", - KeyLen: "size += len(s) * msgp.Int64Size", + GoType: "int64", + PackageName: "Int64", + DecodeValue: "ReadInt64", + EncodeValue: "WriteInt64", + AppendValue: "AppendInt64", + KeyLen: "size += len(s) * msgp.Int64Size", + JSONAppendKey: "strconv.AppendInt(dst, int64(k), 10)", + JSONParseKey: "jsonParseSigned[int64](raw, 64)", }, { - GoType: "uint64", - PackageName: "Uint64", - DecodeValue: "ReadUint64", - EncodeValue: "WriteUint64", - AppendValue: "AppendUint64", - KeyLen: "size += len(s) * msgp.Uint64Size", + GoType: "uint64", + PackageName: "Uint64", + DecodeValue: "ReadUint64", + EncodeValue: "WriteUint64", + AppendValue: "AppendUint64", + KeyLen: "size += len(s) * msgp.Uint64Size", + JSONAppendKey: "strconv.AppendUint(dst, uint64(k), 10)", + JSONParseKey: "jsonParseUnsigned[uint64](raw, 64)", }, { - GoType: "float64", - PackageName: "Float64", - DecodeValue: "ReadFloat64", - EncodeValue: "WriteFloat", - AppendValue: "AppendFloat", - KeyLen: "size += len(s) * msgp.Float64Size", + GoType: "float64", + PackageName: "Float64", + DecodeValue: "ReadFloat64", + EncodeValue: "WriteFloat", + AppendValue: "AppendFloat", + KeyLen: "size += len(s) * msgp.Float64Size", + JSONAppendKey: "strconv.AppendFloat(dst, float64(k), 'f', -1, 64)", + JSONParseKey: "jsonParseFloat[float64](raw, 64)", }, { - GoType: "float32", - PackageName: "Float32", - DecodeValue: "ReadFloat32", - EncodeValue: "WriteFloat32", - AppendValue: "AppendFloat32", - KeyLen: "size += len(s) * msgp.Float32Size", + GoType: "float32", + PackageName: "Float32", + DecodeValue: "ReadFloat32", + EncodeValue: "WriteFloat32", + AppendValue: "AppendFloat32", + KeyLen: "size += len(s) * msgp.Float32Size", + JSONAppendKey: "strconv.AppendFloat(dst, float64(k), 'f', -1, 32)", + JSONParseKey: "jsonParseFloat[float32](raw, 32)", }, } @@ -900,6 +1121,7 @@ package setof import ( "slices" "sort" + "strconv" "github.com/tinylib/msgp/msgp" )`) @@ -907,6 +1129,8 @@ import ( base := replacers[0] for _, r := range replacers[1:] { replaced := unsorted + template + replaced = strings.ReplaceAll(replaced, base.JSONAppendKey, r.JSONAppendKey) + replaced = strings.ReplaceAll(replaced, base.JSONParseKey, r.JSONParseKey) replaced = strings.ReplaceAll(replaced, base.GoType, r.GoType) replaced = strings.ReplaceAll(replaced, base.PackageName, r.PackageName) replaced = strings.ReplaceAll(replaced, base.EncodeValue, r.EncodeValue) @@ -917,6 +1141,8 @@ import ( fmt.Fprintln(out, replaced) replaced = sorted + template + replaced = strings.ReplaceAll(replaced, base.JSONAppendKey, r.JSONAppendKey) + replaced = strings.ReplaceAll(replaced, base.JSONParseKey, r.JSONParseKey) if r.Sorter != "" { replaced = strings.ReplaceAll(replaced, base.Sorter, r.Sorter) } @@ -943,6 +1169,7 @@ package setof import ( "bytes" + "encoding/json" "fmt" "testing" diff --git a/msgp/setof/generated.go b/msgp/setof/generated.go index 9cf64d0a..a4be1aba 100644 --- a/msgp/setof/generated.go +++ b/msgp/setof/generated.go @@ -5,6 +5,7 @@ package setof import ( "slices" "sort" + "strconv" "github.com/tinylib/msgp/msgp" ) @@ -59,6 +60,25 @@ func (s String) AsSlice() []string { return dst } +// MarshalJSON implements json.Marshaler. +func (s String) MarshalJSON() ([]byte, error) { + if s == nil { + return []byte("null"), nil + } + dst := make([]byte, 0, 2+len(s)*10) + dst = append(dst, '[') + first := true + for k := range s { + if !first { + dst = append(dst, ',') + } + first = false + dst = jsonAppendQuote(dst, k) + } + dst = append(dst, ']') + return dst, nil +} + // DecodeMsg decodes the message from the reader. func (s *String) DecodeMsg(reader *msgp.Reader) error { if reader.IsNil() { @@ -128,6 +148,33 @@ func (s String) Msgsize() int { return size } +// UnmarshalJSON implements json.Unmarshaler. +func (s *String) UnmarshalJSON(data []byte) error { + if isJSONNull(data) { + *s = nil + return nil + } + dst := *s + if dst != nil { + clear(dst) + } else { + dst = make(String) + } + err := jsonArrayIter(data, func(raw []byte) error { + k, parseErr := jsonParseQuoted(raw) + if parseErr != nil { + return parseErr + } + dst[k] = struct{}{} + return nil + }) + if err != nil { + return err + } + *s = dst + return nil +} + // StringFromSlice creates a String from a slice. func StringFromSlice(s []string) String { if s == nil { @@ -202,6 +249,24 @@ func (s StringSorted) AsSlice() []string { return keys } +// MarshalJSON implements json.Marshaler. +func (s StringSorted) MarshalJSON() ([]byte, error) { + if s == nil { + return []byte("null"), nil + } + keys := s.AsSlice() + dst := make([]byte, 0, 2+len(keys)*10) + dst = append(dst, '[') + for i, k := range keys { + if i > 0 { + dst = append(dst, ',') + } + dst = jsonAppendQuote(dst, k) + } + dst = append(dst, ']') + return dst, nil +} + // DecodeMsg decodes the message from the reader. func (s *StringSorted) DecodeMsg(reader *msgp.Reader) error { if reader.IsNil() { @@ -271,6 +336,33 @@ func (s StringSorted) Msgsize() int { return size } +// UnmarshalJSON implements json.Unmarshaler. +func (s *StringSorted) UnmarshalJSON(data []byte) error { + if isJSONNull(data) { + *s = nil + return nil + } + dst := *s + if dst != nil { + clear(dst) + } else { + dst = make(StringSorted) + } + err := jsonArrayIter(data, func(raw []byte) error { + k, parseErr := jsonParseQuoted(raw) + if parseErr != nil { + return parseErr + } + dst[k] = struct{}{} + return nil + }) + if err != nil { + return err + } + *s = dst + return nil +} + // StringSortedFromSlice creates a StringSorted from a slice. func StringSortedFromSlice(s []string) StringSorted { if s == nil { @@ -333,6 +425,25 @@ func (s Int) AsSlice() []int { return dst } +// MarshalJSON implements json.Marshaler. +func (s Int) MarshalJSON() ([]byte, error) { + if s == nil { + return []byte("null"), nil + } + dst := make([]byte, 0, 2+len(s)*10) + dst = append(dst, '[') + first := true + for k := range s { + if !first { + dst = append(dst, ',') + } + first = false + dst = strconv.AppendInt(dst, int64(k), 10) + } + dst = append(dst, ']') + return dst, nil +} + // DecodeMsg decodes the message from the reader. func (s *Int) DecodeMsg(reader *msgp.Reader) error { if reader.IsNil() { @@ -400,6 +511,33 @@ func (s Int) Msgsize() int { return size } +// UnmarshalJSON implements json.Unmarshaler. +func (s *Int) UnmarshalJSON(data []byte) error { + if isJSONNull(data) { + *s = nil + return nil + } + dst := *s + if dst != nil { + clear(dst) + } else { + dst = make(Int) + } + err := jsonArrayIter(data, func(raw []byte) error { + k, parseErr := jsonParseSigned[int](raw, 0) + if parseErr != nil { + return parseErr + } + dst[k] = struct{}{} + return nil + }) + if err != nil { + return err + } + *s = dst + return nil +} + // IntFromSlice creates a Int from a slice. func IntFromSlice(s []int) Int { if s == nil { @@ -489,6 +627,24 @@ func (s IntSorted) AsSlice() []int { return keys } +// MarshalJSON implements json.Marshaler. +func (s IntSorted) MarshalJSON() ([]byte, error) { + if s == nil { + return []byte("null"), nil + } + keys := s.AsSlice() + dst := make([]byte, 0, 2+len(keys)*10) + dst = append(dst, '[') + for i, k := range keys { + if i > 0 { + dst = append(dst, ',') + } + dst = strconv.AppendInt(dst, int64(k), 10) + } + dst = append(dst, ']') + return dst, nil +} + // DecodeMsg decodes the message from the reader. func (s *IntSorted) DecodeMsg(reader *msgp.Reader) error { if reader.IsNil() { @@ -556,6 +712,33 @@ func (s IntSorted) Msgsize() int { return size } +// UnmarshalJSON implements json.Unmarshaler. +func (s *IntSorted) UnmarshalJSON(data []byte) error { + if isJSONNull(data) { + *s = nil + return nil + } + dst := *s + if dst != nil { + clear(dst) + } else { + dst = make(IntSorted) + } + err := jsonArrayIter(data, func(raw []byte) error { + k, parseErr := jsonParseSigned[int](raw, 0) + if parseErr != nil { + return parseErr + } + dst[k] = struct{}{} + return nil + }) + if err != nil { + return err + } + *s = dst + return nil +} + // IntSortedFromSlice creates a IntSorted from a slice. func IntSortedFromSlice(s []int) IntSorted { if s == nil { @@ -618,6 +801,25 @@ func (s Uint) AsSlice() []uint { return dst } +// MarshalJSON implements json.Marshaler. +func (s Uint) MarshalJSON() ([]byte, error) { + if s == nil { + return []byte("null"), nil + } + dst := make([]byte, 0, 2+len(s)*10) + dst = append(dst, '[') + first := true + for k := range s { + if !first { + dst = append(dst, ',') + } + first = false + dst = strconv.AppendUint(dst, uint64(k), 10) + } + dst = append(dst, ']') + return dst, nil +} + // DecodeMsg decodes the message from the reader. func (s *Uint) DecodeMsg(reader *msgp.Reader) error { if reader.IsNil() { @@ -685,6 +887,33 @@ func (s Uint) Msgsize() int { return size } +// UnmarshalJSON implements json.Unmarshaler. +func (s *Uint) UnmarshalJSON(data []byte) error { + if isJSONNull(data) { + *s = nil + return nil + } + dst := *s + if dst != nil { + clear(dst) + } else { + dst = make(Uint) + } + err := jsonArrayIter(data, func(raw []byte) error { + k, parseErr := jsonParseUnsigned[uint](raw, 0) + if parseErr != nil { + return parseErr + } + dst[k] = struct{}{} + return nil + }) + if err != nil { + return err + } + *s = dst + return nil +} + // UintFromSlice creates a Uint from a slice. func UintFromSlice(s []uint) Uint { if s == nil { @@ -774,6 +1003,24 @@ func (s UintSorted) AsSlice() []uint { return keys } +// MarshalJSON implements json.Marshaler. +func (s UintSorted) MarshalJSON() ([]byte, error) { + if s == nil { + return []byte("null"), nil + } + keys := s.AsSlice() + dst := make([]byte, 0, 2+len(keys)*10) + dst = append(dst, '[') + for i, k := range keys { + if i > 0 { + dst = append(dst, ',') + } + dst = strconv.AppendUint(dst, uint64(k), 10) + } + dst = append(dst, ']') + return dst, nil +} + // DecodeMsg decodes the message from the reader. func (s *UintSorted) DecodeMsg(reader *msgp.Reader) error { if reader.IsNil() { @@ -841,6 +1088,33 @@ func (s UintSorted) Msgsize() int { return size } +// UnmarshalJSON implements json.Unmarshaler. +func (s *UintSorted) UnmarshalJSON(data []byte) error { + if isJSONNull(data) { + *s = nil + return nil + } + dst := *s + if dst != nil { + clear(dst) + } else { + dst = make(UintSorted) + } + err := jsonArrayIter(data, func(raw []byte) error { + k, parseErr := jsonParseUnsigned[uint](raw, 0) + if parseErr != nil { + return parseErr + } + dst[k] = struct{}{} + return nil + }) + if err != nil { + return err + } + *s = dst + return nil +} + // UintSortedFromSlice creates a UintSorted from a slice. func UintSortedFromSlice(s []uint) UintSorted { if s == nil { @@ -903,6 +1177,25 @@ func (s Byte) AsSlice() []byte { return dst } +// MarshalJSON implements json.Marshaler. +func (s Byte) MarshalJSON() ([]byte, error) { + if s == nil { + return []byte("null"), nil + } + dst := make([]byte, 0, 2+len(s)*10) + dst = append(dst, '[') + first := true + for k := range s { + if !first { + dst = append(dst, ',') + } + first = false + dst = strconv.AppendUint(dst, uint64(k), 10) + } + dst = append(dst, ']') + return dst, nil +} + // DecodeMsg decodes the message from the reader. func (s *Byte) DecodeMsg(reader *msgp.Reader) error { if reader.IsNil() { @@ -970,6 +1263,33 @@ func (s Byte) Msgsize() int { return size } +// UnmarshalJSON implements json.Unmarshaler. +func (s *Byte) UnmarshalJSON(data []byte) error { + if isJSONNull(data) { + *s = nil + return nil + } + dst := *s + if dst != nil { + clear(dst) + } else { + dst = make(Byte) + } + err := jsonArrayIter(data, func(raw []byte) error { + k, parseErr := jsonParseUnsigned[byte](raw, 8) + if parseErr != nil { + return parseErr + } + dst[k] = struct{}{} + return nil + }) + if err != nil { + return err + } + *s = dst + return nil +} + // ByteFromSlice creates a Byte from a slice. func ByteFromSlice(s []byte) Byte { if s == nil { @@ -1059,6 +1379,24 @@ func (s ByteSorted) AsSlice() []byte { return keys } +// MarshalJSON implements json.Marshaler. +func (s ByteSorted) MarshalJSON() ([]byte, error) { + if s == nil { + return []byte("null"), nil + } + keys := s.AsSlice() + dst := make([]byte, 0, 2+len(keys)*10) + dst = append(dst, '[') + for i, k := range keys { + if i > 0 { + dst = append(dst, ',') + } + dst = strconv.AppendUint(dst, uint64(k), 10) + } + dst = append(dst, ']') + return dst, nil +} + // DecodeMsg decodes the message from the reader. func (s *ByteSorted) DecodeMsg(reader *msgp.Reader) error { if reader.IsNil() { @@ -1126,6 +1464,33 @@ func (s ByteSorted) Msgsize() int { return size } +// UnmarshalJSON implements json.Unmarshaler. +func (s *ByteSorted) UnmarshalJSON(data []byte) error { + if isJSONNull(data) { + *s = nil + return nil + } + dst := *s + if dst != nil { + clear(dst) + } else { + dst = make(ByteSorted) + } + err := jsonArrayIter(data, func(raw []byte) error { + k, parseErr := jsonParseUnsigned[byte](raw, 8) + if parseErr != nil { + return parseErr + } + dst[k] = struct{}{} + return nil + }) + if err != nil { + return err + } + *s = dst + return nil +} + // ByteSortedFromSlice creates a ByteSorted from a slice. func ByteSortedFromSlice(s []byte) ByteSorted { if s == nil { @@ -1188,6 +1553,25 @@ func (s Int8) AsSlice() []int8 { return dst } +// MarshalJSON implements json.Marshaler. +func (s Int8) MarshalJSON() ([]byte, error) { + if s == nil { + return []byte("null"), nil + } + dst := make([]byte, 0, 2+len(s)*10) + dst = append(dst, '[') + first := true + for k := range s { + if !first { + dst = append(dst, ',') + } + first = false + dst = strconv.AppendInt(dst, int64(k), 10) + } + dst = append(dst, ']') + return dst, nil +} + // DecodeMsg decodes the message from the reader. func (s *Int8) DecodeMsg(reader *msgp.Reader) error { if reader.IsNil() { @@ -1255,6 +1639,33 @@ func (s Int8) Msgsize() int { return size } +// UnmarshalJSON implements json.Unmarshaler. +func (s *Int8) UnmarshalJSON(data []byte) error { + if isJSONNull(data) { + *s = nil + return nil + } + dst := *s + if dst != nil { + clear(dst) + } else { + dst = make(Int8) + } + err := jsonArrayIter(data, func(raw []byte) error { + k, parseErr := jsonParseSigned[int8](raw, 8) + if parseErr != nil { + return parseErr + } + dst[k] = struct{}{} + return nil + }) + if err != nil { + return err + } + *s = dst + return nil +} + // Int8FromSlice creates a Int8 from a slice. func Int8FromSlice(s []int8) Int8 { if s == nil { @@ -1344,6 +1755,24 @@ func (s Int8Sorted) AsSlice() []int8 { return keys } +// MarshalJSON implements json.Marshaler. +func (s Int8Sorted) MarshalJSON() ([]byte, error) { + if s == nil { + return []byte("null"), nil + } + keys := s.AsSlice() + dst := make([]byte, 0, 2+len(keys)*10) + dst = append(dst, '[') + for i, k := range keys { + if i > 0 { + dst = append(dst, ',') + } + dst = strconv.AppendInt(dst, int64(k), 10) + } + dst = append(dst, ']') + return dst, nil +} + // DecodeMsg decodes the message from the reader. func (s *Int8Sorted) DecodeMsg(reader *msgp.Reader) error { if reader.IsNil() { @@ -1411,6 +1840,33 @@ func (s Int8Sorted) Msgsize() int { return size } +// UnmarshalJSON implements json.Unmarshaler. +func (s *Int8Sorted) UnmarshalJSON(data []byte) error { + if isJSONNull(data) { + *s = nil + return nil + } + dst := *s + if dst != nil { + clear(dst) + } else { + dst = make(Int8Sorted) + } + err := jsonArrayIter(data, func(raw []byte) error { + k, parseErr := jsonParseSigned[int8](raw, 8) + if parseErr != nil { + return parseErr + } + dst[k] = struct{}{} + return nil + }) + if err != nil { + return err + } + *s = dst + return nil +} + // Int8SortedFromSlice creates a Int8Sorted from a slice. func Int8SortedFromSlice(s []int8) Int8Sorted { if s == nil { @@ -1473,6 +1929,25 @@ func (s Uint8) AsSlice() []uint8 { return dst } +// MarshalJSON implements json.Marshaler. +func (s Uint8) MarshalJSON() ([]byte, error) { + if s == nil { + return []byte("null"), nil + } + dst := make([]byte, 0, 2+len(s)*10) + dst = append(dst, '[') + first := true + for k := range s { + if !first { + dst = append(dst, ',') + } + first = false + dst = strconv.AppendUint(dst, uint64(k), 10) + } + dst = append(dst, ']') + return dst, nil +} + // DecodeMsg decodes the message from the reader. func (s *Uint8) DecodeMsg(reader *msgp.Reader) error { if reader.IsNil() { @@ -1540,6 +2015,33 @@ func (s Uint8) Msgsize() int { return size } +// UnmarshalJSON implements json.Unmarshaler. +func (s *Uint8) UnmarshalJSON(data []byte) error { + if isJSONNull(data) { + *s = nil + return nil + } + dst := *s + if dst != nil { + clear(dst) + } else { + dst = make(Uint8) + } + err := jsonArrayIter(data, func(raw []byte) error { + k, parseErr := jsonParseUnsigned[uint8](raw, 8) + if parseErr != nil { + return parseErr + } + dst[k] = struct{}{} + return nil + }) + if err != nil { + return err + } + *s = dst + return nil +} + // Uint8FromSlice creates a Uint8 from a slice. func Uint8FromSlice(s []uint8) Uint8 { if s == nil { @@ -1629,6 +2131,24 @@ func (s Uint8Sorted) AsSlice() []uint8 { return keys } +// MarshalJSON implements json.Marshaler. +func (s Uint8Sorted) MarshalJSON() ([]byte, error) { + if s == nil { + return []byte("null"), nil + } + keys := s.AsSlice() + dst := make([]byte, 0, 2+len(keys)*10) + dst = append(dst, '[') + for i, k := range keys { + if i > 0 { + dst = append(dst, ',') + } + dst = strconv.AppendUint(dst, uint64(k), 10) + } + dst = append(dst, ']') + return dst, nil +} + // DecodeMsg decodes the message from the reader. func (s *Uint8Sorted) DecodeMsg(reader *msgp.Reader) error { if reader.IsNil() { @@ -1696,6 +2216,33 @@ func (s Uint8Sorted) Msgsize() int { return size } +// UnmarshalJSON implements json.Unmarshaler. +func (s *Uint8Sorted) UnmarshalJSON(data []byte) error { + if isJSONNull(data) { + *s = nil + return nil + } + dst := *s + if dst != nil { + clear(dst) + } else { + dst = make(Uint8Sorted) + } + err := jsonArrayIter(data, func(raw []byte) error { + k, parseErr := jsonParseUnsigned[uint8](raw, 8) + if parseErr != nil { + return parseErr + } + dst[k] = struct{}{} + return nil + }) + if err != nil { + return err + } + *s = dst + return nil +} + // Uint8SortedFromSlice creates a Uint8Sorted from a slice. func Uint8SortedFromSlice(s []uint8) Uint8Sorted { if s == nil { @@ -1758,6 +2305,25 @@ func (s Int16) AsSlice() []int16 { return dst } +// MarshalJSON implements json.Marshaler. +func (s Int16) MarshalJSON() ([]byte, error) { + if s == nil { + return []byte("null"), nil + } + dst := make([]byte, 0, 2+len(s)*10) + dst = append(dst, '[') + first := true + for k := range s { + if !first { + dst = append(dst, ',') + } + first = false + dst = strconv.AppendInt(dst, int64(k), 10) + } + dst = append(dst, ']') + return dst, nil +} + // DecodeMsg decodes the message from the reader. func (s *Int16) DecodeMsg(reader *msgp.Reader) error { if reader.IsNil() { @@ -1825,6 +2391,33 @@ func (s Int16) Msgsize() int { return size } +// UnmarshalJSON implements json.Unmarshaler. +func (s *Int16) UnmarshalJSON(data []byte) error { + if isJSONNull(data) { + *s = nil + return nil + } + dst := *s + if dst != nil { + clear(dst) + } else { + dst = make(Int16) + } + err := jsonArrayIter(data, func(raw []byte) error { + k, parseErr := jsonParseSigned[int16](raw, 16) + if parseErr != nil { + return parseErr + } + dst[k] = struct{}{} + return nil + }) + if err != nil { + return err + } + *s = dst + return nil +} + // Int16FromSlice creates a Int16 from a slice. func Int16FromSlice(s []int16) Int16 { if s == nil { @@ -1914,6 +2507,24 @@ func (s Int16Sorted) AsSlice() []int16 { return keys } +// MarshalJSON implements json.Marshaler. +func (s Int16Sorted) MarshalJSON() ([]byte, error) { + if s == nil { + return []byte("null"), nil + } + keys := s.AsSlice() + dst := make([]byte, 0, 2+len(keys)*10) + dst = append(dst, '[') + for i, k := range keys { + if i > 0 { + dst = append(dst, ',') + } + dst = strconv.AppendInt(dst, int64(k), 10) + } + dst = append(dst, ']') + return dst, nil +} + // DecodeMsg decodes the message from the reader. func (s *Int16Sorted) DecodeMsg(reader *msgp.Reader) error { if reader.IsNil() { @@ -1981,6 +2592,33 @@ func (s Int16Sorted) Msgsize() int { return size } +// UnmarshalJSON implements json.Unmarshaler. +func (s *Int16Sorted) UnmarshalJSON(data []byte) error { + if isJSONNull(data) { + *s = nil + return nil + } + dst := *s + if dst != nil { + clear(dst) + } else { + dst = make(Int16Sorted) + } + err := jsonArrayIter(data, func(raw []byte) error { + k, parseErr := jsonParseSigned[int16](raw, 16) + if parseErr != nil { + return parseErr + } + dst[k] = struct{}{} + return nil + }) + if err != nil { + return err + } + *s = dst + return nil +} + // Int16SortedFromSlice creates a Int16Sorted from a slice. func Int16SortedFromSlice(s []int16) Int16Sorted { if s == nil { @@ -2043,6 +2681,25 @@ func (s Uint16) AsSlice() []uint16 { return dst } +// MarshalJSON implements json.Marshaler. +func (s Uint16) MarshalJSON() ([]byte, error) { + if s == nil { + return []byte("null"), nil + } + dst := make([]byte, 0, 2+len(s)*10) + dst = append(dst, '[') + first := true + for k := range s { + if !first { + dst = append(dst, ',') + } + first = false + dst = strconv.AppendUint(dst, uint64(k), 10) + } + dst = append(dst, ']') + return dst, nil +} + // DecodeMsg decodes the message from the reader. func (s *Uint16) DecodeMsg(reader *msgp.Reader) error { if reader.IsNil() { @@ -2110,6 +2767,33 @@ func (s Uint16) Msgsize() int { return size } +// UnmarshalJSON implements json.Unmarshaler. +func (s *Uint16) UnmarshalJSON(data []byte) error { + if isJSONNull(data) { + *s = nil + return nil + } + dst := *s + if dst != nil { + clear(dst) + } else { + dst = make(Uint16) + } + err := jsonArrayIter(data, func(raw []byte) error { + k, parseErr := jsonParseUnsigned[uint16](raw, 16) + if parseErr != nil { + return parseErr + } + dst[k] = struct{}{} + return nil + }) + if err != nil { + return err + } + *s = dst + return nil +} + // Uint16FromSlice creates a Uint16 from a slice. func Uint16FromSlice(s []uint16) Uint16 { if s == nil { @@ -2199,6 +2883,24 @@ func (s Uint16Sorted) AsSlice() []uint16 { return keys } +// MarshalJSON implements json.Marshaler. +func (s Uint16Sorted) MarshalJSON() ([]byte, error) { + if s == nil { + return []byte("null"), nil + } + keys := s.AsSlice() + dst := make([]byte, 0, 2+len(keys)*10) + dst = append(dst, '[') + for i, k := range keys { + if i > 0 { + dst = append(dst, ',') + } + dst = strconv.AppendUint(dst, uint64(k), 10) + } + dst = append(dst, ']') + return dst, nil +} + // DecodeMsg decodes the message from the reader. func (s *Uint16Sorted) DecodeMsg(reader *msgp.Reader) error { if reader.IsNil() { @@ -2266,6 +2968,33 @@ func (s Uint16Sorted) Msgsize() int { return size } +// UnmarshalJSON implements json.Unmarshaler. +func (s *Uint16Sorted) UnmarshalJSON(data []byte) error { + if isJSONNull(data) { + *s = nil + return nil + } + dst := *s + if dst != nil { + clear(dst) + } else { + dst = make(Uint16Sorted) + } + err := jsonArrayIter(data, func(raw []byte) error { + k, parseErr := jsonParseUnsigned[uint16](raw, 16) + if parseErr != nil { + return parseErr + } + dst[k] = struct{}{} + return nil + }) + if err != nil { + return err + } + *s = dst + return nil +} + // Uint16SortedFromSlice creates a Uint16Sorted from a slice. func Uint16SortedFromSlice(s []uint16) Uint16Sorted { if s == nil { @@ -2328,6 +3057,25 @@ func (s Int32) AsSlice() []int32 { return dst } +// MarshalJSON implements json.Marshaler. +func (s Int32) MarshalJSON() ([]byte, error) { + if s == nil { + return []byte("null"), nil + } + dst := make([]byte, 0, 2+len(s)*10) + dst = append(dst, '[') + first := true + for k := range s { + if !first { + dst = append(dst, ',') + } + first = false + dst = strconv.AppendInt(dst, int64(k), 10) + } + dst = append(dst, ']') + return dst, nil +} + // DecodeMsg decodes the message from the reader. func (s *Int32) DecodeMsg(reader *msgp.Reader) error { if reader.IsNil() { @@ -2395,6 +3143,33 @@ func (s Int32) Msgsize() int { return size } +// UnmarshalJSON implements json.Unmarshaler. +func (s *Int32) UnmarshalJSON(data []byte) error { + if isJSONNull(data) { + *s = nil + return nil + } + dst := *s + if dst != nil { + clear(dst) + } else { + dst = make(Int32) + } + err := jsonArrayIter(data, func(raw []byte) error { + k, parseErr := jsonParseSigned[int32](raw, 32) + if parseErr != nil { + return parseErr + } + dst[k] = struct{}{} + return nil + }) + if err != nil { + return err + } + *s = dst + return nil +} + // Int32FromSlice creates a Int32 from a slice. func Int32FromSlice(s []int32) Int32 { if s == nil { @@ -2479,9 +3254,27 @@ func (s Int32Sorted) AsSlice() []int32 { if a < b { return -1 } - return 1 - }) - return keys + return 1 + }) + return keys +} + +// MarshalJSON implements json.Marshaler. +func (s Int32Sorted) MarshalJSON() ([]byte, error) { + if s == nil { + return []byte("null"), nil + } + keys := s.AsSlice() + dst := make([]byte, 0, 2+len(keys)*10) + dst = append(dst, '[') + for i, k := range keys { + if i > 0 { + dst = append(dst, ',') + } + dst = strconv.AppendInt(dst, int64(k), 10) + } + dst = append(dst, ']') + return dst, nil } // DecodeMsg decodes the message from the reader. @@ -2551,6 +3344,33 @@ func (s Int32Sorted) Msgsize() int { return size } +// UnmarshalJSON implements json.Unmarshaler. +func (s *Int32Sorted) UnmarshalJSON(data []byte) error { + if isJSONNull(data) { + *s = nil + return nil + } + dst := *s + if dst != nil { + clear(dst) + } else { + dst = make(Int32Sorted) + } + err := jsonArrayIter(data, func(raw []byte) error { + k, parseErr := jsonParseSigned[int32](raw, 32) + if parseErr != nil { + return parseErr + } + dst[k] = struct{}{} + return nil + }) + if err != nil { + return err + } + *s = dst + return nil +} + // Int32SortedFromSlice creates a Int32Sorted from a slice. func Int32SortedFromSlice(s []int32) Int32Sorted { if s == nil { @@ -2613,6 +3433,25 @@ func (s Uint32) AsSlice() []uint32 { return dst } +// MarshalJSON implements json.Marshaler. +func (s Uint32) MarshalJSON() ([]byte, error) { + if s == nil { + return []byte("null"), nil + } + dst := make([]byte, 0, 2+len(s)*10) + dst = append(dst, '[') + first := true + for k := range s { + if !first { + dst = append(dst, ',') + } + first = false + dst = strconv.AppendUint(dst, uint64(k), 10) + } + dst = append(dst, ']') + return dst, nil +} + // DecodeMsg decodes the message from the reader. func (s *Uint32) DecodeMsg(reader *msgp.Reader) error { if reader.IsNil() { @@ -2680,6 +3519,33 @@ func (s Uint32) Msgsize() int { return size } +// UnmarshalJSON implements json.Unmarshaler. +func (s *Uint32) UnmarshalJSON(data []byte) error { + if isJSONNull(data) { + *s = nil + return nil + } + dst := *s + if dst != nil { + clear(dst) + } else { + dst = make(Uint32) + } + err := jsonArrayIter(data, func(raw []byte) error { + k, parseErr := jsonParseUnsigned[uint32](raw, 32) + if parseErr != nil { + return parseErr + } + dst[k] = struct{}{} + return nil + }) + if err != nil { + return err + } + *s = dst + return nil +} + // Uint32FromSlice creates a Uint32 from a slice. func Uint32FromSlice(s []uint32) Uint32 { if s == nil { @@ -2769,6 +3635,24 @@ func (s Uint32Sorted) AsSlice() []uint32 { return keys } +// MarshalJSON implements json.Marshaler. +func (s Uint32Sorted) MarshalJSON() ([]byte, error) { + if s == nil { + return []byte("null"), nil + } + keys := s.AsSlice() + dst := make([]byte, 0, 2+len(keys)*10) + dst = append(dst, '[') + for i, k := range keys { + if i > 0 { + dst = append(dst, ',') + } + dst = strconv.AppendUint(dst, uint64(k), 10) + } + dst = append(dst, ']') + return dst, nil +} + // DecodeMsg decodes the message from the reader. func (s *Uint32Sorted) DecodeMsg(reader *msgp.Reader) error { if reader.IsNil() { @@ -2836,6 +3720,33 @@ func (s Uint32Sorted) Msgsize() int { return size } +// UnmarshalJSON implements json.Unmarshaler. +func (s *Uint32Sorted) UnmarshalJSON(data []byte) error { + if isJSONNull(data) { + *s = nil + return nil + } + dst := *s + if dst != nil { + clear(dst) + } else { + dst = make(Uint32Sorted) + } + err := jsonArrayIter(data, func(raw []byte) error { + k, parseErr := jsonParseUnsigned[uint32](raw, 32) + if parseErr != nil { + return parseErr + } + dst[k] = struct{}{} + return nil + }) + if err != nil { + return err + } + *s = dst + return nil +} + // Uint32SortedFromSlice creates a Uint32Sorted from a slice. func Uint32SortedFromSlice(s []uint32) Uint32Sorted { if s == nil { @@ -2898,6 +3809,25 @@ func (s Int64) AsSlice() []int64 { return dst } +// MarshalJSON implements json.Marshaler. +func (s Int64) MarshalJSON() ([]byte, error) { + if s == nil { + return []byte("null"), nil + } + dst := make([]byte, 0, 2+len(s)*10) + dst = append(dst, '[') + first := true + for k := range s { + if !first { + dst = append(dst, ',') + } + first = false + dst = strconv.AppendInt(dst, int64(k), 10) + } + dst = append(dst, ']') + return dst, nil +} + // DecodeMsg decodes the message from the reader. func (s *Int64) DecodeMsg(reader *msgp.Reader) error { if reader.IsNil() { @@ -2965,6 +3895,33 @@ func (s Int64) Msgsize() int { return size } +// UnmarshalJSON implements json.Unmarshaler. +func (s *Int64) UnmarshalJSON(data []byte) error { + if isJSONNull(data) { + *s = nil + return nil + } + dst := *s + if dst != nil { + clear(dst) + } else { + dst = make(Int64) + } + err := jsonArrayIter(data, func(raw []byte) error { + k, parseErr := jsonParseSigned[int64](raw, 64) + if parseErr != nil { + return parseErr + } + dst[k] = struct{}{} + return nil + }) + if err != nil { + return err + } + *s = dst + return nil +} + // Int64FromSlice creates a Int64 from a slice. func Int64FromSlice(s []int64) Int64 { if s == nil { @@ -3054,6 +4011,24 @@ func (s Int64Sorted) AsSlice() []int64 { return keys } +// MarshalJSON implements json.Marshaler. +func (s Int64Sorted) MarshalJSON() ([]byte, error) { + if s == nil { + return []byte("null"), nil + } + keys := s.AsSlice() + dst := make([]byte, 0, 2+len(keys)*10) + dst = append(dst, '[') + for i, k := range keys { + if i > 0 { + dst = append(dst, ',') + } + dst = strconv.AppendInt(dst, int64(k), 10) + } + dst = append(dst, ']') + return dst, nil +} + // DecodeMsg decodes the message from the reader. func (s *Int64Sorted) DecodeMsg(reader *msgp.Reader) error { if reader.IsNil() { @@ -3121,6 +4096,33 @@ func (s Int64Sorted) Msgsize() int { return size } +// UnmarshalJSON implements json.Unmarshaler. +func (s *Int64Sorted) UnmarshalJSON(data []byte) error { + if isJSONNull(data) { + *s = nil + return nil + } + dst := *s + if dst != nil { + clear(dst) + } else { + dst = make(Int64Sorted) + } + err := jsonArrayIter(data, func(raw []byte) error { + k, parseErr := jsonParseSigned[int64](raw, 64) + if parseErr != nil { + return parseErr + } + dst[k] = struct{}{} + return nil + }) + if err != nil { + return err + } + *s = dst + return nil +} + // Int64SortedFromSlice creates a Int64Sorted from a slice. func Int64SortedFromSlice(s []int64) Int64Sorted { if s == nil { @@ -3183,6 +4185,25 @@ func (s Uint64) AsSlice() []uint64 { return dst } +// MarshalJSON implements json.Marshaler. +func (s Uint64) MarshalJSON() ([]byte, error) { + if s == nil { + return []byte("null"), nil + } + dst := make([]byte, 0, 2+len(s)*10) + dst = append(dst, '[') + first := true + for k := range s { + if !first { + dst = append(dst, ',') + } + first = false + dst = strconv.AppendUint(dst, uint64(k), 10) + } + dst = append(dst, ']') + return dst, nil +} + // DecodeMsg decodes the message from the reader. func (s *Uint64) DecodeMsg(reader *msgp.Reader) error { if reader.IsNil() { @@ -3250,6 +4271,33 @@ func (s Uint64) Msgsize() int { return size } +// UnmarshalJSON implements json.Unmarshaler. +func (s *Uint64) UnmarshalJSON(data []byte) error { + if isJSONNull(data) { + *s = nil + return nil + } + dst := *s + if dst != nil { + clear(dst) + } else { + dst = make(Uint64) + } + err := jsonArrayIter(data, func(raw []byte) error { + k, parseErr := jsonParseUnsigned[uint64](raw, 64) + if parseErr != nil { + return parseErr + } + dst[k] = struct{}{} + return nil + }) + if err != nil { + return err + } + *s = dst + return nil +} + // Uint64FromSlice creates a Uint64 from a slice. func Uint64FromSlice(s []uint64) Uint64 { if s == nil { @@ -3339,6 +4387,24 @@ func (s Uint64Sorted) AsSlice() []uint64 { return keys } +// MarshalJSON implements json.Marshaler. +func (s Uint64Sorted) MarshalJSON() ([]byte, error) { + if s == nil { + return []byte("null"), nil + } + keys := s.AsSlice() + dst := make([]byte, 0, 2+len(keys)*10) + dst = append(dst, '[') + for i, k := range keys { + if i > 0 { + dst = append(dst, ',') + } + dst = strconv.AppendUint(dst, uint64(k), 10) + } + dst = append(dst, ']') + return dst, nil +} + // DecodeMsg decodes the message from the reader. func (s *Uint64Sorted) DecodeMsg(reader *msgp.Reader) error { if reader.IsNil() { @@ -3406,6 +4472,33 @@ func (s Uint64Sorted) Msgsize() int { return size } +// UnmarshalJSON implements json.Unmarshaler. +func (s *Uint64Sorted) UnmarshalJSON(data []byte) error { + if isJSONNull(data) { + *s = nil + return nil + } + dst := *s + if dst != nil { + clear(dst) + } else { + dst = make(Uint64Sorted) + } + err := jsonArrayIter(data, func(raw []byte) error { + k, parseErr := jsonParseUnsigned[uint64](raw, 64) + if parseErr != nil { + return parseErr + } + dst[k] = struct{}{} + return nil + }) + if err != nil { + return err + } + *s = dst + return nil +} + // Uint64SortedFromSlice creates a Uint64Sorted from a slice. func Uint64SortedFromSlice(s []uint64) Uint64Sorted { if s == nil { @@ -3468,6 +4561,25 @@ func (s Float64) AsSlice() []float64 { return dst } +// MarshalJSON implements json.Marshaler. +func (s Float64) MarshalJSON() ([]byte, error) { + if s == nil { + return []byte("null"), nil + } + dst := make([]byte, 0, 2+len(s)*10) + dst = append(dst, '[') + first := true + for k := range s { + if !first { + dst = append(dst, ',') + } + first = false + dst = strconv.AppendFloat(dst, float64(k), 'f', -1, 64) + } + dst = append(dst, ']') + return dst, nil +} + // DecodeMsg decodes the message from the reader. func (s *Float64) DecodeMsg(reader *msgp.Reader) error { if reader.IsNil() { @@ -3535,6 +4647,33 @@ func (s Float64) Msgsize() int { return size } +// UnmarshalJSON implements json.Unmarshaler. +func (s *Float64) UnmarshalJSON(data []byte) error { + if isJSONNull(data) { + *s = nil + return nil + } + dst := *s + if dst != nil { + clear(dst) + } else { + dst = make(Float64) + } + err := jsonArrayIter(data, func(raw []byte) error { + k, parseErr := jsonParseFloat[float64](raw, 64) + if parseErr != nil { + return parseErr + } + dst[k] = struct{}{} + return nil + }) + if err != nil { + return err + } + *s = dst + return nil +} + // Float64FromSlice creates a Float64 from a slice. func Float64FromSlice(s []float64) Float64 { if s == nil { @@ -3624,6 +4763,24 @@ func (s Float64Sorted) AsSlice() []float64 { return keys } +// MarshalJSON implements json.Marshaler. +func (s Float64Sorted) MarshalJSON() ([]byte, error) { + if s == nil { + return []byte("null"), nil + } + keys := s.AsSlice() + dst := make([]byte, 0, 2+len(keys)*10) + dst = append(dst, '[') + for i, k := range keys { + if i > 0 { + dst = append(dst, ',') + } + dst = strconv.AppendFloat(dst, float64(k), 'f', -1, 64) + } + dst = append(dst, ']') + return dst, nil +} + // DecodeMsg decodes the message from the reader. func (s *Float64Sorted) DecodeMsg(reader *msgp.Reader) error { if reader.IsNil() { @@ -3691,6 +4848,33 @@ func (s Float64Sorted) Msgsize() int { return size } +// UnmarshalJSON implements json.Unmarshaler. +func (s *Float64Sorted) UnmarshalJSON(data []byte) error { + if isJSONNull(data) { + *s = nil + return nil + } + dst := *s + if dst != nil { + clear(dst) + } else { + dst = make(Float64Sorted) + } + err := jsonArrayIter(data, func(raw []byte) error { + k, parseErr := jsonParseFloat[float64](raw, 64) + if parseErr != nil { + return parseErr + } + dst[k] = struct{}{} + return nil + }) + if err != nil { + return err + } + *s = dst + return nil +} + // Float64SortedFromSlice creates a Float64Sorted from a slice. func Float64SortedFromSlice(s []float64) Float64Sorted { if s == nil { @@ -3753,6 +4937,25 @@ func (s Float32) AsSlice() []float32 { return dst } +// MarshalJSON implements json.Marshaler. +func (s Float32) MarshalJSON() ([]byte, error) { + if s == nil { + return []byte("null"), nil + } + dst := make([]byte, 0, 2+len(s)*10) + dst = append(dst, '[') + first := true + for k := range s { + if !first { + dst = append(dst, ',') + } + first = false + dst = strconv.AppendFloat(dst, float64(k), 'f', -1, 32) + } + dst = append(dst, ']') + return dst, nil +} + // DecodeMsg decodes the message from the reader. func (s *Float32) DecodeMsg(reader *msgp.Reader) error { if reader.IsNil() { @@ -3820,6 +5023,33 @@ func (s Float32) Msgsize() int { return size } +// UnmarshalJSON implements json.Unmarshaler. +func (s *Float32) UnmarshalJSON(data []byte) error { + if isJSONNull(data) { + *s = nil + return nil + } + dst := *s + if dst != nil { + clear(dst) + } else { + dst = make(Float32) + } + err := jsonArrayIter(data, func(raw []byte) error { + k, parseErr := jsonParseFloat[float32](raw, 32) + if parseErr != nil { + return parseErr + } + dst[k] = struct{}{} + return nil + }) + if err != nil { + return err + } + *s = dst + return nil +} + // Float32FromSlice creates a Float32 from a slice. func Float32FromSlice(s []float32) Float32 { if s == nil { @@ -3909,6 +5139,24 @@ func (s Float32Sorted) AsSlice() []float32 { return keys } +// MarshalJSON implements json.Marshaler. +func (s Float32Sorted) MarshalJSON() ([]byte, error) { + if s == nil { + return []byte("null"), nil + } + keys := s.AsSlice() + dst := make([]byte, 0, 2+len(keys)*10) + dst = append(dst, '[') + for i, k := range keys { + if i > 0 { + dst = append(dst, ',') + } + dst = strconv.AppendFloat(dst, float64(k), 'f', -1, 32) + } + dst = append(dst, ']') + return dst, nil +} + // DecodeMsg decodes the message from the reader. func (s *Float32Sorted) DecodeMsg(reader *msgp.Reader) error { if reader.IsNil() { @@ -3976,6 +5224,33 @@ func (s Float32Sorted) Msgsize() int { return size } +// UnmarshalJSON implements json.Unmarshaler. +func (s *Float32Sorted) UnmarshalJSON(data []byte) error { + if isJSONNull(data) { + *s = nil + return nil + } + dst := *s + if dst != nil { + clear(dst) + } else { + dst = make(Float32Sorted) + } + err := jsonArrayIter(data, func(raw []byte) error { + k, parseErr := jsonParseFloat[float32](raw, 32) + if parseErr != nil { + return parseErr + } + dst[k] = struct{}{} + return nil + }) + if err != nil { + return err + } + *s = dst + return nil +} + // Float32SortedFromSlice creates a Float32Sorted from a slice. func Float32SortedFromSlice(s []float32) Float32Sorted { if s == nil { diff --git a/msgp/setof/generated_test.go b/msgp/setof/generated_test.go index 64608127..48e510e5 100644 --- a/msgp/setof/generated_test.go +++ b/msgp/setof/generated_test.go @@ -4,6 +4,7 @@ package setof import ( "bytes" + "encoding/json" "fmt" "testing" @@ -203,6 +204,92 @@ func TestString_EmptySet(t *testing.T) { } } +func TestString_JSONRoundTrip(t *testing.T) { + set := make(String) + set["val0"] = struct{}{} + set["val1"] = struct{}{} + set["val2"] = struct{}{} + set["val3"] = struct{}{} + set["val4"] = struct{}{} + + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON failed: %v", err) + } + + // Verify JSON is an array + if len(data) == 0 || data[0] != '[' || data[len(data)-1] != ']' { + t.Fatalf("expected JSON array, got: %s", data) + } + + // Verify it unmarshals as a generic JSON array + var arr []json.RawMessage + if err := json.Unmarshal(data, &arr); err != nil { + t.Fatalf("JSON is not a valid array: %v", err) + } + if len(arr) != len(set) { + t.Fatalf("JSON array length mismatch: expected %d, got %d", len(set), len(arr)) + } + + var decoded String + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON failed: %v", err) + } + + if len(set) != len(decoded) { + t.Fatalf("length mismatch: expected %d, got %d", len(set), len(decoded)) + } + + for k := range set { + if _, ok := decoded[k]; !ok { + t.Fatalf("missing key: %v", k) + } + } +} + +func TestString_JSONNil(t *testing.T) { + var nilSet String + + data, err := json.Marshal(nilSet) + if err != nil { + t.Fatalf("MarshalJSON nil failed: %v", err) + } + if string(data) != "null" { + t.Fatalf("expected null, got %s", data) + } + + var decoded String + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON nil failed: %v", err) + } + if decoded != nil { + t.Fatal("expected nil, got non-nil") + } +} + +func TestString_JSONEmpty(t *testing.T) { + set := make(String) + + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON empty failed: %v", err) + } + if string(data) != "[]" { + t.Fatalf("expected [], got %s", data) + } + + var decoded String + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON empty failed: %v", err) + } + if len(decoded) != 0 { + t.Fatalf("expected empty set, got length %d", len(decoded)) + } +} + func TestStringSorted_RoundTrip(t *testing.T) { set := make(StringSorted) set["val0"] = struct{}{} @@ -396,6 +483,92 @@ func TestStringSorted_EmptySet(t *testing.T) { } } +func TestStringSorted_JSONRoundTrip(t *testing.T) { + set := make(StringSorted) + set["val0"] = struct{}{} + set["val1"] = struct{}{} + set["val2"] = struct{}{} + set["val3"] = struct{}{} + set["val4"] = struct{}{} + + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON failed: %v", err) + } + + // Verify JSON is an array + if len(data) == 0 || data[0] != '[' || data[len(data)-1] != ']' { + t.Fatalf("expected JSON array, got: %s", data) + } + + // Verify it unmarshals as a generic JSON array + var arr []json.RawMessage + if err := json.Unmarshal(data, &arr); err != nil { + t.Fatalf("JSON is not a valid array: %v", err) + } + if len(arr) != len(set) { + t.Fatalf("JSON array length mismatch: expected %d, got %d", len(set), len(arr)) + } + + var decoded StringSorted + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON failed: %v", err) + } + + if len(set) != len(decoded) { + t.Fatalf("length mismatch: expected %d, got %d", len(set), len(decoded)) + } + + for k := range set { + if _, ok := decoded[k]; !ok { + t.Fatalf("missing key: %v", k) + } + } +} + +func TestStringSorted_JSONNil(t *testing.T) { + var nilSet StringSorted + + data, err := json.Marshal(nilSet) + if err != nil { + t.Fatalf("MarshalJSON nil failed: %v", err) + } + if string(data) != "null" { + t.Fatalf("expected null, got %s", data) + } + + var decoded StringSorted + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON nil failed: %v", err) + } + if decoded != nil { + t.Fatal("expected nil, got non-nil") + } +} + +func TestStringSorted_JSONEmpty(t *testing.T) { + set := make(StringSorted) + + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON empty failed: %v", err) + } + if string(data) != "[]" { + t.Fatalf("expected [], got %s", data) + } + + var decoded StringSorted + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON empty failed: %v", err) + } + if len(decoded) != 0 { + t.Fatalf("expected empty set, got length %d", len(decoded)) + } +} + func BenchmarkString_EncodeMsg(b *testing.B) { sizes := []int{10, 100, 1000} @@ -533,6 +706,53 @@ func BenchmarkString_FromSlice(b *testing.B) { } } +func BenchmarkString_MarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(String) + for i := 0; i < size; i++ { + set[fmt.Sprintf("val%d", i)] = struct{}{} + } + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := json.Marshal(set) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + +func BenchmarkString_UnmarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(String) + for i := 0; i < size; i++ { + set[fmt.Sprintf("val%d", i)] = struct{}{} + } + + data, _ := json.Marshal(set) + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + var decoded String + err := json.Unmarshal(data, &decoded) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + func BenchmarkStringSorted_EncodeMsg(b *testing.B) { sizes := []int{10, 100, 1000} @@ -670,6 +890,53 @@ func BenchmarkStringSorted_FromSlice(b *testing.B) { } } +func BenchmarkStringSorted_MarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(StringSorted) + for i := 0; i < size; i++ { + set[fmt.Sprintf("val%d", i)] = struct{}{} + } + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := json.Marshal(set) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + +func BenchmarkStringSorted_UnmarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(StringSorted) + for i := 0; i < size; i++ { + set[fmt.Sprintf("val%d", i)] = struct{}{} + } + + data, _ := json.Marshal(set) + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + var decoded StringSorted + err := json.Unmarshal(data, &decoded) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + func TestInt_RoundTrip(t *testing.T) { set := make(Int) set[0] = struct{}{} @@ -863,28 +1130,37 @@ func TestInt_EmptySet(t *testing.T) { } } -func TestIntSorted_RoundTrip(t *testing.T) { - set := make(IntSorted) +func TestInt_JSONRoundTrip(t *testing.T) { + set := make(Int) set[0] = struct{}{} set[1] = struct{}{} set[2] = struct{}{} set[3] = struct{}{} set[4] = struct{}{} - // Test EncodeMsg/DecodeMsg - var buf bytes.Buffer - writer := msgp.NewWriter(&buf) - err := set.EncodeMsg(writer) + data, err := json.Marshal(set) if err != nil { - t.Fatalf("EncodeMsg failed: %v", err) + t.Fatalf("MarshalJSON failed: %v", err) } - writer.Flush() - reader := msgp.NewReader(&buf) - var decoded IntSorted - err = decoded.DecodeMsg(reader) + // Verify JSON is an array + if len(data) == 0 || data[0] != '[' || data[len(data)-1] != ']' { + t.Fatalf("expected JSON array, got: %s", data) + } + + // Verify it unmarshals as a generic JSON array + var arr []json.RawMessage + if err := json.Unmarshal(data, &arr); err != nil { + t.Fatalf("JSON is not a valid array: %v", err) + } + if len(arr) != len(set) { + t.Fatalf("JSON array length mismatch: expected %d, got %d", len(set), len(arr)) + } + + var decoded Int + err = json.Unmarshal(data, &decoded) if err != nil { - t.Fatalf("DecodeMsg failed: %v", err) + t.Fatalf("UnmarshalJSON failed: %v", err) } if len(set) != len(decoded) { @@ -896,31 +1172,51 @@ func TestIntSorted_RoundTrip(t *testing.T) { t.Fatalf("missing key: %v", k) } } +} - // Test MarshalMsg/UnmarshalMsg - data, err := set.MarshalMsg(nil) +func TestInt_JSONNil(t *testing.T) { + var nilSet Int + + data, err := json.Marshal(nilSet) if err != nil { - t.Fatalf("MarshalMsg failed: %v", err) + t.Fatalf("MarshalJSON nil failed: %v", err) + } + if string(data) != "null" { + t.Fatalf("expected null, got %s", data) } - var unmarshaled IntSorted - _, err = unmarshaled.UnmarshalMsg(data) + var decoded Int + err = json.Unmarshal(data, &decoded) if err != nil { - t.Fatalf("UnmarshalMsg failed: %v", err) + t.Fatalf("UnmarshalJSON nil failed: %v", err) + } + if decoded != nil { + t.Fatal("expected nil, got non-nil") } +} - if len(set) != len(unmarshaled) { - t.Fatalf("length mismatch: expected %d, got %d", len(set), len(unmarshaled)) +func TestInt_JSONEmpty(t *testing.T) { + set := make(Int) + + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON empty failed: %v", err) + } + if string(data) != "[]" { + t.Fatalf("expected [], got %s", data) } - for k := range set { - if _, ok := unmarshaled[k]; !ok { - t.Fatalf("missing key: %v", k) - } + var decoded Int + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON empty failed: %v", err) + } + if len(decoded) != 0 { + t.Fatalf("expected empty set, got length %d", len(decoded)) } } -func TestIntSorted_AsSlice(t *testing.T) { +func TestIntSorted_RoundTrip(t *testing.T) { set := make(IntSorted) set[0] = struct{}{} set[1] = struct{}{} @@ -928,11 +1224,68 @@ func TestIntSorted_AsSlice(t *testing.T) { set[3] = struct{}{} set[4] = struct{}{} - slice := set.AsSlice() - if len(slice) != len(set) { - t.Fatalf("length mismatch: expected %d, got %d", len(set), len(slice)) - } - + // Test EncodeMsg/DecodeMsg + var buf bytes.Buffer + writer := msgp.NewWriter(&buf) + err := set.EncodeMsg(writer) + if err != nil { + t.Fatalf("EncodeMsg failed: %v", err) + } + writer.Flush() + + reader := msgp.NewReader(&buf) + var decoded IntSorted + err = decoded.DecodeMsg(reader) + if err != nil { + t.Fatalf("DecodeMsg failed: %v", err) + } + + if len(set) != len(decoded) { + t.Fatalf("length mismatch: expected %d, got %d", len(set), len(decoded)) + } + + for k := range set { + if _, ok := decoded[k]; !ok { + t.Fatalf("missing key: %v", k) + } + } + + // Test MarshalMsg/UnmarshalMsg + data, err := set.MarshalMsg(nil) + if err != nil { + t.Fatalf("MarshalMsg failed: %v", err) + } + + var unmarshaled IntSorted + _, err = unmarshaled.UnmarshalMsg(data) + if err != nil { + t.Fatalf("UnmarshalMsg failed: %v", err) + } + + if len(set) != len(unmarshaled) { + t.Fatalf("length mismatch: expected %d, got %d", len(set), len(unmarshaled)) + } + + for k := range set { + if _, ok := unmarshaled[k]; !ok { + t.Fatalf("missing key: %v", k) + } + } +} + +func TestIntSorted_AsSlice(t *testing.T) { + set := make(IntSorted) + set[0] = struct{}{} + set[1] = struct{}{} + set[2] = struct{}{} + set[3] = struct{}{} + set[4] = struct{}{} + + slice := set.AsSlice() + if len(slice) != len(set) { + t.Fatalf("length mismatch: expected %d, got %d", len(set), len(slice)) + } + found := make(map[int]bool) for _, v := range slice { found[v] = true @@ -1056,6 +1409,92 @@ func TestIntSorted_EmptySet(t *testing.T) { } } +func TestIntSorted_JSONRoundTrip(t *testing.T) { + set := make(IntSorted) + set[0] = struct{}{} + set[1] = struct{}{} + set[2] = struct{}{} + set[3] = struct{}{} + set[4] = struct{}{} + + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON failed: %v", err) + } + + // Verify JSON is an array + if len(data) == 0 || data[0] != '[' || data[len(data)-1] != ']' { + t.Fatalf("expected JSON array, got: %s", data) + } + + // Verify it unmarshals as a generic JSON array + var arr []json.RawMessage + if err := json.Unmarshal(data, &arr); err != nil { + t.Fatalf("JSON is not a valid array: %v", err) + } + if len(arr) != len(set) { + t.Fatalf("JSON array length mismatch: expected %d, got %d", len(set), len(arr)) + } + + var decoded IntSorted + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON failed: %v", err) + } + + if len(set) != len(decoded) { + t.Fatalf("length mismatch: expected %d, got %d", len(set), len(decoded)) + } + + for k := range set { + if _, ok := decoded[k]; !ok { + t.Fatalf("missing key: %v", k) + } + } +} + +func TestIntSorted_JSONNil(t *testing.T) { + var nilSet IntSorted + + data, err := json.Marshal(nilSet) + if err != nil { + t.Fatalf("MarshalJSON nil failed: %v", err) + } + if string(data) != "null" { + t.Fatalf("expected null, got %s", data) + } + + var decoded IntSorted + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON nil failed: %v", err) + } + if decoded != nil { + t.Fatal("expected nil, got non-nil") + } +} + +func TestIntSorted_JSONEmpty(t *testing.T) { + set := make(IntSorted) + + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON empty failed: %v", err) + } + if string(data) != "[]" { + t.Fatalf("expected [], got %s", data) + } + + var decoded IntSorted + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON empty failed: %v", err) + } + if len(decoded) != 0 { + t.Fatalf("expected empty set, got length %d", len(decoded)) + } +} + func BenchmarkInt_EncodeMsg(b *testing.B) { sizes := []int{10, 100, 1000} @@ -1193,6 +1632,53 @@ func BenchmarkInt_FromSlice(b *testing.B) { } } +func BenchmarkInt_MarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(Int) + for i := 0; i < size; i++ { + set[int(i)] = struct{}{} + } + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := json.Marshal(set) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + +func BenchmarkInt_UnmarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(Int) + for i := 0; i < size; i++ { + set[int(i)] = struct{}{} + } + + data, _ := json.Marshal(set) + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + var decoded Int + err := json.Unmarshal(data, &decoded) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + func BenchmarkIntSorted_EncodeMsg(b *testing.B) { sizes := []int{10, 100, 1000} @@ -1330,6 +1816,53 @@ func BenchmarkIntSorted_FromSlice(b *testing.B) { } } +func BenchmarkIntSorted_MarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(IntSorted) + for i := 0; i < size; i++ { + set[int(i)] = struct{}{} + } + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := json.Marshal(set) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + +func BenchmarkIntSorted_UnmarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(IntSorted) + for i := 0; i < size; i++ { + set[int(i)] = struct{}{} + } + + data, _ := json.Marshal(set) + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + var decoded IntSorted + err := json.Unmarshal(data, &decoded) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + func TestUint_RoundTrip(t *testing.T) { set := make(Uint) set[0] = struct{}{} @@ -1523,28 +2056,37 @@ func TestUint_EmptySet(t *testing.T) { } } -func TestUintSorted_RoundTrip(t *testing.T) { - set := make(UintSorted) +func TestUint_JSONRoundTrip(t *testing.T) { + set := make(Uint) set[0] = struct{}{} set[1] = struct{}{} set[2] = struct{}{} set[3] = struct{}{} set[4] = struct{}{} - // Test EncodeMsg/DecodeMsg - var buf bytes.Buffer - writer := msgp.NewWriter(&buf) - err := set.EncodeMsg(writer) + data, err := json.Marshal(set) if err != nil { - t.Fatalf("EncodeMsg failed: %v", err) + t.Fatalf("MarshalJSON failed: %v", err) } - writer.Flush() - reader := msgp.NewReader(&buf) - var decoded UintSorted - err = decoded.DecodeMsg(reader) + // Verify JSON is an array + if len(data) == 0 || data[0] != '[' || data[len(data)-1] != ']' { + t.Fatalf("expected JSON array, got: %s", data) + } + + // Verify it unmarshals as a generic JSON array + var arr []json.RawMessage + if err := json.Unmarshal(data, &arr); err != nil { + t.Fatalf("JSON is not a valid array: %v", err) + } + if len(arr) != len(set) { + t.Fatalf("JSON array length mismatch: expected %d, got %d", len(set), len(arr)) + } + + var decoded Uint + err = json.Unmarshal(data, &decoded) if err != nil { - t.Fatalf("DecodeMsg failed: %v", err) + t.Fatalf("UnmarshalJSON failed: %v", err) } if len(set) != len(decoded) { @@ -1556,31 +2098,51 @@ func TestUintSorted_RoundTrip(t *testing.T) { t.Fatalf("missing key: %v", k) } } +} - // Test MarshalMsg/UnmarshalMsg - data, err := set.MarshalMsg(nil) +func TestUint_JSONNil(t *testing.T) { + var nilSet Uint + + data, err := json.Marshal(nilSet) if err != nil { - t.Fatalf("MarshalMsg failed: %v", err) + t.Fatalf("MarshalJSON nil failed: %v", err) + } + if string(data) != "null" { + t.Fatalf("expected null, got %s", data) } - var unmarshaled UintSorted - _, err = unmarshaled.UnmarshalMsg(data) + var decoded Uint + err = json.Unmarshal(data, &decoded) if err != nil { - t.Fatalf("UnmarshalMsg failed: %v", err) + t.Fatalf("UnmarshalJSON nil failed: %v", err) + } + if decoded != nil { + t.Fatal("expected nil, got non-nil") } +} - if len(set) != len(unmarshaled) { - t.Fatalf("length mismatch: expected %d, got %d", len(set), len(unmarshaled)) +func TestUint_JSONEmpty(t *testing.T) { + set := make(Uint) + + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON empty failed: %v", err) + } + if string(data) != "[]" { + t.Fatalf("expected [], got %s", data) } - for k := range set { - if _, ok := unmarshaled[k]; !ok { - t.Fatalf("missing key: %v", k) - } + var decoded Uint + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON empty failed: %v", err) + } + if len(decoded) != 0 { + t.Fatalf("expected empty set, got length %d", len(decoded)) } } -func TestUintSorted_AsSlice(t *testing.T) { +func TestUintSorted_RoundTrip(t *testing.T) { set := make(UintSorted) set[0] = struct{}{} set[1] = struct{}{} @@ -1588,7 +2150,64 @@ func TestUintSorted_AsSlice(t *testing.T) { set[3] = struct{}{} set[4] = struct{}{} - slice := set.AsSlice() + // Test EncodeMsg/DecodeMsg + var buf bytes.Buffer + writer := msgp.NewWriter(&buf) + err := set.EncodeMsg(writer) + if err != nil { + t.Fatalf("EncodeMsg failed: %v", err) + } + writer.Flush() + + reader := msgp.NewReader(&buf) + var decoded UintSorted + err = decoded.DecodeMsg(reader) + if err != nil { + t.Fatalf("DecodeMsg failed: %v", err) + } + + if len(set) != len(decoded) { + t.Fatalf("length mismatch: expected %d, got %d", len(set), len(decoded)) + } + + for k := range set { + if _, ok := decoded[k]; !ok { + t.Fatalf("missing key: %v", k) + } + } + + // Test MarshalMsg/UnmarshalMsg + data, err := set.MarshalMsg(nil) + if err != nil { + t.Fatalf("MarshalMsg failed: %v", err) + } + + var unmarshaled UintSorted + _, err = unmarshaled.UnmarshalMsg(data) + if err != nil { + t.Fatalf("UnmarshalMsg failed: %v", err) + } + + if len(set) != len(unmarshaled) { + t.Fatalf("length mismatch: expected %d, got %d", len(set), len(unmarshaled)) + } + + for k := range set { + if _, ok := unmarshaled[k]; !ok { + t.Fatalf("missing key: %v", k) + } + } +} + +func TestUintSorted_AsSlice(t *testing.T) { + set := make(UintSorted) + set[0] = struct{}{} + set[1] = struct{}{} + set[2] = struct{}{} + set[3] = struct{}{} + set[4] = struct{}{} + + slice := set.AsSlice() if len(slice) != len(set) { t.Fatalf("length mismatch: expected %d, got %d", len(set), len(slice)) } @@ -1716,6 +2335,92 @@ func TestUintSorted_EmptySet(t *testing.T) { } } +func TestUintSorted_JSONRoundTrip(t *testing.T) { + set := make(UintSorted) + set[0] = struct{}{} + set[1] = struct{}{} + set[2] = struct{}{} + set[3] = struct{}{} + set[4] = struct{}{} + + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON failed: %v", err) + } + + // Verify JSON is an array + if len(data) == 0 || data[0] != '[' || data[len(data)-1] != ']' { + t.Fatalf("expected JSON array, got: %s", data) + } + + // Verify it unmarshals as a generic JSON array + var arr []json.RawMessage + if err := json.Unmarshal(data, &arr); err != nil { + t.Fatalf("JSON is not a valid array: %v", err) + } + if len(arr) != len(set) { + t.Fatalf("JSON array length mismatch: expected %d, got %d", len(set), len(arr)) + } + + var decoded UintSorted + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON failed: %v", err) + } + + if len(set) != len(decoded) { + t.Fatalf("length mismatch: expected %d, got %d", len(set), len(decoded)) + } + + for k := range set { + if _, ok := decoded[k]; !ok { + t.Fatalf("missing key: %v", k) + } + } +} + +func TestUintSorted_JSONNil(t *testing.T) { + var nilSet UintSorted + + data, err := json.Marshal(nilSet) + if err != nil { + t.Fatalf("MarshalJSON nil failed: %v", err) + } + if string(data) != "null" { + t.Fatalf("expected null, got %s", data) + } + + var decoded UintSorted + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON nil failed: %v", err) + } + if decoded != nil { + t.Fatal("expected nil, got non-nil") + } +} + +func TestUintSorted_JSONEmpty(t *testing.T) { + set := make(UintSorted) + + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON empty failed: %v", err) + } + if string(data) != "[]" { + t.Fatalf("expected [], got %s", data) + } + + var decoded UintSorted + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON empty failed: %v", err) + } + if len(decoded) != 0 { + t.Fatalf("expected empty set, got length %d", len(decoded)) + } +} + func BenchmarkUint_EncodeMsg(b *testing.B) { sizes := []int{10, 100, 1000} @@ -1853,6 +2558,53 @@ func BenchmarkUint_FromSlice(b *testing.B) { } } +func BenchmarkUint_MarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(Uint) + for i := 0; i < size; i++ { + set[uint(i)] = struct{}{} + } + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := json.Marshal(set) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + +func BenchmarkUint_UnmarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(Uint) + for i := 0; i < size; i++ { + set[uint(i)] = struct{}{} + } + + data, _ := json.Marshal(set) + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + var decoded Uint + err := json.Unmarshal(data, &decoded) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + func BenchmarkUintSorted_EncodeMsg(b *testing.B) { sizes := []int{10, 100, 1000} @@ -1990,6 +2742,53 @@ func BenchmarkUintSorted_FromSlice(b *testing.B) { } } +func BenchmarkUintSorted_MarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(UintSorted) + for i := 0; i < size; i++ { + set[uint(i)] = struct{}{} + } + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := json.Marshal(set) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + +func BenchmarkUintSorted_UnmarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(UintSorted) + for i := 0; i < size; i++ { + set[uint(i)] = struct{}{} + } + + data, _ := json.Marshal(set) + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + var decoded UintSorted + err := json.Unmarshal(data, &decoded) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + func TestByte_RoundTrip(t *testing.T) { set := make(Byte) set[0] = struct{}{} @@ -2183,28 +2982,37 @@ func TestByte_EmptySet(t *testing.T) { } } -func TestByteSorted_RoundTrip(t *testing.T) { - set := make(ByteSorted) +func TestByte_JSONRoundTrip(t *testing.T) { + set := make(Byte) set[0] = struct{}{} set[1] = struct{}{} set[2] = struct{}{} set[3] = struct{}{} set[4] = struct{}{} - // Test EncodeMsg/DecodeMsg - var buf bytes.Buffer - writer := msgp.NewWriter(&buf) - err := set.EncodeMsg(writer) + data, err := json.Marshal(set) if err != nil { - t.Fatalf("EncodeMsg failed: %v", err) + t.Fatalf("MarshalJSON failed: %v", err) } - writer.Flush() - reader := msgp.NewReader(&buf) - var decoded ByteSorted - err = decoded.DecodeMsg(reader) + // Verify JSON is an array + if len(data) == 0 || data[0] != '[' || data[len(data)-1] != ']' { + t.Fatalf("expected JSON array, got: %s", data) + } + + // Verify it unmarshals as a generic JSON array + var arr []json.RawMessage + if err := json.Unmarshal(data, &arr); err != nil { + t.Fatalf("JSON is not a valid array: %v", err) + } + if len(arr) != len(set) { + t.Fatalf("JSON array length mismatch: expected %d, got %d", len(set), len(arr)) + } + + var decoded Byte + err = json.Unmarshal(data, &decoded) if err != nil { - t.Fatalf("DecodeMsg failed: %v", err) + t.Fatalf("UnmarshalJSON failed: %v", err) } if len(set) != len(decoded) { @@ -2216,31 +3024,51 @@ func TestByteSorted_RoundTrip(t *testing.T) { t.Fatalf("missing key: %v", k) } } +} - // Test MarshalMsg/UnmarshalMsg - data, err := set.MarshalMsg(nil) +func TestByte_JSONNil(t *testing.T) { + var nilSet Byte + + data, err := json.Marshal(nilSet) if err != nil { - t.Fatalf("MarshalMsg failed: %v", err) + t.Fatalf("MarshalJSON nil failed: %v", err) + } + if string(data) != "null" { + t.Fatalf("expected null, got %s", data) } - var unmarshaled ByteSorted - _, err = unmarshaled.UnmarshalMsg(data) + var decoded Byte + err = json.Unmarshal(data, &decoded) if err != nil { - t.Fatalf("UnmarshalMsg failed: %v", err) + t.Fatalf("UnmarshalJSON nil failed: %v", err) + } + if decoded != nil { + t.Fatal("expected nil, got non-nil") } +} - if len(set) != len(unmarshaled) { - t.Fatalf("length mismatch: expected %d, got %d", len(set), len(unmarshaled)) +func TestByte_JSONEmpty(t *testing.T) { + set := make(Byte) + + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON empty failed: %v", err) + } + if string(data) != "[]" { + t.Fatalf("expected [], got %s", data) } - for k := range set { - if _, ok := unmarshaled[k]; !ok { - t.Fatalf("missing key: %v", k) - } + var decoded Byte + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON empty failed: %v", err) + } + if len(decoded) != 0 { + t.Fatalf("expected empty set, got length %d", len(decoded)) } } -func TestByteSorted_AsSlice(t *testing.T) { +func TestByteSorted_RoundTrip(t *testing.T) { set := make(ByteSorted) set[0] = struct{}{} set[1] = struct{}{} @@ -2248,11 +3076,68 @@ func TestByteSorted_AsSlice(t *testing.T) { set[3] = struct{}{} set[4] = struct{}{} - slice := set.AsSlice() - if len(slice) != len(set) { - t.Fatalf("length mismatch: expected %d, got %d", len(set), len(slice)) - } - + // Test EncodeMsg/DecodeMsg + var buf bytes.Buffer + writer := msgp.NewWriter(&buf) + err := set.EncodeMsg(writer) + if err != nil { + t.Fatalf("EncodeMsg failed: %v", err) + } + writer.Flush() + + reader := msgp.NewReader(&buf) + var decoded ByteSorted + err = decoded.DecodeMsg(reader) + if err != nil { + t.Fatalf("DecodeMsg failed: %v", err) + } + + if len(set) != len(decoded) { + t.Fatalf("length mismatch: expected %d, got %d", len(set), len(decoded)) + } + + for k := range set { + if _, ok := decoded[k]; !ok { + t.Fatalf("missing key: %v", k) + } + } + + // Test MarshalMsg/UnmarshalMsg + data, err := set.MarshalMsg(nil) + if err != nil { + t.Fatalf("MarshalMsg failed: %v", err) + } + + var unmarshaled ByteSorted + _, err = unmarshaled.UnmarshalMsg(data) + if err != nil { + t.Fatalf("UnmarshalMsg failed: %v", err) + } + + if len(set) != len(unmarshaled) { + t.Fatalf("length mismatch: expected %d, got %d", len(set), len(unmarshaled)) + } + + for k := range set { + if _, ok := unmarshaled[k]; !ok { + t.Fatalf("missing key: %v", k) + } + } +} + +func TestByteSorted_AsSlice(t *testing.T) { + set := make(ByteSorted) + set[0] = struct{}{} + set[1] = struct{}{} + set[2] = struct{}{} + set[3] = struct{}{} + set[4] = struct{}{} + + slice := set.AsSlice() + if len(slice) != len(set) { + t.Fatalf("length mismatch: expected %d, got %d", len(set), len(slice)) + } + found := make(map[byte]bool) for _, v := range slice { found[v] = true @@ -2376,6 +3261,92 @@ func TestByteSorted_EmptySet(t *testing.T) { } } +func TestByteSorted_JSONRoundTrip(t *testing.T) { + set := make(ByteSorted) + set[0] = struct{}{} + set[1] = struct{}{} + set[2] = struct{}{} + set[3] = struct{}{} + set[4] = struct{}{} + + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON failed: %v", err) + } + + // Verify JSON is an array + if len(data) == 0 || data[0] != '[' || data[len(data)-1] != ']' { + t.Fatalf("expected JSON array, got: %s", data) + } + + // Verify it unmarshals as a generic JSON array + var arr []json.RawMessage + if err := json.Unmarshal(data, &arr); err != nil { + t.Fatalf("JSON is not a valid array: %v", err) + } + if len(arr) != len(set) { + t.Fatalf("JSON array length mismatch: expected %d, got %d", len(set), len(arr)) + } + + var decoded ByteSorted + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON failed: %v", err) + } + + if len(set) != len(decoded) { + t.Fatalf("length mismatch: expected %d, got %d", len(set), len(decoded)) + } + + for k := range set { + if _, ok := decoded[k]; !ok { + t.Fatalf("missing key: %v", k) + } + } +} + +func TestByteSorted_JSONNil(t *testing.T) { + var nilSet ByteSorted + + data, err := json.Marshal(nilSet) + if err != nil { + t.Fatalf("MarshalJSON nil failed: %v", err) + } + if string(data) != "null" { + t.Fatalf("expected null, got %s", data) + } + + var decoded ByteSorted + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON nil failed: %v", err) + } + if decoded != nil { + t.Fatal("expected nil, got non-nil") + } +} + +func TestByteSorted_JSONEmpty(t *testing.T) { + set := make(ByteSorted) + + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON empty failed: %v", err) + } + if string(data) != "[]" { + t.Fatalf("expected [], got %s", data) + } + + var decoded ByteSorted + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON empty failed: %v", err) + } + if len(decoded) != 0 { + t.Fatalf("expected empty set, got length %d", len(decoded)) + } +} + func BenchmarkByte_EncodeMsg(b *testing.B) { sizes := []int{10, 100, 1000} @@ -2513,6 +3484,53 @@ func BenchmarkByte_FromSlice(b *testing.B) { } } +func BenchmarkByte_MarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(Byte) + for i := 0; i < size; i++ { + set[byte(i%256)] = struct{}{} + } + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := json.Marshal(set) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + +func BenchmarkByte_UnmarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(Byte) + for i := 0; i < size; i++ { + set[byte(i%256)] = struct{}{} + } + + data, _ := json.Marshal(set) + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + var decoded Byte + err := json.Unmarshal(data, &decoded) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + func BenchmarkByteSorted_EncodeMsg(b *testing.B) { sizes := []int{10, 100, 1000} @@ -2650,6 +3668,53 @@ func BenchmarkByteSorted_FromSlice(b *testing.B) { } } +func BenchmarkByteSorted_MarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(ByteSorted) + for i := 0; i < size; i++ { + set[byte(i%256)] = struct{}{} + } + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := json.Marshal(set) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + +func BenchmarkByteSorted_UnmarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(ByteSorted) + for i := 0; i < size; i++ { + set[byte(i%256)] = struct{}{} + } + + data, _ := json.Marshal(set) + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + var decoded ByteSorted + err := json.Unmarshal(data, &decoded) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + func TestInt8_RoundTrip(t *testing.T) { set := make(Int8) set[-128] = struct{}{} @@ -2843,28 +3908,37 @@ func TestInt8_EmptySet(t *testing.T) { } } -func TestInt8Sorted_RoundTrip(t *testing.T) { - set := make(Int8Sorted) +func TestInt8_JSONRoundTrip(t *testing.T) { + set := make(Int8) set[-128] = struct{}{} set[-127] = struct{}{} set[-126] = struct{}{} set[-125] = struct{}{} set[-124] = struct{}{} - // Test EncodeMsg/DecodeMsg - var buf bytes.Buffer - writer := msgp.NewWriter(&buf) - err := set.EncodeMsg(writer) + data, err := json.Marshal(set) if err != nil { - t.Fatalf("EncodeMsg failed: %v", err) + t.Fatalf("MarshalJSON failed: %v", err) } - writer.Flush() - reader := msgp.NewReader(&buf) - var decoded Int8Sorted - err = decoded.DecodeMsg(reader) + // Verify JSON is an array + if len(data) == 0 || data[0] != '[' || data[len(data)-1] != ']' { + t.Fatalf("expected JSON array, got: %s", data) + } + + // Verify it unmarshals as a generic JSON array + var arr []json.RawMessage + if err := json.Unmarshal(data, &arr); err != nil { + t.Fatalf("JSON is not a valid array: %v", err) + } + if len(arr) != len(set) { + t.Fatalf("JSON array length mismatch: expected %d, got %d", len(set), len(arr)) + } + + var decoded Int8 + err = json.Unmarshal(data, &decoded) if err != nil { - t.Fatalf("DecodeMsg failed: %v", err) + t.Fatalf("UnmarshalJSON failed: %v", err) } if len(set) != len(decoded) { @@ -2876,31 +3950,51 @@ func TestInt8Sorted_RoundTrip(t *testing.T) { t.Fatalf("missing key: %v", k) } } +} - // Test MarshalMsg/UnmarshalMsg - data, err := set.MarshalMsg(nil) +func TestInt8_JSONNil(t *testing.T) { + var nilSet Int8 + + data, err := json.Marshal(nilSet) if err != nil { - t.Fatalf("MarshalMsg failed: %v", err) + t.Fatalf("MarshalJSON nil failed: %v", err) + } + if string(data) != "null" { + t.Fatalf("expected null, got %s", data) } - var unmarshaled Int8Sorted - _, err = unmarshaled.UnmarshalMsg(data) + var decoded Int8 + err = json.Unmarshal(data, &decoded) if err != nil { - t.Fatalf("UnmarshalMsg failed: %v", err) + t.Fatalf("UnmarshalJSON nil failed: %v", err) + } + if decoded != nil { + t.Fatal("expected nil, got non-nil") } +} - if len(set) != len(unmarshaled) { - t.Fatalf("length mismatch: expected %d, got %d", len(set), len(unmarshaled)) +func TestInt8_JSONEmpty(t *testing.T) { + set := make(Int8) + + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON empty failed: %v", err) + } + if string(data) != "[]" { + t.Fatalf("expected [], got %s", data) } - for k := range set { - if _, ok := unmarshaled[k]; !ok { - t.Fatalf("missing key: %v", k) - } + var decoded Int8 + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON empty failed: %v", err) + } + if len(decoded) != 0 { + t.Fatalf("expected empty set, got length %d", len(decoded)) } } -func TestInt8Sorted_AsSlice(t *testing.T) { +func TestInt8Sorted_RoundTrip(t *testing.T) { set := make(Int8Sorted) set[-128] = struct{}{} set[-127] = struct{}{} @@ -2908,7 +4002,64 @@ func TestInt8Sorted_AsSlice(t *testing.T) { set[-125] = struct{}{} set[-124] = struct{}{} - slice := set.AsSlice() + // Test EncodeMsg/DecodeMsg + var buf bytes.Buffer + writer := msgp.NewWriter(&buf) + err := set.EncodeMsg(writer) + if err != nil { + t.Fatalf("EncodeMsg failed: %v", err) + } + writer.Flush() + + reader := msgp.NewReader(&buf) + var decoded Int8Sorted + err = decoded.DecodeMsg(reader) + if err != nil { + t.Fatalf("DecodeMsg failed: %v", err) + } + + if len(set) != len(decoded) { + t.Fatalf("length mismatch: expected %d, got %d", len(set), len(decoded)) + } + + for k := range set { + if _, ok := decoded[k]; !ok { + t.Fatalf("missing key: %v", k) + } + } + + // Test MarshalMsg/UnmarshalMsg + data, err := set.MarshalMsg(nil) + if err != nil { + t.Fatalf("MarshalMsg failed: %v", err) + } + + var unmarshaled Int8Sorted + _, err = unmarshaled.UnmarshalMsg(data) + if err != nil { + t.Fatalf("UnmarshalMsg failed: %v", err) + } + + if len(set) != len(unmarshaled) { + t.Fatalf("length mismatch: expected %d, got %d", len(set), len(unmarshaled)) + } + + for k := range set { + if _, ok := unmarshaled[k]; !ok { + t.Fatalf("missing key: %v", k) + } + } +} + +func TestInt8Sorted_AsSlice(t *testing.T) { + set := make(Int8Sorted) + set[-128] = struct{}{} + set[-127] = struct{}{} + set[-126] = struct{}{} + set[-125] = struct{}{} + set[-124] = struct{}{} + + slice := set.AsSlice() if len(slice) != len(set) { t.Fatalf("length mismatch: expected %d, got %d", len(set), len(slice)) } @@ -3036,6 +4187,92 @@ func TestInt8Sorted_EmptySet(t *testing.T) { } } +func TestInt8Sorted_JSONRoundTrip(t *testing.T) { + set := make(Int8Sorted) + set[-128] = struct{}{} + set[-127] = struct{}{} + set[-126] = struct{}{} + set[-125] = struct{}{} + set[-124] = struct{}{} + + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON failed: %v", err) + } + + // Verify JSON is an array + if len(data) == 0 || data[0] != '[' || data[len(data)-1] != ']' { + t.Fatalf("expected JSON array, got: %s", data) + } + + // Verify it unmarshals as a generic JSON array + var arr []json.RawMessage + if err := json.Unmarshal(data, &arr); err != nil { + t.Fatalf("JSON is not a valid array: %v", err) + } + if len(arr) != len(set) { + t.Fatalf("JSON array length mismatch: expected %d, got %d", len(set), len(arr)) + } + + var decoded Int8Sorted + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON failed: %v", err) + } + + if len(set) != len(decoded) { + t.Fatalf("length mismatch: expected %d, got %d", len(set), len(decoded)) + } + + for k := range set { + if _, ok := decoded[k]; !ok { + t.Fatalf("missing key: %v", k) + } + } +} + +func TestInt8Sorted_JSONNil(t *testing.T) { + var nilSet Int8Sorted + + data, err := json.Marshal(nilSet) + if err != nil { + t.Fatalf("MarshalJSON nil failed: %v", err) + } + if string(data) != "null" { + t.Fatalf("expected null, got %s", data) + } + + var decoded Int8Sorted + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON nil failed: %v", err) + } + if decoded != nil { + t.Fatal("expected nil, got non-nil") + } +} + +func TestInt8Sorted_JSONEmpty(t *testing.T) { + set := make(Int8Sorted) + + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON empty failed: %v", err) + } + if string(data) != "[]" { + t.Fatalf("expected [], got %s", data) + } + + var decoded Int8Sorted + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON empty failed: %v", err) + } + if len(decoded) != 0 { + t.Fatalf("expected empty set, got length %d", len(decoded)) + } +} + func BenchmarkInt8_EncodeMsg(b *testing.B) { sizes := []int{10, 100, 1000} @@ -3173,6 +4410,53 @@ func BenchmarkInt8_FromSlice(b *testing.B) { } } +func BenchmarkInt8_MarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(Int8) + for i := 0; i < size; i++ { + set[int8((i%256)-128)] = struct{}{} + } + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := json.Marshal(set) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + +func BenchmarkInt8_UnmarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(Int8) + for i := 0; i < size; i++ { + set[int8((i%256)-128)] = struct{}{} + } + + data, _ := json.Marshal(set) + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + var decoded Int8 + err := json.Unmarshal(data, &decoded) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + func BenchmarkInt8Sorted_EncodeMsg(b *testing.B) { sizes := []int{10, 100, 1000} @@ -3310,6 +4594,53 @@ func BenchmarkInt8Sorted_FromSlice(b *testing.B) { } } +func BenchmarkInt8Sorted_MarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(Int8Sorted) + for i := 0; i < size; i++ { + set[int8((i%256)-128)] = struct{}{} + } + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := json.Marshal(set) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + +func BenchmarkInt8Sorted_UnmarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(Int8Sorted) + for i := 0; i < size; i++ { + set[int8((i%256)-128)] = struct{}{} + } + + data, _ := json.Marshal(set) + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + var decoded Int8Sorted + err := json.Unmarshal(data, &decoded) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + func TestUint8_RoundTrip(t *testing.T) { set := make(Uint8) set[0] = struct{}{} @@ -3503,28 +4834,37 @@ func TestUint8_EmptySet(t *testing.T) { } } -func TestUint8Sorted_RoundTrip(t *testing.T) { - set := make(Uint8Sorted) +func TestUint8_JSONRoundTrip(t *testing.T) { + set := make(Uint8) set[0] = struct{}{} set[1] = struct{}{} set[2] = struct{}{} set[3] = struct{}{} set[4] = struct{}{} - // Test EncodeMsg/DecodeMsg - var buf bytes.Buffer - writer := msgp.NewWriter(&buf) - err := set.EncodeMsg(writer) + data, err := json.Marshal(set) if err != nil { - t.Fatalf("EncodeMsg failed: %v", err) + t.Fatalf("MarshalJSON failed: %v", err) } - writer.Flush() - reader := msgp.NewReader(&buf) - var decoded Uint8Sorted - err = decoded.DecodeMsg(reader) + // Verify JSON is an array + if len(data) == 0 || data[0] != '[' || data[len(data)-1] != ']' { + t.Fatalf("expected JSON array, got: %s", data) + } + + // Verify it unmarshals as a generic JSON array + var arr []json.RawMessage + if err := json.Unmarshal(data, &arr); err != nil { + t.Fatalf("JSON is not a valid array: %v", err) + } + if len(arr) != len(set) { + t.Fatalf("JSON array length mismatch: expected %d, got %d", len(set), len(arr)) + } + + var decoded Uint8 + err = json.Unmarshal(data, &decoded) if err != nil { - t.Fatalf("DecodeMsg failed: %v", err) + t.Fatalf("UnmarshalJSON failed: %v", err) } if len(set) != len(decoded) { @@ -3536,31 +4876,51 @@ func TestUint8Sorted_RoundTrip(t *testing.T) { t.Fatalf("missing key: %v", k) } } +} - // Test MarshalMsg/UnmarshalMsg - data, err := set.MarshalMsg(nil) +func TestUint8_JSONNil(t *testing.T) { + var nilSet Uint8 + + data, err := json.Marshal(nilSet) if err != nil { - t.Fatalf("MarshalMsg failed: %v", err) + t.Fatalf("MarshalJSON nil failed: %v", err) + } + if string(data) != "null" { + t.Fatalf("expected null, got %s", data) } - var unmarshaled Uint8Sorted - _, err = unmarshaled.UnmarshalMsg(data) + var decoded Uint8 + err = json.Unmarshal(data, &decoded) if err != nil { - t.Fatalf("UnmarshalMsg failed: %v", err) + t.Fatalf("UnmarshalJSON nil failed: %v", err) + } + if decoded != nil { + t.Fatal("expected nil, got non-nil") } +} - if len(set) != len(unmarshaled) { - t.Fatalf("length mismatch: expected %d, got %d", len(set), len(unmarshaled)) +func TestUint8_JSONEmpty(t *testing.T) { + set := make(Uint8) + + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON empty failed: %v", err) + } + if string(data) != "[]" { + t.Fatalf("expected [], got %s", data) } - for k := range set { - if _, ok := unmarshaled[k]; !ok { - t.Fatalf("missing key: %v", k) - } + var decoded Uint8 + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON empty failed: %v", err) + } + if len(decoded) != 0 { + t.Fatalf("expected empty set, got length %d", len(decoded)) } } -func TestUint8Sorted_AsSlice(t *testing.T) { +func TestUint8Sorted_RoundTrip(t *testing.T) { set := make(Uint8Sorted) set[0] = struct{}{} set[1] = struct{}{} @@ -3568,11 +4928,68 @@ func TestUint8Sorted_AsSlice(t *testing.T) { set[3] = struct{}{} set[4] = struct{}{} - slice := set.AsSlice() - if len(slice) != len(set) { - t.Fatalf("length mismatch: expected %d, got %d", len(set), len(slice)) - } - + // Test EncodeMsg/DecodeMsg + var buf bytes.Buffer + writer := msgp.NewWriter(&buf) + err := set.EncodeMsg(writer) + if err != nil { + t.Fatalf("EncodeMsg failed: %v", err) + } + writer.Flush() + + reader := msgp.NewReader(&buf) + var decoded Uint8Sorted + err = decoded.DecodeMsg(reader) + if err != nil { + t.Fatalf("DecodeMsg failed: %v", err) + } + + if len(set) != len(decoded) { + t.Fatalf("length mismatch: expected %d, got %d", len(set), len(decoded)) + } + + for k := range set { + if _, ok := decoded[k]; !ok { + t.Fatalf("missing key: %v", k) + } + } + + // Test MarshalMsg/UnmarshalMsg + data, err := set.MarshalMsg(nil) + if err != nil { + t.Fatalf("MarshalMsg failed: %v", err) + } + + var unmarshaled Uint8Sorted + _, err = unmarshaled.UnmarshalMsg(data) + if err != nil { + t.Fatalf("UnmarshalMsg failed: %v", err) + } + + if len(set) != len(unmarshaled) { + t.Fatalf("length mismatch: expected %d, got %d", len(set), len(unmarshaled)) + } + + for k := range set { + if _, ok := unmarshaled[k]; !ok { + t.Fatalf("missing key: %v", k) + } + } +} + +func TestUint8Sorted_AsSlice(t *testing.T) { + set := make(Uint8Sorted) + set[0] = struct{}{} + set[1] = struct{}{} + set[2] = struct{}{} + set[3] = struct{}{} + set[4] = struct{}{} + + slice := set.AsSlice() + if len(slice) != len(set) { + t.Fatalf("length mismatch: expected %d, got %d", len(set), len(slice)) + } + found := make(map[uint8]bool) for _, v := range slice { found[v] = true @@ -3696,6 +5113,92 @@ func TestUint8Sorted_EmptySet(t *testing.T) { } } +func TestUint8Sorted_JSONRoundTrip(t *testing.T) { + set := make(Uint8Sorted) + set[0] = struct{}{} + set[1] = struct{}{} + set[2] = struct{}{} + set[3] = struct{}{} + set[4] = struct{}{} + + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON failed: %v", err) + } + + // Verify JSON is an array + if len(data) == 0 || data[0] != '[' || data[len(data)-1] != ']' { + t.Fatalf("expected JSON array, got: %s", data) + } + + // Verify it unmarshals as a generic JSON array + var arr []json.RawMessage + if err := json.Unmarshal(data, &arr); err != nil { + t.Fatalf("JSON is not a valid array: %v", err) + } + if len(arr) != len(set) { + t.Fatalf("JSON array length mismatch: expected %d, got %d", len(set), len(arr)) + } + + var decoded Uint8Sorted + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON failed: %v", err) + } + + if len(set) != len(decoded) { + t.Fatalf("length mismatch: expected %d, got %d", len(set), len(decoded)) + } + + for k := range set { + if _, ok := decoded[k]; !ok { + t.Fatalf("missing key: %v", k) + } + } +} + +func TestUint8Sorted_JSONNil(t *testing.T) { + var nilSet Uint8Sorted + + data, err := json.Marshal(nilSet) + if err != nil { + t.Fatalf("MarshalJSON nil failed: %v", err) + } + if string(data) != "null" { + t.Fatalf("expected null, got %s", data) + } + + var decoded Uint8Sorted + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON nil failed: %v", err) + } + if decoded != nil { + t.Fatal("expected nil, got non-nil") + } +} + +func TestUint8Sorted_JSONEmpty(t *testing.T) { + set := make(Uint8Sorted) + + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON empty failed: %v", err) + } + if string(data) != "[]" { + t.Fatalf("expected [], got %s", data) + } + + var decoded Uint8Sorted + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON empty failed: %v", err) + } + if len(decoded) != 0 { + t.Fatalf("expected empty set, got length %d", len(decoded)) + } +} + func BenchmarkUint8_EncodeMsg(b *testing.B) { sizes := []int{10, 100, 1000} @@ -3833,6 +5336,53 @@ func BenchmarkUint8_FromSlice(b *testing.B) { } } +func BenchmarkUint8_MarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(Uint8) + for i := 0; i < size; i++ { + set[uint8(i%256)] = struct{}{} + } + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := json.Marshal(set) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + +func BenchmarkUint8_UnmarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(Uint8) + for i := 0; i < size; i++ { + set[uint8(i%256)] = struct{}{} + } + + data, _ := json.Marshal(set) + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + var decoded Uint8 + err := json.Unmarshal(data, &decoded) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + func BenchmarkUint8Sorted_EncodeMsg(b *testing.B) { sizes := []int{10, 100, 1000} @@ -3970,6 +5520,53 @@ func BenchmarkUint8Sorted_FromSlice(b *testing.B) { } } +func BenchmarkUint8Sorted_MarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(Uint8Sorted) + for i := 0; i < size; i++ { + set[uint8(i%256)] = struct{}{} + } + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := json.Marshal(set) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + +func BenchmarkUint8Sorted_UnmarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(Uint8Sorted) + for i := 0; i < size; i++ { + set[uint8(i%256)] = struct{}{} + } + + data, _ := json.Marshal(set) + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + var decoded Uint8Sorted + err := json.Unmarshal(data, &decoded) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + func TestInt16_RoundTrip(t *testing.T) { set := make(Int16) set[-32768] = struct{}{} @@ -4163,28 +5760,37 @@ func TestInt16_EmptySet(t *testing.T) { } } -func TestInt16Sorted_RoundTrip(t *testing.T) { - set := make(Int16Sorted) +func TestInt16_JSONRoundTrip(t *testing.T) { + set := make(Int16) set[-32768] = struct{}{} set[-32767] = struct{}{} set[-32766] = struct{}{} set[-32765] = struct{}{} set[-32764] = struct{}{} - // Test EncodeMsg/DecodeMsg - var buf bytes.Buffer - writer := msgp.NewWriter(&buf) - err := set.EncodeMsg(writer) + data, err := json.Marshal(set) if err != nil { - t.Fatalf("EncodeMsg failed: %v", err) + t.Fatalf("MarshalJSON failed: %v", err) } - writer.Flush() - reader := msgp.NewReader(&buf) - var decoded Int16Sorted - err = decoded.DecodeMsg(reader) + // Verify JSON is an array + if len(data) == 0 || data[0] != '[' || data[len(data)-1] != ']' { + t.Fatalf("expected JSON array, got: %s", data) + } + + // Verify it unmarshals as a generic JSON array + var arr []json.RawMessage + if err := json.Unmarshal(data, &arr); err != nil { + t.Fatalf("JSON is not a valid array: %v", err) + } + if len(arr) != len(set) { + t.Fatalf("JSON array length mismatch: expected %d, got %d", len(set), len(arr)) + } + + var decoded Int16 + err = json.Unmarshal(data, &decoded) if err != nil { - t.Fatalf("DecodeMsg failed: %v", err) + t.Fatalf("UnmarshalJSON failed: %v", err) } if len(set) != len(decoded) { @@ -4196,31 +5802,51 @@ func TestInt16Sorted_RoundTrip(t *testing.T) { t.Fatalf("missing key: %v", k) } } +} - // Test MarshalMsg/UnmarshalMsg - data, err := set.MarshalMsg(nil) +func TestInt16_JSONNil(t *testing.T) { + var nilSet Int16 + + data, err := json.Marshal(nilSet) if err != nil { - t.Fatalf("MarshalMsg failed: %v", err) + t.Fatalf("MarshalJSON nil failed: %v", err) + } + if string(data) != "null" { + t.Fatalf("expected null, got %s", data) } - var unmarshaled Int16Sorted - _, err = unmarshaled.UnmarshalMsg(data) + var decoded Int16 + err = json.Unmarshal(data, &decoded) if err != nil { - t.Fatalf("UnmarshalMsg failed: %v", err) + t.Fatalf("UnmarshalJSON nil failed: %v", err) + } + if decoded != nil { + t.Fatal("expected nil, got non-nil") } +} - if len(set) != len(unmarshaled) { - t.Fatalf("length mismatch: expected %d, got %d", len(set), len(unmarshaled)) +func TestInt16_JSONEmpty(t *testing.T) { + set := make(Int16) + + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON empty failed: %v", err) + } + if string(data) != "[]" { + t.Fatalf("expected [], got %s", data) } - for k := range set { - if _, ok := unmarshaled[k]; !ok { - t.Fatalf("missing key: %v", k) - } + var decoded Int16 + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON empty failed: %v", err) + } + if len(decoded) != 0 { + t.Fatalf("expected empty set, got length %d", len(decoded)) } } -func TestInt16Sorted_AsSlice(t *testing.T) { +func TestInt16Sorted_RoundTrip(t *testing.T) { set := make(Int16Sorted) set[-32768] = struct{}{} set[-32767] = struct{}{} @@ -4228,7 +5854,64 @@ func TestInt16Sorted_AsSlice(t *testing.T) { set[-32765] = struct{}{} set[-32764] = struct{}{} - slice := set.AsSlice() + // Test EncodeMsg/DecodeMsg + var buf bytes.Buffer + writer := msgp.NewWriter(&buf) + err := set.EncodeMsg(writer) + if err != nil { + t.Fatalf("EncodeMsg failed: %v", err) + } + writer.Flush() + + reader := msgp.NewReader(&buf) + var decoded Int16Sorted + err = decoded.DecodeMsg(reader) + if err != nil { + t.Fatalf("DecodeMsg failed: %v", err) + } + + if len(set) != len(decoded) { + t.Fatalf("length mismatch: expected %d, got %d", len(set), len(decoded)) + } + + for k := range set { + if _, ok := decoded[k]; !ok { + t.Fatalf("missing key: %v", k) + } + } + + // Test MarshalMsg/UnmarshalMsg + data, err := set.MarshalMsg(nil) + if err != nil { + t.Fatalf("MarshalMsg failed: %v", err) + } + + var unmarshaled Int16Sorted + _, err = unmarshaled.UnmarshalMsg(data) + if err != nil { + t.Fatalf("UnmarshalMsg failed: %v", err) + } + + if len(set) != len(unmarshaled) { + t.Fatalf("length mismatch: expected %d, got %d", len(set), len(unmarshaled)) + } + + for k := range set { + if _, ok := unmarshaled[k]; !ok { + t.Fatalf("missing key: %v", k) + } + } +} + +func TestInt16Sorted_AsSlice(t *testing.T) { + set := make(Int16Sorted) + set[-32768] = struct{}{} + set[-32767] = struct{}{} + set[-32766] = struct{}{} + set[-32765] = struct{}{} + set[-32764] = struct{}{} + + slice := set.AsSlice() if len(slice) != len(set) { t.Fatalf("length mismatch: expected %d, got %d", len(set), len(slice)) } @@ -4356,6 +6039,92 @@ func TestInt16Sorted_EmptySet(t *testing.T) { } } +func TestInt16Sorted_JSONRoundTrip(t *testing.T) { + set := make(Int16Sorted) + set[-32768] = struct{}{} + set[-32767] = struct{}{} + set[-32766] = struct{}{} + set[-32765] = struct{}{} + set[-32764] = struct{}{} + + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON failed: %v", err) + } + + // Verify JSON is an array + if len(data) == 0 || data[0] != '[' || data[len(data)-1] != ']' { + t.Fatalf("expected JSON array, got: %s", data) + } + + // Verify it unmarshals as a generic JSON array + var arr []json.RawMessage + if err := json.Unmarshal(data, &arr); err != nil { + t.Fatalf("JSON is not a valid array: %v", err) + } + if len(arr) != len(set) { + t.Fatalf("JSON array length mismatch: expected %d, got %d", len(set), len(arr)) + } + + var decoded Int16Sorted + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON failed: %v", err) + } + + if len(set) != len(decoded) { + t.Fatalf("length mismatch: expected %d, got %d", len(set), len(decoded)) + } + + for k := range set { + if _, ok := decoded[k]; !ok { + t.Fatalf("missing key: %v", k) + } + } +} + +func TestInt16Sorted_JSONNil(t *testing.T) { + var nilSet Int16Sorted + + data, err := json.Marshal(nilSet) + if err != nil { + t.Fatalf("MarshalJSON nil failed: %v", err) + } + if string(data) != "null" { + t.Fatalf("expected null, got %s", data) + } + + var decoded Int16Sorted + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON nil failed: %v", err) + } + if decoded != nil { + t.Fatal("expected nil, got non-nil") + } +} + +func TestInt16Sorted_JSONEmpty(t *testing.T) { + set := make(Int16Sorted) + + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON empty failed: %v", err) + } + if string(data) != "[]" { + t.Fatalf("expected [], got %s", data) + } + + var decoded Int16Sorted + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON empty failed: %v", err) + } + if len(decoded) != 0 { + t.Fatalf("expected empty set, got length %d", len(decoded)) + } +} + func BenchmarkInt16_EncodeMsg(b *testing.B) { sizes := []int{10, 100, 1000} @@ -4493,6 +6262,53 @@ func BenchmarkInt16_FromSlice(b *testing.B) { } } +func BenchmarkInt16_MarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(Int16) + for i := 0; i < size; i++ { + set[int16((i%65536)-32768)] = struct{}{} + } + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := json.Marshal(set) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + +func BenchmarkInt16_UnmarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(Int16) + for i := 0; i < size; i++ { + set[int16((i%65536)-32768)] = struct{}{} + } + + data, _ := json.Marshal(set) + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + var decoded Int16 + err := json.Unmarshal(data, &decoded) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + func BenchmarkInt16Sorted_EncodeMsg(b *testing.B) { sizes := []int{10, 100, 1000} @@ -4630,6 +6446,53 @@ func BenchmarkInt16Sorted_FromSlice(b *testing.B) { } } +func BenchmarkInt16Sorted_MarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(Int16Sorted) + for i := 0; i < size; i++ { + set[int16((i%65536)-32768)] = struct{}{} + } + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := json.Marshal(set) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + +func BenchmarkInt16Sorted_UnmarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(Int16Sorted) + for i := 0; i < size; i++ { + set[int16((i%65536)-32768)] = struct{}{} + } + + data, _ := json.Marshal(set) + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + var decoded Int16Sorted + err := json.Unmarshal(data, &decoded) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + func TestUint16_RoundTrip(t *testing.T) { set := make(Uint16) set[0] = struct{}{} @@ -4823,28 +6686,37 @@ func TestUint16_EmptySet(t *testing.T) { } } -func TestUint16Sorted_RoundTrip(t *testing.T) { - set := make(Uint16Sorted) +func TestUint16_JSONRoundTrip(t *testing.T) { + set := make(Uint16) set[0] = struct{}{} set[1] = struct{}{} set[2] = struct{}{} set[3] = struct{}{} set[4] = struct{}{} - // Test EncodeMsg/DecodeMsg - var buf bytes.Buffer - writer := msgp.NewWriter(&buf) - err := set.EncodeMsg(writer) + data, err := json.Marshal(set) if err != nil { - t.Fatalf("EncodeMsg failed: %v", err) + t.Fatalf("MarshalJSON failed: %v", err) } - writer.Flush() - reader := msgp.NewReader(&buf) - var decoded Uint16Sorted - err = decoded.DecodeMsg(reader) + // Verify JSON is an array + if len(data) == 0 || data[0] != '[' || data[len(data)-1] != ']' { + t.Fatalf("expected JSON array, got: %s", data) + } + + // Verify it unmarshals as a generic JSON array + var arr []json.RawMessage + if err := json.Unmarshal(data, &arr); err != nil { + t.Fatalf("JSON is not a valid array: %v", err) + } + if len(arr) != len(set) { + t.Fatalf("JSON array length mismatch: expected %d, got %d", len(set), len(arr)) + } + + var decoded Uint16 + err = json.Unmarshal(data, &decoded) if err != nil { - t.Fatalf("DecodeMsg failed: %v", err) + t.Fatalf("UnmarshalJSON failed: %v", err) } if len(set) != len(decoded) { @@ -4856,31 +6728,51 @@ func TestUint16Sorted_RoundTrip(t *testing.T) { t.Fatalf("missing key: %v", k) } } +} - // Test MarshalMsg/UnmarshalMsg - data, err := set.MarshalMsg(nil) +func TestUint16_JSONNil(t *testing.T) { + var nilSet Uint16 + + data, err := json.Marshal(nilSet) if err != nil { - t.Fatalf("MarshalMsg failed: %v", err) + t.Fatalf("MarshalJSON nil failed: %v", err) + } + if string(data) != "null" { + t.Fatalf("expected null, got %s", data) } - var unmarshaled Uint16Sorted - _, err = unmarshaled.UnmarshalMsg(data) + var decoded Uint16 + err = json.Unmarshal(data, &decoded) if err != nil { - t.Fatalf("UnmarshalMsg failed: %v", err) + t.Fatalf("UnmarshalJSON nil failed: %v", err) + } + if decoded != nil { + t.Fatal("expected nil, got non-nil") } +} - if len(set) != len(unmarshaled) { - t.Fatalf("length mismatch: expected %d, got %d", len(set), len(unmarshaled)) +func TestUint16_JSONEmpty(t *testing.T) { + set := make(Uint16) + + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON empty failed: %v", err) + } + if string(data) != "[]" { + t.Fatalf("expected [], got %s", data) } - for k := range set { - if _, ok := unmarshaled[k]; !ok { - t.Fatalf("missing key: %v", k) - } + var decoded Uint16 + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON empty failed: %v", err) + } + if len(decoded) != 0 { + t.Fatalf("expected empty set, got length %d", len(decoded)) } } -func TestUint16Sorted_AsSlice(t *testing.T) { +func TestUint16Sorted_RoundTrip(t *testing.T) { set := make(Uint16Sorted) set[0] = struct{}{} set[1] = struct{}{} @@ -4888,11 +6780,68 @@ func TestUint16Sorted_AsSlice(t *testing.T) { set[3] = struct{}{} set[4] = struct{}{} - slice := set.AsSlice() - if len(slice) != len(set) { - t.Fatalf("length mismatch: expected %d, got %d", len(set), len(slice)) - } - + // Test EncodeMsg/DecodeMsg + var buf bytes.Buffer + writer := msgp.NewWriter(&buf) + err := set.EncodeMsg(writer) + if err != nil { + t.Fatalf("EncodeMsg failed: %v", err) + } + writer.Flush() + + reader := msgp.NewReader(&buf) + var decoded Uint16Sorted + err = decoded.DecodeMsg(reader) + if err != nil { + t.Fatalf("DecodeMsg failed: %v", err) + } + + if len(set) != len(decoded) { + t.Fatalf("length mismatch: expected %d, got %d", len(set), len(decoded)) + } + + for k := range set { + if _, ok := decoded[k]; !ok { + t.Fatalf("missing key: %v", k) + } + } + + // Test MarshalMsg/UnmarshalMsg + data, err := set.MarshalMsg(nil) + if err != nil { + t.Fatalf("MarshalMsg failed: %v", err) + } + + var unmarshaled Uint16Sorted + _, err = unmarshaled.UnmarshalMsg(data) + if err != nil { + t.Fatalf("UnmarshalMsg failed: %v", err) + } + + if len(set) != len(unmarshaled) { + t.Fatalf("length mismatch: expected %d, got %d", len(set), len(unmarshaled)) + } + + for k := range set { + if _, ok := unmarshaled[k]; !ok { + t.Fatalf("missing key: %v", k) + } + } +} + +func TestUint16Sorted_AsSlice(t *testing.T) { + set := make(Uint16Sorted) + set[0] = struct{}{} + set[1] = struct{}{} + set[2] = struct{}{} + set[3] = struct{}{} + set[4] = struct{}{} + + slice := set.AsSlice() + if len(slice) != len(set) { + t.Fatalf("length mismatch: expected %d, got %d", len(set), len(slice)) + } + found := make(map[uint16]bool) for _, v := range slice { found[v] = true @@ -5016,6 +6965,92 @@ func TestUint16Sorted_EmptySet(t *testing.T) { } } +func TestUint16Sorted_JSONRoundTrip(t *testing.T) { + set := make(Uint16Sorted) + set[0] = struct{}{} + set[1] = struct{}{} + set[2] = struct{}{} + set[3] = struct{}{} + set[4] = struct{}{} + + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON failed: %v", err) + } + + // Verify JSON is an array + if len(data) == 0 || data[0] != '[' || data[len(data)-1] != ']' { + t.Fatalf("expected JSON array, got: %s", data) + } + + // Verify it unmarshals as a generic JSON array + var arr []json.RawMessage + if err := json.Unmarshal(data, &arr); err != nil { + t.Fatalf("JSON is not a valid array: %v", err) + } + if len(arr) != len(set) { + t.Fatalf("JSON array length mismatch: expected %d, got %d", len(set), len(arr)) + } + + var decoded Uint16Sorted + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON failed: %v", err) + } + + if len(set) != len(decoded) { + t.Fatalf("length mismatch: expected %d, got %d", len(set), len(decoded)) + } + + for k := range set { + if _, ok := decoded[k]; !ok { + t.Fatalf("missing key: %v", k) + } + } +} + +func TestUint16Sorted_JSONNil(t *testing.T) { + var nilSet Uint16Sorted + + data, err := json.Marshal(nilSet) + if err != nil { + t.Fatalf("MarshalJSON nil failed: %v", err) + } + if string(data) != "null" { + t.Fatalf("expected null, got %s", data) + } + + var decoded Uint16Sorted + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON nil failed: %v", err) + } + if decoded != nil { + t.Fatal("expected nil, got non-nil") + } +} + +func TestUint16Sorted_JSONEmpty(t *testing.T) { + set := make(Uint16Sorted) + + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON empty failed: %v", err) + } + if string(data) != "[]" { + t.Fatalf("expected [], got %s", data) + } + + var decoded Uint16Sorted + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON empty failed: %v", err) + } + if len(decoded) != 0 { + t.Fatalf("expected empty set, got length %d", len(decoded)) + } +} + func BenchmarkUint16_EncodeMsg(b *testing.B) { sizes := []int{10, 100, 1000} @@ -5153,6 +7188,53 @@ func BenchmarkUint16_FromSlice(b *testing.B) { } } +func BenchmarkUint16_MarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(Uint16) + for i := 0; i < size; i++ { + set[uint16(i%65536)] = struct{}{} + } + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := json.Marshal(set) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + +func BenchmarkUint16_UnmarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(Uint16) + for i := 0; i < size; i++ { + set[uint16(i%65536)] = struct{}{} + } + + data, _ := json.Marshal(set) + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + var decoded Uint16 + err := json.Unmarshal(data, &decoded) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + func BenchmarkUint16Sorted_EncodeMsg(b *testing.B) { sizes := []int{10, 100, 1000} @@ -5290,6 +7372,53 @@ func BenchmarkUint16Sorted_FromSlice(b *testing.B) { } } +func BenchmarkUint16Sorted_MarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(Uint16Sorted) + for i := 0; i < size; i++ { + set[uint16(i%65536)] = struct{}{} + } + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := json.Marshal(set) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + +func BenchmarkUint16Sorted_UnmarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(Uint16Sorted) + for i := 0; i < size; i++ { + set[uint16(i%65536)] = struct{}{} + } + + data, _ := json.Marshal(set) + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + var decoded Uint16Sorted + err := json.Unmarshal(data, &decoded) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + func TestInt32_RoundTrip(t *testing.T) { set := make(Int32) set[0] = struct{}{} @@ -5483,28 +7612,37 @@ func TestInt32_EmptySet(t *testing.T) { } } -func TestInt32Sorted_RoundTrip(t *testing.T) { - set := make(Int32Sorted) +func TestInt32_JSONRoundTrip(t *testing.T) { + set := make(Int32) set[0] = struct{}{} set[1] = struct{}{} set[2] = struct{}{} set[3] = struct{}{} set[4] = struct{}{} - // Test EncodeMsg/DecodeMsg - var buf bytes.Buffer - writer := msgp.NewWriter(&buf) - err := set.EncodeMsg(writer) + data, err := json.Marshal(set) if err != nil { - t.Fatalf("EncodeMsg failed: %v", err) + t.Fatalf("MarshalJSON failed: %v", err) } - writer.Flush() - reader := msgp.NewReader(&buf) - var decoded Int32Sorted - err = decoded.DecodeMsg(reader) + // Verify JSON is an array + if len(data) == 0 || data[0] != '[' || data[len(data)-1] != ']' { + t.Fatalf("expected JSON array, got: %s", data) + } + + // Verify it unmarshals as a generic JSON array + var arr []json.RawMessage + if err := json.Unmarshal(data, &arr); err != nil { + t.Fatalf("JSON is not a valid array: %v", err) + } + if len(arr) != len(set) { + t.Fatalf("JSON array length mismatch: expected %d, got %d", len(set), len(arr)) + } + + var decoded Int32 + err = json.Unmarshal(data, &decoded) if err != nil { - t.Fatalf("DecodeMsg failed: %v", err) + t.Fatalf("UnmarshalJSON failed: %v", err) } if len(set) != len(decoded) { @@ -5516,31 +7654,51 @@ func TestInt32Sorted_RoundTrip(t *testing.T) { t.Fatalf("missing key: %v", k) } } +} - // Test MarshalMsg/UnmarshalMsg - data, err := set.MarshalMsg(nil) +func TestInt32_JSONNil(t *testing.T) { + var nilSet Int32 + + data, err := json.Marshal(nilSet) if err != nil { - t.Fatalf("MarshalMsg failed: %v", err) + t.Fatalf("MarshalJSON nil failed: %v", err) + } + if string(data) != "null" { + t.Fatalf("expected null, got %s", data) } - var unmarshaled Int32Sorted - _, err = unmarshaled.UnmarshalMsg(data) + var decoded Int32 + err = json.Unmarshal(data, &decoded) if err != nil { - t.Fatalf("UnmarshalMsg failed: %v", err) + t.Fatalf("UnmarshalJSON nil failed: %v", err) + } + if decoded != nil { + t.Fatal("expected nil, got non-nil") } +} - if len(set) != len(unmarshaled) { - t.Fatalf("length mismatch: expected %d, got %d", len(set), len(unmarshaled)) +func TestInt32_JSONEmpty(t *testing.T) { + set := make(Int32) + + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON empty failed: %v", err) + } + if string(data) != "[]" { + t.Fatalf("expected [], got %s", data) } - for k := range set { - if _, ok := unmarshaled[k]; !ok { - t.Fatalf("missing key: %v", k) - } + var decoded Int32 + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON empty failed: %v", err) + } + if len(decoded) != 0 { + t.Fatalf("expected empty set, got length %d", len(decoded)) } } -func TestInt32Sorted_AsSlice(t *testing.T) { +func TestInt32Sorted_RoundTrip(t *testing.T) { set := make(Int32Sorted) set[0] = struct{}{} set[1] = struct{}{} @@ -5548,7 +7706,64 @@ func TestInt32Sorted_AsSlice(t *testing.T) { set[3] = struct{}{} set[4] = struct{}{} - slice := set.AsSlice() + // Test EncodeMsg/DecodeMsg + var buf bytes.Buffer + writer := msgp.NewWriter(&buf) + err := set.EncodeMsg(writer) + if err != nil { + t.Fatalf("EncodeMsg failed: %v", err) + } + writer.Flush() + + reader := msgp.NewReader(&buf) + var decoded Int32Sorted + err = decoded.DecodeMsg(reader) + if err != nil { + t.Fatalf("DecodeMsg failed: %v", err) + } + + if len(set) != len(decoded) { + t.Fatalf("length mismatch: expected %d, got %d", len(set), len(decoded)) + } + + for k := range set { + if _, ok := decoded[k]; !ok { + t.Fatalf("missing key: %v", k) + } + } + + // Test MarshalMsg/UnmarshalMsg + data, err := set.MarshalMsg(nil) + if err != nil { + t.Fatalf("MarshalMsg failed: %v", err) + } + + var unmarshaled Int32Sorted + _, err = unmarshaled.UnmarshalMsg(data) + if err != nil { + t.Fatalf("UnmarshalMsg failed: %v", err) + } + + if len(set) != len(unmarshaled) { + t.Fatalf("length mismatch: expected %d, got %d", len(set), len(unmarshaled)) + } + + for k := range set { + if _, ok := unmarshaled[k]; !ok { + t.Fatalf("missing key: %v", k) + } + } +} + +func TestInt32Sorted_AsSlice(t *testing.T) { + set := make(Int32Sorted) + set[0] = struct{}{} + set[1] = struct{}{} + set[2] = struct{}{} + set[3] = struct{}{} + set[4] = struct{}{} + + slice := set.AsSlice() if len(slice) != len(set) { t.Fatalf("length mismatch: expected %d, got %d", len(set), len(slice)) } @@ -5676,6 +7891,92 @@ func TestInt32Sorted_EmptySet(t *testing.T) { } } +func TestInt32Sorted_JSONRoundTrip(t *testing.T) { + set := make(Int32Sorted) + set[0] = struct{}{} + set[1] = struct{}{} + set[2] = struct{}{} + set[3] = struct{}{} + set[4] = struct{}{} + + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON failed: %v", err) + } + + // Verify JSON is an array + if len(data) == 0 || data[0] != '[' || data[len(data)-1] != ']' { + t.Fatalf("expected JSON array, got: %s", data) + } + + // Verify it unmarshals as a generic JSON array + var arr []json.RawMessage + if err := json.Unmarshal(data, &arr); err != nil { + t.Fatalf("JSON is not a valid array: %v", err) + } + if len(arr) != len(set) { + t.Fatalf("JSON array length mismatch: expected %d, got %d", len(set), len(arr)) + } + + var decoded Int32Sorted + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON failed: %v", err) + } + + if len(set) != len(decoded) { + t.Fatalf("length mismatch: expected %d, got %d", len(set), len(decoded)) + } + + for k := range set { + if _, ok := decoded[k]; !ok { + t.Fatalf("missing key: %v", k) + } + } +} + +func TestInt32Sorted_JSONNil(t *testing.T) { + var nilSet Int32Sorted + + data, err := json.Marshal(nilSet) + if err != nil { + t.Fatalf("MarshalJSON nil failed: %v", err) + } + if string(data) != "null" { + t.Fatalf("expected null, got %s", data) + } + + var decoded Int32Sorted + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON nil failed: %v", err) + } + if decoded != nil { + t.Fatal("expected nil, got non-nil") + } +} + +func TestInt32Sorted_JSONEmpty(t *testing.T) { + set := make(Int32Sorted) + + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON empty failed: %v", err) + } + if string(data) != "[]" { + t.Fatalf("expected [], got %s", data) + } + + var decoded Int32Sorted + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON empty failed: %v", err) + } + if len(decoded) != 0 { + t.Fatalf("expected empty set, got length %d", len(decoded)) + } +} + func BenchmarkInt32_EncodeMsg(b *testing.B) { sizes := []int{10, 100, 1000} @@ -5813,6 +8114,53 @@ func BenchmarkInt32_FromSlice(b *testing.B) { } } +func BenchmarkInt32_MarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(Int32) + for i := 0; i < size; i++ { + set[int32(i)] = struct{}{} + } + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := json.Marshal(set) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + +func BenchmarkInt32_UnmarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(Int32) + for i := 0; i < size; i++ { + set[int32(i)] = struct{}{} + } + + data, _ := json.Marshal(set) + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + var decoded Int32 + err := json.Unmarshal(data, &decoded) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + func BenchmarkInt32Sorted_EncodeMsg(b *testing.B) { sizes := []int{10, 100, 1000} @@ -5950,6 +8298,53 @@ func BenchmarkInt32Sorted_FromSlice(b *testing.B) { } } +func BenchmarkInt32Sorted_MarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(Int32Sorted) + for i := 0; i < size; i++ { + set[int32(i)] = struct{}{} + } + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := json.Marshal(set) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + +func BenchmarkInt32Sorted_UnmarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(Int32Sorted) + for i := 0; i < size; i++ { + set[int32(i)] = struct{}{} + } + + data, _ := json.Marshal(set) + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + var decoded Int32Sorted + err := json.Unmarshal(data, &decoded) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + func TestUint32_RoundTrip(t *testing.T) { set := make(Uint32) set[0] = struct{}{} @@ -6143,28 +8538,37 @@ func TestUint32_EmptySet(t *testing.T) { } } -func TestUint32Sorted_RoundTrip(t *testing.T) { - set := make(Uint32Sorted) +func TestUint32_JSONRoundTrip(t *testing.T) { + set := make(Uint32) set[0] = struct{}{} set[1] = struct{}{} set[2] = struct{}{} set[3] = struct{}{} set[4] = struct{}{} - // Test EncodeMsg/DecodeMsg - var buf bytes.Buffer - writer := msgp.NewWriter(&buf) - err := set.EncodeMsg(writer) + data, err := json.Marshal(set) if err != nil { - t.Fatalf("EncodeMsg failed: %v", err) + t.Fatalf("MarshalJSON failed: %v", err) } - writer.Flush() - reader := msgp.NewReader(&buf) - var decoded Uint32Sorted - err = decoded.DecodeMsg(reader) + // Verify JSON is an array + if len(data) == 0 || data[0] != '[' || data[len(data)-1] != ']' { + t.Fatalf("expected JSON array, got: %s", data) + } + + // Verify it unmarshals as a generic JSON array + var arr []json.RawMessage + if err := json.Unmarshal(data, &arr); err != nil { + t.Fatalf("JSON is not a valid array: %v", err) + } + if len(arr) != len(set) { + t.Fatalf("JSON array length mismatch: expected %d, got %d", len(set), len(arr)) + } + + var decoded Uint32 + err = json.Unmarshal(data, &decoded) if err != nil { - t.Fatalf("DecodeMsg failed: %v", err) + t.Fatalf("UnmarshalJSON failed: %v", err) } if len(set) != len(decoded) { @@ -6176,31 +8580,51 @@ func TestUint32Sorted_RoundTrip(t *testing.T) { t.Fatalf("missing key: %v", k) } } +} - // Test MarshalMsg/UnmarshalMsg - data, err := set.MarshalMsg(nil) +func TestUint32_JSONNil(t *testing.T) { + var nilSet Uint32 + + data, err := json.Marshal(nilSet) if err != nil { - t.Fatalf("MarshalMsg failed: %v", err) + t.Fatalf("MarshalJSON nil failed: %v", err) + } + if string(data) != "null" { + t.Fatalf("expected null, got %s", data) } - var unmarshaled Uint32Sorted - _, err = unmarshaled.UnmarshalMsg(data) + var decoded Uint32 + err = json.Unmarshal(data, &decoded) if err != nil { - t.Fatalf("UnmarshalMsg failed: %v", err) + t.Fatalf("UnmarshalJSON nil failed: %v", err) + } + if decoded != nil { + t.Fatal("expected nil, got non-nil") } +} - if len(set) != len(unmarshaled) { - t.Fatalf("length mismatch: expected %d, got %d", len(set), len(unmarshaled)) +func TestUint32_JSONEmpty(t *testing.T) { + set := make(Uint32) + + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON empty failed: %v", err) + } + if string(data) != "[]" { + t.Fatalf("expected [], got %s", data) } - for k := range set { - if _, ok := unmarshaled[k]; !ok { - t.Fatalf("missing key: %v", k) - } + var decoded Uint32 + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON empty failed: %v", err) + } + if len(decoded) != 0 { + t.Fatalf("expected empty set, got length %d", len(decoded)) } } -func TestUint32Sorted_AsSlice(t *testing.T) { +func TestUint32Sorted_RoundTrip(t *testing.T) { set := make(Uint32Sorted) set[0] = struct{}{} set[1] = struct{}{} @@ -6208,11 +8632,68 @@ func TestUint32Sorted_AsSlice(t *testing.T) { set[3] = struct{}{} set[4] = struct{}{} - slice := set.AsSlice() - if len(slice) != len(set) { - t.Fatalf("length mismatch: expected %d, got %d", len(set), len(slice)) - } - + // Test EncodeMsg/DecodeMsg + var buf bytes.Buffer + writer := msgp.NewWriter(&buf) + err := set.EncodeMsg(writer) + if err != nil { + t.Fatalf("EncodeMsg failed: %v", err) + } + writer.Flush() + + reader := msgp.NewReader(&buf) + var decoded Uint32Sorted + err = decoded.DecodeMsg(reader) + if err != nil { + t.Fatalf("DecodeMsg failed: %v", err) + } + + if len(set) != len(decoded) { + t.Fatalf("length mismatch: expected %d, got %d", len(set), len(decoded)) + } + + for k := range set { + if _, ok := decoded[k]; !ok { + t.Fatalf("missing key: %v", k) + } + } + + // Test MarshalMsg/UnmarshalMsg + data, err := set.MarshalMsg(nil) + if err != nil { + t.Fatalf("MarshalMsg failed: %v", err) + } + + var unmarshaled Uint32Sorted + _, err = unmarshaled.UnmarshalMsg(data) + if err != nil { + t.Fatalf("UnmarshalMsg failed: %v", err) + } + + if len(set) != len(unmarshaled) { + t.Fatalf("length mismatch: expected %d, got %d", len(set), len(unmarshaled)) + } + + for k := range set { + if _, ok := unmarshaled[k]; !ok { + t.Fatalf("missing key: %v", k) + } + } +} + +func TestUint32Sorted_AsSlice(t *testing.T) { + set := make(Uint32Sorted) + set[0] = struct{}{} + set[1] = struct{}{} + set[2] = struct{}{} + set[3] = struct{}{} + set[4] = struct{}{} + + slice := set.AsSlice() + if len(slice) != len(set) { + t.Fatalf("length mismatch: expected %d, got %d", len(set), len(slice)) + } + found := make(map[uint32]bool) for _, v := range slice { found[v] = true @@ -6336,6 +8817,92 @@ func TestUint32Sorted_EmptySet(t *testing.T) { } } +func TestUint32Sorted_JSONRoundTrip(t *testing.T) { + set := make(Uint32Sorted) + set[0] = struct{}{} + set[1] = struct{}{} + set[2] = struct{}{} + set[3] = struct{}{} + set[4] = struct{}{} + + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON failed: %v", err) + } + + // Verify JSON is an array + if len(data) == 0 || data[0] != '[' || data[len(data)-1] != ']' { + t.Fatalf("expected JSON array, got: %s", data) + } + + // Verify it unmarshals as a generic JSON array + var arr []json.RawMessage + if err := json.Unmarshal(data, &arr); err != nil { + t.Fatalf("JSON is not a valid array: %v", err) + } + if len(arr) != len(set) { + t.Fatalf("JSON array length mismatch: expected %d, got %d", len(set), len(arr)) + } + + var decoded Uint32Sorted + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON failed: %v", err) + } + + if len(set) != len(decoded) { + t.Fatalf("length mismatch: expected %d, got %d", len(set), len(decoded)) + } + + for k := range set { + if _, ok := decoded[k]; !ok { + t.Fatalf("missing key: %v", k) + } + } +} + +func TestUint32Sorted_JSONNil(t *testing.T) { + var nilSet Uint32Sorted + + data, err := json.Marshal(nilSet) + if err != nil { + t.Fatalf("MarshalJSON nil failed: %v", err) + } + if string(data) != "null" { + t.Fatalf("expected null, got %s", data) + } + + var decoded Uint32Sorted + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON nil failed: %v", err) + } + if decoded != nil { + t.Fatal("expected nil, got non-nil") + } +} + +func TestUint32Sorted_JSONEmpty(t *testing.T) { + set := make(Uint32Sorted) + + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON empty failed: %v", err) + } + if string(data) != "[]" { + t.Fatalf("expected [], got %s", data) + } + + var decoded Uint32Sorted + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON empty failed: %v", err) + } + if len(decoded) != 0 { + t.Fatalf("expected empty set, got length %d", len(decoded)) + } +} + func BenchmarkUint32_EncodeMsg(b *testing.B) { sizes := []int{10, 100, 1000} @@ -6473,6 +9040,53 @@ func BenchmarkUint32_FromSlice(b *testing.B) { } } +func BenchmarkUint32_MarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(Uint32) + for i := 0; i < size; i++ { + set[uint32(i)] = struct{}{} + } + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := json.Marshal(set) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + +func BenchmarkUint32_UnmarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(Uint32) + for i := 0; i < size; i++ { + set[uint32(i)] = struct{}{} + } + + data, _ := json.Marshal(set) + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + var decoded Uint32 + err := json.Unmarshal(data, &decoded) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + func BenchmarkUint32Sorted_EncodeMsg(b *testing.B) { sizes := []int{10, 100, 1000} @@ -6610,6 +9224,53 @@ func BenchmarkUint32Sorted_FromSlice(b *testing.B) { } } +func BenchmarkUint32Sorted_MarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(Uint32Sorted) + for i := 0; i < size; i++ { + set[uint32(i)] = struct{}{} + } + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := json.Marshal(set) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + +func BenchmarkUint32Sorted_UnmarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(Uint32Sorted) + for i := 0; i < size; i++ { + set[uint32(i)] = struct{}{} + } + + data, _ := json.Marshal(set) + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + var decoded Uint32Sorted + err := json.Unmarshal(data, &decoded) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + func TestInt64_RoundTrip(t *testing.T) { set := make(Int64) set[0] = struct{}{} @@ -6803,6 +9464,92 @@ func TestInt64_EmptySet(t *testing.T) { } } +func TestInt64_JSONRoundTrip(t *testing.T) { + set := make(Int64) + set[0] = struct{}{} + set[1] = struct{}{} + set[2] = struct{}{} + set[3] = struct{}{} + set[4] = struct{}{} + + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON failed: %v", err) + } + + // Verify JSON is an array + if len(data) == 0 || data[0] != '[' || data[len(data)-1] != ']' { + t.Fatalf("expected JSON array, got: %s", data) + } + + // Verify it unmarshals as a generic JSON array + var arr []json.RawMessage + if err := json.Unmarshal(data, &arr); err != nil { + t.Fatalf("JSON is not a valid array: %v", err) + } + if len(arr) != len(set) { + t.Fatalf("JSON array length mismatch: expected %d, got %d", len(set), len(arr)) + } + + var decoded Int64 + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON failed: %v", err) + } + + if len(set) != len(decoded) { + t.Fatalf("length mismatch: expected %d, got %d", len(set), len(decoded)) + } + + for k := range set { + if _, ok := decoded[k]; !ok { + t.Fatalf("missing key: %v", k) + } + } +} + +func TestInt64_JSONNil(t *testing.T) { + var nilSet Int64 + + data, err := json.Marshal(nilSet) + if err != nil { + t.Fatalf("MarshalJSON nil failed: %v", err) + } + if string(data) != "null" { + t.Fatalf("expected null, got %s", data) + } + + var decoded Int64 + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON nil failed: %v", err) + } + if decoded != nil { + t.Fatal("expected nil, got non-nil") + } +} + +func TestInt64_JSONEmpty(t *testing.T) { + set := make(Int64) + + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON empty failed: %v", err) + } + if string(data) != "[]" { + t.Fatalf("expected [], got %s", data) + } + + var decoded Int64 + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON empty failed: %v", err) + } + if len(decoded) != 0 { + t.Fatalf("expected empty set, got length %d", len(decoded)) + } +} + func TestInt64Sorted_RoundTrip(t *testing.T) { set := make(Int64Sorted) set[0] = struct{}{} @@ -6941,58 +9688,144 @@ func TestInt64Sorted_NilHandling(t *testing.T) { t.Fatal("expected nil, got non-nil") } - // Test AsSlice on nil - slice := nilSet.AsSlice() - if slice != nil { - t.Fatal("expected nil slice, got non-nil") + // Test AsSlice on nil + slice := nilSet.AsSlice() + if slice != nil { + t.Fatal("expected nil slice, got non-nil") + } + + // Test FromSlice with nil + fromNilSlice := Int64SortedFromSlice(nil) + if fromNilSlice != nil { + t.Fatal("expected nil from nil slice, got non-nil") + } +} + +func TestInt64Sorted_EmptySet(t *testing.T) { + set := make(Int64Sorted) + + // Test empty set encoding + var buf bytes.Buffer + writer := msgp.NewWriter(&buf) + err := set.EncodeMsg(writer) + if err != nil { + t.Fatalf("EncodeMsg failed for empty: %v", err) + } + writer.Flush() + + // Test empty set decoding + reader := msgp.NewReader(&buf) + var decoded Int64Sorted + err = decoded.DecodeMsg(reader) + if err != nil { + t.Fatalf("DecodeMsg failed for empty: %v", err) + } + + if len(decoded) != 0 { + t.Fatalf("expected empty set, got length %d", len(decoded)) + } + + // Test empty set marshaling + data, err := set.MarshalMsg(nil) + if err != nil { + t.Fatalf("MarshalMsg failed for empty: %v", err) + } + + // Test empty set unmarshaling + var unmarshaled Int64Sorted + _, err = unmarshaled.UnmarshalMsg(data) + if err != nil { + t.Fatalf("UnmarshalMsg failed for empty: %v", err) + } + + if len(unmarshaled) != 0 { + t.Fatalf("expected empty set, got length %d", len(unmarshaled)) + } +} + +func TestInt64Sorted_JSONRoundTrip(t *testing.T) { + set := make(Int64Sorted) + set[0] = struct{}{} + set[1] = struct{}{} + set[2] = struct{}{} + set[3] = struct{}{} + set[4] = struct{}{} + + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON failed: %v", err) + } + + // Verify JSON is an array + if len(data) == 0 || data[0] != '[' || data[len(data)-1] != ']' { + t.Fatalf("expected JSON array, got: %s", data) + } + + // Verify it unmarshals as a generic JSON array + var arr []json.RawMessage + if err := json.Unmarshal(data, &arr); err != nil { + t.Fatalf("JSON is not a valid array: %v", err) + } + if len(arr) != len(set) { + t.Fatalf("JSON array length mismatch: expected %d, got %d", len(set), len(arr)) + } + + var decoded Int64Sorted + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON failed: %v", err) + } + + if len(set) != len(decoded) { + t.Fatalf("length mismatch: expected %d, got %d", len(set), len(decoded)) } - // Test FromSlice with nil - fromNilSlice := Int64SortedFromSlice(nil) - if fromNilSlice != nil { - t.Fatal("expected nil from nil slice, got non-nil") + for k := range set { + if _, ok := decoded[k]; !ok { + t.Fatalf("missing key: %v", k) + } } } -func TestInt64Sorted_EmptySet(t *testing.T) { - set := make(Int64Sorted) +func TestInt64Sorted_JSONNil(t *testing.T) { + var nilSet Int64Sorted - // Test empty set encoding - var buf bytes.Buffer - writer := msgp.NewWriter(&buf) - err := set.EncodeMsg(writer) + data, err := json.Marshal(nilSet) if err != nil { - t.Fatalf("EncodeMsg failed for empty: %v", err) + t.Fatalf("MarshalJSON nil failed: %v", err) + } + if string(data) != "null" { + t.Fatalf("expected null, got %s", data) } - writer.Flush() - // Test empty set decoding - reader := msgp.NewReader(&buf) var decoded Int64Sorted - err = decoded.DecodeMsg(reader) + err = json.Unmarshal(data, &decoded) if err != nil { - t.Fatalf("DecodeMsg failed for empty: %v", err) + t.Fatalf("UnmarshalJSON nil failed: %v", err) } - - if len(decoded) != 0 { - t.Fatalf("expected empty set, got length %d", len(decoded)) + if decoded != nil { + t.Fatal("expected nil, got non-nil") } +} - // Test empty set marshaling - data, err := set.MarshalMsg(nil) +func TestInt64Sorted_JSONEmpty(t *testing.T) { + set := make(Int64Sorted) + + data, err := json.Marshal(set) if err != nil { - t.Fatalf("MarshalMsg failed for empty: %v", err) + t.Fatalf("MarshalJSON empty failed: %v", err) + } + if string(data) != "[]" { + t.Fatalf("expected [], got %s", data) } - // Test empty set unmarshaling - var unmarshaled Int64Sorted - _, err = unmarshaled.UnmarshalMsg(data) + var decoded Int64Sorted + err = json.Unmarshal(data, &decoded) if err != nil { - t.Fatalf("UnmarshalMsg failed for empty: %v", err) + t.Fatalf("UnmarshalJSON empty failed: %v", err) } - - if len(unmarshaled) != 0 { - t.Fatalf("expected empty set, got length %d", len(unmarshaled)) + if len(decoded) != 0 { + t.Fatalf("expected empty set, got length %d", len(decoded)) } } @@ -7133,6 +9966,53 @@ func BenchmarkInt64_FromSlice(b *testing.B) { } } +func BenchmarkInt64_MarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(Int64) + for i := 0; i < size; i++ { + set[int64(i)] = struct{}{} + } + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := json.Marshal(set) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + +func BenchmarkInt64_UnmarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(Int64) + for i := 0; i < size; i++ { + set[int64(i)] = struct{}{} + } + + data, _ := json.Marshal(set) + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + var decoded Int64 + err := json.Unmarshal(data, &decoded) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + func BenchmarkInt64Sorted_EncodeMsg(b *testing.B) { sizes := []int{10, 100, 1000} @@ -7270,6 +10150,53 @@ func BenchmarkInt64Sorted_FromSlice(b *testing.B) { } } +func BenchmarkInt64Sorted_MarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(Int64Sorted) + for i := 0; i < size; i++ { + set[int64(i)] = struct{}{} + } + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := json.Marshal(set) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + +func BenchmarkInt64Sorted_UnmarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(Int64Sorted) + for i := 0; i < size; i++ { + set[int64(i)] = struct{}{} + } + + data, _ := json.Marshal(set) + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + var decoded Int64Sorted + err := json.Unmarshal(data, &decoded) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + func TestUint64_RoundTrip(t *testing.T) { set := make(Uint64) set[0] = struct{}{} @@ -7463,6 +10390,92 @@ func TestUint64_EmptySet(t *testing.T) { } } +func TestUint64_JSONRoundTrip(t *testing.T) { + set := make(Uint64) + set[0] = struct{}{} + set[1] = struct{}{} + set[2] = struct{}{} + set[3] = struct{}{} + set[4] = struct{}{} + + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON failed: %v", err) + } + + // Verify JSON is an array + if len(data) == 0 || data[0] != '[' || data[len(data)-1] != ']' { + t.Fatalf("expected JSON array, got: %s", data) + } + + // Verify it unmarshals as a generic JSON array + var arr []json.RawMessage + if err := json.Unmarshal(data, &arr); err != nil { + t.Fatalf("JSON is not a valid array: %v", err) + } + if len(arr) != len(set) { + t.Fatalf("JSON array length mismatch: expected %d, got %d", len(set), len(arr)) + } + + var decoded Uint64 + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON failed: %v", err) + } + + if len(set) != len(decoded) { + t.Fatalf("length mismatch: expected %d, got %d", len(set), len(decoded)) + } + + for k := range set { + if _, ok := decoded[k]; !ok { + t.Fatalf("missing key: %v", k) + } + } +} + +func TestUint64_JSONNil(t *testing.T) { + var nilSet Uint64 + + data, err := json.Marshal(nilSet) + if err != nil { + t.Fatalf("MarshalJSON nil failed: %v", err) + } + if string(data) != "null" { + t.Fatalf("expected null, got %s", data) + } + + var decoded Uint64 + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON nil failed: %v", err) + } + if decoded != nil { + t.Fatal("expected nil, got non-nil") + } +} + +func TestUint64_JSONEmpty(t *testing.T) { + set := make(Uint64) + + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON empty failed: %v", err) + } + if string(data) != "[]" { + t.Fatalf("expected [], got %s", data) + } + + var decoded Uint64 + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON empty failed: %v", err) + } + if len(decoded) != 0 { + t.Fatalf("expected empty set, got length %d", len(decoded)) + } +} + func TestUint64Sorted_RoundTrip(t *testing.T) { set := make(Uint64Sorted) set[0] = struct{}{} @@ -7634,25 +10647,111 @@ func TestUint64Sorted_EmptySet(t *testing.T) { t.Fatalf("DecodeMsg failed for empty: %v", err) } - if len(decoded) != 0 { - t.Fatalf("expected empty set, got length %d", len(decoded)) - } + if len(decoded) != 0 { + t.Fatalf("expected empty set, got length %d", len(decoded)) + } + + // Test empty set marshaling + data, err := set.MarshalMsg(nil) + if err != nil { + t.Fatalf("MarshalMsg failed for empty: %v", err) + } + + // Test empty set unmarshaling + var unmarshaled Uint64Sorted + _, err = unmarshaled.UnmarshalMsg(data) + if err != nil { + t.Fatalf("UnmarshalMsg failed for empty: %v", err) + } + + if len(unmarshaled) != 0 { + t.Fatalf("expected empty set, got length %d", len(unmarshaled)) + } +} + +func TestUint64Sorted_JSONRoundTrip(t *testing.T) { + set := make(Uint64Sorted) + set[0] = struct{}{} + set[1] = struct{}{} + set[2] = struct{}{} + set[3] = struct{}{} + set[4] = struct{}{} + + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON failed: %v", err) + } + + // Verify JSON is an array + if len(data) == 0 || data[0] != '[' || data[len(data)-1] != ']' { + t.Fatalf("expected JSON array, got: %s", data) + } + + // Verify it unmarshals as a generic JSON array + var arr []json.RawMessage + if err := json.Unmarshal(data, &arr); err != nil { + t.Fatalf("JSON is not a valid array: %v", err) + } + if len(arr) != len(set) { + t.Fatalf("JSON array length mismatch: expected %d, got %d", len(set), len(arr)) + } + + var decoded Uint64Sorted + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON failed: %v", err) + } + + if len(set) != len(decoded) { + t.Fatalf("length mismatch: expected %d, got %d", len(set), len(decoded)) + } + + for k := range set { + if _, ok := decoded[k]; !ok { + t.Fatalf("missing key: %v", k) + } + } +} + +func TestUint64Sorted_JSONNil(t *testing.T) { + var nilSet Uint64Sorted + + data, err := json.Marshal(nilSet) + if err != nil { + t.Fatalf("MarshalJSON nil failed: %v", err) + } + if string(data) != "null" { + t.Fatalf("expected null, got %s", data) + } + + var decoded Uint64Sorted + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON nil failed: %v", err) + } + if decoded != nil { + t.Fatal("expected nil, got non-nil") + } +} + +func TestUint64Sorted_JSONEmpty(t *testing.T) { + set := make(Uint64Sorted) - // Test empty set marshaling - data, err := set.MarshalMsg(nil) + data, err := json.Marshal(set) if err != nil { - t.Fatalf("MarshalMsg failed for empty: %v", err) + t.Fatalf("MarshalJSON empty failed: %v", err) + } + if string(data) != "[]" { + t.Fatalf("expected [], got %s", data) } - // Test empty set unmarshaling - var unmarshaled Uint64Sorted - _, err = unmarshaled.UnmarshalMsg(data) + var decoded Uint64Sorted + err = json.Unmarshal(data, &decoded) if err != nil { - t.Fatalf("UnmarshalMsg failed for empty: %v", err) + t.Fatalf("UnmarshalJSON empty failed: %v", err) } - - if len(unmarshaled) != 0 { - t.Fatalf("expected empty set, got length %d", len(unmarshaled)) + if len(decoded) != 0 { + t.Fatalf("expected empty set, got length %d", len(decoded)) } } @@ -7793,6 +10892,53 @@ func BenchmarkUint64_FromSlice(b *testing.B) { } } +func BenchmarkUint64_MarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(Uint64) + for i := 0; i < size; i++ { + set[uint64(i)] = struct{}{} + } + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := json.Marshal(set) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + +func BenchmarkUint64_UnmarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(Uint64) + for i := 0; i < size; i++ { + set[uint64(i)] = struct{}{} + } + + data, _ := json.Marshal(set) + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + var decoded Uint64 + err := json.Unmarshal(data, &decoded) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + func BenchmarkUint64Sorted_EncodeMsg(b *testing.B) { sizes := []int{10, 100, 1000} @@ -7930,6 +11076,53 @@ func BenchmarkUint64Sorted_FromSlice(b *testing.B) { } } +func BenchmarkUint64Sorted_MarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(Uint64Sorted) + for i := 0; i < size; i++ { + set[uint64(i)] = struct{}{} + } + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := json.Marshal(set) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + +func BenchmarkUint64Sorted_UnmarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(Uint64Sorted) + for i := 0; i < size; i++ { + set[uint64(i)] = struct{}{} + } + + data, _ := json.Marshal(set) + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + var decoded Uint64Sorted + err := json.Unmarshal(data, &decoded) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + func TestFloat64_RoundTrip(t *testing.T) { set := make(Float64) set[0.0] = struct{}{} @@ -8123,6 +11316,92 @@ func TestFloat64_EmptySet(t *testing.T) { } } +func TestFloat64_JSONRoundTrip(t *testing.T) { + set := make(Float64) + set[0.0] = struct{}{} + set[1.0] = struct{}{} + set[2.0] = struct{}{} + set[3.0] = struct{}{} + set[4.0] = struct{}{} + + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON failed: %v", err) + } + + // Verify JSON is an array + if len(data) == 0 || data[0] != '[' || data[len(data)-1] != ']' { + t.Fatalf("expected JSON array, got: %s", data) + } + + // Verify it unmarshals as a generic JSON array + var arr []json.RawMessage + if err := json.Unmarshal(data, &arr); err != nil { + t.Fatalf("JSON is not a valid array: %v", err) + } + if len(arr) != len(set) { + t.Fatalf("JSON array length mismatch: expected %d, got %d", len(set), len(arr)) + } + + var decoded Float64 + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON failed: %v", err) + } + + if len(set) != len(decoded) { + t.Fatalf("length mismatch: expected %d, got %d", len(set), len(decoded)) + } + + for k := range set { + if _, ok := decoded[k]; !ok { + t.Fatalf("missing key: %v", k) + } + } +} + +func TestFloat64_JSONNil(t *testing.T) { + var nilSet Float64 + + data, err := json.Marshal(nilSet) + if err != nil { + t.Fatalf("MarshalJSON nil failed: %v", err) + } + if string(data) != "null" { + t.Fatalf("expected null, got %s", data) + } + + var decoded Float64 + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON nil failed: %v", err) + } + if decoded != nil { + t.Fatal("expected nil, got non-nil") + } +} + +func TestFloat64_JSONEmpty(t *testing.T) { + set := make(Float64) + + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON empty failed: %v", err) + } + if string(data) != "[]" { + t.Fatalf("expected [], got %s", data) + } + + var decoded Float64 + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON empty failed: %v", err) + } + if len(decoded) != 0 { + t.Fatalf("expected empty set, got length %d", len(decoded)) + } +} + func TestFloat64Sorted_RoundTrip(t *testing.T) { set := make(Float64Sorted) set[0.0] = struct{}{} @@ -8316,6 +11595,92 @@ func TestFloat64Sorted_EmptySet(t *testing.T) { } } +func TestFloat64Sorted_JSONRoundTrip(t *testing.T) { + set := make(Float64Sorted) + set[0.0] = struct{}{} + set[1.0] = struct{}{} + set[2.0] = struct{}{} + set[3.0] = struct{}{} + set[4.0] = struct{}{} + + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON failed: %v", err) + } + + // Verify JSON is an array + if len(data) == 0 || data[0] != '[' || data[len(data)-1] != ']' { + t.Fatalf("expected JSON array, got: %s", data) + } + + // Verify it unmarshals as a generic JSON array + var arr []json.RawMessage + if err := json.Unmarshal(data, &arr); err != nil { + t.Fatalf("JSON is not a valid array: %v", err) + } + if len(arr) != len(set) { + t.Fatalf("JSON array length mismatch: expected %d, got %d", len(set), len(arr)) + } + + var decoded Float64Sorted + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON failed: %v", err) + } + + if len(set) != len(decoded) { + t.Fatalf("length mismatch: expected %d, got %d", len(set), len(decoded)) + } + + for k := range set { + if _, ok := decoded[k]; !ok { + t.Fatalf("missing key: %v", k) + } + } +} + +func TestFloat64Sorted_JSONNil(t *testing.T) { + var nilSet Float64Sorted + + data, err := json.Marshal(nilSet) + if err != nil { + t.Fatalf("MarshalJSON nil failed: %v", err) + } + if string(data) != "null" { + t.Fatalf("expected null, got %s", data) + } + + var decoded Float64Sorted + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON nil failed: %v", err) + } + if decoded != nil { + t.Fatal("expected nil, got non-nil") + } +} + +func TestFloat64Sorted_JSONEmpty(t *testing.T) { + set := make(Float64Sorted) + + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON empty failed: %v", err) + } + if string(data) != "[]" { + t.Fatalf("expected [], got %s", data) + } + + var decoded Float64Sorted + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON empty failed: %v", err) + } + if len(decoded) != 0 { + t.Fatalf("expected empty set, got length %d", len(decoded)) + } +} + func BenchmarkFloat64_EncodeMsg(b *testing.B) { sizes := []int{10, 100, 1000} @@ -8434,20 +11799,67 @@ func BenchmarkFloat64_AsSlice(b *testing.B) { } } -func BenchmarkFloat64_FromSlice(b *testing.B) { +func BenchmarkFloat64_FromSlice(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + slice := make([]float64, size) + for i := 0; i < size; i++ { + slice[i] = float64(i) + } + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = Float64FromSlice(slice) + } + }) + } +} + +func BenchmarkFloat64_MarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(Float64) + for i := 0; i < size; i++ { + set[float64(i)] = struct{}{} + } + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := json.Marshal(set) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + +func BenchmarkFloat64_UnmarshalJSON(b *testing.B) { sizes := []int{10, 100, 1000} for _, size := range sizes { b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { - slice := make([]float64, size) + set := make(Float64) for i := 0; i < size; i++ { - slice[i] = float64(i) + set[float64(i)] = struct{}{} } + data, _ := json.Marshal(set) + b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { - _ = Float64FromSlice(slice) + var decoded Float64 + err := json.Unmarshal(data, &decoded) + if err != nil { + b.Fatal(err) + } } }) } @@ -8590,6 +12002,53 @@ func BenchmarkFloat64Sorted_FromSlice(b *testing.B) { } } +func BenchmarkFloat64Sorted_MarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(Float64Sorted) + for i := 0; i < size; i++ { + set[float64(i)] = struct{}{} + } + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := json.Marshal(set) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + +func BenchmarkFloat64Sorted_UnmarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(Float64Sorted) + for i := 0; i < size; i++ { + set[float64(i)] = struct{}{} + } + + data, _ := json.Marshal(set) + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + var decoded Float64Sorted + err := json.Unmarshal(data, &decoded) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + func TestFloat32_RoundTrip(t *testing.T) { set := make(Float32) set[0.0] = struct{}{} @@ -8783,6 +12242,92 @@ func TestFloat32_EmptySet(t *testing.T) { } } +func TestFloat32_JSONRoundTrip(t *testing.T) { + set := make(Float32) + set[0.0] = struct{}{} + set[1.0] = struct{}{} + set[2.0] = struct{}{} + set[3.0] = struct{}{} + set[4.0] = struct{}{} + + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON failed: %v", err) + } + + // Verify JSON is an array + if len(data) == 0 || data[0] != '[' || data[len(data)-1] != ']' { + t.Fatalf("expected JSON array, got: %s", data) + } + + // Verify it unmarshals as a generic JSON array + var arr []json.RawMessage + if err := json.Unmarshal(data, &arr); err != nil { + t.Fatalf("JSON is not a valid array: %v", err) + } + if len(arr) != len(set) { + t.Fatalf("JSON array length mismatch: expected %d, got %d", len(set), len(arr)) + } + + var decoded Float32 + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON failed: %v", err) + } + + if len(set) != len(decoded) { + t.Fatalf("length mismatch: expected %d, got %d", len(set), len(decoded)) + } + + for k := range set { + if _, ok := decoded[k]; !ok { + t.Fatalf("missing key: %v", k) + } + } +} + +func TestFloat32_JSONNil(t *testing.T) { + var nilSet Float32 + + data, err := json.Marshal(nilSet) + if err != nil { + t.Fatalf("MarshalJSON nil failed: %v", err) + } + if string(data) != "null" { + t.Fatalf("expected null, got %s", data) + } + + var decoded Float32 + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON nil failed: %v", err) + } + if decoded != nil { + t.Fatal("expected nil, got non-nil") + } +} + +func TestFloat32_JSONEmpty(t *testing.T) { + set := make(Float32) + + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON empty failed: %v", err) + } + if string(data) != "[]" { + t.Fatalf("expected [], got %s", data) + } + + var decoded Float32 + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON empty failed: %v", err) + } + if len(decoded) != 0 { + t.Fatalf("expected empty set, got length %d", len(decoded)) + } +} + func TestFloat32Sorted_RoundTrip(t *testing.T) { set := make(Float32Sorted) set[0.0] = struct{}{} @@ -8976,6 +12521,92 @@ func TestFloat32Sorted_EmptySet(t *testing.T) { } } +func TestFloat32Sorted_JSONRoundTrip(t *testing.T) { + set := make(Float32Sorted) + set[0.0] = struct{}{} + set[1.0] = struct{}{} + set[2.0] = struct{}{} + set[3.0] = struct{}{} + set[4.0] = struct{}{} + + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON failed: %v", err) + } + + // Verify JSON is an array + if len(data) == 0 || data[0] != '[' || data[len(data)-1] != ']' { + t.Fatalf("expected JSON array, got: %s", data) + } + + // Verify it unmarshals as a generic JSON array + var arr []json.RawMessage + if err := json.Unmarshal(data, &arr); err != nil { + t.Fatalf("JSON is not a valid array: %v", err) + } + if len(arr) != len(set) { + t.Fatalf("JSON array length mismatch: expected %d, got %d", len(set), len(arr)) + } + + var decoded Float32Sorted + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON failed: %v", err) + } + + if len(set) != len(decoded) { + t.Fatalf("length mismatch: expected %d, got %d", len(set), len(decoded)) + } + + for k := range set { + if _, ok := decoded[k]; !ok { + t.Fatalf("missing key: %v", k) + } + } +} + +func TestFloat32Sorted_JSONNil(t *testing.T) { + var nilSet Float32Sorted + + data, err := json.Marshal(nilSet) + if err != nil { + t.Fatalf("MarshalJSON nil failed: %v", err) + } + if string(data) != "null" { + t.Fatalf("expected null, got %s", data) + } + + var decoded Float32Sorted + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON nil failed: %v", err) + } + if decoded != nil { + t.Fatal("expected nil, got non-nil") + } +} + +func TestFloat32Sorted_JSONEmpty(t *testing.T) { + set := make(Float32Sorted) + + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON empty failed: %v", err) + } + if string(data) != "[]" { + t.Fatalf("expected [], got %s", data) + } + + var decoded Float32Sorted + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("UnmarshalJSON empty failed: %v", err) + } + if len(decoded) != 0 { + t.Fatalf("expected empty set, got length %d", len(decoded)) + } +} + func BenchmarkFloat32_EncodeMsg(b *testing.B) { sizes := []int{10, 100, 1000} @@ -9113,6 +12744,53 @@ func BenchmarkFloat32_FromSlice(b *testing.B) { } } +func BenchmarkFloat32_MarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(Float32) + for i := 0; i < size; i++ { + set[float32(i)] = struct{}{} + } + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := json.Marshal(set) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + +func BenchmarkFloat32_UnmarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(Float32) + for i := 0; i < size; i++ { + set[float32(i)] = struct{}{} + } + + data, _ := json.Marshal(set) + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + var decoded Float32 + err := json.Unmarshal(data, &decoded) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + func BenchmarkFloat32Sorted_EncodeMsg(b *testing.B) { sizes := []int{10, 100, 1000} @@ -9249,3 +12927,50 @@ func BenchmarkFloat32Sorted_FromSlice(b *testing.B) { }) } } + +func BenchmarkFloat32Sorted_MarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(Float32Sorted) + for i := 0; i < size; i++ { + set[float32(i)] = struct{}{} + } + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := json.Marshal(set) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + +func BenchmarkFloat32Sorted_UnmarshalJSON(b *testing.B) { + sizes := []int{10, 100, 1000} + + for _, size := range sizes { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + set := make(Float32Sorted) + for i := 0; i < size; i++ { + set[float32(i)] = struct{}{} + } + + data, _ := json.Marshal(set) + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + var decoded Float32Sorted + err := json.Unmarshal(data, &decoded) + if err != nil { + b.Fatal(err) + } + } + }) + } +} diff --git a/msgp/setof/json.go b/msgp/setof/json.go new file mode 100644 index 00000000..077d97b3 --- /dev/null +++ b/msgp/setof/json.go @@ -0,0 +1,152 @@ +package setof + +import ( + "bytes" + "encoding/json" + "fmt" + "strconv" + "unicode/utf8" +) + +// isJSONNull reports whether data is the JSON literal "null". +func isJSONNull(data []byte) bool { + return string(data) == "null" +} + +func skipWS(data []byte, i int) int { + for i < len(data) && (data[i] == ' ' || data[i] == '\t' || data[i] == '\n' || data[i] == '\r') { + i++ + } + return i +} + +// jsonArrayIter calls fn for each raw element in a JSON array. +// String elements include their surrounding quotes. Does not allocate. +func jsonArrayIter(data []byte, fn func(raw []byte) error) error { + i := skipWS(data, 0) + if i >= len(data) || data[i] != '[' { + return fmt.Errorf("setof: expected '[', got %q", string(data[i:])) + } + i = skipWS(data, i+1) + if i < len(data) && data[i] == ']' { + return nil + } + for { + i = skipWS(data, i) + if i >= len(data) { + return fmt.Errorf("setof: unexpected end of JSON array") + } + start := i + if data[i] == '"' { + i++ + for i < len(data) { + if data[i] == '\\' { + i += 2 + continue + } + if data[i] == '"' { + i++ + break + } + i++ + } + } else { + for i < len(data) && data[i] != ',' && data[i] != ']' && + data[i] != ' ' && data[i] != '\t' && data[i] != '\n' && data[i] != '\r' { + i++ + } + } + if err := fn(data[start:i]); err != nil { + return err + } + i = skipWS(data, i) + if i >= len(data) { + return fmt.Errorf("setof: unexpected end of JSON array") + } + if data[i] == ']' { + return nil + } + if data[i] != ',' { + return fmt.Errorf("setof: expected ',' or ']', got '%c'", data[i]) + } + i++ + } +} + +// jsonAppendQuote appends a JSON-encoded string to dst. +// Invalid UTF-8 is replaced with U+FFFD, matching encoding/json behavior. +func jsonAppendQuote(dst []byte, s string) []byte { + dst = append(dst, '"') + for _, r := range s { + if r >= 0x20 && r != '"' && r != '\\' { + dst = utf8.AppendRune(dst, r) + continue + } + switch r { + case '"', '\\': + dst = append(dst, '\\', byte(r)) + case '\b': + dst = append(dst, '\\', 'b') + case '\f': + dst = append(dst, '\\', 'f') + case '\n': + dst = append(dst, '\\', 'n') + case '\r': + dst = append(dst, '\\', 'r') + case '\t': + dst = append(dst, '\\', 't') + default: + dst = append(dst, '\\', 'u', '0', '0', hexDigit(byte(r>>4)), hexDigit(byte(r&0xf))) + } + } + dst = append(dst, '"') + return dst +} + +func hexDigit(b byte) byte { + if b < 10 { + return '0' + b + } + return 'a' + b - 10 +} + +// jsonParseQuoted parses a JSON string element (including quotes). +func jsonParseQuoted(b []byte) (string, error) { + if len(b) < 2 || b[0] != '"' || b[len(b)-1] != '"' { + return "", fmt.Errorf("setof: invalid JSON string: %s", b) + } + inner := b[1 : len(b)-1] + if bytes.IndexByte(inner, '\\') < 0 { + return string(inner), nil + } + var s string + err := json.Unmarshal(b, &s) + return s, err +} + +type signedInt interface { + ~int | ~int8 | ~int16 | ~int32 | ~int64 +} + +type unsignedInt interface { + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 +} + +type floatNum interface { + ~float32 | ~float64 +} + +func jsonParseSigned[T signedInt](b []byte, bitSize int) (T, error) { + v, err := strconv.ParseInt(string(b), 10, bitSize) + return T(v), err +} + +func jsonParseUnsigned[T unsignedInt](b []byte, bitSize int) (T, error) { + v, err := strconv.ParseUint(string(b), 10, bitSize) + return T(v), err +} + +func jsonParseFloat[T floatNum](b []byte, bitSize int) (T, error) { + v, err := strconv.ParseFloat(string(b), bitSize) + return T(v), err +} diff --git a/msgp/setof/setof.go b/msgp/setof/setof.go index 6e82c18c..3831f248 100644 --- a/msgp/setof/setof.go +++ b/msgp/setof/setof.go @@ -1,8 +1,8 @@ // Package setof allows serializing sets map[T]struct{} as arrays. // -// Nil maps are preserved as a nil value on stream. -// -// A deterministic, sorted version is available, with slightly lower performance. +// Both msgpack and JSON encoding are supported. Nil maps are preserved +// as nil/null. A deterministic, sorted version is available for each type, +// with slightly lower performance. package setof From 3ffdd81b261ee0cdacb04c365b62b61489531f32 Mon Sep 17 00:00:00 2001 From: Klaus Post Date: Wed, 13 May 2026 10:20:34 +0200 Subject: [PATCH 2/3] Clarify what the helper supports. --- msgp/setof/json.go | 1 + 1 file changed, 1 insertion(+) diff --git a/msgp/setof/json.go b/msgp/setof/json.go index 077d97b3..3130bff4 100644 --- a/msgp/setof/json.go +++ b/msgp/setof/json.go @@ -22,6 +22,7 @@ func skipWS(data []byte, i int) int { // jsonArrayIter calls fn for each raw element in a JSON array. // String elements include their surrounding quotes. Does not allocate. +// Simple string and integer types are supported. func jsonArrayIter(data []byte, fn func(raw []byte) error) error { i := skipWS(data, 0) if i >= len(data) || data[i] != '[' { From 6e28304d2a6d84b7c6ec43d921410a908a827679 Mon Sep 17 00:00:00 2001 From: Klaus Post Date: Mon, 25 May 2026 11:14:42 +0200 Subject: [PATCH 3/3] Clarify and add fuzz test. --- msgp/setof/json.go | 2 + msgp/setof/json_fuzz_test.go | 141 +++++++++++++++++++++++++++++++++++ 2 files changed, 143 insertions(+) create mode 100644 msgp/setof/json_fuzz_test.go diff --git a/msgp/setof/json.go b/msgp/setof/json.go index 3130bff4..3acf3c05 100644 --- a/msgp/setof/json.go +++ b/msgp/setof/json.go @@ -80,6 +80,7 @@ func jsonAppendQuote(dst []byte, s string) []byte { dst = append(dst, '"') for _, r := range s { if r >= 0x20 && r != '"' && r != '\\' { + // Any printable rune... dst = utf8.AppendRune(dst, r) continue } @@ -97,6 +98,7 @@ func jsonAppendQuote(dst []byte, s string) []byte { case '\t': dst = append(dst, '\\', 't') default: + // reachable only when r < 0x20 (other control chars); always fits in \u00XX dst = append(dst, '\\', 'u', '0', '0', hexDigit(byte(r>>4)), hexDigit(byte(r&0xf))) } } diff --git a/msgp/setof/json_fuzz_test.go b/msgp/setof/json_fuzz_test.go new file mode 100644 index 00000000..378377dc --- /dev/null +++ b/msgp/setof/json_fuzz_test.go @@ -0,0 +1,141 @@ +package setof + +import ( + "encoding/json" + "math" + "reflect" + "testing" +) + +func FuzzStringJSON(f *testing.F) { + seeds := []string{ + "", + "hello", + "a\"b\\c", + string([]byte{0x00, 0x01, 0x02}), + string([]byte{0x00, 0x7F}), + "\b\f\n\r\t", + string([]byte{0x0B, 0x1F}), + "こんにちは", + string([]byte{0xFF, 0xFE}), + string([]byte{0xC0, 0xC1}), + string([]byte{0xED, 0xA0, 0x80}), + string([]byte{0x80}), + "🎉", + "\"quoted\"", + "line1\nline2", + "", + } + for _, s := range seeds { + f.Add(s) + } + f.Fuzz(func(t *testing.T, s string) { + set := String{s: {}} + + ourData, err := json.Marshal(set) + if err != nil { + t.Fatalf("our MarshalJSON failed: %v", err) + } + + var fromOurs []string + if err := json.Unmarshal(ourData, &fromOurs); err != nil { + t.Fatalf("stdlib couldn't decode our JSON %q: %v", ourData, err) + } + if len(fromOurs) != 1 { + t.Fatalf("expected 1 element, got %d", len(fromOurs)) + } + + stdData, err := json.Marshal([]string{s}) + if err != nil { + t.Fatalf("stdlib MarshalJSON failed: %v", err) + } + var fromStd []string + if err := json.Unmarshal(stdData, &fromStd); err != nil { + t.Fatalf("stdlib couldn't decode its own JSON: %v", err) + } + + if !reflect.DeepEqual(fromOurs, fromStd) { + t.Errorf("decoded value differs from stdlib:\n ours = %q (% x)\n stdlib = %q (% x)\n ourJSON = %s\n stdJSON = %s", + fromOurs[0], fromOurs[0], fromStd[0], fromStd[0], ourData, stdData) + } + + var rt String + if err := json.Unmarshal(ourData, &rt); err != nil { + t.Fatalf("our UnmarshalJSON failed: %v", err) + } + if len(rt) != 1 { + t.Fatalf("round-trip wrong length: %d", len(rt)) + } + for k := range rt { + if k != fromOurs[0] { + t.Errorf("round-trip lost data: got %q, want %q", k, fromOurs[0]) + } + } + + var rtFromStd String + if err := json.Unmarshal(stdData, &rtFromStd); err != nil { + t.Fatalf("our UnmarshalJSON failed on stdlib JSON %q: %v", stdData, err) + } + if len(rtFromStd) != 1 { + t.Fatalf("stdlib JSON wrong length: %d", len(rtFromStd)) + } + for k := range rtFromStd { + if k != fromStd[0] { + t.Errorf("our decode of stdlib JSON wrong: got %q, want %q", k, fromStd[0]) + } + } + }) +} + +func FuzzIntJSON(f *testing.F) { + for _, n := range []int{0, 1, -1, 42, -42, math.MaxInt, math.MinInt, math.MaxInt32, math.MinInt32} { + f.Add(n) + } + f.Fuzz(func(t *testing.T, n int) { + set := Int{n: {}} + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON failed for %d: %v", n, err) + } + + var fromStd []int + if err := json.Unmarshal(data, &fromStd); err != nil { + t.Fatalf("stdlib couldn't decode our JSON %q: %v", data, err) + } + if len(fromStd) != 1 || fromStd[0] != n { + t.Errorf("stdlib decoded %v, want [%d]", fromStd, n) + } + + var rt Int + if err := json.Unmarshal(data, &rt); err != nil { + t.Fatalf("UnmarshalJSON failed for %q: %v", data, err) + } + if _, ok := rt[n]; !ok || len(rt) != 1 { + t.Errorf("round-trip lost %d: got %v", n, rt) + } + }) +} + +func FuzzFloat64JSON(f *testing.F) { + for _, x := range []float64{0, 1, -1, 0.5, -0.5, 1.5e10, -1.5e-10, math.MaxFloat64, math.SmallestNonzeroFloat64} { + f.Add(x) + } + f.Fuzz(func(t *testing.T, x float64) { + if math.IsNaN(x) || math.IsInf(x, 0) { + t.Skip("NaN/Inf not representable in JSON") + } + set := Float64{x: {}} + data, err := json.Marshal(set) + if err != nil { + t.Fatalf("MarshalJSON failed for %g: %v", x, err) + } + + var rt Float64 + if err := json.Unmarshal(data, &rt); err != nil { + t.Fatalf("UnmarshalJSON failed for %q: %v", data, err) + } + if _, ok := rt[x]; !ok || len(rt) != 1 { + t.Errorf("round-trip lost %g: got %v (JSON=%s)", x, rt, data) + } + }) +}