diff --git a/src/encoding/json/encode.go b/src/encoding/json/encode.go index 0035a65cfc..bd55c7caf0 100644 --- a/src/encoding/json/encode.go +++ b/src/encoding/json/encode.go @@ -12,13 +12,13 @@ package json import ( "bytes" + "cmp" "encoding" "encoding/base64" "fmt" "math" "reflect" "slices" - "sort" "strconv" "strings" "sync" @@ -1162,21 +1162,23 @@ func typeFields(t reflect.Type) structFields { } } - sort.Slice(fields, func(i, j int) bool { - x := fields + slices.SortFunc(fields, func(a, b field) int { // sort field by name, breaking ties with depth, then // breaking ties with "name came from json tag", then // breaking ties with index sequence. - if x[i].name != x[j].name { - return x[i].name < x[j].name + if c := strings.Compare(a.name, b.name); c != 0 { + return c } - if len(x[i].index) != len(x[j].index) { - return len(x[i].index) < len(x[j].index) + if c := cmp.Compare(len(a.index), len(b.index)); c != 0 { + return c } - if x[i].tag != x[j].tag { - return x[i].tag + if a.tag != b.tag { + if a.tag { + return -1 + } + return +1 } - return slices.Compare(x[i].index, x[j].index) == -1 + return slices.Compare(a.index, b.index) }) // Delete all fields that are hidden by the Go rules for embedded fields, diff --git a/src/net/http/server.go b/src/net/http/server.go index 2a1108b5d4..cd0303b5b9 100644 --- a/src/net/http/server.go +++ b/src/net/http/server.go @@ -183,7 +183,7 @@ type Flusher interface { // should always test for this ability at runtime. type Hijacker interface { // Hijack lets the caller take over the connection. - // After a call to Hijack, the HTTP server library + // After a call to Hijack the HTTP server library // will not do anything else with the connection. // // It becomes the caller's responsibility to manage @@ -224,7 +224,7 @@ type CloseNotifier interface { // that the channel receives a value. // // If the protocol is HTTP/1.1 and CloseNotify is called while - // processing an idempotent request (such as a GET) while + // processing an idempotent request (such as GET) while // HTTP/1.1 pipelining is in use, the arrival of a subsequent // pipelined request may cause a value to be sent on the // returned channel. In practice HTTP/1.1 pipelining is not @@ -1102,9 +1102,9 @@ func (w *response) Header() Header { // maxPostHandlerReadBytes is the max number of Request.Body bytes not // consumed by a handler that the server will read from the client -// in order to keep a connection alive. If there are more bytes than -// this, it makes the server paranoid instead and sends a "Connection: -// close" response. +// in order to keep a connection alive. If there are more bytes +// than this, the server, to be paranoid, instead sends a +// "Connection close" response. // // This number is approximately what a typical machine's TCP buffer // size is anyway. (if we have the bytes on the machine, we might as diff --git a/src/net/lookup_plan9.go b/src/net/lookup_plan9.go index 2532a0e967..588174b1fc 100644 --- a/src/net/lookup_plan9.go +++ b/src/net/lookup_plan9.go @@ -109,17 +109,11 @@ func queryDNS(ctx context.Context, addr string, typ string) (res []string, err e func handlePlan9DNSError(err error, name string) error { if stringsHasSuffix(err.Error(), "dns: name does not exist") || stringsHasSuffix(err.Error(), "dns: resource does not exist; negrcode 0") || - stringsHasSuffix(err.Error(), "dns: resource does not exist; negrcode") { - return &DNSError{ - Err: errNoSuchHost.Error(), - Name: name, - IsNotFound: true, - } - } - return &DNSError{ - Err: err.Error(), - Name: name, + stringsHasSuffix(err.Error(), "dns: resource does not exist; negrcode") || + stringsHasSuffix(err.Error(), "dns failure") { + err = errNoSuchHost } + return newDNSError(err, name, "") } // toLower returns a lower-case version of in. Restricting us to @@ -169,10 +163,7 @@ func (*Resolver) lookupHost(ctx context.Context, host string) (addrs []string, e // host names in local network (e.g. from /lib/ndb/local) lines, err := queryCS(ctx, "net", host, "1") if err != nil { - if stringsHasSuffix(err.Error(), "dns failure") { - err = errNoSuchHost - } - return nil, newDNSError(err, host, "") + return nil, handlePlan9DNSError(err, host) } loop: for _, line := range lines { diff --git a/src/net/lookup_test.go b/src/net/lookup_test.go index bd58498fbc..97b37f2841 100644 --- a/src/net/lookup_test.go +++ b/src/net/lookup_test.go @@ -1634,6 +1634,10 @@ func TestLookupNoSuchHost(t *testing.T) { } func TestDNSErrorUnwrap(t *testing.T) { + if runtime.GOOS == "plan9" { + // The Plan 9 implementation of the resolver doesn't use the Dial function yet. See https://go.dev/cl/409234 + t.Skip("skipping on plan9") + } rDeadlineExcceeded := &Resolver{PreferGo: true, Dial: func(ctx context.Context, network, address string) (Conn, error) { return nil, context.DeadlineExceeded }} diff --git a/src/net/url/url.go b/src/net/url/url.go index f362958edd..7cd6913ad7 100644 --- a/src/net/url/url.go +++ b/src/net/url/url.go @@ -814,6 +814,22 @@ func validOptionalPort(port string) bool { // - if u.Fragment is empty, #fragment is omitted. func (u *URL) String() string { var buf strings.Builder + + n := len(u.Scheme) + if u.Opaque != "" { + n += len(u.Opaque) + } else { + if !u.OmitHost && (u.Scheme != "" || u.Host != "" || u.User != nil) { + username := u.User.Username() + password, _ := u.User.Password() + n += len(username) + len(password) + len(u.Host) + } + n += len(u.Path) + } + n += len(u.RawQuery) + len(u.RawFragment) + n += len(":" + "//" + "//" + ":" + "@" + "/" + "./" + "?" + "#") + buf.Grow(n) + if u.Scheme != "" { buf.WriteString(u.Scheme) buf.WriteByte(':') diff --git a/src/slices/slices.go b/src/slices/slices.go index ae4c2adbf4..857ab46314 100644 --- a/src/slices/slices.go +++ b/src/slices/slices.go @@ -355,20 +355,21 @@ func Clone[S ~[]E, E any](s S) S { // which may have a smaller length. // Compact zeroes the elements between the new length and the original length. func Compact[S ~[]E, E comparable](s S) S { - if len(s) > 1 { - for k := 1; k < len(s); k++ { - if s[k] == s[k-1] { - s2 := s[k:] - for k2 := 1; k2 < len(s2); k2++ { - if s2[k2] != s2[k2-1] { - s[k] = s2[k2] - k++ - } + if len(s) < 2 { + return s + } + for k := 1; k < len(s); k++ { + if s[k] == s[k-1] { + s2 := s[k:] + for k2 := 1; k2 < len(s2); k2++ { + if s2[k2] != s2[k2-1] { + s[k] = s2[k2] + k++ } - - clear(s[k:]) // zero/nil out the obsolete elements, for GC - return s[:k] } + + clear(s[k:]) // zero/nil out the obsolete elements, for GC + return s[:k] } } return s @@ -378,20 +379,21 @@ func Compact[S ~[]E, E comparable](s S) S { // For runs of elements that compare equal, CompactFunc keeps the first one. // CompactFunc zeroes the elements between the new length and the original length. func CompactFunc[S ~[]E, E any](s S, eq func(E, E) bool) S { - if len(s) > 1 { - for k := 1; k < len(s); k++ { - if eq(s[k], s[k-1]) { - s2 := s[k:] - for k2 := 1; k2 < len(s2); k2++ { - if !eq(s2[k2], s2[k2-1]) { - s[k] = s2[k2] - k++ - } + if len(s) < 2 { + return s + } + for k := 1; k < len(s); k++ { + if eq(s[k], s[k-1]) { + s2 := s[k:] + for k2 := 1; k2 < len(s2); k2++ { + if !eq(s2[k2], s2[k2-1]) { + s[k] = s2[k2] + k++ } - - clear(s[k:]) // zero/nil out the obsolete elements, for GC - return s[:k] } + + clear(s[k:]) // zero/nil out the obsolete elements, for GC + return s[:k] } } return s diff --git a/src/time/time.go b/src/time/time.go index 8c24e1c481..0bbdeaecf5 100644 --- a/src/time/time.go +++ b/src/time/time.go @@ -53,7 +53,10 @@ // // On some systems the monotonic clock will stop if the computer goes to sleep. // On such a system, t.Sub(u) may not accurately reflect the actual -// time that passed between t and u. +// time that passed between t and u. The same applies to other functions and +// methods that subtract times, such as [Since], [Until], [Before], [After], +// [Add], [Sub], [Equal] and [Compare]. In some cases, you may need to strip +// the monotonic clock to get accurate results. // // Because the monotonic clock reading has no meaning outside // the current process, the serialized forms generated by t.GobEncode,