diff --git a/apidiff/v0.0.10.txt b/apidiff/v0.0.10.txt
new file mode 100644
index 0000000..c48bc07
--- /dev/null
+++ b/apidiff/v0.0.10.txt
@@ -0,0 +1,76 @@
+Below are the incompatible changes between v0.0.9 and v0.0.10, per package.
+
+# dane
+- Dial: changed from func(context.Context, *golang.org/x/exp/slog.Logger, github.com/mjl-/mox/dns.Resolver, string, string, []github.com/mjl-/adns.TLSAUsage, *crypto/x509.CertPool) (net.Conn, github.com/mjl-/adns.TLSA, error) to func(context.Context, *log/slog.Logger, github.com/mjl-/mox/dns.Resolver, string, string, []github.com/mjl-/adns.TLSAUsage, *crypto/x509.CertPool) (net.Conn, github.com/mjl-/adns.TLSA, error)
+- TLSClientConfig: changed from func(*golang.org/x/exp/slog.Logger, []github.com/mjl-/adns.TLSA, github.com/mjl-/mox/dns.Domain, []github.com/mjl-/mox/dns.Domain, *github.com/mjl-/adns.TLSA, *crypto/x509.CertPool) crypto/tls.Config to func(*log/slog.Logger, []github.com/mjl-/adns.TLSA, github.com/mjl-/mox/dns.Domain, []github.com/mjl-/mox/dns.Domain, *github.com/mjl-/adns.TLSA, *crypto/x509.CertPool) crypto/tls.Config
+- Verify: changed from func(*golang.org/x/exp/slog.Logger, []github.com/mjl-/adns.TLSA, crypto/tls.ConnectionState, github.com/mjl-/mox/dns.Domain, []github.com/mjl-/mox/dns.Domain, *crypto/x509.CertPool) (bool, github.com/mjl-/adns.TLSA, error) to func(*log/slog.Logger, []github.com/mjl-/adns.TLSA, crypto/tls.ConnectionState, github.com/mjl-/mox/dns.Domain, []github.com/mjl-/mox/dns.Domain, *crypto/x509.CertPool) (bool, github.com/mjl-/adns.TLSA, error)
+
+# dmarc
+- Lookup: changed from func(context.Context, *golang.org/x/exp/slog.Logger, github.com/mjl-/mox/dns.Resolver, github.com/mjl-/mox/dns.Domain) (Status, github.com/mjl-/mox/dns.Domain, *Record, string, bool, error) to func(context.Context, *log/slog.Logger, github.com/mjl-/mox/dns.Resolver, github.com/mjl-/mox/dns.Domain) (Status, github.com/mjl-/mox/dns.Domain, *Record, string, bool, error)
+- LookupExternalReportsAccepted: changed from func(context.Context, *golang.org/x/exp/slog.Logger, github.com/mjl-/mox/dns.Resolver, github.com/mjl-/mox/dns.Domain, github.com/mjl-/mox/dns.Domain) (bool, Status, []*Record, []string, bool, error) to func(context.Context, *log/slog.Logger, github.com/mjl-/mox/dns.Resolver, github.com/mjl-/mox/dns.Domain, github.com/mjl-/mox/dns.Domain) (bool, Status, []*Record, []string, bool, error)
+- Verify: changed from func(context.Context, *golang.org/x/exp/slog.Logger, github.com/mjl-/mox/dns.Resolver, github.com/mjl-/mox/dns.Domain, []github.com/mjl-/mox/dkim.Result, github.com/mjl-/mox/spf.Status, *github.com/mjl-/mox/dns.Domain, bool) (bool, Result) to func(context.Context, *log/slog.Logger, github.com/mjl-/mox/dns.Resolver, github.com/mjl-/mox/dns.Domain, []github.com/mjl-/mox/dkim.Result, github.com/mjl-/mox/spf.Status, *github.com/mjl-/mox/dns.Domain, bool) (bool, Result)
+
+# dmarcrpt
+- ParseMessageReport: changed from func(*golang.org/x/exp/slog.Logger, io.ReaderAt) (*Feedback, error) to func(*log/slog.Logger, io.ReaderAt) (*Feedback, error)
+
+# dns
+- StrictResolver.Log: changed from *golang.org/x/exp/slog.Logger to *log/slog.Logger
+
+# dnsbl
+- CheckHealth: changed from func(context.Context, *golang.org/x/exp/slog.Logger, github.com/mjl-/mox/dns.Resolver, github.com/mjl-/mox/dns.Domain) error to func(context.Context, *log/slog.Logger, github.com/mjl-/mox/dns.Resolver, github.com/mjl-/mox/dns.Domain) error
+- Lookup: changed from func(context.Context, *golang.org/x/exp/slog.Logger, github.com/mjl-/mox/dns.Resolver, github.com/mjl-/mox/dns.Domain, net.IP) (Status, string, error) to func(context.Context, *log/slog.Logger, github.com/mjl-/mox/dns.Resolver, github.com/mjl-/mox/dns.Domain, net.IP) (Status, string, error)
+
+# iprev
+
+# message
+- (*Part).ParseNextPart: changed from func(*golang.org/x/exp/slog.Logger) (*Part, error) to func(*log/slog.Logger) (*Part, error)
+- (*Part).Walk: changed from func(*golang.org/x/exp/slog.Logger, *Part) error to func(*log/slog.Logger, *Part) error
+- EnsurePart: changed from func(*golang.org/x/exp/slog.Logger, bool, io.ReaderAt, int64) (Part, error) to func(*log/slog.Logger, bool, io.ReaderAt, int64) (Part, error)
+- From: changed from func(*golang.org/x/exp/slog.Logger, bool, io.ReaderAt) (github.com/mjl-/mox/smtp.Address, *Envelope, net/textproto.MIMEHeader, error) to func(*log/slog.Logger, bool, io.ReaderAt) (github.com/mjl-/mox/smtp.Address, *Envelope, net/textproto.MIMEHeader, error)
+- Parse: changed from func(*golang.org/x/exp/slog.Logger, bool, io.ReaderAt) (Part, error) to func(*log/slog.Logger, bool, io.ReaderAt) (Part, error)
+
+# mtasts
+- FetchPolicy: changed from func(context.Context, *golang.org/x/exp/slog.Logger, github.com/mjl-/mox/dns.Domain) (*Policy, string, error) to func(context.Context, *log/slog.Logger, github.com/mjl-/mox/dns.Domain) (*Policy, string, error)
+- Get: changed from func(context.Context, *golang.org/x/exp/slog.Logger, github.com/mjl-/mox/dns.Resolver, github.com/mjl-/mox/dns.Domain) (*Record, *Policy, string, error) to func(context.Context, *log/slog.Logger, github.com/mjl-/mox/dns.Resolver, github.com/mjl-/mox/dns.Domain) (*Record, *Policy, string, error)
+- HTTPClientObserve: changed from func(context.Context, *golang.org/x/exp/slog.Logger, string, string, int, error, time.Time) to func(context.Context, *log/slog.Logger, string, string, int, error, time.Time)
+- LookupRecord: changed from func(context.Context, *golang.org/x/exp/slog.Logger, github.com/mjl-/mox/dns.Resolver, github.com/mjl-/mox/dns.Domain) (*Record, string, error) to func(context.Context, *log/slog.Logger, github.com/mjl-/mox/dns.Resolver, github.com/mjl-/mox/dns.Domain) (*Record, string, error)
+
+# publicsuffix
+- List.Lookup: changed from func(context.Context, *golang.org/x/exp/slog.Logger, github.com/mjl-/mox/dns.Domain) github.com/mjl-/mox/dns.Domain to func(context.Context, *log/slog.Logger, github.com/mjl-/mox/dns.Domain) github.com/mjl-/mox/dns.Domain
+- Lookup: changed from func(context.Context, *golang.org/x/exp/slog.Logger, github.com/mjl-/mox/dns.Domain) github.com/mjl-/mox/dns.Domain to func(context.Context, *log/slog.Logger, github.com/mjl-/mox/dns.Domain) github.com/mjl-/mox/dns.Domain
+- ParseList: changed from func(*golang.org/x/exp/slog.Logger, io.Reader) (List, error) to func(*log/slog.Logger, io.Reader) (List, error)
+
+# ratelimit
+
+# sasl
+
+# scram
+
+# smtp
+
+# smtpclient
+- Dial: changed from func(context.Context, *golang.org/x/exp/slog.Logger, Dialer, github.com/mjl-/mox/dns.IPDomain, []net.IP, int, map[string][]net.IP, []net.IP) (net.Conn, net.IP, error) to func(context.Context, *log/slog.Logger, Dialer, github.com/mjl-/mox/dns.IPDomain, []net.IP, int, map[string][]net.IP, []net.IP) (net.Conn, net.IP, error)
+- GatherDestinations: changed from func(context.Context, *golang.org/x/exp/slog.Logger, github.com/mjl-/mox/dns.Resolver, github.com/mjl-/mox/dns.IPDomain) (bool, bool, bool, github.com/mjl-/mox/dns.Domain, []github.com/mjl-/mox/dns.IPDomain, bool, error) to func(context.Context, *log/slog.Logger, github.com/mjl-/mox/dns.Resolver, github.com/mjl-/mox/dns.IPDomain) (bool, bool, bool, github.com/mjl-/mox/dns.Domain, []github.com/mjl-/mox/dns.IPDomain, bool, error)
+- GatherIPs: changed from func(context.Context, *golang.org/x/exp/slog.Logger, github.com/mjl-/mox/dns.Resolver, github.com/mjl-/mox/dns.IPDomain, map[string][]net.IP) (bool, bool, github.com/mjl-/mox/dns.Domain, []net.IP, bool, error) to func(context.Context, *log/slog.Logger, github.com/mjl-/mox/dns.Resolver, github.com/mjl-/mox/dns.IPDomain, map[string][]net.IP) (bool, bool, github.com/mjl-/mox/dns.Domain, []net.IP, bool, error)
+- GatherTLSA: changed from func(context.Context, *golang.org/x/exp/slog.Logger, github.com/mjl-/mox/dns.Resolver, github.com/mjl-/mox/dns.Domain, bool, github.com/mjl-/mox/dns.Domain) (bool, []github.com/mjl-/adns.TLSA, github.com/mjl-/mox/dns.Domain, error) to func(context.Context, *log/slog.Logger, github.com/mjl-/mox/dns.Resolver, github.com/mjl-/mox/dns.Domain, bool, github.com/mjl-/mox/dns.Domain) (bool, []github.com/mjl-/adns.TLSA, github.com/mjl-/mox/dns.Domain, error)
+- New: changed from func(context.Context, *golang.org/x/exp/slog.Logger, net.Conn, TLSMode, bool, github.com/mjl-/mox/dns.Domain, github.com/mjl-/mox/dns.Domain, Opts) (*Client, error) to func(context.Context, *log/slog.Logger, net.Conn, TLSMode, bool, github.com/mjl-/mox/dns.Domain, github.com/mjl-/mox/dns.Domain, Opts) (*Client, error)
+
+# spf
+- Evaluate: changed from func(context.Context, *golang.org/x/exp/slog.Logger, *Record, github.com/mjl-/mox/dns.Resolver, Args) (Status, string, string, bool, error) to func(context.Context, *log/slog.Logger, *Record, github.com/mjl-/mox/dns.Resolver, Args) (Status, string, string, bool, error)
+- Lookup: changed from func(context.Context, *golang.org/x/exp/slog.Logger, github.com/mjl-/mox/dns.Resolver, github.com/mjl-/mox/dns.Domain) (Status, string, *Record, bool, error) to func(context.Context, *log/slog.Logger, github.com/mjl-/mox/dns.Resolver, github.com/mjl-/mox/dns.Domain) (Status, string, *Record, bool, error)
+- Verify: changed from func(context.Context, *golang.org/x/exp/slog.Logger, github.com/mjl-/mox/dns.Resolver, Args) (Received, github.com/mjl-/mox/dns.Domain, string, bool, error) to func(context.Context, *log/slog.Logger, github.com/mjl-/mox/dns.Resolver, Args) (Received, github.com/mjl-/mox/dns.Domain, string, bool, error)
+
+# subjectpass
+- Generate: changed from func(*golang.org/x/exp/slog.Logger, github.com/mjl-/mox/smtp.Address, []byte, time.Time) string to func(*log/slog.Logger, github.com/mjl-/mox/smtp.Address, []byte, time.Time) string
+- Verify: changed from func(*golang.org/x/exp/slog.Logger, io.ReaderAt, []byte, time.Duration) error to func(*log/slog.Logger, io.ReaderAt, []byte, time.Duration) error
+
+# tlsrpt
+- Lookup: changed from func(context.Context, *golang.org/x/exp/slog.Logger, github.com/mjl-/mox/dns.Resolver, github.com/mjl-/mox/dns.Domain) (*Record, string, error) to func(context.Context, *log/slog.Logger, github.com/mjl-/mox/dns.Resolver, github.com/mjl-/mox/dns.Domain) (*Record, string, error)
+- ParseMessage: changed from func(*golang.org/x/exp/slog.Logger, io.ReaderAt) (*ReportJSON, error) to func(*log/slog.Logger, io.ReaderAt) (*ReportJSON, error)
+
+# updates
+- Check: changed from func(context.Context, *golang.org/x/exp/slog.Logger, github.com/mjl-/mox/dns.Resolver, github.com/mjl-/mox/dns.Domain, Version, string, []byte) (Version, *Record, *Changelog, error) to func(context.Context, *log/slog.Logger, github.com/mjl-/mox/dns.Resolver, github.com/mjl-/mox/dns.Domain, Version, string, []byte) (Version, *Record, *Changelog, error)
+- FetchChangelog: changed from func(context.Context, *golang.org/x/exp/slog.Logger, string, Version, []byte) (*Changelog, error) to func(context.Context, *log/slog.Logger, string, Version, []byte) (*Changelog, error)
+- HTTPClientObserve: changed from func(context.Context, *golang.org/x/exp/slog.Logger, string, string, int, error, time.Time) to func(context.Context, *log/slog.Logger, string, string, int, error, time.Time)
+- Lookup: changed from func(context.Context, *golang.org/x/exp/slog.Logger, github.com/mjl-/mox/dns.Resolver, github.com/mjl-/mox/dns.Domain) (Version, *Record, error) to func(context.Context, *log/slog.Logger, github.com/mjl-/mox/dns.Resolver, github.com/mjl-/mox/dns.Domain) (Version, *Record, error)
+
diff --git a/autotls/autotls.go b/autotls/autotls.go
index 13b2f53..587ee14 100644
--- a/autotls/autotls.go
+++ b/autotls/autotls.go
@@ -20,6 +20,7 @@ import (
"errors"
"fmt"
"io"
+ "log/slog"
"net"
"os"
"path/filepath"
@@ -29,7 +30,6 @@ import (
"time"
"golang.org/x/crypto/acme"
- "golang.org/x/exp/slog"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
diff --git a/backup.go b/backup.go
index 6022399..9695101 100644
--- a/backup.go
+++ b/backup.go
@@ -7,13 +7,12 @@ import (
"fmt"
"io"
"io/fs"
+ "log/slog"
"os"
"path/filepath"
"strings"
"time"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/bstore"
"github.com/mjl-/mox/dmarcdb"
diff --git a/ctl.go b/ctl.go
index 4d551ae..393f3d2 100644
--- a/ctl.go
+++ b/ctl.go
@@ -7,6 +7,7 @@ import (
"fmt"
"io"
"log"
+ "log/slog"
"net"
"os"
"path/filepath"
@@ -16,8 +17,6 @@ import (
"strings"
"time"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/bstore"
"github.com/mjl-/mox/dns"
diff --git a/dane/dane.go b/dane/dane.go
index 1129fed..46dd8ef 100644
--- a/dane/dane.go
+++ b/dane/dane.go
@@ -55,12 +55,11 @@ import (
"crypto/x509"
"errors"
"fmt"
+ "log/slog"
"net"
"strings"
"time"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/adns"
"github.com/mjl-/mox/dns"
diff --git a/dane/dane_test.go b/dane/dane_test.go
index 1795186..42dad3e 100644
--- a/dane/dane_test.go
+++ b/dane/dane_test.go
@@ -12,6 +12,7 @@ import (
"crypto/x509/pkix"
"errors"
"fmt"
+ "log/slog"
"math/big"
"net"
"reflect"
@@ -20,8 +21,6 @@ import (
"testing"
"time"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/adns"
"github.com/mjl-/mox/dns"
diff --git a/dane/examples_test.go b/dane/examples_test.go
index c3768fd..f373122 100644
--- a/dane/examples_test.go
+++ b/dane/examples_test.go
@@ -4,8 +4,7 @@ import (
"context"
"crypto/x509"
"log"
-
- "golang.org/x/exp/slog"
+ "log/slog"
"github.com/mjl-/adns"
diff --git a/dkim/dkim.go b/dkim/dkim.go
index dedced9..52e7617 100644
--- a/dkim/dkim.go
+++ b/dkim/dkim.go
@@ -21,11 +21,10 @@ import (
"fmt"
"hash"
"io"
+ "log/slog"
"strings"
"time"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/mox/dns"
"github.com/mjl-/mox/mlog"
"github.com/mjl-/mox/moxio"
diff --git a/dmarc/dmarc.go b/dmarc/dmarc.go
index a105481..ccfc8b1 100644
--- a/dmarc/dmarc.go
+++ b/dmarc/dmarc.go
@@ -14,6 +14,7 @@ import (
"context"
"errors"
"fmt"
+ "log/slog"
mathrand "math/rand"
"time"
@@ -23,8 +24,6 @@ import (
"github.com/mjl-/mox/publicsuffix"
"github.com/mjl-/mox/spf"
"github.com/mjl-/mox/stub"
-
- "golang.org/x/exp/slog"
)
var (
diff --git a/dmarc/examples_test.go b/dmarc/examples_test.go
index 55498db..3dc6965 100644
--- a/dmarc/examples_test.go
+++ b/dmarc/examples_test.go
@@ -3,11 +3,10 @@ package dmarc_test
import (
"context"
"log"
+ "log/slog"
"net"
"strings"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/mox/dkim"
"github.com/mjl-/mox/dmarc"
"github.com/mjl-/mox/dns"
diff --git a/dmarcdb/eval.go b/dmarcdb/eval.go
index 85cf599..35c8722 100644
--- a/dmarcdb/eval.go
+++ b/dmarcdb/eval.go
@@ -9,6 +9,7 @@ import (
"errors"
"fmt"
"io"
+ "log/slog"
"mime"
"mime/multipart"
"net/textproto"
@@ -16,14 +17,13 @@ import (
"os"
"path/filepath"
"runtime/debug"
+ "slices"
"sort"
"strings"
"sync"
"time"
"golang.org/x/exp/maps"
- "golang.org/x/exp/slices"
- "golang.org/x/exp/slog"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
diff --git a/dmarcdb/eval_test.go b/dmarcdb/eval_test.go
index 04e5e9f..f37c340 100644
--- a/dmarcdb/eval_test.go
+++ b/dmarcdb/eval_test.go
@@ -6,6 +6,7 @@ import (
"encoding/xml"
"fmt"
"io"
+ "log/slog"
"os"
"path/filepath"
"reflect"
@@ -13,8 +14,6 @@ import (
"testing"
"time"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/mox/dmarcrpt"
"github.com/mjl-/mox/dns"
"github.com/mjl-/mox/mlog"
diff --git a/dmarcrpt/parse.go b/dmarcrpt/parse.go
index 7660d58..504e610 100644
--- a/dmarcrpt/parse.go
+++ b/dmarcrpt/parse.go
@@ -9,11 +9,10 @@ import (
"errors"
"fmt"
"io"
+ "log/slog"
"net/http"
"strings"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/mox/message"
"github.com/mjl-/mox/mlog"
"github.com/mjl-/mox/moxio"
diff --git a/dns/mock.go b/dns/mock.go
index 5a09bda..11de8e2 100644
--- a/dns/mock.go
+++ b/dns/mock.go
@@ -4,8 +4,7 @@ import (
"context"
"fmt"
"net"
-
- "golang.org/x/exp/slices"
+ "slices"
"github.com/mjl-/adns"
)
diff --git a/dns/resolver.go b/dns/resolver.go
index 0c5deab..c0119e1 100644
--- a/dns/resolver.go
+++ b/dns/resolver.go
@@ -4,14 +4,13 @@ import (
"context"
"errors"
"fmt"
+ "log/slog"
"net"
"os"
"runtime"
"strings"
"time"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/adns"
"github.com/mjl-/mox/mlog"
diff --git a/dnsbl/dnsbl.go b/dnsbl/dnsbl.go
index 17a479b..cb10a39 100644
--- a/dnsbl/dnsbl.go
+++ b/dnsbl/dnsbl.go
@@ -18,13 +18,12 @@ import (
"context"
"errors"
"fmt"
+ "log/slog"
"net"
"strconv"
"strings"
"time"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/mox/dns"
"github.com/mjl-/mox/mlog"
"github.com/mjl-/mox/stub"
diff --git a/dnsbl/examples_test.go b/dnsbl/examples_test.go
index 102946f..b9b4cbf 100644
--- a/dnsbl/examples_test.go
+++ b/dnsbl/examples_test.go
@@ -3,10 +3,9 @@ package dnsbl_test
import (
"context"
"log"
+ "log/slog"
"net"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/mox/dns"
"github.com/mjl-/mox/dnsbl"
)
diff --git a/dsn/parse.go b/dsn/parse.go
index f5bcf99..97e7827 100644
--- a/dsn/parse.go
+++ b/dsn/parse.go
@@ -4,13 +4,12 @@ import (
"bufio"
"fmt"
"io"
+ "log/slog"
"net/textproto"
"strconv"
"strings"
"time"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/mox/dns"
"github.com/mjl-/mox/message"
"github.com/mjl-/mox/mlog"
diff --git a/go.mod b/go.mod
index 5b38b2c..cb3800e 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,6 @@
module github.com/mjl-/mox
-go 1.20
+go 1.21
require (
github.com/mjl-/adns v0.0.0-20231109160910-82839fe3e6ae
diff --git a/go.sum b/go.sum
index 8b29ac7..06ee0ae 100644
--- a/go.sum
+++ b/go.sum
@@ -17,6 +17,7 @@ github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
+github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
@@ -66,6 +67,7 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
+github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
go.etcd.io/bbolt v1.3.8 h1:xs88BrvEv273UsB79e0hcVrlUWmS0a8upikMFhSyAtA=
go.etcd.io/bbolt v1.3.8/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
@@ -87,6 +89,7 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
+golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -109,5 +112,6 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
rsc.io/qr v0.2.0 h1:6vBLea5/NRMVTz8V66gipeLycZMl/+UlFmk8DvqQ6WY=
rsc.io/qr v0.2.0/go.mod h1:IF+uZjkb9fqyeF/4tlBoynqmQxUoPfWEKh921coOuXs=
diff --git a/http/autoconf.go b/http/autoconf.go
index 09a3690..3c877e4 100644
--- a/http/autoconf.go
+++ b/http/autoconf.go
@@ -3,11 +3,10 @@ package http
import (
"encoding/xml"
"fmt"
+ "log/slog"
"net/http"
"strings"
- "golang.org/x/exp/slog"
-
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
"rsc.io/qr"
diff --git a/http/gzcache.go b/http/gzcache.go
index f3208c8..db7f88d 100644
--- a/http/gzcache.go
+++ b/http/gzcache.go
@@ -7,6 +7,7 @@ import (
"fmt"
"io"
"io/fs"
+ "log/slog"
"net/http"
"os"
"path/filepath"
@@ -16,8 +17,6 @@ import (
"sync"
"time"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/mox/mlog"
)
diff --git a/http/mobileconfig.go b/http/mobileconfig.go
index 4e8164b..373573e 100644
--- a/http/mobileconfig.go
+++ b/http/mobileconfig.go
@@ -6,11 +6,11 @@ import (
"crypto/sha256"
"encoding/xml"
"fmt"
+ "slices"
"sort"
"strings"
"golang.org/x/exp/maps"
- "golang.org/x/exp/slices"
"github.com/mjl-/mox/mox-"
"github.com/mjl-/mox/smtp"
diff --git a/http/mtasts.go b/http/mtasts.go
index 47f90eb..3d762ef 100644
--- a/http/mtasts.go
+++ b/http/mtasts.go
@@ -1,13 +1,12 @@
package http
import (
+ "log/slog"
"net"
"net/http"
"strings"
"time"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/mox/dns"
"github.com/mjl-/mox/mlog"
"github.com/mjl-/mox/mox-"
diff --git a/http/web.go b/http/web.go
index def777f..d60d6d9 100644
--- a/http/web.go
+++ b/http/web.go
@@ -10,6 +10,7 @@ import (
"fmt"
"io"
golog "log"
+ "log/slog"
"net"
"net/http"
"os"
@@ -21,7 +22,6 @@ import (
_ "net/http/pprof"
"golang.org/x/exp/maps"
- "golang.org/x/exp/slog"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
diff --git a/http/webserver.go b/http/webserver.go
index ec92679..ad9c14d 100644
--- a/http/webserver.go
+++ b/http/webserver.go
@@ -13,6 +13,7 @@ import (
"io"
"io/fs"
golog "log"
+ "log/slog"
"net"
"net/http"
"net/http/httputil"
@@ -25,8 +26,6 @@ import (
"syscall"
"time"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/mox/config"
"github.com/mjl-/mox/dns"
"github.com/mjl-/mox/mlog"
diff --git a/imapserver/fetch.go b/imapserver/fetch.go
index 731c7db..1cb666a 100644
--- a/imapserver/fetch.go
+++ b/imapserver/fetch.go
@@ -7,12 +7,12 @@ import (
"errors"
"fmt"
"io"
+ "log/slog"
"net/textproto"
"sort"
"strings"
"golang.org/x/exp/maps"
- "golang.org/x/exp/slog"
"github.com/mjl-/bstore"
diff --git a/imapserver/search.go b/imapserver/search.go
index b1bfc0b..e112164 100644
--- a/imapserver/search.go
+++ b/imapserver/search.go
@@ -2,11 +2,10 @@ package imapserver
import (
"fmt"
+ "log/slog"
"net/textproto"
"strings"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/bstore"
"github.com/mjl-/mox/message"
diff --git a/imapserver/server.go b/imapserver/server.go
index 3b6dc77..ee1c23a 100644
--- a/imapserver/server.go
+++ b/imapserver/server.go
@@ -44,6 +44,7 @@ import (
"fmt"
"hash"
"io"
+ "log/slog"
"math"
"net"
"os"
@@ -51,14 +52,13 @@ import (
"path/filepath"
"regexp"
"runtime/debug"
+ "slices"
"sort"
"strings"
"sync"
"time"
"golang.org/x/exp/maps"
- "golang.org/x/exp/slices"
- "golang.org/x/exp/slog"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
diff --git a/import.go b/import.go
index b3c8427..e7d78ec 100644
--- a/import.go
+++ b/import.go
@@ -8,6 +8,7 @@ import (
"fmt"
"io"
"log"
+ "log/slog"
"net"
"os"
"path/filepath"
@@ -16,7 +17,6 @@ import (
"time"
"golang.org/x/exp/maps"
- "golang.org/x/exp/slog"
"github.com/mjl-/mox/config"
"github.com/mjl-/mox/message"
diff --git a/integration_test.go b/integration_test.go
index 7c2e577..38514a0 100644
--- a/integration_test.go
+++ b/integration_test.go
@@ -7,6 +7,7 @@ package main
import (
"crypto/tls"
"fmt"
+ "log/slog"
"net"
"os"
"os/exec"
@@ -14,8 +15,6 @@ import (
"testing"
"time"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/mox/dns"
"github.com/mjl-/mox/imapclient"
"github.com/mjl-/mox/mlog"
diff --git a/iprev/iprev.go b/iprev/iprev.go
index 52b67d1..aadf3de 100644
--- a/iprev/iprev.go
+++ b/iprev/iprev.go
@@ -6,11 +6,10 @@ import (
"context"
"errors"
"fmt"
+ "log/slog"
"net"
"time"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/mox/dns"
"github.com/mjl-/mox/mlog"
"github.com/mjl-/mox/stub"
diff --git a/junk/filter.go b/junk/filter.go
index 57bf78a..1de8059 100644
--- a/junk/filter.go
+++ b/junk/filter.go
@@ -15,14 +15,13 @@ import (
"errors"
"fmt"
"io"
+ "log/slog"
"math"
"os"
"path/filepath"
"sort"
"time"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/bstore"
"github.com/mjl-/mox/message"
diff --git a/localserve.go b/localserve.go
index 84910db..a1848c2 100644
--- a/localserve.go
+++ b/localserve.go
@@ -11,6 +11,7 @@ import (
"encoding/pem"
"fmt"
golog "log"
+ "log/slog"
"math/big"
"net"
"os"
@@ -21,7 +22,6 @@ import (
"time"
"golang.org/x/crypto/bcrypt"
- "golang.org/x/exp/slog"
"github.com/mjl-/sconf"
diff --git a/main.go b/main.go
index 9a8550d..d152aff 100644
--- a/main.go
+++ b/main.go
@@ -21,18 +21,18 @@ import (
"io"
"io/fs"
"log"
+ "log/slog"
"net"
"net/url"
"os"
"path/filepath"
"runtime"
+ "slices"
"strconv"
"strings"
"time"
"golang.org/x/crypto/bcrypt"
- "golang.org/x/exp/slices"
- "golang.org/x/exp/slog"
"github.com/mjl-/adns"
diff --git a/message/examples_test.go b/message/examples_test.go
index 3101d7b..9b465ab 100644
--- a/message/examples_test.go
+++ b/message/examples_test.go
@@ -6,11 +6,10 @@ import (
"fmt"
"io"
"log"
+ "log/slog"
"strings"
"time"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/mox/dns"
"github.com/mjl-/mox/message"
"github.com/mjl-/mox/smtp"
diff --git a/message/from.go b/message/from.go
index 0d2a1b3..0ce33f2 100644
--- a/message/from.go
+++ b/message/from.go
@@ -3,10 +3,9 @@ package message
import (
"fmt"
"io"
+ "log/slog"
"net/textproto"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/mox/dns"
"github.com/mjl-/mox/mlog"
"github.com/mjl-/mox/smtp"
diff --git a/message/part.go b/message/part.go
index 07012b1..4f13dca 100644
--- a/message/part.go
+++ b/message/part.go
@@ -14,6 +14,7 @@ import (
"errors"
"fmt"
"io"
+ "log/slog"
"mime"
"mime/quotedprintable"
"net/mail"
@@ -21,7 +22,6 @@ import (
"strings"
"time"
- "golang.org/x/exp/slog"
"golang.org/x/text/encoding/ianaindex"
"github.com/mjl-/mox/mlog"
diff --git a/metrics.go b/metrics.go
index 693f611..b0bffb3 100644
--- a/metrics.go
+++ b/metrics.go
@@ -4,11 +4,10 @@ import (
"context"
"errors"
"fmt"
+ "log/slog"
"os"
"time"
- "golang.org/x/exp/slog"
-
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
diff --git a/mlog/log.go b/mlog/log.go
index 6619ef4..0c2f685 100644
--- a/mlog/log.go
+++ b/mlog/log.go
@@ -18,14 +18,13 @@ import (
"encoding/base64"
"fmt"
"io"
+ "log/slog"
"os"
"reflect"
"strconv"
"strings"
"sync/atomic"
"time"
-
- "golang.org/x/exp/slog"
)
var noctx = context.Background()
diff --git a/mox-/admin.go b/mox-/admin.go
index c5f51ed..acbb5c0 100644
--- a/mox-/admin.go
+++ b/mox-/admin.go
@@ -11,6 +11,7 @@ import (
"crypto/x509"
"encoding/pem"
"fmt"
+ "log/slog"
"net"
"net/url"
"os"
@@ -20,7 +21,6 @@ import (
"time"
"golang.org/x/exp/maps"
- "golang.org/x/exp/slog"
"github.com/mjl-/adns"
diff --git a/mox-/config.go b/mox-/config.go
index f184ae3..b082641 100644
--- a/mox-/config.go
+++ b/mox-/config.go
@@ -16,6 +16,7 @@ import (
"errors"
"fmt"
"io"
+ "log/slog"
"net"
"net/http"
"net/url"
@@ -29,7 +30,6 @@ import (
"sync"
"time"
- "golang.org/x/exp/slog"
"golang.org/x/text/unicode/norm"
"github.com/mjl-/autocert"
diff --git a/mox-/forkexec_unix.go b/mox-/forkexec_unix.go
index 687f7ff..f96aa18 100644
--- a/mox-/forkexec_unix.go
+++ b/mox-/forkexec_unix.go
@@ -3,12 +3,11 @@
package mox
import (
+ "log/slog"
"os"
"os/signal"
"strings"
"syscall"
-
- "golang.org/x/exp/slog"
)
// Fork and exec as unprivileged user.
diff --git a/mox-/tlsrecv.go b/mox-/tlsrecv.go
index dab0879..6e1be20 100644
--- a/mox-/tlsrecv.go
+++ b/mox-/tlsrecv.go
@@ -3,8 +3,7 @@ package mox
import (
"crypto/tls"
"fmt"
-
- "golang.org/x/exp/slog"
+ "log/slog"
"github.com/mjl-/mox/mlog"
)
diff --git a/mox-/webappfile.go b/mox-/webappfile.go
index 3545580..42aefaf 100644
--- a/mox-/webappfile.go
+++ b/mox-/webappfile.go
@@ -7,14 +7,13 @@ import (
"errors"
"fmt"
"io"
+ "log/slog"
"net/http"
"os"
"strings"
"sync"
"time"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/mox/mlog"
"github.com/mjl-/mox/moxvar"
)
diff --git a/moxio/bufpool.go b/moxio/bufpool.go
index 32acd16..f3e79dc 100644
--- a/moxio/bufpool.go
+++ b/moxio/bufpool.go
@@ -5,8 +5,7 @@ import (
"errors"
"fmt"
"io"
-
- "golang.org/x/exp/slog"
+ "log/slog"
"github.com/mjl-/mox/mlog"
)
diff --git a/moxio/linkcopy.go b/moxio/linkcopy.go
index 9e8753a..bd1a497 100644
--- a/moxio/linkcopy.go
+++ b/moxio/linkcopy.go
@@ -3,10 +3,9 @@ package moxio
import (
"fmt"
"io"
+ "log/slog"
"os"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/mox/mlog"
)
diff --git a/moxio/trace.go b/moxio/trace.go
index a4890ec..dc67bfd 100644
--- a/moxio/trace.go
+++ b/moxio/trace.go
@@ -2,8 +2,7 @@ package moxio
import (
"io"
-
- "golang.org/x/exp/slog"
+ "log/slog"
"github.com/mjl-/mox/mlog"
)
diff --git a/mtasts/examples_test.go b/mtasts/examples_test.go
index 0a2fd81..9a6c69d 100644
--- a/mtasts/examples_test.go
+++ b/mtasts/examples_test.go
@@ -4,8 +4,7 @@ import (
"context"
"errors"
"log"
-
- "golang.org/x/exp/slog"
+ "log/slog"
"github.com/mjl-/mox/dns"
"github.com/mjl-/mox/mtasts"
diff --git a/mtasts/mtasts.go b/mtasts/mtasts.go
index beaa5f3..ef2ef14 100644
--- a/mtasts/mtasts.go
+++ b/mtasts/mtasts.go
@@ -16,12 +16,11 @@ import (
"errors"
"fmt"
"io"
+ "log/slog"
"net/http"
"strings"
"time"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/adns"
"github.com/mjl-/mox/dns"
diff --git a/mtasts/mtasts_test.go b/mtasts/mtasts_test.go
index ed45a34..8a3aa62 100644
--- a/mtasts/mtasts_test.go
+++ b/mtasts/mtasts_test.go
@@ -9,6 +9,7 @@ import (
"errors"
"io"
golog "log"
+ "log/slog"
"math/big"
"net"
"net/http"
@@ -18,8 +19,6 @@ import (
"testing"
"time"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/adns"
"github.com/mjl-/mox/dns"
diff --git a/mtastsdb/db.go b/mtastsdb/db.go
index 516e642..9a13cd8 100644
--- a/mtastsdb/db.go
+++ b/mtastsdb/db.go
@@ -10,14 +10,13 @@ import (
"crypto/tls"
"errors"
"fmt"
+ "log/slog"
"os"
"path/filepath"
"strings"
"sync"
"time"
- "golang.org/x/exp/slog"
-
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
diff --git a/mtastsdb/refresh.go b/mtastsdb/refresh.go
index 46c2d25..d61df91 100644
--- a/mtastsdb/refresh.go
+++ b/mtastsdb/refresh.go
@@ -4,12 +4,11 @@ import (
"context"
"errors"
"fmt"
+ "log/slog"
mathrand "math/rand"
"runtime/debug"
"time"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/bstore"
"github.com/mjl-/mox/dns"
diff --git a/publicsuffix/examples_test.go b/publicsuffix/examples_test.go
index 2dc6bec..20981df 100644
--- a/publicsuffix/examples_test.go
+++ b/publicsuffix/examples_test.go
@@ -3,8 +3,7 @@ package publicsuffix_test
import (
"context"
"fmt"
-
- "golang.org/x/exp/slog"
+ "log/slog"
"github.com/mjl-/mox/dns"
"github.com/mjl-/mox/publicsuffix"
diff --git a/publicsuffix/list.go b/publicsuffix/list.go
index 90d046f..f74f192 100644
--- a/publicsuffix/list.go
+++ b/publicsuffix/list.go
@@ -14,11 +14,11 @@ import (
"context"
"fmt"
"io"
+ "log/slog"
"strings"
_ "embed"
- "golang.org/x/exp/slog"
"golang.org/x/net/idna"
"github.com/mjl-/mox/dns"
diff --git a/queue/direct.go b/queue/direct.go
index 2763e3e..62c8c43 100644
--- a/queue/direct.go
+++ b/queue/direct.go
@@ -6,13 +6,12 @@ import (
"errors"
"fmt"
"io"
+ "log/slog"
"net"
"os"
"strings"
"time"
- "golang.org/x/exp/slog"
-
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
diff --git a/queue/dsn.go b/queue/dsn.go
index b238dff..1c451c7 100644
--- a/queue/dsn.go
+++ b/queue/dsn.go
@@ -4,11 +4,10 @@ import (
"bufio"
"context"
"fmt"
+ "log/slog"
"os"
"time"
- "golang.org/x/exp/slog"
-
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
diff --git a/queue/queue.go b/queue/queue.go
index c6e459e..0f7114f 100644
--- a/queue/queue.go
+++ b/queue/queue.go
@@ -7,6 +7,7 @@ import (
"context"
"fmt"
"io"
+ "log/slog"
"net"
"os"
"path/filepath"
@@ -15,7 +16,6 @@ import (
"strings"
"time"
- "golang.org/x/exp/slog"
"golang.org/x/net/proxy"
"github.com/prometheus/client_golang/prometheus"
diff --git a/queue/submit.go b/queue/submit.go
index 45cd3ae..21ed08d 100644
--- a/queue/submit.go
+++ b/queue/submit.go
@@ -7,13 +7,12 @@ import (
"errors"
"fmt"
"io"
+ "log/slog"
"net"
"os"
+ "slices"
"time"
- "golang.org/x/exp/slices"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/mox/config"
"github.com/mjl-/mox/dns"
"github.com/mjl-/mox/dsn"
diff --git a/rfc/xr.go b/rfc/xr.go
index 227feea..60f9f01 100644
--- a/rfc/xr.go
+++ b/rfc/xr.go
@@ -11,14 +11,13 @@ import (
"fmt"
htmltemplate "html/template"
"log"
+ "maps"
"os"
"path/filepath"
"regexp"
"sort"
"strconv"
"strings"
-
- "golang.org/x/exp/maps"
)
var destdir string
diff --git a/sendmail.go b/sendmail.go
index 5148256..88d8f17 100644
--- a/sendmail.go
+++ b/sendmail.go
@@ -12,11 +12,10 @@ import (
"net/mail"
"os"
"path/filepath"
+ "slices"
"strings"
"time"
- "golang.org/x/exp/slices"
-
"github.com/mjl-/sconf"
"github.com/mjl-/mox/dns"
diff --git a/serve_unix.go b/serve_unix.go
index 0a5ca9a..4c9c262 100644
--- a/serve_unix.go
+++ b/serve_unix.go
@@ -7,6 +7,7 @@ import (
cryptorand "crypto/rand"
"fmt"
"io/fs"
+ "log/slog"
"net"
"os"
"os/signal"
@@ -18,8 +19,6 @@ import (
"syscall"
"time"
- "golang.org/x/exp/slog"
-
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
diff --git a/smtpclient/client.go b/smtpclient/client.go
index 8f5f0de..4fd8d86 100644
--- a/smtpclient/client.go
+++ b/smtpclient/client.go
@@ -35,14 +35,13 @@ import (
"errors"
"fmt"
"io"
+ "log/slog"
"net"
"reflect"
"strconv"
"strings"
"time"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/adns"
"github.com/mjl-/mox/dane"
diff --git a/smtpclient/client_test.go b/smtpclient/client_test.go
index 5105449..87702f3 100644
--- a/smtpclient/client_test.go
+++ b/smtpclient/client_test.go
@@ -14,6 +14,7 @@ import (
"fmt"
"hash"
"io"
+ "log/slog"
"math/big"
"net"
"reflect"
@@ -21,8 +22,6 @@ import (
"testing"
"time"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/mox/dns"
"github.com/mjl-/mox/mlog"
"github.com/mjl-/mox/sasl"
diff --git a/smtpclient/dial.go b/smtpclient/dial.go
index 742f9d8..b5d2a49 100644
--- a/smtpclient/dial.go
+++ b/smtpclient/dial.go
@@ -3,11 +3,10 @@ package smtpclient
import (
"context"
"fmt"
+ "log/slog"
"net"
"time"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/mox/dns"
"github.com/mjl-/mox/mlog"
)
diff --git a/smtpclient/examples_test.go b/smtpclient/examples_test.go
index fdeab89..cbdd03d 100644
--- a/smtpclient/examples_test.go
+++ b/smtpclient/examples_test.go
@@ -4,12 +4,11 @@ import (
"context"
"crypto/tls"
"log"
+ "log/slog"
"net"
+ "slices"
"strings"
- "golang.org/x/exp/slices"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/mox/dns"
"github.com/mjl-/mox/sasl"
"github.com/mjl-/mox/smtpclient"
diff --git a/smtpclient/gather.go b/smtpclient/gather.go
index 1d28948..4035f82 100644
--- a/smtpclient/gather.go
+++ b/smtpclient/gather.go
@@ -7,13 +7,12 @@ import (
"crypto/x509"
"errors"
"fmt"
+ "log/slog"
"net"
"sort"
"strings"
"time"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/adns"
"github.com/mjl-/mox/dns"
diff --git a/smtpserver/analyze.go b/smtpserver/analyze.go
index 02097ec..c858426 100644
--- a/smtpserver/analyze.go
+++ b/smtpserver/analyze.go
@@ -3,13 +3,12 @@ package smtpserver
import (
"context"
"fmt"
+ "log/slog"
"net"
"os"
"strings"
"time"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/bstore"
"github.com/mjl-/mox/dkim"
diff --git a/smtpserver/rejects.go b/smtpserver/rejects.go
index 2ac5bf7..71013c2 100644
--- a/smtpserver/rejects.go
+++ b/smtpserver/rejects.go
@@ -6,10 +6,9 @@ import (
"crypto/sha256"
"fmt"
"io"
+ "log/slog"
"os"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/bstore"
"github.com/mjl-/mox/message"
diff --git a/smtpserver/reputation.go b/smtpserver/reputation.go
index 45bb05b..631235f 100644
--- a/smtpserver/reputation.go
+++ b/smtpserver/reputation.go
@@ -3,10 +3,9 @@ package smtpserver
import (
"errors"
"fmt"
+ "log/slog"
"time"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/bstore"
"github.com/mjl-/mox/mlog"
diff --git a/smtpserver/server.go b/smtpserver/server.go
index f05a9f0..827dd8e 100644
--- a/smtpserver/server.go
+++ b/smtpserver/server.go
@@ -15,6 +15,7 @@ import (
"fmt"
"hash"
"io"
+ "log/slog"
"math"
"net"
"net/textproto"
@@ -27,7 +28,6 @@ import (
"time"
"golang.org/x/exp/maps"
- "golang.org/x/exp/slog"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
diff --git a/smtpserver/server_test.go b/smtpserver/server_test.go
index 1608fe2..3c0b175 100644
--- a/smtpserver/server_test.go
+++ b/smtpserver/server_test.go
@@ -13,6 +13,7 @@ import (
"encoding/base64"
"errors"
"fmt"
+ "log/slog"
"math/big"
"mime/quotedprintable"
"net"
@@ -23,8 +24,6 @@ import (
"testing"
"time"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/bstore"
"github.com/mjl-/mox/config"
diff --git a/spf/examples_test.go b/spf/examples_test.go
index bd96c36..65b6e8f 100644
--- a/spf/examples_test.go
+++ b/spf/examples_test.go
@@ -3,10 +3,9 @@ package spf_test
import (
"context"
"log"
+ "log/slog"
"net"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/mox/dns"
"github.com/mjl-/mox/smtp"
"github.com/mjl-/mox/spf"
diff --git a/spf/spf.go b/spf/spf.go
index 06e27ec..48120c9 100644
--- a/spf/spf.go
+++ b/spf/spf.go
@@ -10,14 +10,13 @@ import (
"context"
"errors"
"fmt"
+ "log/slog"
"net"
"net/url"
"strconv"
"strings"
"time"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/mox/dns"
"github.com/mjl-/mox/mlog"
"github.com/mjl-/mox/smtp"
diff --git a/store/account.go b/store/account.go
index bacd39f..1fd98a9 100644
--- a/store/account.go
+++ b/store/account.go
@@ -33,9 +33,11 @@ import (
"fmt"
"hash"
"io"
+ "log/slog"
"os"
"path/filepath"
"runtime/debug"
+ "slices"
"sort"
"strconv"
"strings"
@@ -43,8 +45,6 @@ import (
"time"
"golang.org/x/crypto/bcrypt"
- "golang.org/x/exp/slices"
- "golang.org/x/exp/slog"
"golang.org/x/text/unicode/norm"
"github.com/mjl-/bstore"
diff --git a/store/cleanuptemp.go b/store/cleanuptemp.go
index 10bb148..499dbc3 100644
--- a/store/cleanuptemp.go
+++ b/store/cleanuptemp.go
@@ -1,10 +1,9 @@
package store
import (
+ "log/slog"
"os"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/mox/mlog"
)
diff --git a/store/export.go b/store/export.go
index 527b05c..80f3229 100644
--- a/store/export.go
+++ b/store/export.go
@@ -8,14 +8,13 @@ import (
"context"
"fmt"
"io"
+ "log/slog"
"os"
"path/filepath"
"sort"
"strings"
"time"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/bstore"
"github.com/mjl-/mox/mlog"
diff --git a/store/import.go b/store/import.go
index e6528bb..fa73b34 100644
--- a/store/import.go
+++ b/store/import.go
@@ -6,6 +6,7 @@ import (
"errors"
"fmt"
"io"
+ "log/slog"
"os"
"path/filepath"
"strconv"
@@ -13,7 +14,6 @@ import (
"time"
"golang.org/x/exp/maps"
- "golang.org/x/exp/slog"
"github.com/mjl-/mox/mlog"
)
diff --git a/store/session.go b/store/session.go
index aaa4573..a2a2a82 100644
--- a/store/session.go
+++ b/store/session.go
@@ -6,12 +6,11 @@ import (
"encoding/base64"
"errors"
"fmt"
+ "log/slog"
"runtime/debug"
"sync"
"time"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/bstore"
"github.com/mjl-/mox/metrics"
diff --git a/store/threads.go b/store/threads.go
index 5b9c82c..df5328d 100644
--- a/store/threads.go
+++ b/store/threads.go
@@ -6,13 +6,12 @@ import (
"errors"
"fmt"
"io"
+ "log/slog"
"runtime"
+ "slices"
"sort"
"time"
- "golang.org/x/exp/slices"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/bstore"
"github.com/mjl-/mox/message"
diff --git a/store/train.go b/store/train.go
index 72b6311..48cb5b3 100644
--- a/store/train.go
+++ b/store/train.go
@@ -4,11 +4,10 @@ import (
"context"
"errors"
"fmt"
+ "log/slog"
"os"
"path/filepath"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/bstore"
"github.com/mjl-/mox/config"
diff --git a/stub/metrics.go b/stub/metrics.go
index e3e16a2..5d49b7e 100644
--- a/stub/metrics.go
+++ b/stub/metrics.go
@@ -2,9 +2,8 @@ package stub
import (
"context"
+ "log/slog"
"time"
-
- "golang.org/x/exp/slog"
)
func HTTPClientObserveIgnore(ctx context.Context, log *slog.Logger, pkg, method string, statusCode int, err error, start time.Time) {
diff --git a/subjectpass/subjectpass.go b/subjectpass/subjectpass.go
index 0f98680..4d731b6 100644
--- a/subjectpass/subjectpass.go
+++ b/subjectpass/subjectpass.go
@@ -14,11 +14,10 @@ import (
"errors"
"fmt"
"io"
+ "log/slog"
"strings"
"time"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/mox/dns"
"github.com/mjl-/mox/message"
"github.com/mjl-/mox/mlog"
diff --git a/tlsrpt/examples_test.go b/tlsrpt/examples_test.go
index 0fccb2a..bbf9d97 100644
--- a/tlsrpt/examples_test.go
+++ b/tlsrpt/examples_test.go
@@ -3,10 +3,9 @@ package tlsrpt_test
import (
"context"
"log"
+ "log/slog"
"strings"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/mox/dns"
"github.com/mjl-/mox/tlsrpt"
)
diff --git a/tlsrpt/lookup.go b/tlsrpt/lookup.go
index 3c255b9..54ba5d5 100644
--- a/tlsrpt/lookup.go
+++ b/tlsrpt/lookup.go
@@ -4,10 +4,9 @@ import (
"context"
"errors"
"fmt"
+ "log/slog"
"time"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/mox/dns"
"github.com/mjl-/mox/mlog"
"github.com/mjl-/mox/stub"
diff --git a/tlsrpt/report.go b/tlsrpt/report.go
index 21c9634..5e09d33 100644
--- a/tlsrpt/report.go
+++ b/tlsrpt/report.go
@@ -9,16 +9,15 @@ import (
"errors"
"fmt"
"io"
+ "log/slog"
"net"
"os"
"reflect"
+ "slices"
"sort"
"strings"
"time"
- "golang.org/x/exp/slices"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/adns"
"github.com/mjl-/mox/dns"
diff --git a/tlsrptdb/report.go b/tlsrptdb/report.go
index 56a8c3e..e1e1ba6 100644
--- a/tlsrptdb/report.go
+++ b/tlsrptdb/report.go
@@ -4,12 +4,11 @@ package tlsrptdb
import (
"context"
"fmt"
+ "log/slog"
"os"
"path/filepath"
"time"
- "golang.org/x/exp/slog"
-
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
diff --git a/tlsrptsend/send.go b/tlsrptsend/send.go
index 36bbad7..a8bb0b2 100644
--- a/tlsrptsend/send.go
+++ b/tlsrptsend/send.go
@@ -19,19 +19,18 @@ import (
"errors"
"fmt"
"io"
+ "log/slog"
"mime"
"mime/multipart"
"net/textproto"
"net/url"
"os"
"runtime/debug"
+ "slices"
"strings"
"sync"
"time"
- "golang.org/x/exp/slices"
- "golang.org/x/exp/slog"
-
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
diff --git a/tlsrptsend/send_test.go b/tlsrptsend/send_test.go
index 7a988c7..08839de 100644
--- a/tlsrptsend/send_test.go
+++ b/tlsrptsend/send_test.go
@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"io"
+ "log/slog"
"os"
"path/filepath"
"reflect"
@@ -11,8 +12,6 @@ import (
"testing"
"time"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/bstore"
"github.com/mjl-/mox/dns"
diff --git a/updates/updates.go b/updates/updates.go
index 31d735f..658fb26 100644
--- a/updates/updates.go
+++ b/updates/updates.go
@@ -16,13 +16,12 @@ import (
"encoding/json"
"errors"
"fmt"
+ "log/slog"
"net/http"
"strconv"
"strings"
"time"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/mox/dns"
"github.com/mjl-/mox/mlog"
"github.com/mjl-/mox/moxio"
diff --git a/vendor/golang.org/x/exp/constraints/constraints.go b/vendor/golang.org/x/exp/constraints/constraints.go
deleted file mode 100644
index 2c033df..0000000
--- a/vendor/golang.org/x/exp/constraints/constraints.go
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2021 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package constraints defines a set of useful constraints to be used
-// with type parameters.
-package constraints
-
-// Signed is a constraint that permits any signed integer type.
-// If future releases of Go add new predeclared signed integer types,
-// this constraint will be modified to include them.
-type Signed interface {
- ~int | ~int8 | ~int16 | ~int32 | ~int64
-}
-
-// Unsigned is a constraint that permits any unsigned integer type.
-// If future releases of Go add new predeclared unsigned integer types,
-// this constraint will be modified to include them.
-type Unsigned interface {
- ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
-}
-
-// Integer is a constraint that permits any integer type.
-// If future releases of Go add new predeclared integer types,
-// this constraint will be modified to include them.
-type Integer interface {
- Signed | Unsigned
-}
-
-// Float is a constraint that permits any floating-point type.
-// If future releases of Go add new predeclared floating-point types,
-// this constraint will be modified to include them.
-type Float interface {
- ~float32 | ~float64
-}
-
-// Complex is a constraint that permits any complex numeric type.
-// If future releases of Go add new predeclared complex numeric types,
-// this constraint will be modified to include them.
-type Complex interface {
- ~complex64 | ~complex128
-}
-
-// Ordered is a constraint that permits any ordered type: any type
-// that supports the operators < <= >= >.
-// If future releases of Go add new ordered types,
-// this constraint will be modified to include them.
-type Ordered interface {
- Integer | Float | ~string
-}
diff --git a/vendor/golang.org/x/exp/slices/cmp.go b/vendor/golang.org/x/exp/slices/cmp.go
deleted file mode 100644
index fbf1934..0000000
--- a/vendor/golang.org/x/exp/slices/cmp.go
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2023 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package slices
-
-import "golang.org/x/exp/constraints"
-
-// min is a version of the predeclared function from the Go 1.21 release.
-func min[T constraints.Ordered](a, b T) T {
- if a < b || isNaN(a) {
- return a
- }
- return b
-}
-
-// max is a version of the predeclared function from the Go 1.21 release.
-func max[T constraints.Ordered](a, b T) T {
- if a > b || isNaN(a) {
- return a
- }
- return b
-}
-
-// cmpLess is a copy of cmp.Less from the Go 1.21 release.
-func cmpLess[T constraints.Ordered](x, y T) bool {
- return (isNaN(x) && !isNaN(y)) || x < y
-}
-
-// cmpCompare is a copy of cmp.Compare from the Go 1.21 release.
-func cmpCompare[T constraints.Ordered](x, y T) int {
- xNaN := isNaN(x)
- yNaN := isNaN(y)
- if xNaN && yNaN {
- return 0
- }
- if xNaN || x < y {
- return -1
- }
- if yNaN || x > y {
- return +1
- }
- return 0
-}
diff --git a/vendor/golang.org/x/exp/slices/slices.go b/vendor/golang.org/x/exp/slices/slices.go
deleted file mode 100644
index 5e8158b..0000000
--- a/vendor/golang.org/x/exp/slices/slices.go
+++ /dev/null
@@ -1,499 +0,0 @@
-// Copyright 2021 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package slices defines various functions useful with slices of any type.
-package slices
-
-import (
- "unsafe"
-
- "golang.org/x/exp/constraints"
-)
-
-// Equal reports whether two slices are equal: the same length and all
-// elements equal. If the lengths are different, Equal returns false.
-// Otherwise, the elements are compared in increasing index order, and the
-// comparison stops at the first unequal pair.
-// Floating point NaNs are not considered equal.
-func Equal[S ~[]E, E comparable](s1, s2 S) bool {
- if len(s1) != len(s2) {
- return false
- }
- for i := range s1 {
- if s1[i] != s2[i] {
- return false
- }
- }
- return true
-}
-
-// EqualFunc reports whether two slices are equal using an equality
-// function on each pair of elements. If the lengths are different,
-// EqualFunc returns false. Otherwise, the elements are compared in
-// increasing index order, and the comparison stops at the first index
-// for which eq returns false.
-func EqualFunc[S1 ~[]E1, S2 ~[]E2, E1, E2 any](s1 S1, s2 S2, eq func(E1, E2) bool) bool {
- if len(s1) != len(s2) {
- return false
- }
- for i, v1 := range s1 {
- v2 := s2[i]
- if !eq(v1, v2) {
- return false
- }
- }
- return true
-}
-
-// Compare compares the elements of s1 and s2, using [cmp.Compare] on each pair
-// of elements. The elements are compared sequentially, starting at index 0,
-// until one element is not equal to the other.
-// The result of comparing the first non-matching elements is returned.
-// If both slices are equal until one of them ends, the shorter slice is
-// considered less than the longer one.
-// The result is 0 if s1 == s2, -1 if s1 < s2, and +1 if s1 > s2.
-func Compare[S ~[]E, E constraints.Ordered](s1, s2 S) int {
- for i, v1 := range s1 {
- if i >= len(s2) {
- return +1
- }
- v2 := s2[i]
- if c := cmpCompare(v1, v2); c != 0 {
- return c
- }
- }
- if len(s1) < len(s2) {
- return -1
- }
- return 0
-}
-
-// CompareFunc is like [Compare] but uses a custom comparison function on each
-// pair of elements.
-// The result is the first non-zero result of cmp; if cmp always
-// returns 0 the result is 0 if len(s1) == len(s2), -1 if len(s1) < len(s2),
-// and +1 if len(s1) > len(s2).
-func CompareFunc[S1 ~[]E1, S2 ~[]E2, E1, E2 any](s1 S1, s2 S2, cmp func(E1, E2) int) int {
- for i, v1 := range s1 {
- if i >= len(s2) {
- return +1
- }
- v2 := s2[i]
- if c := cmp(v1, v2); c != 0 {
- return c
- }
- }
- if len(s1) < len(s2) {
- return -1
- }
- return 0
-}
-
-// Index returns the index of the first occurrence of v in s,
-// or -1 if not present.
-func Index[S ~[]E, E comparable](s S, v E) int {
- for i := range s {
- if v == s[i] {
- return i
- }
- }
- return -1
-}
-
-// IndexFunc returns the first index i satisfying f(s[i]),
-// or -1 if none do.
-func IndexFunc[S ~[]E, E any](s S, f func(E) bool) int {
- for i := range s {
- if f(s[i]) {
- return i
- }
- }
- return -1
-}
-
-// Contains reports whether v is present in s.
-func Contains[S ~[]E, E comparable](s S, v E) bool {
- return Index(s, v) >= 0
-}
-
-// ContainsFunc reports whether at least one
-// element e of s satisfies f(e).
-func ContainsFunc[S ~[]E, E any](s S, f func(E) bool) bool {
- return IndexFunc(s, f) >= 0
-}
-
-// Insert inserts the values v... into s at index i,
-// returning the modified slice.
-// The elements at s[i:] are shifted up to make room.
-// In the returned slice r, r[i] == v[0],
-// and r[i+len(v)] == value originally at r[i].
-// Insert panics if i is out of range.
-// This function is O(len(s) + len(v)).
-func Insert[S ~[]E, E any](s S, i int, v ...E) S {
- m := len(v)
- if m == 0 {
- return s
- }
- n := len(s)
- if i == n {
- return append(s, v...)
- }
- if n+m > cap(s) {
- // Use append rather than make so that we bump the size of
- // the slice up to the next storage class.
- // This is what Grow does but we don't call Grow because
- // that might copy the values twice.
- s2 := append(s[:i], make(S, n+m-i)...)
- copy(s2[i:], v)
- copy(s2[i+m:], s[i:])
- return s2
- }
- s = s[:n+m]
-
- // before:
- // s: aaaaaaaabbbbccccccccdddd
- // ^ ^ ^ ^
- // i i+m n n+m
- // after:
- // s: aaaaaaaavvvvbbbbcccccccc
- // ^ ^ ^ ^
- // i i+m n n+m
- //
- // a are the values that don't move in s.
- // v are the values copied in from v.
- // b and c are the values from s that are shifted up in index.
- // d are the values that get overwritten, never to be seen again.
-
- if !overlaps(v, s[i+m:]) {
- // Easy case - v does not overlap either the c or d regions.
- // (It might be in some of a or b, or elsewhere entirely.)
- // The data we copy up doesn't write to v at all, so just do it.
-
- copy(s[i+m:], s[i:])
-
- // Now we have
- // s: aaaaaaaabbbbbbbbcccccccc
- // ^ ^ ^ ^
- // i i+m n n+m
- // Note the b values are duplicated.
-
- copy(s[i:], v)
-
- // Now we have
- // s: aaaaaaaavvvvbbbbcccccccc
- // ^ ^ ^ ^
- // i i+m n n+m
- // That's the result we want.
- return s
- }
-
- // The hard case - v overlaps c or d. We can't just shift up
- // the data because we'd move or clobber the values we're trying
- // to insert.
- // So instead, write v on top of d, then rotate.
- copy(s[n:], v)
-
- // Now we have
- // s: aaaaaaaabbbbccccccccvvvv
- // ^ ^ ^ ^
- // i i+m n n+m
-
- rotateRight(s[i:], m)
-
- // Now we have
- // s: aaaaaaaavvvvbbbbcccccccc
- // ^ ^ ^ ^
- // i i+m n n+m
- // That's the result we want.
- return s
-}
-
-// Delete removes the elements s[i:j] from s, returning the modified slice.
-// Delete panics if s[i:j] is not a valid slice of s.
-// Delete is O(len(s)-j), so if many items must be deleted, it is better to
-// make a single call deleting them all together than to delete one at a time.
-// Delete might not modify the elements s[len(s)-(j-i):len(s)]. If those
-// elements contain pointers you might consider zeroing those elements so that
-// objects they reference can be garbage collected.
-func Delete[S ~[]E, E any](s S, i, j int) S {
- _ = s[i:j] // bounds check
-
- return append(s[:i], s[j:]...)
-}
-
-// DeleteFunc removes any elements from s for which del returns true,
-// returning the modified slice.
-// When DeleteFunc removes m elements, it might not modify the elements
-// s[len(s)-m:len(s)]. If those elements contain pointers you might consider
-// zeroing those elements so that objects they reference can be garbage
-// collected.
-func DeleteFunc[S ~[]E, E any](s S, del func(E) bool) S {
- i := IndexFunc(s, del)
- if i == -1 {
- return s
- }
- // Don't start copying elements until we find one to delete.
- for j := i + 1; j < len(s); j++ {
- if v := s[j]; !del(v) {
- s[i] = v
- i++
- }
- }
- return s[:i]
-}
-
-// Replace replaces the elements s[i:j] by the given v, and returns the
-// modified slice. Replace panics if s[i:j] is not a valid slice of s.
-func Replace[S ~[]E, E any](s S, i, j int, v ...E) S {
- _ = s[i:j] // verify that i:j is a valid subslice
-
- if i == j {
- return Insert(s, i, v...)
- }
- if j == len(s) {
- return append(s[:i], v...)
- }
-
- tot := len(s[:i]) + len(v) + len(s[j:])
- if tot > cap(s) {
- // Too big to fit, allocate and copy over.
- s2 := append(s[:i], make(S, tot-i)...) // See Insert
- copy(s2[i:], v)
- copy(s2[i+len(v):], s[j:])
- return s2
- }
-
- r := s[:tot]
-
- if i+len(v) <= j {
- // Easy, as v fits in the deleted portion.
- copy(r[i:], v)
- if i+len(v) != j {
- copy(r[i+len(v):], s[j:])
- }
- return r
- }
-
- // We are expanding (v is bigger than j-i).
- // The situation is something like this:
- // (example has i=4,j=8,len(s)=16,len(v)=6)
- // s: aaaaxxxxbbbbbbbbyy
- // ^ ^ ^ ^
- // i j len(s) tot
- // a: prefix of s
- // x: deleted range
- // b: more of s
- // y: area to expand into
-
- if !overlaps(r[i+len(v):], v) {
- // Easy, as v is not clobbered by the first copy.
- copy(r[i+len(v):], s[j:])
- copy(r[i:], v)
- return r
- }
-
- // This is a situation where we don't have a single place to which
- // we can copy v. Parts of it need to go to two different places.
- // We want to copy the prefix of v into y and the suffix into x, then
- // rotate |y| spots to the right.
- //
- // v[2:] v[:2]
- // | |
- // s: aaaavvvvbbbbbbbbvv
- // ^ ^ ^ ^
- // i j len(s) tot
- //
- // If either of those two destinations don't alias v, then we're good.
- y := len(v) - (j - i) // length of y portion
-
- if !overlaps(r[i:j], v) {
- copy(r[i:j], v[y:])
- copy(r[len(s):], v[:y])
- rotateRight(r[i:], y)
- return r
- }
- if !overlaps(r[len(s):], v) {
- copy(r[len(s):], v[:y])
- copy(r[i:j], v[y:])
- rotateRight(r[i:], y)
- return r
- }
-
- // Now we know that v overlaps both x and y.
- // That means that the entirety of b is *inside* v.
- // So we don't need to preserve b at all; instead we
- // can copy v first, then copy the b part of v out of
- // v to the right destination.
- k := startIdx(v, s[j:])
- copy(r[i:], v)
- copy(r[i+len(v):], r[i+k:])
- return r
-}
-
-// Clone returns a copy of the slice.
-// The elements are copied using assignment, so this is a shallow clone.
-func Clone[S ~[]E, E any](s S) S {
- // Preserve nil in case it matters.
- if s == nil {
- return nil
- }
- return append(S([]E{}), s...)
-}
-
-// Compact replaces consecutive runs of equal elements with a single copy.
-// This is like the uniq command found on Unix.
-// Compact modifies the contents of the slice s and returns the modified slice,
-// which may have a smaller length.
-// When Compact discards m elements in total, it might not modify the elements
-// s[len(s)-m:len(s)]. If those elements contain pointers you might consider
-// zeroing those elements so that objects they reference can be garbage collected.
-func Compact[S ~[]E, E comparable](s S) S {
- if len(s) < 2 {
- return s
- }
- i := 1
- for k := 1; k < len(s); k++ {
- if s[k] != s[k-1] {
- if i != k {
- s[i] = s[k]
- }
- i++
- }
- }
- return s[:i]
-}
-
-// CompactFunc is like [Compact] but uses an equality function to compare elements.
-// For runs of elements that compare equal, CompactFunc keeps the first one.
-func CompactFunc[S ~[]E, E any](s S, eq func(E, E) bool) S {
- if len(s) < 2 {
- return s
- }
- i := 1
- for k := 1; k < len(s); k++ {
- if !eq(s[k], s[k-1]) {
- if i != k {
- s[i] = s[k]
- }
- i++
- }
- }
- return s[:i]
-}
-
-// Grow increases the slice's capacity, if necessary, to guarantee space for
-// another n elements. After Grow(n), at least n elements can be appended
-// to the slice without another allocation. If n is negative or too large to
-// allocate the memory, Grow panics.
-func Grow[S ~[]E, E any](s S, n int) S {
- if n < 0 {
- panic("cannot be negative")
- }
- if n -= cap(s) - len(s); n > 0 {
- // TODO(https://go.dev/issue/53888): Make using []E instead of S
- // to workaround a compiler bug where the runtime.growslice optimization
- // does not take effect. Revert when the compiler is fixed.
- s = append([]E(s)[:cap(s)], make([]E, n)...)[:len(s)]
- }
- return s
-}
-
-// Clip removes unused capacity from the slice, returning s[:len(s):len(s)].
-func Clip[S ~[]E, E any](s S) S {
- return s[:len(s):len(s)]
-}
-
-// Rotation algorithm explanation:
-//
-// rotate left by 2
-// start with
-// 0123456789
-// split up like this
-// 01 234567 89
-// swap first 2 and last 2
-// 89 234567 01
-// join first parts
-// 89234567 01
-// recursively rotate first left part by 2
-// 23456789 01
-// join at the end
-// 2345678901
-//
-// rotate left by 8
-// start with
-// 0123456789
-// split up like this
-// 01 234567 89
-// swap first 2 and last 2
-// 89 234567 01
-// join last parts
-// 89 23456701
-// recursively rotate second part left by 6
-// 89 01234567
-// join at the end
-// 8901234567
-
-// TODO: There are other rotate algorithms.
-// This algorithm has the desirable property that it moves each element exactly twice.
-// The triple-reverse algorithm is simpler and more cache friendly, but takes more writes.
-// The follow-cycles algorithm can be 1-write but it is not very cache friendly.
-
-// rotateLeft rotates b left by n spaces.
-// s_final[i] = s_orig[i+r], wrapping around.
-func rotateLeft[E any](s []E, r int) {
- for r != 0 && r != len(s) {
- if r*2 <= len(s) {
- swap(s[:r], s[len(s)-r:])
- s = s[:len(s)-r]
- } else {
- swap(s[:len(s)-r], s[r:])
- s, r = s[len(s)-r:], r*2-len(s)
- }
- }
-}
-func rotateRight[E any](s []E, r int) {
- rotateLeft(s, len(s)-r)
-}
-
-// swap swaps the contents of x and y. x and y must be equal length and disjoint.
-func swap[E any](x, y []E) {
- for i := 0; i < len(x); i++ {
- x[i], y[i] = y[i], x[i]
- }
-}
-
-// overlaps reports whether the memory ranges a[0:len(a)] and b[0:len(b)] overlap.
-func overlaps[E any](a, b []E) bool {
- if len(a) == 0 || len(b) == 0 {
- return false
- }
- elemSize := unsafe.Sizeof(a[0])
- if elemSize == 0 {
- return false
- }
- // TODO: use a runtime/unsafe facility once one becomes available. See issue 12445.
- // Also see crypto/internal/alias/alias.go:AnyOverlap
- return uintptr(unsafe.Pointer(&a[0])) <= uintptr(unsafe.Pointer(&b[len(b)-1]))+(elemSize-1) &&
- uintptr(unsafe.Pointer(&b[0])) <= uintptr(unsafe.Pointer(&a[len(a)-1]))+(elemSize-1)
-}
-
-// startIdx returns the index in haystack where the needle starts.
-// prerequisite: the needle must be aliased entirely inside the haystack.
-func startIdx[E any](haystack, needle []E) int {
- p := &needle[0]
- for i := range haystack {
- if p == &haystack[i] {
- return i
- }
- }
- // TODO: what if the overlap is by a non-integral number of Es?
- panic("needle not found")
-}
-
-// Reverse reverses the elements of the slice in place.
-func Reverse[S ~[]E, E any](s S) {
- for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
- s[i], s[j] = s[j], s[i]
- }
-}
diff --git a/vendor/golang.org/x/exp/slices/sort.go b/vendor/golang.org/x/exp/slices/sort.go
deleted file mode 100644
index b67897f..0000000
--- a/vendor/golang.org/x/exp/slices/sort.go
+++ /dev/null
@@ -1,195 +0,0 @@
-// Copyright 2022 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-//go:generate go run $GOROOT/src/sort/gen_sort_variants.go -exp
-
-package slices
-
-import (
- "math/bits"
-
- "golang.org/x/exp/constraints"
-)
-
-// Sort sorts a slice of any ordered type in ascending order.
-// When sorting floating-point numbers, NaNs are ordered before other values.
-func Sort[S ~[]E, E constraints.Ordered](x S) {
- n := len(x)
- pdqsortOrdered(x, 0, n, bits.Len(uint(n)))
-}
-
-// SortFunc sorts the slice x in ascending order as determined by the cmp
-// function. This sort is not guaranteed to be stable.
-// cmp(a, b) should return a negative number when a < b, a positive number when
-// a > b and zero when a == b.
-//
-// SortFunc requires that cmp is a strict weak ordering.
-// See https://en.wikipedia.org/wiki/Weak_ordering#Strict_weak_orderings.
-func SortFunc[S ~[]E, E any](x S, cmp func(a, b E) int) {
- n := len(x)
- pdqsortCmpFunc(x, 0, n, bits.Len(uint(n)), cmp)
-}
-
-// SortStableFunc sorts the slice x while keeping the original order of equal
-// elements, using cmp to compare elements in the same way as [SortFunc].
-func SortStableFunc[S ~[]E, E any](x S, cmp func(a, b E) int) {
- stableCmpFunc(x, len(x), cmp)
-}
-
-// IsSorted reports whether x is sorted in ascending order.
-func IsSorted[S ~[]E, E constraints.Ordered](x S) bool {
- for i := len(x) - 1; i > 0; i-- {
- if cmpLess(x[i], x[i-1]) {
- return false
- }
- }
- return true
-}
-
-// IsSortedFunc reports whether x is sorted in ascending order, with cmp as the
-// comparison function as defined by [SortFunc].
-func IsSortedFunc[S ~[]E, E any](x S, cmp func(a, b E) int) bool {
- for i := len(x) - 1; i > 0; i-- {
- if cmp(x[i], x[i-1]) < 0 {
- return false
- }
- }
- return true
-}
-
-// Min returns the minimal value in x. It panics if x is empty.
-// For floating-point numbers, Min propagates NaNs (any NaN value in x
-// forces the output to be NaN).
-func Min[S ~[]E, E constraints.Ordered](x S) E {
- if len(x) < 1 {
- panic("slices.Min: empty list")
- }
- m := x[0]
- for i := 1; i < len(x); i++ {
- m = min(m, x[i])
- }
- return m
-}
-
-// MinFunc returns the minimal value in x, using cmp to compare elements.
-// It panics if x is empty. If there is more than one minimal element
-// according to the cmp function, MinFunc returns the first one.
-func MinFunc[S ~[]E, E any](x S, cmp func(a, b E) int) E {
- if len(x) < 1 {
- panic("slices.MinFunc: empty list")
- }
- m := x[0]
- for i := 1; i < len(x); i++ {
- if cmp(x[i], m) < 0 {
- m = x[i]
- }
- }
- return m
-}
-
-// Max returns the maximal value in x. It panics if x is empty.
-// For floating-point E, Max propagates NaNs (any NaN value in x
-// forces the output to be NaN).
-func Max[S ~[]E, E constraints.Ordered](x S) E {
- if len(x) < 1 {
- panic("slices.Max: empty list")
- }
- m := x[0]
- for i := 1; i < len(x); i++ {
- m = max(m, x[i])
- }
- return m
-}
-
-// MaxFunc returns the maximal value in x, using cmp to compare elements.
-// It panics if x is empty. If there is more than one maximal element
-// according to the cmp function, MaxFunc returns the first one.
-func MaxFunc[S ~[]E, E any](x S, cmp func(a, b E) int) E {
- if len(x) < 1 {
- panic("slices.MaxFunc: empty list")
- }
- m := x[0]
- for i := 1; i < len(x); i++ {
- if cmp(x[i], m) > 0 {
- m = x[i]
- }
- }
- return m
-}
-
-// BinarySearch searches for target in a sorted slice and returns the position
-// where target is found, or the position where target would appear in the
-// sort order; it also returns a bool saying whether the target is really found
-// in the slice. The slice must be sorted in increasing order.
-func BinarySearch[S ~[]E, E constraints.Ordered](x S, target E) (int, bool) {
- // Inlining is faster than calling BinarySearchFunc with a lambda.
- n := len(x)
- // Define x[-1] < target and x[n] >= target.
- // Invariant: x[i-1] < target, x[j] >= target.
- i, j := 0, n
- for i < j {
- h := int(uint(i+j) >> 1) // avoid overflow when computing h
- // i ≤ h < j
- if cmpLess(x[h], target) {
- i = h + 1 // preserves x[i-1] < target
- } else {
- j = h // preserves x[j] >= target
- }
- }
- // i == j, x[i-1] < target, and x[j] (= x[i]) >= target => answer is i.
- return i, i < n && (x[i] == target || (isNaN(x[i]) && isNaN(target)))
-}
-
-// BinarySearchFunc works like [BinarySearch], but uses a custom comparison
-// function. The slice must be sorted in increasing order, where "increasing"
-// is defined by cmp. cmp should return 0 if the slice element matches
-// the target, a negative number if the slice element precedes the target,
-// or a positive number if the slice element follows the target.
-// cmp must implement the same ordering as the slice, such that if
-// cmp(a, t) < 0 and cmp(b, t) >= 0, then a must precede b in the slice.
-func BinarySearchFunc[S ~[]E, E, T any](x S, target T, cmp func(E, T) int) (int, bool) {
- n := len(x)
- // Define cmp(x[-1], target) < 0 and cmp(x[n], target) >= 0 .
- // Invariant: cmp(x[i - 1], target) < 0, cmp(x[j], target) >= 0.
- i, j := 0, n
- for i < j {
- h := int(uint(i+j) >> 1) // avoid overflow when computing h
- // i ≤ h < j
- if cmp(x[h], target) < 0 {
- i = h + 1 // preserves cmp(x[i - 1], target) < 0
- } else {
- j = h // preserves cmp(x[j], target) >= 0
- }
- }
- // i == j, cmp(x[i-1], target) < 0, and cmp(x[j], target) (= cmp(x[i], target)) >= 0 => answer is i.
- return i, i < n && cmp(x[i], target) == 0
-}
-
-type sortedHint int // hint for pdqsort when choosing the pivot
-
-const (
- unknownHint sortedHint = iota
- increasingHint
- decreasingHint
-)
-
-// xorshift paper: https://www.jstatsoft.org/article/view/v008i14/xorshift.pdf
-type xorshift uint64
-
-func (r *xorshift) Next() uint64 {
- *r ^= *r << 13
- *r ^= *r >> 17
- *r ^= *r << 5
- return uint64(*r)
-}
-
-func nextPowerOfTwo(length int) uint {
- return 1 << bits.Len(uint(length))
-}
-
-// isNaN reports whether x is a NaN without requiring the math package.
-// This will always return false if T is not floating-point.
-func isNaN[T constraints.Ordered](x T) bool {
- return x != x
-}
diff --git a/vendor/golang.org/x/exp/slices/zsortanyfunc.go b/vendor/golang.org/x/exp/slices/zsortanyfunc.go
deleted file mode 100644
index 06f2c7a..0000000
--- a/vendor/golang.org/x/exp/slices/zsortanyfunc.go
+++ /dev/null
@@ -1,479 +0,0 @@
-// Code generated by gen_sort_variants.go; DO NOT EDIT.
-
-// Copyright 2022 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package slices
-
-// insertionSortCmpFunc sorts data[a:b] using insertion sort.
-func insertionSortCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) {
- for i := a + 1; i < b; i++ {
- for j := i; j > a && (cmp(data[j], data[j-1]) < 0); j-- {
- data[j], data[j-1] = data[j-1], data[j]
- }
- }
-}
-
-// siftDownCmpFunc implements the heap property on data[lo:hi].
-// first is an offset into the array where the root of the heap lies.
-func siftDownCmpFunc[E any](data []E, lo, hi, first int, cmp func(a, b E) int) {
- root := lo
- for {
- child := 2*root + 1
- if child >= hi {
- break
- }
- if child+1 < hi && (cmp(data[first+child], data[first+child+1]) < 0) {
- child++
- }
- if !(cmp(data[first+root], data[first+child]) < 0) {
- return
- }
- data[first+root], data[first+child] = data[first+child], data[first+root]
- root = child
- }
-}
-
-func heapSortCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) {
- first := a
- lo := 0
- hi := b - a
-
- // Build heap with greatest element at top.
- for i := (hi - 1) / 2; i >= 0; i-- {
- siftDownCmpFunc(data, i, hi, first, cmp)
- }
-
- // Pop elements, largest first, into end of data.
- for i := hi - 1; i >= 0; i-- {
- data[first], data[first+i] = data[first+i], data[first]
- siftDownCmpFunc(data, lo, i, first, cmp)
- }
-}
-
-// pdqsortCmpFunc sorts data[a:b].
-// The algorithm based on pattern-defeating quicksort(pdqsort), but without the optimizations from BlockQuicksort.
-// pdqsort paper: https://arxiv.org/pdf/2106.05123.pdf
-// C++ implementation: https://github.com/orlp/pdqsort
-// Rust implementation: https://docs.rs/pdqsort/latest/pdqsort/
-// limit is the number of allowed bad (very unbalanced) pivots before falling back to heapsort.
-func pdqsortCmpFunc[E any](data []E, a, b, limit int, cmp func(a, b E) int) {
- const maxInsertion = 12
-
- var (
- wasBalanced = true // whether the last partitioning was reasonably balanced
- wasPartitioned = true // whether the slice was already partitioned
- )
-
- for {
- length := b - a
-
- if length <= maxInsertion {
- insertionSortCmpFunc(data, a, b, cmp)
- return
- }
-
- // Fall back to heapsort if too many bad choices were made.
- if limit == 0 {
- heapSortCmpFunc(data, a, b, cmp)
- return
- }
-
- // If the last partitioning was imbalanced, we need to breaking patterns.
- if !wasBalanced {
- breakPatternsCmpFunc(data, a, b, cmp)
- limit--
- }
-
- pivot, hint := choosePivotCmpFunc(data, a, b, cmp)
- if hint == decreasingHint {
- reverseRangeCmpFunc(data, a, b, cmp)
- // The chosen pivot was pivot-a elements after the start of the array.
- // After reversing it is pivot-a elements before the end of the array.
- // The idea came from Rust's implementation.
- pivot = (b - 1) - (pivot - a)
- hint = increasingHint
- }
-
- // The slice is likely already sorted.
- if wasBalanced && wasPartitioned && hint == increasingHint {
- if partialInsertionSortCmpFunc(data, a, b, cmp) {
- return
- }
- }
-
- // Probably the slice contains many duplicate elements, partition the slice into
- // elements equal to and elements greater than the pivot.
- if a > 0 && !(cmp(data[a-1], data[pivot]) < 0) {
- mid := partitionEqualCmpFunc(data, a, b, pivot, cmp)
- a = mid
- continue
- }
-
- mid, alreadyPartitioned := partitionCmpFunc(data, a, b, pivot, cmp)
- wasPartitioned = alreadyPartitioned
-
- leftLen, rightLen := mid-a, b-mid
- balanceThreshold := length / 8
- if leftLen < rightLen {
- wasBalanced = leftLen >= balanceThreshold
- pdqsortCmpFunc(data, a, mid, limit, cmp)
- a = mid + 1
- } else {
- wasBalanced = rightLen >= balanceThreshold
- pdqsortCmpFunc(data, mid+1, b, limit, cmp)
- b = mid
- }
- }
-}
-
-// partitionCmpFunc does one quicksort partition.
-// Let p = data[pivot]
-// Moves elements in data[a:b] around, so that data[i]
=p for inewpivot.
-// On return, data[newpivot] = p
-func partitionCmpFunc[E any](data []E, a, b, pivot int, cmp func(a, b E) int) (newpivot int, alreadyPartitioned bool) {
- data[a], data[pivot] = data[pivot], data[a]
- i, j := a+1, b-1 // i and j are inclusive of the elements remaining to be partitioned
-
- for i <= j && (cmp(data[i], data[a]) < 0) {
- i++
- }
- for i <= j && !(cmp(data[j], data[a]) < 0) {
- j--
- }
- if i > j {
- data[j], data[a] = data[a], data[j]
- return j, true
- }
- data[i], data[j] = data[j], data[i]
- i++
- j--
-
- for {
- for i <= j && (cmp(data[i], data[a]) < 0) {
- i++
- }
- for i <= j && !(cmp(data[j], data[a]) < 0) {
- j--
- }
- if i > j {
- break
- }
- data[i], data[j] = data[j], data[i]
- i++
- j--
- }
- data[j], data[a] = data[a], data[j]
- return j, false
-}
-
-// partitionEqualCmpFunc partitions data[a:b] into elements equal to data[pivot] followed by elements greater than data[pivot].
-// It assumed that data[a:b] does not contain elements smaller than the data[pivot].
-func partitionEqualCmpFunc[E any](data []E, a, b, pivot int, cmp func(a, b E) int) (newpivot int) {
- data[a], data[pivot] = data[pivot], data[a]
- i, j := a+1, b-1 // i and j are inclusive of the elements remaining to be partitioned
-
- for {
- for i <= j && !(cmp(data[a], data[i]) < 0) {
- i++
- }
- for i <= j && (cmp(data[a], data[j]) < 0) {
- j--
- }
- if i > j {
- break
- }
- data[i], data[j] = data[j], data[i]
- i++
- j--
- }
- return i
-}
-
-// partialInsertionSortCmpFunc partially sorts a slice, returns true if the slice is sorted at the end.
-func partialInsertionSortCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) bool {
- const (
- maxSteps = 5 // maximum number of adjacent out-of-order pairs that will get shifted
- shortestShifting = 50 // don't shift any elements on short arrays
- )
- i := a + 1
- for j := 0; j < maxSteps; j++ {
- for i < b && !(cmp(data[i], data[i-1]) < 0) {
- i++
- }
-
- if i == b {
- return true
- }
-
- if b-a < shortestShifting {
- return false
- }
-
- data[i], data[i-1] = data[i-1], data[i]
-
- // Shift the smaller one to the left.
- if i-a >= 2 {
- for j := i - 1; j >= 1; j-- {
- if !(cmp(data[j], data[j-1]) < 0) {
- break
- }
- data[j], data[j-1] = data[j-1], data[j]
- }
- }
- // Shift the greater one to the right.
- if b-i >= 2 {
- for j := i + 1; j < b; j++ {
- if !(cmp(data[j], data[j-1]) < 0) {
- break
- }
- data[j], data[j-1] = data[j-1], data[j]
- }
- }
- }
- return false
-}
-
-// breakPatternsCmpFunc scatters some elements around in an attempt to break some patterns
-// that might cause imbalanced partitions in quicksort.
-func breakPatternsCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) {
- length := b - a
- if length >= 8 {
- random := xorshift(length)
- modulus := nextPowerOfTwo(length)
-
- for idx := a + (length/4)*2 - 1; idx <= a+(length/4)*2+1; idx++ {
- other := int(uint(random.Next()) & (modulus - 1))
- if other >= length {
- other -= length
- }
- data[idx], data[a+other] = data[a+other], data[idx]
- }
- }
-}
-
-// choosePivotCmpFunc chooses a pivot in data[a:b].
-//
-// [0,8): chooses a static pivot.
-// [8,shortestNinther): uses the simple median-of-three method.
-// [shortestNinther,∞): uses the Tukey ninther method.
-func choosePivotCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) (pivot int, hint sortedHint) {
- const (
- shortestNinther = 50
- maxSwaps = 4 * 3
- )
-
- l := b - a
-
- var (
- swaps int
- i = a + l/4*1
- j = a + l/4*2
- k = a + l/4*3
- )
-
- if l >= 8 {
- if l >= shortestNinther {
- // Tukey ninther method, the idea came from Rust's implementation.
- i = medianAdjacentCmpFunc(data, i, &swaps, cmp)
- j = medianAdjacentCmpFunc(data, j, &swaps, cmp)
- k = medianAdjacentCmpFunc(data, k, &swaps, cmp)
- }
- // Find the median among i, j, k and stores it into j.
- j = medianCmpFunc(data, i, j, k, &swaps, cmp)
- }
-
- switch swaps {
- case 0:
- return j, increasingHint
- case maxSwaps:
- return j, decreasingHint
- default:
- return j, unknownHint
- }
-}
-
-// order2CmpFunc returns x,y where data[x] <= data[y], where x,y=a,b or x,y=b,a.
-func order2CmpFunc[E any](data []E, a, b int, swaps *int, cmp func(a, b E) int) (int, int) {
- if cmp(data[b], data[a]) < 0 {
- *swaps++
- return b, a
- }
- return a, b
-}
-
-// medianCmpFunc returns x where data[x] is the median of data[a],data[b],data[c], where x is a, b, or c.
-func medianCmpFunc[E any](data []E, a, b, c int, swaps *int, cmp func(a, b E) int) int {
- a, b = order2CmpFunc(data, a, b, swaps, cmp)
- b, c = order2CmpFunc(data, b, c, swaps, cmp)
- a, b = order2CmpFunc(data, a, b, swaps, cmp)
- return b
-}
-
-// medianAdjacentCmpFunc finds the median of data[a - 1], data[a], data[a + 1] and stores the index into a.
-func medianAdjacentCmpFunc[E any](data []E, a int, swaps *int, cmp func(a, b E) int) int {
- return medianCmpFunc(data, a-1, a, a+1, swaps, cmp)
-}
-
-func reverseRangeCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) {
- i := a
- j := b - 1
- for i < j {
- data[i], data[j] = data[j], data[i]
- i++
- j--
- }
-}
-
-func swapRangeCmpFunc[E any](data []E, a, b, n int, cmp func(a, b E) int) {
- for i := 0; i < n; i++ {
- data[a+i], data[b+i] = data[b+i], data[a+i]
- }
-}
-
-func stableCmpFunc[E any](data []E, n int, cmp func(a, b E) int) {
- blockSize := 20 // must be > 0
- a, b := 0, blockSize
- for b <= n {
- insertionSortCmpFunc(data, a, b, cmp)
- a = b
- b += blockSize
- }
- insertionSortCmpFunc(data, a, n, cmp)
-
- for blockSize < n {
- a, b = 0, 2*blockSize
- for b <= n {
- symMergeCmpFunc(data, a, a+blockSize, b, cmp)
- a = b
- b += 2 * blockSize
- }
- if m := a + blockSize; m < n {
- symMergeCmpFunc(data, a, m, n, cmp)
- }
- blockSize *= 2
- }
-}
-
-// symMergeCmpFunc merges the two sorted subsequences data[a:m] and data[m:b] using
-// the SymMerge algorithm from Pok-Son Kim and Arne Kutzner, "Stable Minimum
-// Storage Merging by Symmetric Comparisons", in Susanne Albers and Tomasz
-// Radzik, editors, Algorithms - ESA 2004, volume 3221 of Lecture Notes in
-// Computer Science, pages 714-723. Springer, 2004.
-//
-// Let M = m-a and N = b-n. Wolog M < N.
-// The recursion depth is bound by ceil(log(N+M)).
-// The algorithm needs O(M*log(N/M + 1)) calls to data.Less.
-// The algorithm needs O((M+N)*log(M)) calls to data.Swap.
-//
-// The paper gives O((M+N)*log(M)) as the number of assignments assuming a
-// rotation algorithm which uses O(M+N+gcd(M+N)) assignments. The argumentation
-// in the paper carries through for Swap operations, especially as the block
-// swapping rotate uses only O(M+N) Swaps.
-//
-// symMerge assumes non-degenerate arguments: a < m && m < b.
-// Having the caller check this condition eliminates many leaf recursion calls,
-// which improves performance.
-func symMergeCmpFunc[E any](data []E, a, m, b int, cmp func(a, b E) int) {
- // Avoid unnecessary recursions of symMerge
- // by direct insertion of data[a] into data[m:b]
- // if data[a:m] only contains one element.
- if m-a == 1 {
- // Use binary search to find the lowest index i
- // such that data[i] >= data[a] for m <= i < b.
- // Exit the search loop with i == b in case no such index exists.
- i := m
- j := b
- for i < j {
- h := int(uint(i+j) >> 1)
- if cmp(data[h], data[a]) < 0 {
- i = h + 1
- } else {
- j = h
- }
- }
- // Swap values until data[a] reaches the position before i.
- for k := a; k < i-1; k++ {
- data[k], data[k+1] = data[k+1], data[k]
- }
- return
- }
-
- // Avoid unnecessary recursions of symMerge
- // by direct insertion of data[m] into data[a:m]
- // if data[m:b] only contains one element.
- if b-m == 1 {
- // Use binary search to find the lowest index i
- // such that data[i] > data[m] for a <= i < m.
- // Exit the search loop with i == m in case no such index exists.
- i := a
- j := m
- for i < j {
- h := int(uint(i+j) >> 1)
- if !(cmp(data[m], data[h]) < 0) {
- i = h + 1
- } else {
- j = h
- }
- }
- // Swap values until data[m] reaches the position i.
- for k := m; k > i; k-- {
- data[k], data[k-1] = data[k-1], data[k]
- }
- return
- }
-
- mid := int(uint(a+b) >> 1)
- n := mid + m
- var start, r int
- if m > mid {
- start = n - b
- r = mid
- } else {
- start = a
- r = m
- }
- p := n - 1
-
- for start < r {
- c := int(uint(start+r) >> 1)
- if !(cmp(data[p-c], data[c]) < 0) {
- start = c + 1
- } else {
- r = c
- }
- }
-
- end := n - start
- if start < m && m < end {
- rotateCmpFunc(data, start, m, end, cmp)
- }
- if a < start && start < mid {
- symMergeCmpFunc(data, a, start, mid, cmp)
- }
- if mid < end && end < b {
- symMergeCmpFunc(data, mid, end, b, cmp)
- }
-}
-
-// rotateCmpFunc rotates two consecutive blocks u = data[a:m] and v = data[m:b] in data:
-// Data of the form 'x u v y' is changed to 'x v u y'.
-// rotate performs at most b-a many calls to data.Swap,
-// and it assumes non-degenerate arguments: a < m && m < b.
-func rotateCmpFunc[E any](data []E, a, m, b int, cmp func(a, b E) int) {
- i := m - a
- j := b - m
-
- for i != j {
- if i > j {
- swapRangeCmpFunc(data, m-i, m, j, cmp)
- i -= j
- } else {
- swapRangeCmpFunc(data, m-i, m+j-i, i, cmp)
- j -= i
- }
- }
- // i == j
- swapRangeCmpFunc(data, m-i, m, i, cmp)
-}
diff --git a/vendor/golang.org/x/exp/slices/zsortordered.go b/vendor/golang.org/x/exp/slices/zsortordered.go
deleted file mode 100644
index 99b47c3..0000000
--- a/vendor/golang.org/x/exp/slices/zsortordered.go
+++ /dev/null
@@ -1,481 +0,0 @@
-// Code generated by gen_sort_variants.go; DO NOT EDIT.
-
-// Copyright 2022 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package slices
-
-import "golang.org/x/exp/constraints"
-
-// insertionSortOrdered sorts data[a:b] using insertion sort.
-func insertionSortOrdered[E constraints.Ordered](data []E, a, b int) {
- for i := a + 1; i < b; i++ {
- for j := i; j > a && cmpLess(data[j], data[j-1]); j-- {
- data[j], data[j-1] = data[j-1], data[j]
- }
- }
-}
-
-// siftDownOrdered implements the heap property on data[lo:hi].
-// first is an offset into the array where the root of the heap lies.
-func siftDownOrdered[E constraints.Ordered](data []E, lo, hi, first int) {
- root := lo
- for {
- child := 2*root + 1
- if child >= hi {
- break
- }
- if child+1 < hi && cmpLess(data[first+child], data[first+child+1]) {
- child++
- }
- if !cmpLess(data[first+root], data[first+child]) {
- return
- }
- data[first+root], data[first+child] = data[first+child], data[first+root]
- root = child
- }
-}
-
-func heapSortOrdered[E constraints.Ordered](data []E, a, b int) {
- first := a
- lo := 0
- hi := b - a
-
- // Build heap with greatest element at top.
- for i := (hi - 1) / 2; i >= 0; i-- {
- siftDownOrdered(data, i, hi, first)
- }
-
- // Pop elements, largest first, into end of data.
- for i := hi - 1; i >= 0; i-- {
- data[first], data[first+i] = data[first+i], data[first]
- siftDownOrdered(data, lo, i, first)
- }
-}
-
-// pdqsortOrdered sorts data[a:b].
-// The algorithm based on pattern-defeating quicksort(pdqsort), but without the optimizations from BlockQuicksort.
-// pdqsort paper: https://arxiv.org/pdf/2106.05123.pdf
-// C++ implementation: https://github.com/orlp/pdqsort
-// Rust implementation: https://docs.rs/pdqsort/latest/pdqsort/
-// limit is the number of allowed bad (very unbalanced) pivots before falling back to heapsort.
-func pdqsortOrdered[E constraints.Ordered](data []E, a, b, limit int) {
- const maxInsertion = 12
-
- var (
- wasBalanced = true // whether the last partitioning was reasonably balanced
- wasPartitioned = true // whether the slice was already partitioned
- )
-
- for {
- length := b - a
-
- if length <= maxInsertion {
- insertionSortOrdered(data, a, b)
- return
- }
-
- // Fall back to heapsort if too many bad choices were made.
- if limit == 0 {
- heapSortOrdered(data, a, b)
- return
- }
-
- // If the last partitioning was imbalanced, we need to breaking patterns.
- if !wasBalanced {
- breakPatternsOrdered(data, a, b)
- limit--
- }
-
- pivot, hint := choosePivotOrdered(data, a, b)
- if hint == decreasingHint {
- reverseRangeOrdered(data, a, b)
- // The chosen pivot was pivot-a elements after the start of the array.
- // After reversing it is pivot-a elements before the end of the array.
- // The idea came from Rust's implementation.
- pivot = (b - 1) - (pivot - a)
- hint = increasingHint
- }
-
- // The slice is likely already sorted.
- if wasBalanced && wasPartitioned && hint == increasingHint {
- if partialInsertionSortOrdered(data, a, b) {
- return
- }
- }
-
- // Probably the slice contains many duplicate elements, partition the slice into
- // elements equal to and elements greater than the pivot.
- if a > 0 && !cmpLess(data[a-1], data[pivot]) {
- mid := partitionEqualOrdered(data, a, b, pivot)
- a = mid
- continue
- }
-
- mid, alreadyPartitioned := partitionOrdered(data, a, b, pivot)
- wasPartitioned = alreadyPartitioned
-
- leftLen, rightLen := mid-a, b-mid
- balanceThreshold := length / 8
- if leftLen < rightLen {
- wasBalanced = leftLen >= balanceThreshold
- pdqsortOrdered(data, a, mid, limit)
- a = mid + 1
- } else {
- wasBalanced = rightLen >= balanceThreshold
- pdqsortOrdered(data, mid+1, b, limit)
- b = mid
- }
- }
-}
-
-// partitionOrdered does one quicksort partition.
-// Let p = data[pivot]
-// Moves elements in data[a:b] around, so that data[i]=p for inewpivot.
-// On return, data[newpivot] = p
-func partitionOrdered[E constraints.Ordered](data []E, a, b, pivot int) (newpivot int, alreadyPartitioned bool) {
- data[a], data[pivot] = data[pivot], data[a]
- i, j := a+1, b-1 // i and j are inclusive of the elements remaining to be partitioned
-
- for i <= j && cmpLess(data[i], data[a]) {
- i++
- }
- for i <= j && !cmpLess(data[j], data[a]) {
- j--
- }
- if i > j {
- data[j], data[a] = data[a], data[j]
- return j, true
- }
- data[i], data[j] = data[j], data[i]
- i++
- j--
-
- for {
- for i <= j && cmpLess(data[i], data[a]) {
- i++
- }
- for i <= j && !cmpLess(data[j], data[a]) {
- j--
- }
- if i > j {
- break
- }
- data[i], data[j] = data[j], data[i]
- i++
- j--
- }
- data[j], data[a] = data[a], data[j]
- return j, false
-}
-
-// partitionEqualOrdered partitions data[a:b] into elements equal to data[pivot] followed by elements greater than data[pivot].
-// It assumed that data[a:b] does not contain elements smaller than the data[pivot].
-func partitionEqualOrdered[E constraints.Ordered](data []E, a, b, pivot int) (newpivot int) {
- data[a], data[pivot] = data[pivot], data[a]
- i, j := a+1, b-1 // i and j are inclusive of the elements remaining to be partitioned
-
- for {
- for i <= j && !cmpLess(data[a], data[i]) {
- i++
- }
- for i <= j && cmpLess(data[a], data[j]) {
- j--
- }
- if i > j {
- break
- }
- data[i], data[j] = data[j], data[i]
- i++
- j--
- }
- return i
-}
-
-// partialInsertionSortOrdered partially sorts a slice, returns true if the slice is sorted at the end.
-func partialInsertionSortOrdered[E constraints.Ordered](data []E, a, b int) bool {
- const (
- maxSteps = 5 // maximum number of adjacent out-of-order pairs that will get shifted
- shortestShifting = 50 // don't shift any elements on short arrays
- )
- i := a + 1
- for j := 0; j < maxSteps; j++ {
- for i < b && !cmpLess(data[i], data[i-1]) {
- i++
- }
-
- if i == b {
- return true
- }
-
- if b-a < shortestShifting {
- return false
- }
-
- data[i], data[i-1] = data[i-1], data[i]
-
- // Shift the smaller one to the left.
- if i-a >= 2 {
- for j := i - 1; j >= 1; j-- {
- if !cmpLess(data[j], data[j-1]) {
- break
- }
- data[j], data[j-1] = data[j-1], data[j]
- }
- }
- // Shift the greater one to the right.
- if b-i >= 2 {
- for j := i + 1; j < b; j++ {
- if !cmpLess(data[j], data[j-1]) {
- break
- }
- data[j], data[j-1] = data[j-1], data[j]
- }
- }
- }
- return false
-}
-
-// breakPatternsOrdered scatters some elements around in an attempt to break some patterns
-// that might cause imbalanced partitions in quicksort.
-func breakPatternsOrdered[E constraints.Ordered](data []E, a, b int) {
- length := b - a
- if length >= 8 {
- random := xorshift(length)
- modulus := nextPowerOfTwo(length)
-
- for idx := a + (length/4)*2 - 1; idx <= a+(length/4)*2+1; idx++ {
- other := int(uint(random.Next()) & (modulus - 1))
- if other >= length {
- other -= length
- }
- data[idx], data[a+other] = data[a+other], data[idx]
- }
- }
-}
-
-// choosePivotOrdered chooses a pivot in data[a:b].
-//
-// [0,8): chooses a static pivot.
-// [8,shortestNinther): uses the simple median-of-three method.
-// [shortestNinther,∞): uses the Tukey ninther method.
-func choosePivotOrdered[E constraints.Ordered](data []E, a, b int) (pivot int, hint sortedHint) {
- const (
- shortestNinther = 50
- maxSwaps = 4 * 3
- )
-
- l := b - a
-
- var (
- swaps int
- i = a + l/4*1
- j = a + l/4*2
- k = a + l/4*3
- )
-
- if l >= 8 {
- if l >= shortestNinther {
- // Tukey ninther method, the idea came from Rust's implementation.
- i = medianAdjacentOrdered(data, i, &swaps)
- j = medianAdjacentOrdered(data, j, &swaps)
- k = medianAdjacentOrdered(data, k, &swaps)
- }
- // Find the median among i, j, k and stores it into j.
- j = medianOrdered(data, i, j, k, &swaps)
- }
-
- switch swaps {
- case 0:
- return j, increasingHint
- case maxSwaps:
- return j, decreasingHint
- default:
- return j, unknownHint
- }
-}
-
-// order2Ordered returns x,y where data[x] <= data[y], where x,y=a,b or x,y=b,a.
-func order2Ordered[E constraints.Ordered](data []E, a, b int, swaps *int) (int, int) {
- if cmpLess(data[b], data[a]) {
- *swaps++
- return b, a
- }
- return a, b
-}
-
-// medianOrdered returns x where data[x] is the median of data[a],data[b],data[c], where x is a, b, or c.
-func medianOrdered[E constraints.Ordered](data []E, a, b, c int, swaps *int) int {
- a, b = order2Ordered(data, a, b, swaps)
- b, c = order2Ordered(data, b, c, swaps)
- a, b = order2Ordered(data, a, b, swaps)
- return b
-}
-
-// medianAdjacentOrdered finds the median of data[a - 1], data[a], data[a + 1] and stores the index into a.
-func medianAdjacentOrdered[E constraints.Ordered](data []E, a int, swaps *int) int {
- return medianOrdered(data, a-1, a, a+1, swaps)
-}
-
-func reverseRangeOrdered[E constraints.Ordered](data []E, a, b int) {
- i := a
- j := b - 1
- for i < j {
- data[i], data[j] = data[j], data[i]
- i++
- j--
- }
-}
-
-func swapRangeOrdered[E constraints.Ordered](data []E, a, b, n int) {
- for i := 0; i < n; i++ {
- data[a+i], data[b+i] = data[b+i], data[a+i]
- }
-}
-
-func stableOrdered[E constraints.Ordered](data []E, n int) {
- blockSize := 20 // must be > 0
- a, b := 0, blockSize
- for b <= n {
- insertionSortOrdered(data, a, b)
- a = b
- b += blockSize
- }
- insertionSortOrdered(data, a, n)
-
- for blockSize < n {
- a, b = 0, 2*blockSize
- for b <= n {
- symMergeOrdered(data, a, a+blockSize, b)
- a = b
- b += 2 * blockSize
- }
- if m := a + blockSize; m < n {
- symMergeOrdered(data, a, m, n)
- }
- blockSize *= 2
- }
-}
-
-// symMergeOrdered merges the two sorted subsequences data[a:m] and data[m:b] using
-// the SymMerge algorithm from Pok-Son Kim and Arne Kutzner, "Stable Minimum
-// Storage Merging by Symmetric Comparisons", in Susanne Albers and Tomasz
-// Radzik, editors, Algorithms - ESA 2004, volume 3221 of Lecture Notes in
-// Computer Science, pages 714-723. Springer, 2004.
-//
-// Let M = m-a and N = b-n. Wolog M < N.
-// The recursion depth is bound by ceil(log(N+M)).
-// The algorithm needs O(M*log(N/M + 1)) calls to data.Less.
-// The algorithm needs O((M+N)*log(M)) calls to data.Swap.
-//
-// The paper gives O((M+N)*log(M)) as the number of assignments assuming a
-// rotation algorithm which uses O(M+N+gcd(M+N)) assignments. The argumentation
-// in the paper carries through for Swap operations, especially as the block
-// swapping rotate uses only O(M+N) Swaps.
-//
-// symMerge assumes non-degenerate arguments: a < m && m < b.
-// Having the caller check this condition eliminates many leaf recursion calls,
-// which improves performance.
-func symMergeOrdered[E constraints.Ordered](data []E, a, m, b int) {
- // Avoid unnecessary recursions of symMerge
- // by direct insertion of data[a] into data[m:b]
- // if data[a:m] only contains one element.
- if m-a == 1 {
- // Use binary search to find the lowest index i
- // such that data[i] >= data[a] for m <= i < b.
- // Exit the search loop with i == b in case no such index exists.
- i := m
- j := b
- for i < j {
- h := int(uint(i+j) >> 1)
- if cmpLess(data[h], data[a]) {
- i = h + 1
- } else {
- j = h
- }
- }
- // Swap values until data[a] reaches the position before i.
- for k := a; k < i-1; k++ {
- data[k], data[k+1] = data[k+1], data[k]
- }
- return
- }
-
- // Avoid unnecessary recursions of symMerge
- // by direct insertion of data[m] into data[a:m]
- // if data[m:b] only contains one element.
- if b-m == 1 {
- // Use binary search to find the lowest index i
- // such that data[i] > data[m] for a <= i < m.
- // Exit the search loop with i == m in case no such index exists.
- i := a
- j := m
- for i < j {
- h := int(uint(i+j) >> 1)
- if !cmpLess(data[m], data[h]) {
- i = h + 1
- } else {
- j = h
- }
- }
- // Swap values until data[m] reaches the position i.
- for k := m; k > i; k-- {
- data[k], data[k-1] = data[k-1], data[k]
- }
- return
- }
-
- mid := int(uint(a+b) >> 1)
- n := mid + m
- var start, r int
- if m > mid {
- start = n - b
- r = mid
- } else {
- start = a
- r = m
- }
- p := n - 1
-
- for start < r {
- c := int(uint(start+r) >> 1)
- if !cmpLess(data[p-c], data[c]) {
- start = c + 1
- } else {
- r = c
- }
- }
-
- end := n - start
- if start < m && m < end {
- rotateOrdered(data, start, m, end)
- }
- if a < start && start < mid {
- symMergeOrdered(data, a, start, mid)
- }
- if mid < end && end < b {
- symMergeOrdered(data, mid, end, b)
- }
-}
-
-// rotateOrdered rotates two consecutive blocks u = data[a:m] and v = data[m:b] in data:
-// Data of the form 'x u v y' is changed to 'x v u y'.
-// rotate performs at most b-a many calls to data.Swap,
-// and it assumes non-degenerate arguments: a < m && m < b.
-func rotateOrdered[E constraints.Ordered](data []E, a, m, b int) {
- i := m - a
- j := b - m
-
- for i != j {
- if i > j {
- swapRangeOrdered(data, m-i, m, j)
- i -= j
- } else {
- swapRangeOrdered(data, m-i, m+j-i, i)
- j -= i
- }
- }
- // i == j
- swapRangeOrdered(data, m-i, m, i)
-}
diff --git a/vendor/golang.org/x/exp/slog/attr.go b/vendor/golang.org/x/exp/slog/attr.go
deleted file mode 100644
index a180d0e..0000000
--- a/vendor/golang.org/x/exp/slog/attr.go
+++ /dev/null
@@ -1,102 +0,0 @@
-// Copyright 2022 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package slog
-
-import (
- "fmt"
- "time"
-)
-
-// An Attr is a key-value pair.
-type Attr struct {
- Key string
- Value Value
-}
-
-// String returns an Attr for a string value.
-func String(key, value string) Attr {
- return Attr{key, StringValue(value)}
-}
-
-// Int64 returns an Attr for an int64.
-func Int64(key string, value int64) Attr {
- return Attr{key, Int64Value(value)}
-}
-
-// Int converts an int to an int64 and returns
-// an Attr with that value.
-func Int(key string, value int) Attr {
- return Int64(key, int64(value))
-}
-
-// Uint64 returns an Attr for a uint64.
-func Uint64(key string, v uint64) Attr {
- return Attr{key, Uint64Value(v)}
-}
-
-// Float64 returns an Attr for a floating-point number.
-func Float64(key string, v float64) Attr {
- return Attr{key, Float64Value(v)}
-}
-
-// Bool returns an Attr for a bool.
-func Bool(key string, v bool) Attr {
- return Attr{key, BoolValue(v)}
-}
-
-// Time returns an Attr for a time.Time.
-// It discards the monotonic portion.
-func Time(key string, v time.Time) Attr {
- return Attr{key, TimeValue(v)}
-}
-
-// Duration returns an Attr for a time.Duration.
-func Duration(key string, v time.Duration) Attr {
- return Attr{key, DurationValue(v)}
-}
-
-// Group returns an Attr for a Group Value.
-// The first argument is the key; the remaining arguments
-// are converted to Attrs as in [Logger.Log].
-//
-// Use Group to collect several key-value pairs under a single
-// key on a log line, or as the result of LogValue
-// in order to log a single value as multiple Attrs.
-func Group(key string, args ...any) Attr {
- return Attr{key, GroupValue(argsToAttrSlice(args)...)}
-}
-
-func argsToAttrSlice(args []any) []Attr {
- var (
- attr Attr
- attrs []Attr
- )
- for len(args) > 0 {
- attr, args = argsToAttr(args)
- attrs = append(attrs, attr)
- }
- return attrs
-}
-
-// Any returns an Attr for the supplied value.
-// See [Value.AnyValue] for how values are treated.
-func Any(key string, value any) Attr {
- return Attr{key, AnyValue(value)}
-}
-
-// Equal reports whether a and b have equal keys and values.
-func (a Attr) Equal(b Attr) bool {
- return a.Key == b.Key && a.Value.Equal(b.Value)
-}
-
-func (a Attr) String() string {
- return fmt.Sprintf("%s=%s", a.Key, a.Value)
-}
-
-// isEmpty reports whether a has an empty key and a nil value.
-// That can be written as Attr{} or Any("", nil).
-func (a Attr) isEmpty() bool {
- return a.Key == "" && a.Value.num == 0 && a.Value.any == nil
-}
diff --git a/vendor/golang.org/x/exp/slog/doc.go b/vendor/golang.org/x/exp/slog/doc.go
deleted file mode 100644
index 4beaf86..0000000
--- a/vendor/golang.org/x/exp/slog/doc.go
+++ /dev/null
@@ -1,316 +0,0 @@
-// Copyright 2022 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
-Package slog provides structured logging,
-in which log records include a message,
-a severity level, and various other attributes
-expressed as key-value pairs.
-
-It defines a type, [Logger],
-which provides several methods (such as [Logger.Info] and [Logger.Error])
-for reporting events of interest.
-
-Each Logger is associated with a [Handler].
-A Logger output method creates a [Record] from the method arguments
-and passes it to the Handler, which decides how to handle it.
-There is a default Logger accessible through top-level functions
-(such as [Info] and [Error]) that call the corresponding Logger methods.
-
-A log record consists of a time, a level, a message, and a set of key-value
-pairs, where the keys are strings and the values may be of any type.
-As an example,
-
- slog.Info("hello", "count", 3)
-
-creates a record containing the time of the call,
-a level of Info, the message "hello", and a single
-pair with key "count" and value 3.
-
-The [Info] top-level function calls the [Logger.Info] method on the default Logger.
-In addition to [Logger.Info], there are methods for Debug, Warn and Error levels.
-Besides these convenience methods for common levels,
-there is also a [Logger.Log] method which takes the level as an argument.
-Each of these methods has a corresponding top-level function that uses the
-default logger.
-
-The default handler formats the log record's message, time, level, and attributes
-as a string and passes it to the [log] package.
-
- 2022/11/08 15:28:26 INFO hello count=3
-
-For more control over the output format, create a logger with a different handler.
-This statement uses [New] to create a new logger with a TextHandler
-that writes structured records in text form to standard error:
-
- logger := slog.New(slog.NewTextHandler(os.Stderr, nil))
-
-[TextHandler] output is a sequence of key=value pairs, easily and unambiguously
-parsed by machine. This statement:
-
- logger.Info("hello", "count", 3)
-
-produces this output:
-
- time=2022-11-08T15:28:26.000-05:00 level=INFO msg=hello count=3
-
-The package also provides [JSONHandler], whose output is line-delimited JSON:
-
- logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
- logger.Info("hello", "count", 3)
-
-produces this output:
-
- {"time":"2022-11-08T15:28:26.000000000-05:00","level":"INFO","msg":"hello","count":3}
-
-Both [TextHandler] and [JSONHandler] can be configured with [HandlerOptions].
-There are options for setting the minimum level (see Levels, below),
-displaying the source file and line of the log call, and
-modifying attributes before they are logged.
-
-Setting a logger as the default with
-
- slog.SetDefault(logger)
-
-will cause the top-level functions like [Info] to use it.
-[SetDefault] also updates the default logger used by the [log] package,
-so that existing applications that use [log.Printf] and related functions
-will send log records to the logger's handler without needing to be rewritten.
-
-Some attributes are common to many log calls.
-For example, you may wish to include the URL or trace identifier of a server request
-with all log events arising from the request.
-Rather than repeat the attribute with every log call, you can use [Logger.With]
-to construct a new Logger containing the attributes:
-
- logger2 := logger.With("url", r.URL)
-
-The arguments to With are the same key-value pairs used in [Logger.Info].
-The result is a new Logger with the same handler as the original, but additional
-attributes that will appear in the output of every call.
-
-# Levels
-
-A [Level] is an integer representing the importance or severity of a log event.
-The higher the level, the more severe the event.
-This package defines constants for the most common levels,
-but any int can be used as a level.
-
-In an application, you may wish to log messages only at a certain level or greater.
-One common configuration is to log messages at Info or higher levels,
-suppressing debug logging until it is needed.
-The built-in handlers can be configured with the minimum level to output by
-setting [HandlerOptions.Level].
-The program's `main` function typically does this.
-The default value is LevelInfo.
-
-Setting the [HandlerOptions.Level] field to a [Level] value
-fixes the handler's minimum level throughout its lifetime.
-Setting it to a [LevelVar] allows the level to be varied dynamically.
-A LevelVar holds a Level and is safe to read or write from multiple
-goroutines.
-To vary the level dynamically for an entire program, first initialize
-a global LevelVar:
-
- var programLevel = new(slog.LevelVar) // Info by default
-
-Then use the LevelVar to construct a handler, and make it the default:
-
- h := slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{Level: programLevel})
- slog.SetDefault(slog.New(h))
-
-Now the program can change its logging level with a single statement:
-
- programLevel.Set(slog.LevelDebug)
-
-# Groups
-
-Attributes can be collected into groups.
-A group has a name that is used to qualify the names of its attributes.
-How this qualification is displayed depends on the handler.
-[TextHandler] separates the group and attribute names with a dot.
-[JSONHandler] treats each group as a separate JSON object, with the group name as the key.
-
-Use [Group] to create a Group attribute from a name and a list of key-value pairs:
-
- slog.Group("request",
- "method", r.Method,
- "url", r.URL)
-
-TextHandler would display this group as
-
- request.method=GET request.url=http://example.com
-
-JSONHandler would display it as
-
- "request":{"method":"GET","url":"http://example.com"}
-
-Use [Logger.WithGroup] to qualify all of a Logger's output
-with a group name. Calling WithGroup on a Logger results in a
-new Logger with the same Handler as the original, but with all
-its attributes qualified by the group name.
-
-This can help prevent duplicate attribute keys in large systems,
-where subsystems might use the same keys.
-Pass each subsystem a different Logger with its own group name so that
-potential duplicates are qualified:
-
- logger := slog.Default().With("id", systemID)
- parserLogger := logger.WithGroup("parser")
- parseInput(input, parserLogger)
-
-When parseInput logs with parserLogger, its keys will be qualified with "parser",
-so even if it uses the common key "id", the log line will have distinct keys.
-
-# Contexts
-
-Some handlers may wish to include information from the [context.Context] that is
-available at the call site. One example of such information
-is the identifier for the current span when tracing is enabled.
-
-The [Logger.Log] and [Logger.LogAttrs] methods take a context as a first
-argument, as do their corresponding top-level functions.
-
-Although the convenience methods on Logger (Info and so on) and the
-corresponding top-level functions do not take a context, the alternatives ending
-in "Context" do. For example,
-
- slog.InfoContext(ctx, "message")
-
-It is recommended to pass a context to an output method if one is available.
-
-# Attrs and Values
-
-An [Attr] is a key-value pair. The Logger output methods accept Attrs as well as
-alternating keys and values. The statement
-
- slog.Info("hello", slog.Int("count", 3))
-
-behaves the same as
-
- slog.Info("hello", "count", 3)
-
-There are convenience constructors for [Attr] such as [Int], [String], and [Bool]
-for common types, as well as the function [Any] for constructing Attrs of any
-type.
-
-The value part of an Attr is a type called [Value].
-Like an [any], a Value can hold any Go value,
-but it can represent typical values, including all numbers and strings,
-without an allocation.
-
-For the most efficient log output, use [Logger.LogAttrs].
-It is similar to [Logger.Log] but accepts only Attrs, not alternating
-keys and values; this allows it, too, to avoid allocation.
-
-The call
-
- logger.LogAttrs(nil, slog.LevelInfo, "hello", slog.Int("count", 3))
-
-is the most efficient way to achieve the same output as
-
- slog.Info("hello", "count", 3)
-
-# Customizing a type's logging behavior
-
-If a type implements the [LogValuer] interface, the [Value] returned from its LogValue
-method is used for logging. You can use this to control how values of the type
-appear in logs. For example, you can redact secret information like passwords,
-or gather a struct's fields in a Group. See the examples under [LogValuer] for
-details.
-
-A LogValue method may return a Value that itself implements [LogValuer]. The [Value.Resolve]
-method handles these cases carefully, avoiding infinite loops and unbounded recursion.
-Handler authors and others may wish to use Value.Resolve instead of calling LogValue directly.
-
-# Wrapping output methods
-
-The logger functions use reflection over the call stack to find the file name
-and line number of the logging call within the application. This can produce
-incorrect source information for functions that wrap slog. For instance, if you
-define this function in file mylog.go:
-
- func Infof(format string, args ...any) {
- slog.Default().Info(fmt.Sprintf(format, args...))
- }
-
-and you call it like this in main.go:
-
- Infof(slog.Default(), "hello, %s", "world")
-
-then slog will report the source file as mylog.go, not main.go.
-
-A correct implementation of Infof will obtain the source location
-(pc) and pass it to NewRecord.
-The Infof function in the package-level example called "wrapping"
-demonstrates how to do this.
-
-# Working with Records
-
-Sometimes a Handler will need to modify a Record
-before passing it on to another Handler or backend.
-A Record contains a mixture of simple public fields (e.g. Time, Level, Message)
-and hidden fields that refer to state (such as attributes) indirectly. This
-means that modifying a simple copy of a Record (e.g. by calling
-[Record.Add] or [Record.AddAttrs] to add attributes)
-may have unexpected effects on the original.
-Before modifying a Record, use [Clone] to
-create a copy that shares no state with the original,
-or create a new Record with [NewRecord]
-and build up its Attrs by traversing the old ones with [Record.Attrs].
-
-# Performance considerations
-
-If profiling your application demonstrates that logging is taking significant time,
-the following suggestions may help.
-
-If many log lines have a common attribute, use [Logger.With] to create a Logger with
-that attribute. The built-in handlers will format that attribute only once, at the
-call to [Logger.With]. The [Handler] interface is designed to allow that optimization,
-and a well-written Handler should take advantage of it.
-
-The arguments to a log call are always evaluated, even if the log event is discarded.
-If possible, defer computation so that it happens only if the value is actually logged.
-For example, consider the call
-
- slog.Info("starting request", "url", r.URL.String()) // may compute String unnecessarily
-
-The URL.String method will be called even if the logger discards Info-level events.
-Instead, pass the URL directly:
-
- slog.Info("starting request", "url", &r.URL) // calls URL.String only if needed
-
-The built-in [TextHandler] will call its String method, but only
-if the log event is enabled.
-Avoiding the call to String also preserves the structure of the underlying value.
-For example [JSONHandler] emits the components of the parsed URL as a JSON object.
-If you want to avoid eagerly paying the cost of the String call
-without causing the handler to potentially inspect the structure of the value,
-wrap the value in a fmt.Stringer implementation that hides its Marshal methods.
-
-You can also use the [LogValuer] interface to avoid unnecessary work in disabled log
-calls. Say you need to log some expensive value:
-
- slog.Debug("frobbing", "value", computeExpensiveValue(arg))
-
-Even if this line is disabled, computeExpensiveValue will be called.
-To avoid that, define a type implementing LogValuer:
-
- type expensive struct { arg int }
-
- func (e expensive) LogValue() slog.Value {
- return slog.AnyValue(computeExpensiveValue(e.arg))
- }
-
-Then use a value of that type in log calls:
-
- slog.Debug("frobbing", "value", expensive{arg})
-
-Now computeExpensiveValue will only be called when the line is enabled.
-
-The built-in handlers acquire a lock before calling [io.Writer.Write]
-to ensure that each record is written in one piece. User-defined
-handlers are responsible for their own locking.
-*/
-package slog
diff --git a/vendor/golang.org/x/exp/slog/handler.go b/vendor/golang.org/x/exp/slog/handler.go
deleted file mode 100644
index bd635cb..0000000
--- a/vendor/golang.org/x/exp/slog/handler.go
+++ /dev/null
@@ -1,577 +0,0 @@
-// Copyright 2022 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package slog
-
-import (
- "context"
- "fmt"
- "io"
- "reflect"
- "strconv"
- "sync"
- "time"
-
- "golang.org/x/exp/slices"
- "golang.org/x/exp/slog/internal/buffer"
-)
-
-// A Handler handles log records produced by a Logger..
-//
-// A typical handler may print log records to standard error,
-// or write them to a file or database, or perhaps augment them
-// with additional attributes and pass them on to another handler.
-//
-// Any of the Handler's methods may be called concurrently with itself
-// or with other methods. It is the responsibility of the Handler to
-// manage this concurrency.
-//
-// Users of the slog package should not invoke Handler methods directly.
-// They should use the methods of [Logger] instead.
-type Handler interface {
- // Enabled reports whether the handler handles records at the given level.
- // The handler ignores records whose level is lower.
- // It is called early, before any arguments are processed,
- // to save effort if the log event should be discarded.
- // If called from a Logger method, the first argument is the context
- // passed to that method, or context.Background() if nil was passed
- // or the method does not take a context.
- // The context is passed so Enabled can use its values
- // to make a decision.
- Enabled(context.Context, Level) bool
-
- // Handle handles the Record.
- // It will only be called when Enabled returns true.
- // The Context argument is as for Enabled.
- // It is present solely to provide Handlers access to the context's values.
- // Canceling the context should not affect record processing.
- // (Among other things, log messages may be necessary to debug a
- // cancellation-related problem.)
- //
- // Handle methods that produce output should observe the following rules:
- // - If r.Time is the zero time, ignore the time.
- // - If r.PC is zero, ignore it.
- // - Attr's values should be resolved.
- // - If an Attr's key and value are both the zero value, ignore the Attr.
- // This can be tested with attr.Equal(Attr{}).
- // - If a group's key is empty, inline the group's Attrs.
- // - If a group has no Attrs (even if it has a non-empty key),
- // ignore it.
- Handle(context.Context, Record) error
-
- // WithAttrs returns a new Handler whose attributes consist of
- // both the receiver's attributes and the arguments.
- // The Handler owns the slice: it may retain, modify or discard it.
- WithAttrs(attrs []Attr) Handler
-
- // WithGroup returns a new Handler with the given group appended to
- // the receiver's existing groups.
- // The keys of all subsequent attributes, whether added by With or in a
- // Record, should be qualified by the sequence of group names.
- //
- // How this qualification happens is up to the Handler, so long as
- // this Handler's attribute keys differ from those of another Handler
- // with a different sequence of group names.
- //
- // A Handler should treat WithGroup as starting a Group of Attrs that ends
- // at the end of the log event. That is,
- //
- // logger.WithGroup("s").LogAttrs(level, msg, slog.Int("a", 1), slog.Int("b", 2))
- //
- // should behave like
- //
- // logger.LogAttrs(level, msg, slog.Group("s", slog.Int("a", 1), slog.Int("b", 2)))
- //
- // If the name is empty, WithGroup returns the receiver.
- WithGroup(name string) Handler
-}
-
-type defaultHandler struct {
- ch *commonHandler
- // log.Output, except for testing
- output func(calldepth int, message string) error
-}
-
-func newDefaultHandler(output func(int, string) error) *defaultHandler {
- return &defaultHandler{
- ch: &commonHandler{json: false},
- output: output,
- }
-}
-
-func (*defaultHandler) Enabled(_ context.Context, l Level) bool {
- return l >= LevelInfo
-}
-
-// Collect the level, attributes and message in a string and
-// write it with the default log.Logger.
-// Let the log.Logger handle time and file/line.
-func (h *defaultHandler) Handle(ctx context.Context, r Record) error {
- buf := buffer.New()
- buf.WriteString(r.Level.String())
- buf.WriteByte(' ')
- buf.WriteString(r.Message)
- state := h.ch.newHandleState(buf, true, " ", nil)
- defer state.free()
- state.appendNonBuiltIns(r)
-
- // skip [h.output, defaultHandler.Handle, handlerWriter.Write, log.Output]
- return h.output(4, buf.String())
-}
-
-func (h *defaultHandler) WithAttrs(as []Attr) Handler {
- return &defaultHandler{h.ch.withAttrs(as), h.output}
-}
-
-func (h *defaultHandler) WithGroup(name string) Handler {
- return &defaultHandler{h.ch.withGroup(name), h.output}
-}
-
-// HandlerOptions are options for a TextHandler or JSONHandler.
-// A zero HandlerOptions consists entirely of default values.
-type HandlerOptions struct {
- // AddSource causes the handler to compute the source code position
- // of the log statement and add a SourceKey attribute to the output.
- AddSource bool
-
- // Level reports the minimum record level that will be logged.
- // The handler discards records with lower levels.
- // If Level is nil, the handler assumes LevelInfo.
- // The handler calls Level.Level for each record processed;
- // to adjust the minimum level dynamically, use a LevelVar.
- Level Leveler
-
- // ReplaceAttr is called to rewrite each non-group attribute before it is logged.
- // The attribute's value has been resolved (see [Value.Resolve]).
- // If ReplaceAttr returns an Attr with Key == "", the attribute is discarded.
- //
- // The built-in attributes with keys "time", "level", "source", and "msg"
- // are passed to this function, except that time is omitted
- // if zero, and source is omitted if AddSource is false.
- //
- // The first argument is a list of currently open groups that contain the
- // Attr. It must not be retained or modified. ReplaceAttr is never called
- // for Group attributes, only their contents. For example, the attribute
- // list
- //
- // Int("a", 1), Group("g", Int("b", 2)), Int("c", 3)
- //
- // results in consecutive calls to ReplaceAttr with the following arguments:
- //
- // nil, Int("a", 1)
- // []string{"g"}, Int("b", 2)
- // nil, Int("c", 3)
- //
- // ReplaceAttr can be used to change the default keys of the built-in
- // attributes, convert types (for example, to replace a `time.Time` with the
- // integer seconds since the Unix epoch), sanitize personal information, or
- // remove attributes from the output.
- ReplaceAttr func(groups []string, a Attr) Attr
-}
-
-// Keys for "built-in" attributes.
-const (
- // TimeKey is the key used by the built-in handlers for the time
- // when the log method is called. The associated Value is a [time.Time].
- TimeKey = "time"
- // LevelKey is the key used by the built-in handlers for the level
- // of the log call. The associated value is a [Level].
- LevelKey = "level"
- // MessageKey is the key used by the built-in handlers for the
- // message of the log call. The associated value is a string.
- MessageKey = "msg"
- // SourceKey is the key used by the built-in handlers for the source file
- // and line of the log call. The associated value is a string.
- SourceKey = "source"
-)
-
-type commonHandler struct {
- json bool // true => output JSON; false => output text
- opts HandlerOptions
- preformattedAttrs []byte
- groupPrefix string // for text: prefix of groups opened in preformatting
- groups []string // all groups started from WithGroup
- nOpenGroups int // the number of groups opened in preformattedAttrs
- mu sync.Mutex
- w io.Writer
-}
-
-func (h *commonHandler) clone() *commonHandler {
- // We can't use assignment because we can't copy the mutex.
- return &commonHandler{
- json: h.json,
- opts: h.opts,
- preformattedAttrs: slices.Clip(h.preformattedAttrs),
- groupPrefix: h.groupPrefix,
- groups: slices.Clip(h.groups),
- nOpenGroups: h.nOpenGroups,
- w: h.w,
- }
-}
-
-// enabled reports whether l is greater than or equal to the
-// minimum level.
-func (h *commonHandler) enabled(l Level) bool {
- minLevel := LevelInfo
- if h.opts.Level != nil {
- minLevel = h.opts.Level.Level()
- }
- return l >= minLevel
-}
-
-func (h *commonHandler) withAttrs(as []Attr) *commonHandler {
- h2 := h.clone()
- // Pre-format the attributes as an optimization.
- prefix := buffer.New()
- defer prefix.Free()
- prefix.WriteString(h.groupPrefix)
- state := h2.newHandleState((*buffer.Buffer)(&h2.preformattedAttrs), false, "", prefix)
- defer state.free()
- if len(h2.preformattedAttrs) > 0 {
- state.sep = h.attrSep()
- }
- state.openGroups()
- for _, a := range as {
- state.appendAttr(a)
- }
- // Remember the new prefix for later keys.
- h2.groupPrefix = state.prefix.String()
- // Remember how many opened groups are in preformattedAttrs,
- // so we don't open them again when we handle a Record.
- h2.nOpenGroups = len(h2.groups)
- return h2
-}
-
-func (h *commonHandler) withGroup(name string) *commonHandler {
- if name == "" {
- return h
- }
- h2 := h.clone()
- h2.groups = append(h2.groups, name)
- return h2
-}
-
-func (h *commonHandler) handle(r Record) error {
- state := h.newHandleState(buffer.New(), true, "", nil)
- defer state.free()
- if h.json {
- state.buf.WriteByte('{')
- }
- // Built-in attributes. They are not in a group.
- stateGroups := state.groups
- state.groups = nil // So ReplaceAttrs sees no groups instead of the pre groups.
- rep := h.opts.ReplaceAttr
- // time
- if !r.Time.IsZero() {
- key := TimeKey
- val := r.Time.Round(0) // strip monotonic to match Attr behavior
- if rep == nil {
- state.appendKey(key)
- state.appendTime(val)
- } else {
- state.appendAttr(Time(key, val))
- }
- }
- // level
- key := LevelKey
- val := r.Level
- if rep == nil {
- state.appendKey(key)
- state.appendString(val.String())
- } else {
- state.appendAttr(Any(key, val))
- }
- // source
- if h.opts.AddSource {
- state.appendAttr(Any(SourceKey, r.source()))
- }
- key = MessageKey
- msg := r.Message
- if rep == nil {
- state.appendKey(key)
- state.appendString(msg)
- } else {
- state.appendAttr(String(key, msg))
- }
- state.groups = stateGroups // Restore groups passed to ReplaceAttrs.
- state.appendNonBuiltIns(r)
- state.buf.WriteByte('\n')
-
- h.mu.Lock()
- defer h.mu.Unlock()
- _, err := h.w.Write(*state.buf)
- return err
-}
-
-func (s *handleState) appendNonBuiltIns(r Record) {
- // preformatted Attrs
- if len(s.h.preformattedAttrs) > 0 {
- s.buf.WriteString(s.sep)
- s.buf.Write(s.h.preformattedAttrs)
- s.sep = s.h.attrSep()
- }
- // Attrs in Record -- unlike the built-in ones, they are in groups started
- // from WithGroup.
- s.prefix = buffer.New()
- defer s.prefix.Free()
- s.prefix.WriteString(s.h.groupPrefix)
- s.openGroups()
- r.Attrs(func(a Attr) bool {
- s.appendAttr(a)
- return true
- })
- if s.h.json {
- // Close all open groups.
- for range s.h.groups {
- s.buf.WriteByte('}')
- }
- // Close the top-level object.
- s.buf.WriteByte('}')
- }
-}
-
-// attrSep returns the separator between attributes.
-func (h *commonHandler) attrSep() string {
- if h.json {
- return ","
- }
- return " "
-}
-
-// handleState holds state for a single call to commonHandler.handle.
-// The initial value of sep determines whether to emit a separator
-// before the next key, after which it stays true.
-type handleState struct {
- h *commonHandler
- buf *buffer.Buffer
- freeBuf bool // should buf be freed?
- sep string // separator to write before next key
- prefix *buffer.Buffer // for text: key prefix
- groups *[]string // pool-allocated slice of active groups, for ReplaceAttr
-}
-
-var groupPool = sync.Pool{New: func() any {
- s := make([]string, 0, 10)
- return &s
-}}
-
-func (h *commonHandler) newHandleState(buf *buffer.Buffer, freeBuf bool, sep string, prefix *buffer.Buffer) handleState {
- s := handleState{
- h: h,
- buf: buf,
- freeBuf: freeBuf,
- sep: sep,
- prefix: prefix,
- }
- if h.opts.ReplaceAttr != nil {
- s.groups = groupPool.Get().(*[]string)
- *s.groups = append(*s.groups, h.groups[:h.nOpenGroups]...)
- }
- return s
-}
-
-func (s *handleState) free() {
- if s.freeBuf {
- s.buf.Free()
- }
- if gs := s.groups; gs != nil {
- *gs = (*gs)[:0]
- groupPool.Put(gs)
- }
-}
-
-func (s *handleState) openGroups() {
- for _, n := range s.h.groups[s.h.nOpenGroups:] {
- s.openGroup(n)
- }
-}
-
-// Separator for group names and keys.
-const keyComponentSep = '.'
-
-// openGroup starts a new group of attributes
-// with the given name.
-func (s *handleState) openGroup(name string) {
- if s.h.json {
- s.appendKey(name)
- s.buf.WriteByte('{')
- s.sep = ""
- } else {
- s.prefix.WriteString(name)
- s.prefix.WriteByte(keyComponentSep)
- }
- // Collect group names for ReplaceAttr.
- if s.groups != nil {
- *s.groups = append(*s.groups, name)
- }
-}
-
-// closeGroup ends the group with the given name.
-func (s *handleState) closeGroup(name string) {
- if s.h.json {
- s.buf.WriteByte('}')
- } else {
- (*s.prefix) = (*s.prefix)[:len(*s.prefix)-len(name)-1 /* for keyComponentSep */]
- }
- s.sep = s.h.attrSep()
- if s.groups != nil {
- *s.groups = (*s.groups)[:len(*s.groups)-1]
- }
-}
-
-// appendAttr appends the Attr's key and value using app.
-// It handles replacement and checking for an empty key.
-// after replacement).
-func (s *handleState) appendAttr(a Attr) {
- if rep := s.h.opts.ReplaceAttr; rep != nil && a.Value.Kind() != KindGroup {
- var gs []string
- if s.groups != nil {
- gs = *s.groups
- }
- // Resolve before calling ReplaceAttr, so the user doesn't have to.
- a.Value = a.Value.Resolve()
- a = rep(gs, a)
- }
- a.Value = a.Value.Resolve()
- // Elide empty Attrs.
- if a.isEmpty() {
- return
- }
- // Special case: Source.
- if v := a.Value; v.Kind() == KindAny {
- if src, ok := v.Any().(*Source); ok {
- if s.h.json {
- a.Value = src.group()
- } else {
- a.Value = StringValue(fmt.Sprintf("%s:%d", src.File, src.Line))
- }
- }
- }
- if a.Value.Kind() == KindGroup {
- attrs := a.Value.Group()
- // Output only non-empty groups.
- if len(attrs) > 0 {
- // Inline a group with an empty key.
- if a.Key != "" {
- s.openGroup(a.Key)
- }
- for _, aa := range attrs {
- s.appendAttr(aa)
- }
- if a.Key != "" {
- s.closeGroup(a.Key)
- }
- }
- } else {
- s.appendKey(a.Key)
- s.appendValue(a.Value)
- }
-}
-
-func (s *handleState) appendError(err error) {
- s.appendString(fmt.Sprintf("!ERROR:%v", err))
-}
-
-func (s *handleState) appendKey(key string) {
- s.buf.WriteString(s.sep)
- if s.prefix != nil {
- // TODO: optimize by avoiding allocation.
- s.appendString(string(*s.prefix) + key)
- } else {
- s.appendString(key)
- }
- if s.h.json {
- s.buf.WriteByte(':')
- } else {
- s.buf.WriteByte('=')
- }
- s.sep = s.h.attrSep()
-}
-
-func (s *handleState) appendString(str string) {
- if s.h.json {
- s.buf.WriteByte('"')
- *s.buf = appendEscapedJSONString(*s.buf, str)
- s.buf.WriteByte('"')
- } else {
- // text
- if needsQuoting(str) {
- *s.buf = strconv.AppendQuote(*s.buf, str)
- } else {
- s.buf.WriteString(str)
- }
- }
-}
-
-func (s *handleState) appendValue(v Value) {
- defer func() {
- if r := recover(); r != nil {
- // If it panics with a nil pointer, the most likely cases are
- // an encoding.TextMarshaler or error fails to guard against nil,
- // in which case "" seems to be the feasible choice.
- //
- // Adapted from the code in fmt/print.go.
- if v := reflect.ValueOf(v.any); v.Kind() == reflect.Pointer && v.IsNil() {
- s.appendString("")
- return
- }
-
- // Otherwise just print the original panic message.
- s.appendString(fmt.Sprintf("!PANIC: %v", r))
- }
- }()
-
- var err error
- if s.h.json {
- err = appendJSONValue(s, v)
- } else {
- err = appendTextValue(s, v)
- }
- if err != nil {
- s.appendError(err)
- }
-}
-
-func (s *handleState) appendTime(t time.Time) {
- if s.h.json {
- appendJSONTime(s, t)
- } else {
- writeTimeRFC3339Millis(s.buf, t)
- }
-}
-
-// This takes half the time of Time.AppendFormat.
-func writeTimeRFC3339Millis(buf *buffer.Buffer, t time.Time) {
- year, month, day := t.Date()
- buf.WritePosIntWidth(year, 4)
- buf.WriteByte('-')
- buf.WritePosIntWidth(int(month), 2)
- buf.WriteByte('-')
- buf.WritePosIntWidth(day, 2)
- buf.WriteByte('T')
- hour, min, sec := t.Clock()
- buf.WritePosIntWidth(hour, 2)
- buf.WriteByte(':')
- buf.WritePosIntWidth(min, 2)
- buf.WriteByte(':')
- buf.WritePosIntWidth(sec, 2)
- ns := t.Nanosecond()
- buf.WriteByte('.')
- buf.WritePosIntWidth(ns/1e6, 3)
- _, offsetSeconds := t.Zone()
- if offsetSeconds == 0 {
- buf.WriteByte('Z')
- } else {
- offsetMinutes := offsetSeconds / 60
- if offsetMinutes < 0 {
- buf.WriteByte('-')
- offsetMinutes = -offsetMinutes
- } else {
- buf.WriteByte('+')
- }
- buf.WritePosIntWidth(offsetMinutes/60, 2)
- buf.WriteByte(':')
- buf.WritePosIntWidth(offsetMinutes%60, 2)
- }
-}
diff --git a/vendor/golang.org/x/exp/slog/internal/buffer/buffer.go b/vendor/golang.org/x/exp/slog/internal/buffer/buffer.go
deleted file mode 100644
index 7786c16..0000000
--- a/vendor/golang.org/x/exp/slog/internal/buffer/buffer.go
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright 2022 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package buffer provides a pool-allocated byte buffer.
-package buffer
-
-import (
- "sync"
-)
-
-// Buffer adapted from go/src/fmt/print.go
-type Buffer []byte
-
-// Having an initial size gives a dramatic speedup.
-var bufPool = sync.Pool{
- New: func() any {
- b := make([]byte, 0, 1024)
- return (*Buffer)(&b)
- },
-}
-
-func New() *Buffer {
- return bufPool.Get().(*Buffer)
-}
-
-func (b *Buffer) Free() {
- // To reduce peak allocation, return only smaller buffers to the pool.
- const maxBufferSize = 16 << 10
- if cap(*b) <= maxBufferSize {
- *b = (*b)[:0]
- bufPool.Put(b)
- }
-}
-
-func (b *Buffer) Reset() {
- *b = (*b)[:0]
-}
-
-func (b *Buffer) Write(p []byte) (int, error) {
- *b = append(*b, p...)
- return len(p), nil
-}
-
-func (b *Buffer) WriteString(s string) {
- *b = append(*b, s...)
-}
-
-func (b *Buffer) WriteByte(c byte) {
- *b = append(*b, c)
-}
-
-func (b *Buffer) WritePosInt(i int) {
- b.WritePosIntWidth(i, 0)
-}
-
-// WritePosIntWidth writes non-negative integer i to the buffer, padded on the left
-// by zeroes to the given width. Use a width of 0 to omit padding.
-func (b *Buffer) WritePosIntWidth(i, width int) {
- // Cheap integer to fixed-width decimal ASCII.
- // Copied from log/log.go.
-
- if i < 0 {
- panic("negative int")
- }
-
- // Assemble decimal in reverse order.
- var bb [20]byte
- bp := len(bb) - 1
- for i >= 10 || width > 1 {
- width--
- q := i / 10
- bb[bp] = byte('0' + i - q*10)
- bp--
- i = q
- }
- // i < 10
- bb[bp] = byte('0' + i)
- b.Write(bb[bp:])
-}
-
-func (b *Buffer) String() string {
- return string(*b)
-}
diff --git a/vendor/golang.org/x/exp/slog/internal/ignorepc.go b/vendor/golang.org/x/exp/slog/internal/ignorepc.go
deleted file mode 100644
index d125642..0000000
--- a/vendor/golang.org/x/exp/slog/internal/ignorepc.go
+++ /dev/null
@@ -1,9 +0,0 @@
-// Copyright 2023 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package internal
-
-// If IgnorePC is true, do not invoke runtime.Callers to get the pc.
-// This is solely for benchmarking the slowdown from runtime.Callers.
-var IgnorePC = false
diff --git a/vendor/golang.org/x/exp/slog/json_handler.go b/vendor/golang.org/x/exp/slog/json_handler.go
deleted file mode 100644
index 157ada8..0000000
--- a/vendor/golang.org/x/exp/slog/json_handler.go
+++ /dev/null
@@ -1,336 +0,0 @@
-// Copyright 2022 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package slog
-
-import (
- "bytes"
- "context"
- "encoding/json"
- "errors"
- "fmt"
- "io"
- "strconv"
- "time"
- "unicode/utf8"
-
- "golang.org/x/exp/slog/internal/buffer"
-)
-
-// JSONHandler is a Handler that writes Records to an io.Writer as
-// line-delimited JSON objects.
-type JSONHandler struct {
- *commonHandler
-}
-
-// NewJSONHandler creates a JSONHandler that writes to w,
-// using the given options.
-// If opts is nil, the default options are used.
-func NewJSONHandler(w io.Writer, opts *HandlerOptions) *JSONHandler {
- if opts == nil {
- opts = &HandlerOptions{}
- }
- return &JSONHandler{
- &commonHandler{
- json: true,
- w: w,
- opts: *opts,
- },
- }
-}
-
-// Enabled reports whether the handler handles records at the given level.
-// The handler ignores records whose level is lower.
-func (h *JSONHandler) Enabled(_ context.Context, level Level) bool {
- return h.commonHandler.enabled(level)
-}
-
-// WithAttrs returns a new JSONHandler whose attributes consists
-// of h's attributes followed by attrs.
-func (h *JSONHandler) WithAttrs(attrs []Attr) Handler {
- return &JSONHandler{commonHandler: h.commonHandler.withAttrs(attrs)}
-}
-
-func (h *JSONHandler) WithGroup(name string) Handler {
- return &JSONHandler{commonHandler: h.commonHandler.withGroup(name)}
-}
-
-// Handle formats its argument Record as a JSON object on a single line.
-//
-// If the Record's time is zero, the time is omitted.
-// Otherwise, the key is "time"
-// and the value is output as with json.Marshal.
-//
-// If the Record's level is zero, the level is omitted.
-// Otherwise, the key is "level"
-// and the value of [Level.String] is output.
-//
-// If the AddSource option is set and source information is available,
-// the key is "source"
-// and the value is output as "FILE:LINE".
-//
-// The message's key is "msg".
-//
-// To modify these or other attributes, or remove them from the output, use
-// [HandlerOptions.ReplaceAttr].
-//
-// Values are formatted as with an [encoding/json.Encoder] with SetEscapeHTML(false),
-// with two exceptions.
-//
-// First, an Attr whose Value is of type error is formatted as a string, by
-// calling its Error method. Only errors in Attrs receive this special treatment,
-// not errors embedded in structs, slices, maps or other data structures that
-// are processed by the encoding/json package.
-//
-// Second, an encoding failure does not cause Handle to return an error.
-// Instead, the error message is formatted as a string.
-//
-// Each call to Handle results in a single serialized call to io.Writer.Write.
-func (h *JSONHandler) Handle(_ context.Context, r Record) error {
- return h.commonHandler.handle(r)
-}
-
-// Adapted from time.Time.MarshalJSON to avoid allocation.
-func appendJSONTime(s *handleState, t time.Time) {
- if y := t.Year(); y < 0 || y >= 10000 {
- // RFC 3339 is clear that years are 4 digits exactly.
- // See golang.org/issue/4556#c15 for more discussion.
- s.appendError(errors.New("time.Time year outside of range [0,9999]"))
- }
- s.buf.WriteByte('"')
- *s.buf = t.AppendFormat(*s.buf, time.RFC3339Nano)
- s.buf.WriteByte('"')
-}
-
-func appendJSONValue(s *handleState, v Value) error {
- switch v.Kind() {
- case KindString:
- s.appendString(v.str())
- case KindInt64:
- *s.buf = strconv.AppendInt(*s.buf, v.Int64(), 10)
- case KindUint64:
- *s.buf = strconv.AppendUint(*s.buf, v.Uint64(), 10)
- case KindFloat64:
- // json.Marshal is funny about floats; it doesn't
- // always match strconv.AppendFloat. So just call it.
- // That's expensive, but floats are rare.
- if err := appendJSONMarshal(s.buf, v.Float64()); err != nil {
- return err
- }
- case KindBool:
- *s.buf = strconv.AppendBool(*s.buf, v.Bool())
- case KindDuration:
- // Do what json.Marshal does.
- *s.buf = strconv.AppendInt(*s.buf, int64(v.Duration()), 10)
- case KindTime:
- s.appendTime(v.Time())
- case KindAny:
- a := v.Any()
- _, jm := a.(json.Marshaler)
- if err, ok := a.(error); ok && !jm {
- s.appendString(err.Error())
- } else {
- return appendJSONMarshal(s.buf, a)
- }
- default:
- panic(fmt.Sprintf("bad kind: %s", v.Kind()))
- }
- return nil
-}
-
-func appendJSONMarshal(buf *buffer.Buffer, v any) error {
- // Use a json.Encoder to avoid escaping HTML.
- var bb bytes.Buffer
- enc := json.NewEncoder(&bb)
- enc.SetEscapeHTML(false)
- if err := enc.Encode(v); err != nil {
- return err
- }
- bs := bb.Bytes()
- buf.Write(bs[:len(bs)-1]) // remove final newline
- return nil
-}
-
-// appendEscapedJSONString escapes s for JSON and appends it to buf.
-// It does not surround the string in quotation marks.
-//
-// Modified from encoding/json/encode.go:encodeState.string,
-// with escapeHTML set to false.
-func appendEscapedJSONString(buf []byte, s string) []byte {
- char := func(b byte) { buf = append(buf, b) }
- str := func(s string) { buf = append(buf, s...) }
-
- start := 0
- for i := 0; i < len(s); {
- if b := s[i]; b < utf8.RuneSelf {
- if safeSet[b] {
- i++
- continue
- }
- if start < i {
- str(s[start:i])
- }
- char('\\')
- switch b {
- case '\\', '"':
- char(b)
- case '\n':
- char('n')
- case '\r':
- char('r')
- case '\t':
- char('t')
- default:
- // This encodes bytes < 0x20 except for \t, \n and \r.
- str(`u00`)
- char(hex[b>>4])
- char(hex[b&0xF])
- }
- i++
- start = i
- continue
- }
- c, size := utf8.DecodeRuneInString(s[i:])
- if c == utf8.RuneError && size == 1 {
- if start < i {
- str(s[start:i])
- }
- str(`\ufffd`)
- i += size
- start = i
- continue
- }
- // U+2028 is LINE SEPARATOR.
- // U+2029 is PARAGRAPH SEPARATOR.
- // They are both technically valid characters in JSON strings,
- // but don't work in JSONP, which has to be evaluated as JavaScript,
- // and can lead to security holes there. It is valid JSON to
- // escape them, so we do so unconditionally.
- // See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion.
- if c == '\u2028' || c == '\u2029' {
- if start < i {
- str(s[start:i])
- }
- str(`\u202`)
- char(hex[c&0xF])
- i += size
- start = i
- continue
- }
- i += size
- }
- if start < len(s) {
- str(s[start:])
- }
- return buf
-}
-
-var hex = "0123456789abcdef"
-
-// Copied from encoding/json/tables.go.
-//
-// safeSet holds the value true if the ASCII character with the given array
-// position can be represented inside a JSON string without any further
-// escaping.
-//
-// All values are true except for the ASCII control characters (0-31), the
-// double quote ("), and the backslash character ("\").
-var safeSet = [utf8.RuneSelf]bool{
- ' ': true,
- '!': true,
- '"': false,
- '#': true,
- '$': true,
- '%': true,
- '&': true,
- '\'': true,
- '(': true,
- ')': true,
- '*': true,
- '+': true,
- ',': true,
- '-': true,
- '.': true,
- '/': true,
- '0': true,
- '1': true,
- '2': true,
- '3': true,
- '4': true,
- '5': true,
- '6': true,
- '7': true,
- '8': true,
- '9': true,
- ':': true,
- ';': true,
- '<': true,
- '=': true,
- '>': true,
- '?': true,
- '@': true,
- 'A': true,
- 'B': true,
- 'C': true,
- 'D': true,
- 'E': true,
- 'F': true,
- 'G': true,
- 'H': true,
- 'I': true,
- 'J': true,
- 'K': true,
- 'L': true,
- 'M': true,
- 'N': true,
- 'O': true,
- 'P': true,
- 'Q': true,
- 'R': true,
- 'S': true,
- 'T': true,
- 'U': true,
- 'V': true,
- 'W': true,
- 'X': true,
- 'Y': true,
- 'Z': true,
- '[': true,
- '\\': false,
- ']': true,
- '^': true,
- '_': true,
- '`': true,
- 'a': true,
- 'b': true,
- 'c': true,
- 'd': true,
- 'e': true,
- 'f': true,
- 'g': true,
- 'h': true,
- 'i': true,
- 'j': true,
- 'k': true,
- 'l': true,
- 'm': true,
- 'n': true,
- 'o': true,
- 'p': true,
- 'q': true,
- 'r': true,
- 's': true,
- 't': true,
- 'u': true,
- 'v': true,
- 'w': true,
- 'x': true,
- 'y': true,
- 'z': true,
- '{': true,
- '|': true,
- '}': true,
- '~': true,
- '\u007f': true,
-}
diff --git a/vendor/golang.org/x/exp/slog/level.go b/vendor/golang.org/x/exp/slog/level.go
deleted file mode 100644
index b2365f0..0000000
--- a/vendor/golang.org/x/exp/slog/level.go
+++ /dev/null
@@ -1,201 +0,0 @@
-// Copyright 2022 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package slog
-
-import (
- "errors"
- "fmt"
- "strconv"
- "strings"
- "sync/atomic"
-)
-
-// A Level is the importance or severity of a log event.
-// The higher the level, the more important or severe the event.
-type Level int
-
-// Level numbers are inherently arbitrary,
-// but we picked them to satisfy three constraints.
-// Any system can map them to another numbering scheme if it wishes.
-//
-// First, we wanted the default level to be Info, Since Levels are ints, Info is
-// the default value for int, zero.
-//
-
-// Second, we wanted to make it easy to use levels to specify logger verbosity.
-// Since a larger level means a more severe event, a logger that accepts events
-// with smaller (or more negative) level means a more verbose logger. Logger
-// verbosity is thus the negation of event severity, and the default verbosity
-// of 0 accepts all events at least as severe as INFO.
-//
-// Third, we wanted some room between levels to accommodate schemes with named
-// levels between ours. For example, Google Cloud Logging defines a Notice level
-// between Info and Warn. Since there are only a few of these intermediate
-// levels, the gap between the numbers need not be large. Our gap of 4 matches
-// OpenTelemetry's mapping. Subtracting 9 from an OpenTelemetry level in the
-// DEBUG, INFO, WARN and ERROR ranges converts it to the corresponding slog
-// Level range. OpenTelemetry also has the names TRACE and FATAL, which slog
-// does not. But those OpenTelemetry levels can still be represented as slog
-// Levels by using the appropriate integers.
-//
-// Names for common levels.
-const (
- LevelDebug Level = -4
- LevelInfo Level = 0
- LevelWarn Level = 4
- LevelError Level = 8
-)
-
-// String returns a name for the level.
-// If the level has a name, then that name
-// in uppercase is returned.
-// If the level is between named values, then
-// an integer is appended to the uppercased name.
-// Examples:
-//
-// LevelWarn.String() => "WARN"
-// (LevelInfo+2).String() => "INFO+2"
-func (l Level) String() string {
- str := func(base string, val Level) string {
- if val == 0 {
- return base
- }
- return fmt.Sprintf("%s%+d", base, val)
- }
-
- switch {
- case l < LevelInfo:
- return str("DEBUG", l-LevelDebug)
- case l < LevelWarn:
- return str("INFO", l-LevelInfo)
- case l < LevelError:
- return str("WARN", l-LevelWarn)
- default:
- return str("ERROR", l-LevelError)
- }
-}
-
-// MarshalJSON implements [encoding/json.Marshaler]
-// by quoting the output of [Level.String].
-func (l Level) MarshalJSON() ([]byte, error) {
- // AppendQuote is sufficient for JSON-encoding all Level strings.
- // They don't contain any runes that would produce invalid JSON
- // when escaped.
- return strconv.AppendQuote(nil, l.String()), nil
-}
-
-// UnmarshalJSON implements [encoding/json.Unmarshaler]
-// It accepts any string produced by [Level.MarshalJSON],
-// ignoring case.
-// It also accepts numeric offsets that would result in a different string on
-// output. For example, "Error-8" would marshal as "INFO".
-func (l *Level) UnmarshalJSON(data []byte) error {
- s, err := strconv.Unquote(string(data))
- if err != nil {
- return err
- }
- return l.parse(s)
-}
-
-// MarshalText implements [encoding.TextMarshaler]
-// by calling [Level.String].
-func (l Level) MarshalText() ([]byte, error) {
- return []byte(l.String()), nil
-}
-
-// UnmarshalText implements [encoding.TextUnmarshaler].
-// It accepts any string produced by [Level.MarshalText],
-// ignoring case.
-// It also accepts numeric offsets that would result in a different string on
-// output. For example, "Error-8" would marshal as "INFO".
-func (l *Level) UnmarshalText(data []byte) error {
- return l.parse(string(data))
-}
-
-func (l *Level) parse(s string) (err error) {
- defer func() {
- if err != nil {
- err = fmt.Errorf("slog: level string %q: %w", s, err)
- }
- }()
-
- name := s
- offset := 0
- if i := strings.IndexAny(s, "+-"); i >= 0 {
- name = s[:i]
- offset, err = strconv.Atoi(s[i:])
- if err != nil {
- return err
- }
- }
- switch strings.ToUpper(name) {
- case "DEBUG":
- *l = LevelDebug
- case "INFO":
- *l = LevelInfo
- case "WARN":
- *l = LevelWarn
- case "ERROR":
- *l = LevelError
- default:
- return errors.New("unknown name")
- }
- *l += Level(offset)
- return nil
-}
-
-// Level returns the receiver.
-// It implements Leveler.
-func (l Level) Level() Level { return l }
-
-// A LevelVar is a Level variable, to allow a Handler level to change
-// dynamically.
-// It implements Leveler as well as a Set method,
-// and it is safe for use by multiple goroutines.
-// The zero LevelVar corresponds to LevelInfo.
-type LevelVar struct {
- val atomic.Int64
-}
-
-// Level returns v's level.
-func (v *LevelVar) Level() Level {
- return Level(int(v.val.Load()))
-}
-
-// Set sets v's level to l.
-func (v *LevelVar) Set(l Level) {
- v.val.Store(int64(l))
-}
-
-func (v *LevelVar) String() string {
- return fmt.Sprintf("LevelVar(%s)", v.Level())
-}
-
-// MarshalText implements [encoding.TextMarshaler]
-// by calling [Level.MarshalText].
-func (v *LevelVar) MarshalText() ([]byte, error) {
- return v.Level().MarshalText()
-}
-
-// UnmarshalText implements [encoding.TextUnmarshaler]
-// by calling [Level.UnmarshalText].
-func (v *LevelVar) UnmarshalText(data []byte) error {
- var l Level
- if err := l.UnmarshalText(data); err != nil {
- return err
- }
- v.Set(l)
- return nil
-}
-
-// A Leveler provides a Level value.
-//
-// As Level itself implements Leveler, clients typically supply
-// a Level value wherever a Leveler is needed, such as in HandlerOptions.
-// Clients who need to vary the level dynamically can provide a more complex
-// Leveler implementation such as *LevelVar.
-type Leveler interface {
- Level() Level
-}
diff --git a/vendor/golang.org/x/exp/slog/logger.go b/vendor/golang.org/x/exp/slog/logger.go
deleted file mode 100644
index e87ec99..0000000
--- a/vendor/golang.org/x/exp/slog/logger.go
+++ /dev/null
@@ -1,343 +0,0 @@
-// Copyright 2022 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package slog
-
-import (
- "context"
- "log"
- "runtime"
- "sync/atomic"
- "time"
-
- "golang.org/x/exp/slog/internal"
-)
-
-var defaultLogger atomic.Value
-
-func init() {
- defaultLogger.Store(New(newDefaultHandler(log.Output)))
-}
-
-// Default returns the default Logger.
-func Default() *Logger { return defaultLogger.Load().(*Logger) }
-
-// SetDefault makes l the default Logger.
-// After this call, output from the log package's default Logger
-// (as with [log.Print], etc.) will be logged at LevelInfo using l's Handler.
-func SetDefault(l *Logger) {
- defaultLogger.Store(l)
- // If the default's handler is a defaultHandler, then don't use a handleWriter,
- // or we'll deadlock as they both try to acquire the log default mutex.
- // The defaultHandler will use whatever the log default writer is currently
- // set to, which is correct.
- // This can occur with SetDefault(Default()).
- // See TestSetDefault.
- if _, ok := l.Handler().(*defaultHandler); !ok {
- capturePC := log.Flags()&(log.Lshortfile|log.Llongfile) != 0
- log.SetOutput(&handlerWriter{l.Handler(), LevelInfo, capturePC})
- log.SetFlags(0) // we want just the log message, no time or location
- }
-}
-
-// handlerWriter is an io.Writer that calls a Handler.
-// It is used to link the default log.Logger to the default slog.Logger.
-type handlerWriter struct {
- h Handler
- level Level
- capturePC bool
-}
-
-func (w *handlerWriter) Write(buf []byte) (int, error) {
- if !w.h.Enabled(context.Background(), w.level) {
- return 0, nil
- }
- var pc uintptr
- if !internal.IgnorePC && w.capturePC {
- // skip [runtime.Callers, w.Write, Logger.Output, log.Print]
- var pcs [1]uintptr
- runtime.Callers(4, pcs[:])
- pc = pcs[0]
- }
-
- // Remove final newline.
- origLen := len(buf) // Report that the entire buf was written.
- if len(buf) > 0 && buf[len(buf)-1] == '\n' {
- buf = buf[:len(buf)-1]
- }
- r := NewRecord(time.Now(), w.level, string(buf), pc)
- return origLen, w.h.Handle(context.Background(), r)
-}
-
-// A Logger records structured information about each call to its
-// Log, Debug, Info, Warn, and Error methods.
-// For each call, it creates a Record and passes it to a Handler.
-//
-// To create a new Logger, call [New] or a Logger method
-// that begins "With".
-type Logger struct {
- handler Handler // for structured logging
-}
-
-func (l *Logger) clone() *Logger {
- c := *l
- return &c
-}
-
-// Handler returns l's Handler.
-func (l *Logger) Handler() Handler { return l.handler }
-
-// With returns a new Logger that includes the given arguments, converted to
-// Attrs as in [Logger.Log].
-// The Attrs will be added to each output from the Logger.
-// The new Logger shares the old Logger's context.
-// The new Logger's handler is the result of calling WithAttrs on the receiver's
-// handler.
-func (l *Logger) With(args ...any) *Logger {
- c := l.clone()
- c.handler = l.handler.WithAttrs(argsToAttrSlice(args))
- return c
-}
-
-// WithGroup returns a new Logger that starts a group. The keys of all
-// attributes added to the Logger will be qualified by the given name.
-// (How that qualification happens depends on the [Handler.WithGroup]
-// method of the Logger's Handler.)
-// The new Logger shares the old Logger's context.
-//
-// The new Logger's handler is the result of calling WithGroup on the receiver's
-// handler.
-func (l *Logger) WithGroup(name string) *Logger {
- c := l.clone()
- c.handler = l.handler.WithGroup(name)
- return c
-
-}
-
-// New creates a new Logger with the given non-nil Handler and a nil context.
-func New(h Handler) *Logger {
- if h == nil {
- panic("nil Handler")
- }
- return &Logger{handler: h}
-}
-
-// With calls Logger.With on the default logger.
-func With(args ...any) *Logger {
- return Default().With(args...)
-}
-
-// Enabled reports whether l emits log records at the given context and level.
-func (l *Logger) Enabled(ctx context.Context, level Level) bool {
- if ctx == nil {
- ctx = context.Background()
- }
- return l.Handler().Enabled(ctx, level)
-}
-
-// NewLogLogger returns a new log.Logger such that each call to its Output method
-// dispatches a Record to the specified handler. The logger acts as a bridge from
-// the older log API to newer structured logging handlers.
-func NewLogLogger(h Handler, level Level) *log.Logger {
- return log.New(&handlerWriter{h, level, true}, "", 0)
-}
-
-// Log emits a log record with the current time and the given level and message.
-// The Record's Attrs consist of the Logger's attributes followed by
-// the Attrs specified by args.
-//
-// The attribute arguments are processed as follows:
-// - If an argument is an Attr, it is used as is.
-// - If an argument is a string and this is not the last argument,
-// the following argument is treated as the value and the two are combined
-// into an Attr.
-// - Otherwise, the argument is treated as a value with key "!BADKEY".
-func (l *Logger) Log(ctx context.Context, level Level, msg string, args ...any) {
- l.log(ctx, level, msg, args...)
-}
-
-// LogAttrs is a more efficient version of [Logger.Log] that accepts only Attrs.
-func (l *Logger) LogAttrs(ctx context.Context, level Level, msg string, attrs ...Attr) {
- l.logAttrs(ctx, level, msg, attrs...)
-}
-
-// Debug logs at LevelDebug.
-func (l *Logger) Debug(msg string, args ...any) {
- l.log(nil, LevelDebug, msg, args...)
-}
-
-// DebugContext logs at LevelDebug with the given context.
-func (l *Logger) DebugContext(ctx context.Context, msg string, args ...any) {
- l.log(ctx, LevelDebug, msg, args...)
-}
-
-// DebugCtx logs at LevelDebug with the given context.
-// Deprecated: Use Logger.DebugContext.
-func (l *Logger) DebugCtx(ctx context.Context, msg string, args ...any) {
- l.log(ctx, LevelDebug, msg, args...)
-}
-
-// Info logs at LevelInfo.
-func (l *Logger) Info(msg string, args ...any) {
- l.log(nil, LevelInfo, msg, args...)
-}
-
-// InfoContext logs at LevelInfo with the given context.
-func (l *Logger) InfoContext(ctx context.Context, msg string, args ...any) {
- l.log(ctx, LevelInfo, msg, args...)
-}
-
-// InfoCtx logs at LevelInfo with the given context.
-// Deprecated: Use Logger.InfoContext.
-func (l *Logger) InfoCtx(ctx context.Context, msg string, args ...any) {
- l.log(ctx, LevelInfo, msg, args...)
-}
-
-// Warn logs at LevelWarn.
-func (l *Logger) Warn(msg string, args ...any) {
- l.log(nil, LevelWarn, msg, args...)
-}
-
-// WarnContext logs at LevelWarn with the given context.
-func (l *Logger) WarnContext(ctx context.Context, msg string, args ...any) {
- l.log(ctx, LevelWarn, msg, args...)
-}
-
-// WarnCtx logs at LevelWarn with the given context.
-// Deprecated: Use Logger.WarnContext.
-func (l *Logger) WarnCtx(ctx context.Context, msg string, args ...any) {
- l.log(ctx, LevelWarn, msg, args...)
-}
-
-// Error logs at LevelError.
-func (l *Logger) Error(msg string, args ...any) {
- l.log(nil, LevelError, msg, args...)
-}
-
-// ErrorContext logs at LevelError with the given context.
-func (l *Logger) ErrorContext(ctx context.Context, msg string, args ...any) {
- l.log(ctx, LevelError, msg, args...)
-}
-
-// ErrorCtx logs at LevelError with the given context.
-// Deprecated: Use Logger.ErrorContext.
-func (l *Logger) ErrorCtx(ctx context.Context, msg string, args ...any) {
- l.log(ctx, LevelError, msg, args...)
-}
-
-// log is the low-level logging method for methods that take ...any.
-// It must always be called directly by an exported logging method
-// or function, because it uses a fixed call depth to obtain the pc.
-func (l *Logger) log(ctx context.Context, level Level, msg string, args ...any) {
- if !l.Enabled(ctx, level) {
- return
- }
- var pc uintptr
- if !internal.IgnorePC {
- var pcs [1]uintptr
- // skip [runtime.Callers, this function, this function's caller]
- runtime.Callers(3, pcs[:])
- pc = pcs[0]
- }
- r := NewRecord(time.Now(), level, msg, pc)
- r.Add(args...)
- if ctx == nil {
- ctx = context.Background()
- }
- _ = l.Handler().Handle(ctx, r)
-}
-
-// logAttrs is like [Logger.log], but for methods that take ...Attr.
-func (l *Logger) logAttrs(ctx context.Context, level Level, msg string, attrs ...Attr) {
- if !l.Enabled(ctx, level) {
- return
- }
- var pc uintptr
- if !internal.IgnorePC {
- var pcs [1]uintptr
- // skip [runtime.Callers, this function, this function's caller]
- runtime.Callers(3, pcs[:])
- pc = pcs[0]
- }
- r := NewRecord(time.Now(), level, msg, pc)
- r.AddAttrs(attrs...)
- if ctx == nil {
- ctx = context.Background()
- }
- _ = l.Handler().Handle(ctx, r)
-}
-
-// Debug calls Logger.Debug on the default logger.
-func Debug(msg string, args ...any) {
- Default().log(nil, LevelDebug, msg, args...)
-}
-
-// DebugContext calls Logger.DebugContext on the default logger.
-func DebugContext(ctx context.Context, msg string, args ...any) {
- Default().log(ctx, LevelDebug, msg, args...)
-}
-
-// Info calls Logger.Info on the default logger.
-func Info(msg string, args ...any) {
- Default().log(nil, LevelInfo, msg, args...)
-}
-
-// InfoContext calls Logger.InfoContext on the default logger.
-func InfoContext(ctx context.Context, msg string, args ...any) {
- Default().log(ctx, LevelInfo, msg, args...)
-}
-
-// Warn calls Logger.Warn on the default logger.
-func Warn(msg string, args ...any) {
- Default().log(nil, LevelWarn, msg, args...)
-}
-
-// WarnContext calls Logger.WarnContext on the default logger.
-func WarnContext(ctx context.Context, msg string, args ...any) {
- Default().log(ctx, LevelWarn, msg, args...)
-}
-
-// Error calls Logger.Error on the default logger.
-func Error(msg string, args ...any) {
- Default().log(nil, LevelError, msg, args...)
-}
-
-// ErrorContext calls Logger.ErrorContext on the default logger.
-func ErrorContext(ctx context.Context, msg string, args ...any) {
- Default().log(ctx, LevelError, msg, args...)
-}
-
-// DebugCtx calls Logger.DebugContext on the default logger.
-// Deprecated: call DebugContext.
-func DebugCtx(ctx context.Context, msg string, args ...any) {
- Default().log(ctx, LevelDebug, msg, args...)
-}
-
-// InfoCtx calls Logger.InfoContext on the default logger.
-// Deprecated: call InfoContext.
-func InfoCtx(ctx context.Context, msg string, args ...any) {
- Default().log(ctx, LevelInfo, msg, args...)
-}
-
-// WarnCtx calls Logger.WarnContext on the default logger.
-// Deprecated: call WarnContext.
-func WarnCtx(ctx context.Context, msg string, args ...any) {
- Default().log(ctx, LevelWarn, msg, args...)
-}
-
-// ErrorCtx calls Logger.ErrorContext on the default logger.
-// Deprecated: call ErrorContext.
-func ErrorCtx(ctx context.Context, msg string, args ...any) {
- Default().log(ctx, LevelError, msg, args...)
-}
-
-// Log calls Logger.Log on the default logger.
-func Log(ctx context.Context, level Level, msg string, args ...any) {
- Default().log(ctx, level, msg, args...)
-}
-
-// LogAttrs calls Logger.LogAttrs on the default logger.
-func LogAttrs(ctx context.Context, level Level, msg string, attrs ...Attr) {
- Default().logAttrs(ctx, level, msg, attrs...)
-}
diff --git a/vendor/golang.org/x/exp/slog/noplog.bench b/vendor/golang.org/x/exp/slog/noplog.bench
deleted file mode 100644
index ed9296f..0000000
--- a/vendor/golang.org/x/exp/slog/noplog.bench
+++ /dev/null
@@ -1,36 +0,0 @@
-goos: linux
-goarch: amd64
-pkg: golang.org/x/exp/slog
-cpu: Intel(R) Xeon(R) CPU @ 2.20GHz
-BenchmarkNopLog/attrs-8 1000000 1090 ns/op 0 B/op 0 allocs/op
-BenchmarkNopLog/attrs-8 1000000 1097 ns/op 0 B/op 0 allocs/op
-BenchmarkNopLog/attrs-8 1000000 1078 ns/op 0 B/op 0 allocs/op
-BenchmarkNopLog/attrs-8 1000000 1095 ns/op 0 B/op 0 allocs/op
-BenchmarkNopLog/attrs-8 1000000 1096 ns/op 0 B/op 0 allocs/op
-BenchmarkNopLog/attrs-parallel-8 4007268 308.2 ns/op 0 B/op 0 allocs/op
-BenchmarkNopLog/attrs-parallel-8 4016138 299.7 ns/op 0 B/op 0 allocs/op
-BenchmarkNopLog/attrs-parallel-8 4020529 305.9 ns/op 0 B/op 0 allocs/op
-BenchmarkNopLog/attrs-parallel-8 3977829 303.4 ns/op 0 B/op 0 allocs/op
-BenchmarkNopLog/attrs-parallel-8 3225438 318.5 ns/op 0 B/op 0 allocs/op
-BenchmarkNopLog/keys-values-8 1179256 994.2 ns/op 0 B/op 0 allocs/op
-BenchmarkNopLog/keys-values-8 1000000 1002 ns/op 0 B/op 0 allocs/op
-BenchmarkNopLog/keys-values-8 1216710 993.2 ns/op 0 B/op 0 allocs/op
-BenchmarkNopLog/keys-values-8 1000000 1013 ns/op 0 B/op 0 allocs/op
-BenchmarkNopLog/keys-values-8 1000000 1016 ns/op 0 B/op 0 allocs/op
-BenchmarkNopLog/WithContext-8 989066 1163 ns/op 0 B/op 0 allocs/op
-BenchmarkNopLog/WithContext-8 994116 1163 ns/op 0 B/op 0 allocs/op
-BenchmarkNopLog/WithContext-8 1000000 1152 ns/op 0 B/op 0 allocs/op
-BenchmarkNopLog/WithContext-8 991675 1165 ns/op 0 B/op 0 allocs/op
-BenchmarkNopLog/WithContext-8 965268 1166 ns/op 0 B/op 0 allocs/op
-BenchmarkNopLog/WithContext-parallel-8 3955503 303.3 ns/op 0 B/op 0 allocs/op
-BenchmarkNopLog/WithContext-parallel-8 3861188 307.8 ns/op 0 B/op 0 allocs/op
-BenchmarkNopLog/WithContext-parallel-8 3967752 303.9 ns/op 0 B/op 0 allocs/op
-BenchmarkNopLog/WithContext-parallel-8 3955203 302.7 ns/op 0 B/op 0 allocs/op
-BenchmarkNopLog/WithContext-parallel-8 3948278 301.1 ns/op 0 B/op 0 allocs/op
-BenchmarkNopLog/Ctx-8 940622 1247 ns/op 0 B/op 0 allocs/op
-BenchmarkNopLog/Ctx-8 936381 1257 ns/op 0 B/op 0 allocs/op
-BenchmarkNopLog/Ctx-8 959730 1266 ns/op 0 B/op 0 allocs/op
-BenchmarkNopLog/Ctx-8 943473 1290 ns/op 0 B/op 0 allocs/op
-BenchmarkNopLog/Ctx-8 919414 1259 ns/op 0 B/op 0 allocs/op
-PASS
-ok golang.org/x/exp/slog 40.566s
diff --git a/vendor/golang.org/x/exp/slog/record.go b/vendor/golang.org/x/exp/slog/record.go
deleted file mode 100644
index 38b3440..0000000
--- a/vendor/golang.org/x/exp/slog/record.go
+++ /dev/null
@@ -1,207 +0,0 @@
-// Copyright 2022 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package slog
-
-import (
- "runtime"
- "time"
-
- "golang.org/x/exp/slices"
-)
-
-const nAttrsInline = 5
-
-// A Record holds information about a log event.
-// Copies of a Record share state.
-// Do not modify a Record after handing out a copy to it.
-// Use [Record.Clone] to create a copy with no shared state.
-type Record struct {
- // The time at which the output method (Log, Info, etc.) was called.
- Time time.Time
-
- // The log message.
- Message string
-
- // The level of the event.
- Level Level
-
- // The program counter at the time the record was constructed, as determined
- // by runtime.Callers. If zero, no program counter is available.
- //
- // The only valid use for this value is as an argument to
- // [runtime.CallersFrames]. In particular, it must not be passed to
- // [runtime.FuncForPC].
- PC uintptr
-
- // Allocation optimization: an inline array sized to hold
- // the majority of log calls (based on examination of open-source
- // code). It holds the start of the list of Attrs.
- front [nAttrsInline]Attr
-
- // The number of Attrs in front.
- nFront int
-
- // The list of Attrs except for those in front.
- // Invariants:
- // - len(back) > 0 iff nFront == len(front)
- // - Unused array elements are zero. Used to detect mistakes.
- back []Attr
-}
-
-// NewRecord creates a Record from the given arguments.
-// Use [Record.AddAttrs] to add attributes to the Record.
-//
-// NewRecord is intended for logging APIs that want to support a [Handler] as
-// a backend.
-func NewRecord(t time.Time, level Level, msg string, pc uintptr) Record {
- return Record{
- Time: t,
- Message: msg,
- Level: level,
- PC: pc,
- }
-}
-
-// Clone returns a copy of the record with no shared state.
-// The original record and the clone can both be modified
-// without interfering with each other.
-func (r Record) Clone() Record {
- r.back = slices.Clip(r.back) // prevent append from mutating shared array
- return r
-}
-
-// NumAttrs returns the number of attributes in the Record.
-func (r Record) NumAttrs() int {
- return r.nFront + len(r.back)
-}
-
-// Attrs calls f on each Attr in the Record.
-// Iteration stops if f returns false.
-func (r Record) Attrs(f func(Attr) bool) {
- for i := 0; i < r.nFront; i++ {
- if !f(r.front[i]) {
- return
- }
- }
- for _, a := range r.back {
- if !f(a) {
- return
- }
- }
-}
-
-// AddAttrs appends the given Attrs to the Record's list of Attrs.
-func (r *Record) AddAttrs(attrs ...Attr) {
- n := copy(r.front[r.nFront:], attrs)
- r.nFront += n
- // Check if a copy was modified by slicing past the end
- // and seeing if the Attr there is non-zero.
- if cap(r.back) > len(r.back) {
- end := r.back[:len(r.back)+1][len(r.back)]
- if !end.isEmpty() {
- panic("copies of a slog.Record were both modified")
- }
- }
- r.back = append(r.back, attrs[n:]...)
-}
-
-// Add converts the args to Attrs as described in [Logger.Log],
-// then appends the Attrs to the Record's list of Attrs.
-func (r *Record) Add(args ...any) {
- var a Attr
- for len(args) > 0 {
- a, args = argsToAttr(args)
- if r.nFront < len(r.front) {
- r.front[r.nFront] = a
- r.nFront++
- } else {
- if r.back == nil {
- r.back = make([]Attr, 0, countAttrs(args))
- }
- r.back = append(r.back, a)
- }
- }
-
-}
-
-// countAttrs returns the number of Attrs that would be created from args.
-func countAttrs(args []any) int {
- n := 0
- for i := 0; i < len(args); i++ {
- n++
- if _, ok := args[i].(string); ok {
- i++
- }
- }
- return n
-}
-
-const badKey = "!BADKEY"
-
-// argsToAttr turns a prefix of the nonempty args slice into an Attr
-// and returns the unconsumed portion of the slice.
-// If args[0] is an Attr, it returns it.
-// If args[0] is a string, it treats the first two elements as
-// a key-value pair.
-// Otherwise, it treats args[0] as a value with a missing key.
-func argsToAttr(args []any) (Attr, []any) {
- switch x := args[0].(type) {
- case string:
- if len(args) == 1 {
- return String(badKey, x), nil
- }
- return Any(x, args[1]), args[2:]
-
- case Attr:
- return x, args[1:]
-
- default:
- return Any(badKey, x), args[1:]
- }
-}
-
-// Source describes the location of a line of source code.
-type Source struct {
- // Function is the package path-qualified function name containing the
- // source line. If non-empty, this string uniquely identifies a single
- // function in the program. This may be the empty string if not known.
- Function string `json:"function"`
- // File and Line are the file name and line number (1-based) of the source
- // line. These may be the empty string and zero, respectively, if not known.
- File string `json:"file"`
- Line int `json:"line"`
-}
-
-// attrs returns the non-zero fields of s as a slice of attrs.
-// It is similar to a LogValue method, but we don't want Source
-// to implement LogValuer because it would be resolved before
-// the ReplaceAttr function was called.
-func (s *Source) group() Value {
- var as []Attr
- if s.Function != "" {
- as = append(as, String("function", s.Function))
- }
- if s.File != "" {
- as = append(as, String("file", s.File))
- }
- if s.Line != 0 {
- as = append(as, Int("line", s.Line))
- }
- return GroupValue(as...)
-}
-
-// source returns a Source for the log event.
-// If the Record was created without the necessary information,
-// or if the location is unavailable, it returns a non-nil *Source
-// with zero fields.
-func (r Record) source() *Source {
- fs := runtime.CallersFrames([]uintptr{r.PC})
- f, _ := fs.Next()
- return &Source{
- Function: f.Function,
- File: f.File,
- Line: f.Line,
- }
-}
diff --git a/vendor/golang.org/x/exp/slog/text_handler.go b/vendor/golang.org/x/exp/slog/text_handler.go
deleted file mode 100644
index 75b66b7..0000000
--- a/vendor/golang.org/x/exp/slog/text_handler.go
+++ /dev/null
@@ -1,161 +0,0 @@
-// Copyright 2022 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package slog
-
-import (
- "context"
- "encoding"
- "fmt"
- "io"
- "reflect"
- "strconv"
- "unicode"
- "unicode/utf8"
-)
-
-// TextHandler is a Handler that writes Records to an io.Writer as a
-// sequence of key=value pairs separated by spaces and followed by a newline.
-type TextHandler struct {
- *commonHandler
-}
-
-// NewTextHandler creates a TextHandler that writes to w,
-// using the given options.
-// If opts is nil, the default options are used.
-func NewTextHandler(w io.Writer, opts *HandlerOptions) *TextHandler {
- if opts == nil {
- opts = &HandlerOptions{}
- }
- return &TextHandler{
- &commonHandler{
- json: false,
- w: w,
- opts: *opts,
- },
- }
-}
-
-// Enabled reports whether the handler handles records at the given level.
-// The handler ignores records whose level is lower.
-func (h *TextHandler) Enabled(_ context.Context, level Level) bool {
- return h.commonHandler.enabled(level)
-}
-
-// WithAttrs returns a new TextHandler whose attributes consists
-// of h's attributes followed by attrs.
-func (h *TextHandler) WithAttrs(attrs []Attr) Handler {
- return &TextHandler{commonHandler: h.commonHandler.withAttrs(attrs)}
-}
-
-func (h *TextHandler) WithGroup(name string) Handler {
- return &TextHandler{commonHandler: h.commonHandler.withGroup(name)}
-}
-
-// Handle formats its argument Record as a single line of space-separated
-// key=value items.
-//
-// If the Record's time is zero, the time is omitted.
-// Otherwise, the key is "time"
-// and the value is output in RFC3339 format with millisecond precision.
-//
-// If the Record's level is zero, the level is omitted.
-// Otherwise, the key is "level"
-// and the value of [Level.String] is output.
-//
-// If the AddSource option is set and source information is available,
-// the key is "source" and the value is output as FILE:LINE.
-//
-// The message's key is "msg".
-//
-// To modify these or other attributes, or remove them from the output, use
-// [HandlerOptions.ReplaceAttr].
-//
-// If a value implements [encoding.TextMarshaler], the result of MarshalText is
-// written. Otherwise, the result of fmt.Sprint is written.
-//
-// Keys and values are quoted with [strconv.Quote] if they contain Unicode space
-// characters, non-printing characters, '"' or '='.
-//
-// Keys inside groups consist of components (keys or group names) separated by
-// dots. No further escaping is performed.
-// Thus there is no way to determine from the key "a.b.c" whether there
-// are two groups "a" and "b" and a key "c", or a single group "a.b" and a key "c",
-// or single group "a" and a key "b.c".
-// If it is necessary to reconstruct the group structure of a key
-// even in the presence of dots inside components, use
-// [HandlerOptions.ReplaceAttr] to encode that information in the key.
-//
-// Each call to Handle results in a single serialized call to
-// io.Writer.Write.
-func (h *TextHandler) Handle(_ context.Context, r Record) error {
- return h.commonHandler.handle(r)
-}
-
-func appendTextValue(s *handleState, v Value) error {
- switch v.Kind() {
- case KindString:
- s.appendString(v.str())
- case KindTime:
- s.appendTime(v.time())
- case KindAny:
- if tm, ok := v.any.(encoding.TextMarshaler); ok {
- data, err := tm.MarshalText()
- if err != nil {
- return err
- }
- // TODO: avoid the conversion to string.
- s.appendString(string(data))
- return nil
- }
- if bs, ok := byteSlice(v.any); ok {
- // As of Go 1.19, this only allocates for strings longer than 32 bytes.
- s.buf.WriteString(strconv.Quote(string(bs)))
- return nil
- }
- s.appendString(fmt.Sprintf("%+v", v.Any()))
- default:
- *s.buf = v.append(*s.buf)
- }
- return nil
-}
-
-// byteSlice returns its argument as a []byte if the argument's
-// underlying type is []byte, along with a second return value of true.
-// Otherwise it returns nil, false.
-func byteSlice(a any) ([]byte, bool) {
- if bs, ok := a.([]byte); ok {
- return bs, true
- }
- // Like Printf's %s, we allow both the slice type and the byte element type to be named.
- t := reflect.TypeOf(a)
- if t != nil && t.Kind() == reflect.Slice && t.Elem().Kind() == reflect.Uint8 {
- return reflect.ValueOf(a).Bytes(), true
- }
- return nil, false
-}
-
-func needsQuoting(s string) bool {
- if len(s) == 0 {
- return true
- }
- for i := 0; i < len(s); {
- b := s[i]
- if b < utf8.RuneSelf {
- // Quote anything except a backslash that would need quoting in a
- // JSON string, as well as space and '='
- if b != '\\' && (b == ' ' || b == '=' || !safeSet[b]) {
- return true
- }
- i++
- continue
- }
- r, size := utf8.DecodeRuneInString(s[i:])
- if r == utf8.RuneError || unicode.IsSpace(r) || !unicode.IsPrint(r) {
- return true
- }
- i += size
- }
- return false
-}
diff --git a/vendor/golang.org/x/exp/slog/value.go b/vendor/golang.org/x/exp/slog/value.go
deleted file mode 100644
index 3550c46..0000000
--- a/vendor/golang.org/x/exp/slog/value.go
+++ /dev/null
@@ -1,456 +0,0 @@
-// Copyright 2022 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package slog
-
-import (
- "fmt"
- "math"
- "runtime"
- "strconv"
- "strings"
- "time"
- "unsafe"
-
- "golang.org/x/exp/slices"
-)
-
-// A Value can represent any Go value, but unlike type any,
-// it can represent most small values without an allocation.
-// The zero Value corresponds to nil.
-type Value struct {
- _ [0]func() // disallow ==
- // num holds the value for Kinds Int64, Uint64, Float64, Bool and Duration,
- // the string length for KindString, and nanoseconds since the epoch for KindTime.
- num uint64
- // If any is of type Kind, then the value is in num as described above.
- // If any is of type *time.Location, then the Kind is Time and time.Time value
- // can be constructed from the Unix nanos in num and the location (monotonic time
- // is not preserved).
- // If any is of type stringptr, then the Kind is String and the string value
- // consists of the length in num and the pointer in any.
- // Otherwise, the Kind is Any and any is the value.
- // (This implies that Attrs cannot store values of type Kind, *time.Location
- // or stringptr.)
- any any
-}
-
-// Kind is the kind of a Value.
-type Kind int
-
-// The following list is sorted alphabetically, but it's also important that
-// KindAny is 0 so that a zero Value represents nil.
-
-const (
- KindAny Kind = iota
- KindBool
- KindDuration
- KindFloat64
- KindInt64
- KindString
- KindTime
- KindUint64
- KindGroup
- KindLogValuer
-)
-
-var kindStrings = []string{
- "Any",
- "Bool",
- "Duration",
- "Float64",
- "Int64",
- "String",
- "Time",
- "Uint64",
- "Group",
- "LogValuer",
-}
-
-func (k Kind) String() string {
- if k >= 0 && int(k) < len(kindStrings) {
- return kindStrings[k]
- }
- return ""
-}
-
-// Unexported version of Kind, just so we can store Kinds in Values.
-// (No user-provided value has this type.)
-type kind Kind
-
-// Kind returns v's Kind.
-func (v Value) Kind() Kind {
- switch x := v.any.(type) {
- case Kind:
- return x
- case stringptr:
- return KindString
- case timeLocation:
- return KindTime
- case groupptr:
- return KindGroup
- case LogValuer:
- return KindLogValuer
- case kind: // a kind is just a wrapper for a Kind
- return KindAny
- default:
- return KindAny
- }
-}
-
-//////////////// Constructors
-
-// IntValue returns a Value for an int.
-func IntValue(v int) Value {
- return Int64Value(int64(v))
-}
-
-// Int64Value returns a Value for an int64.
-func Int64Value(v int64) Value {
- return Value{num: uint64(v), any: KindInt64}
-}
-
-// Uint64Value returns a Value for a uint64.
-func Uint64Value(v uint64) Value {
- return Value{num: v, any: KindUint64}
-}
-
-// Float64Value returns a Value for a floating-point number.
-func Float64Value(v float64) Value {
- return Value{num: math.Float64bits(v), any: KindFloat64}
-}
-
-// BoolValue returns a Value for a bool.
-func BoolValue(v bool) Value {
- u := uint64(0)
- if v {
- u = 1
- }
- return Value{num: u, any: KindBool}
-}
-
-// Unexported version of *time.Location, just so we can store *time.Locations in
-// Values. (No user-provided value has this type.)
-type timeLocation *time.Location
-
-// TimeValue returns a Value for a time.Time.
-// It discards the monotonic portion.
-func TimeValue(v time.Time) Value {
- if v.IsZero() {
- // UnixNano on the zero time is undefined, so represent the zero time
- // with a nil *time.Location instead. time.Time.Location method never
- // returns nil, so a Value with any == timeLocation(nil) cannot be
- // mistaken for any other Value, time.Time or otherwise.
- return Value{any: timeLocation(nil)}
- }
- return Value{num: uint64(v.UnixNano()), any: timeLocation(v.Location())}
-}
-
-// DurationValue returns a Value for a time.Duration.
-func DurationValue(v time.Duration) Value {
- return Value{num: uint64(v.Nanoseconds()), any: KindDuration}
-}
-
-// AnyValue returns a Value for the supplied value.
-//
-// If the supplied value is of type Value, it is returned
-// unmodified.
-//
-// Given a value of one of Go's predeclared string, bool, or
-// (non-complex) numeric types, AnyValue returns a Value of kind
-// String, Bool, Uint64, Int64, or Float64. The width of the
-// original numeric type is not preserved.
-//
-// Given a time.Time or time.Duration value, AnyValue returns a Value of kind
-// KindTime or KindDuration. The monotonic time is not preserved.
-//
-// For nil, or values of all other types, including named types whose
-// underlying type is numeric, AnyValue returns a value of kind KindAny.
-func AnyValue(v any) Value {
- switch v := v.(type) {
- case string:
- return StringValue(v)
- case int:
- return Int64Value(int64(v))
- case uint:
- return Uint64Value(uint64(v))
- case int64:
- return Int64Value(v)
- case uint64:
- return Uint64Value(v)
- case bool:
- return BoolValue(v)
- case time.Duration:
- return DurationValue(v)
- case time.Time:
- return TimeValue(v)
- case uint8:
- return Uint64Value(uint64(v))
- case uint16:
- return Uint64Value(uint64(v))
- case uint32:
- return Uint64Value(uint64(v))
- case uintptr:
- return Uint64Value(uint64(v))
- case int8:
- return Int64Value(int64(v))
- case int16:
- return Int64Value(int64(v))
- case int32:
- return Int64Value(int64(v))
- case float64:
- return Float64Value(v)
- case float32:
- return Float64Value(float64(v))
- case []Attr:
- return GroupValue(v...)
- case Kind:
- return Value{any: kind(v)}
- case Value:
- return v
- default:
- return Value{any: v}
- }
-}
-
-//////////////// Accessors
-
-// Any returns v's value as an any.
-func (v Value) Any() any {
- switch v.Kind() {
- case KindAny:
- if k, ok := v.any.(kind); ok {
- return Kind(k)
- }
- return v.any
- case KindLogValuer:
- return v.any
- case KindGroup:
- return v.group()
- case KindInt64:
- return int64(v.num)
- case KindUint64:
- return v.num
- case KindFloat64:
- return v.float()
- case KindString:
- return v.str()
- case KindBool:
- return v.bool()
- case KindDuration:
- return v.duration()
- case KindTime:
- return v.time()
- default:
- panic(fmt.Sprintf("bad kind: %s", v.Kind()))
- }
-}
-
-// Int64 returns v's value as an int64. It panics
-// if v is not a signed integer.
-func (v Value) Int64() int64 {
- if g, w := v.Kind(), KindInt64; g != w {
- panic(fmt.Sprintf("Value kind is %s, not %s", g, w))
- }
- return int64(v.num)
-}
-
-// Uint64 returns v's value as a uint64. It panics
-// if v is not an unsigned integer.
-func (v Value) Uint64() uint64 {
- if g, w := v.Kind(), KindUint64; g != w {
- panic(fmt.Sprintf("Value kind is %s, not %s", g, w))
- }
- return v.num
-}
-
-// Bool returns v's value as a bool. It panics
-// if v is not a bool.
-func (v Value) Bool() bool {
- if g, w := v.Kind(), KindBool; g != w {
- panic(fmt.Sprintf("Value kind is %s, not %s", g, w))
- }
- return v.bool()
-}
-
-func (v Value) bool() bool {
- return v.num == 1
-}
-
-// Duration returns v's value as a time.Duration. It panics
-// if v is not a time.Duration.
-func (v Value) Duration() time.Duration {
- if g, w := v.Kind(), KindDuration; g != w {
- panic(fmt.Sprintf("Value kind is %s, not %s", g, w))
- }
-
- return v.duration()
-}
-
-func (v Value) duration() time.Duration {
- return time.Duration(int64(v.num))
-}
-
-// Float64 returns v's value as a float64. It panics
-// if v is not a float64.
-func (v Value) Float64() float64 {
- if g, w := v.Kind(), KindFloat64; g != w {
- panic(fmt.Sprintf("Value kind is %s, not %s", g, w))
- }
-
- return v.float()
-}
-
-func (v Value) float() float64 {
- return math.Float64frombits(v.num)
-}
-
-// Time returns v's value as a time.Time. It panics
-// if v is not a time.Time.
-func (v Value) Time() time.Time {
- if g, w := v.Kind(), KindTime; g != w {
- panic(fmt.Sprintf("Value kind is %s, not %s", g, w))
- }
- return v.time()
-}
-
-func (v Value) time() time.Time {
- loc := v.any.(timeLocation)
- if loc == nil {
- return time.Time{}
- }
- return time.Unix(0, int64(v.num)).In(loc)
-}
-
-// LogValuer returns v's value as a LogValuer. It panics
-// if v is not a LogValuer.
-func (v Value) LogValuer() LogValuer {
- return v.any.(LogValuer)
-}
-
-// Group returns v's value as a []Attr.
-// It panics if v's Kind is not KindGroup.
-func (v Value) Group() []Attr {
- if sp, ok := v.any.(groupptr); ok {
- return unsafe.Slice((*Attr)(sp), v.num)
- }
- panic("Group: bad kind")
-}
-
-func (v Value) group() []Attr {
- return unsafe.Slice((*Attr)(v.any.(groupptr)), v.num)
-}
-
-//////////////// Other
-
-// Equal reports whether v and w represent the same Go value.
-func (v Value) Equal(w Value) bool {
- k1 := v.Kind()
- k2 := w.Kind()
- if k1 != k2 {
- return false
- }
- switch k1 {
- case KindInt64, KindUint64, KindBool, KindDuration:
- return v.num == w.num
- case KindString:
- return v.str() == w.str()
- case KindFloat64:
- return v.float() == w.float()
- case KindTime:
- return v.time().Equal(w.time())
- case KindAny, KindLogValuer:
- return v.any == w.any // may panic if non-comparable
- case KindGroup:
- return slices.EqualFunc(v.group(), w.group(), Attr.Equal)
- default:
- panic(fmt.Sprintf("bad kind: %s", k1))
- }
-}
-
-// append appends a text representation of v to dst.
-// v is formatted as with fmt.Sprint.
-func (v Value) append(dst []byte) []byte {
- switch v.Kind() {
- case KindString:
- return append(dst, v.str()...)
- case KindInt64:
- return strconv.AppendInt(dst, int64(v.num), 10)
- case KindUint64:
- return strconv.AppendUint(dst, v.num, 10)
- case KindFloat64:
- return strconv.AppendFloat(dst, v.float(), 'g', -1, 64)
- case KindBool:
- return strconv.AppendBool(dst, v.bool())
- case KindDuration:
- return append(dst, v.duration().String()...)
- case KindTime:
- return append(dst, v.time().String()...)
- case KindGroup:
- return fmt.Append(dst, v.group())
- case KindAny, KindLogValuer:
- return fmt.Append(dst, v.any)
- default:
- panic(fmt.Sprintf("bad kind: %s", v.Kind()))
- }
-}
-
-// A LogValuer is any Go value that can convert itself into a Value for logging.
-//
-// This mechanism may be used to defer expensive operations until they are
-// needed, or to expand a single value into a sequence of components.
-type LogValuer interface {
- LogValue() Value
-}
-
-const maxLogValues = 100
-
-// Resolve repeatedly calls LogValue on v while it implements LogValuer,
-// and returns the result.
-// If v resolves to a group, the group's attributes' values are not recursively
-// resolved.
-// If the number of LogValue calls exceeds a threshold, a Value containing an
-// error is returned.
-// Resolve's return value is guaranteed not to be of Kind KindLogValuer.
-func (v Value) Resolve() (rv Value) {
- orig := v
- defer func() {
- if r := recover(); r != nil {
- rv = AnyValue(fmt.Errorf("LogValue panicked\n%s", stack(3, 5)))
- }
- }()
-
- for i := 0; i < maxLogValues; i++ {
- if v.Kind() != KindLogValuer {
- return v
- }
- v = v.LogValuer().LogValue()
- }
- err := fmt.Errorf("LogValue called too many times on Value of type %T", orig.Any())
- return AnyValue(err)
-}
-
-func stack(skip, nFrames int) string {
- pcs := make([]uintptr, nFrames+1)
- n := runtime.Callers(skip+1, pcs)
- if n == 0 {
- return "(no stack)"
- }
- frames := runtime.CallersFrames(pcs[:n])
- var b strings.Builder
- i := 0
- for {
- frame, more := frames.Next()
- fmt.Fprintf(&b, "called from %s (%s:%d)\n", frame.Function, frame.File, frame.Line)
- if !more {
- break
- }
- i++
- if i >= nFrames {
- fmt.Fprintf(&b, "(rest of stack elided)\n")
- break
- }
- }
- return b.String()
-}
diff --git a/vendor/golang.org/x/exp/slog/value_119.go b/vendor/golang.org/x/exp/slog/value_119.go
deleted file mode 100644
index 29b0d73..0000000
--- a/vendor/golang.org/x/exp/slog/value_119.go
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2022 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-//go:build go1.19 && !go1.20
-
-package slog
-
-import (
- "reflect"
- "unsafe"
-)
-
-type (
- stringptr unsafe.Pointer // used in Value.any when the Value is a string
- groupptr unsafe.Pointer // used in Value.any when the Value is a []Attr
-)
-
-// StringValue returns a new Value for a string.
-func StringValue(value string) Value {
- hdr := (*reflect.StringHeader)(unsafe.Pointer(&value))
- return Value{num: uint64(hdr.Len), any: stringptr(hdr.Data)}
-}
-
-func (v Value) str() string {
- var s string
- hdr := (*reflect.StringHeader)(unsafe.Pointer(&s))
- hdr.Data = uintptr(v.any.(stringptr))
- hdr.Len = int(v.num)
- return s
-}
-
-// String returns Value's value as a string, formatted like fmt.Sprint. Unlike
-// the methods Int64, Float64, and so on, which panic if v is of the
-// wrong kind, String never panics.
-func (v Value) String() string {
- if sp, ok := v.any.(stringptr); ok {
- // Inlining this code makes a huge difference.
- var s string
- hdr := (*reflect.StringHeader)(unsafe.Pointer(&s))
- hdr.Data = uintptr(sp)
- hdr.Len = int(v.num)
- return s
- }
- return string(v.append(nil))
-}
-
-// GroupValue returns a new Value for a list of Attrs.
-// The caller must not subsequently mutate the argument slice.
-func GroupValue(as ...Attr) Value {
- hdr := (*reflect.SliceHeader)(unsafe.Pointer(&as))
- return Value{num: uint64(hdr.Len), any: groupptr(hdr.Data)}
-}
diff --git a/vendor/golang.org/x/exp/slog/value_120.go b/vendor/golang.org/x/exp/slog/value_120.go
deleted file mode 100644
index f7d4c09..0000000
--- a/vendor/golang.org/x/exp/slog/value_120.go
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2022 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-//go:build go1.20
-
-package slog
-
-import "unsafe"
-
-type (
- stringptr *byte // used in Value.any when the Value is a string
- groupptr *Attr // used in Value.any when the Value is a []Attr
-)
-
-// StringValue returns a new Value for a string.
-func StringValue(value string) Value {
- return Value{num: uint64(len(value)), any: stringptr(unsafe.StringData(value))}
-}
-
-// GroupValue returns a new Value for a list of Attrs.
-// The caller must not subsequently mutate the argument slice.
-func GroupValue(as ...Attr) Value {
- return Value{num: uint64(len(as)), any: groupptr(unsafe.SliceData(as))}
-}
-
-// String returns Value's value as a string, formatted like fmt.Sprint. Unlike
-// the methods Int64, Float64, and so on, which panic if v is of the
-// wrong kind, String never panics.
-func (v Value) String() string {
- if sp, ok := v.any.(stringptr); ok {
- return unsafe.String(sp, v.num)
- }
- return string(v.append(nil))
-}
-
-func (v Value) str() string {
- return unsafe.String(v.any.(stringptr), v.num)
-}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 0a6fdca..ebc945d 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -73,12 +73,7 @@ golang.org/x/crypto/blowfish
golang.org/x/crypto/pbkdf2
# golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc
## explicit; go 1.20
-golang.org/x/exp/constraints
golang.org/x/exp/maps
-golang.org/x/exp/slices
-golang.org/x/exp/slog
-golang.org/x/exp/slog/internal
-golang.org/x/exp/slog/internal/buffer
# golang.org/x/mod v0.14.0
## explicit; go 1.18
golang.org/x/mod/internal/lazyregexp
diff --git a/verifydata.go b/verifydata.go
index ccb433d..a274ce1 100644
--- a/verifydata.go
+++ b/verifydata.go
@@ -8,11 +8,10 @@ import (
"log"
"os"
"path/filepath"
+ "slices"
"strconv"
"strings"
- "golang.org/x/exp/slices"
-
bolt "go.etcd.io/bbolt"
"github.com/mjl-/bstore"
diff --git a/webaccount/account.go b/webaccount/account.go
index 93dd30f..0ca0904 100644
--- a/webaccount/account.go
+++ b/webaccount/account.go
@@ -13,6 +13,7 @@ import (
"errors"
"fmt"
"io"
+ "log/slog"
"net/http"
"os"
"path/filepath"
@@ -20,8 +21,6 @@ import (
_ "embed"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/sherpa"
"github.com/mjl-/sherpadoc"
"github.com/mjl-/sherpaprom"
diff --git a/webaccount/import.go b/webaccount/import.go
index 236b843..be51a39 100644
--- a/webaccount/import.go
+++ b/webaccount/import.go
@@ -12,6 +12,7 @@ import (
"errors"
"fmt"
"io"
+ "log/slog"
"os"
"path"
"runtime/debug"
@@ -21,7 +22,7 @@ import (
"time"
"golang.org/x/exp/maps"
- "golang.org/x/exp/slog"
+
"golang.org/x/text/unicode/norm"
"github.com/mjl-/bstore"
diff --git a/webadmin/admin.go b/webadmin/admin.go
index a0560cb..5e0b67b 100644
--- a/webadmin/admin.go
+++ b/webadmin/admin.go
@@ -19,6 +19,7 @@ import (
"encoding/json"
"errors"
"fmt"
+ "log/slog"
"net"
"net/http"
"net/url"
@@ -34,7 +35,6 @@ import (
_ "embed"
"golang.org/x/exp/maps"
- "golang.org/x/exp/slog"
"github.com/mjl-/adns"
diff --git a/webauth/webauth.go b/webauth/webauth.go
index 06aab1b..c120f55 100644
--- a/webauth/webauth.go
+++ b/webauth/webauth.go
@@ -38,13 +38,12 @@ import (
"context"
"encoding/json"
"fmt"
+ "log/slog"
"net"
"net/http"
"strings"
"time"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/sherpa"
"github.com/mjl-/mox/metrics"
diff --git a/webmail/api.go b/webmail/api.go
index b3fed70..894da60 100644
--- a/webmail/api.go
+++ b/webmail/api.go
@@ -8,6 +8,7 @@ import (
"errors"
"fmt"
"io"
+ "log/slog"
"mime"
"mime/multipart"
"net"
@@ -24,7 +25,6 @@ import (
_ "embed"
"golang.org/x/exp/maps"
- "golang.org/x/exp/slog"
"github.com/mjl-/bstore"
"github.com/mjl-/sherpa"
diff --git a/webmail/api_test.go b/webmail/api_test.go
index 7428164..e44488a 100644
--- a/webmail/api_test.go
+++ b/webmail/api_test.go
@@ -8,10 +8,9 @@ import (
"os"
"path/filepath"
"runtime/debug"
+ "slices"
"testing"
- "golang.org/x/exp/slices"
-
"github.com/mjl-/bstore"
"github.com/mjl-/sherpa"
diff --git a/webmail/eventwriter.go b/webmail/eventwriter.go
index a070be8..f9a87aa 100644
--- a/webmail/eventwriter.go
+++ b/webmail/eventwriter.go
@@ -6,14 +6,13 @@ import (
"encoding/json"
"fmt"
"io"
+ "log/slog"
mathrand "math/rand"
"net/http"
"runtime/debug"
"sync"
"time"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/mox/metrics"
"github.com/mjl-/mox/mlog"
"github.com/mjl-/mox/store"
diff --git a/webmail/message.go b/webmail/message.go
index 79e195f..cd07457 100644
--- a/webmail/message.go
+++ b/webmail/message.go
@@ -4,11 +4,11 @@ import (
"bufio"
"fmt"
"io"
+ "log/slog"
"mime"
"net/url"
"strings"
- "golang.org/x/exp/slog"
"golang.org/x/text/encoding/ianaindex"
"github.com/mjl-/mox/dns"
diff --git a/webmail/view.go b/webmail/view.go
index b057bdf..c3ff25f 100644
--- a/webmail/view.go
+++ b/webmail/view.go
@@ -10,18 +10,17 @@ import (
"encoding/json"
"errors"
"fmt"
+ "log/slog"
"net/http"
"path/filepath"
"reflect"
"runtime/debug"
+ "slices"
"strconv"
"strings"
"sync"
"time"
- "golang.org/x/exp/slices"
- "golang.org/x/exp/slog"
-
"github.com/mjl-/bstore"
"github.com/mjl-/sherpa"
diff --git a/webmail/webmail.go b/webmail/webmail.go
index 4d686e0..bc70c7b 100644
--- a/webmail/webmail.go
+++ b/webmail/webmail.go
@@ -12,6 +12,7 @@ import (
"errors"
"fmt"
"io"
+ "log/slog"
"mime"
"net/http"
"os"
@@ -23,7 +24,6 @@ import (
_ "embed"
- "golang.org/x/exp/slog"
"golang.org/x/net/html"
"github.com/prometheus/client_golang/prometheus"
diff --git a/website/website.go b/website/website.go
index f5acfe1..9d95aaa 100644
--- a/website/website.go
+++ b/website/website.go
@@ -13,11 +13,10 @@ import (
"io"
"log"
"os"
+ "slices"
"strconv"
"strings"
- "golang.org/x/exp/slices"
-
"github.com/russross/blackfriday/v2"
)