encoding/json/v2: use slices.Sort directly

This is semantically identical and just a cleanup.

Prior to #63397, JSON object names were sorted according to UTF-16
to match the semantic of RFC 8785, but there were a number of
objections in the discussion to using that as the sorting order.

In https://github.com/go-json-experiment/json/pull/121,
we switched to sorting by UTF-8, which matches the behavior
of v1 and avoids an option to toggle the behavior.
However, we should have deleted the stringSlice.Sort method
and just directly called slices.Sort.

From a principled perspective, both UTF-16 and UTF-8 are
reasonable ways to sort JSON object names.
RFC 8259 specifies that the entire JSON text is encoded as UTF-8.
However, the way JSON strings are encoded requires escaping
Unicode codepoints according to UTF-16 surragate halves
(a quirk of JavaScript inherited by JSON).
Thus, JSON is inconsistently both UTF-8 and UTF-16.

Change-Id: Id92b5cc20efe4201827e9d3fccf24ccf894d3e60
Reviewed-on: https://go-review.googlesource.com/c/go/+/713522
Reviewed-by: Johan Brandhorst-Satzkorn <johan.brandhorst@gmail.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
TryBot-Bypass: Damien Neil <dneil@google.com>
Auto-Submit: Damien Neil <dneil@google.com>
Reviewed-by: Daniel Martí <mvdan@mvdan.cc>
Reviewed-by: Damien Neil <dneil@google.com>
This commit is contained in:
Joe Tsai 2025-10-21 10:39:15 -07:00 committed by Gopher Robot
parent 0d3dab9b1d
commit a6a59f0762
4 changed files with 5 additions and 9 deletions

View file

@ -11,8 +11,6 @@ import (
"encoding" "encoding"
"io" "io"
"reflect" "reflect"
"slices"
"strings"
"sync" "sync"
"time" "time"
@ -575,7 +573,3 @@ func putStrings(s *stringSlice) {
} }
stringsPools.Put(s) stringsPools.Put(s)
} }
func (ss *stringSlice) Sort() {
slices.SortFunc(*ss, func(x, y string) int { return strings.Compare(x, y) })
}

View file

@ -10,6 +10,7 @@ import (
"cmp" "cmp"
"math" "math"
"reflect" "reflect"
"slices"
"strconv" "strconv"
"encoding/json/internal" "encoding/json/internal"
@ -153,7 +154,7 @@ func marshalObjectAny(enc *jsontext.Encoder, obj map[string]any, mo *jsonopts.St
(*names)[i] = name (*names)[i] = name
i++ i++
} }
names.Sort() slices.Sort(*names)
for _, name := range *names { for _, name := range *names {
if err := enc.WriteToken(jsontext.String(name)); err != nil { if err := enc.WriteToken(jsontext.String(name)); err != nil {
return err return err

View file

@ -843,7 +843,7 @@ func makeMapArshaler(t reflect.Type) *arshaler {
k.SetIterKey(iter) k.SetIterKey(iter)
(*names)[i] = k.String() (*names)[i] = k.String()
} }
names.Sort() slices.Sort(*names)
for _, name := range *names { for _, name := range *names {
if err := enc.WriteToken(jsontext.String(name)); err != nil { if err := enc.WriteToken(jsontext.String(name)); err != nil {
return err return err

View file

@ -11,6 +11,7 @@ import (
"errors" "errors"
"io" "io"
"reflect" "reflect"
"slices"
"encoding/json/internal/jsonflags" "encoding/json/internal/jsonflags"
"encoding/json/internal/jsonopts" "encoding/json/internal/jsonopts"
@ -146,7 +147,7 @@ func marshalInlinedFallbackAll(enc *jsontext.Encoder, va addressableValue, mo *j
mk.SetIterKey(iter) mk.SetIterKey(iter)
(*names)[i] = mk.String() (*names)[i] = mk.String()
} }
names.Sort() slices.Sort(*names)
for _, name := range *names { for _, name := range *names {
mk.SetString(name) mk.SetString(name)
if err := marshalKey(mk); err != nil { if err := marshalKey(mk); err != nil {