aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2026-08-12 22:34:12 +0900
committerOphestra <cat@gensokyo.uk>2026-08-12 22:34:12 +0900
commit8821d34b108b27dc99d225cdb71bdd1ab58552e4 (patch)
treed66ac151dfae3e0c740891bdd85f97f30d17bf08
parent054a8813d795861765c830369f9dc372cf516077 (diff)
internal/pkg: deduplicate unwrapped input errors
This avoids repeating errors belonging to multiple instances of the same artifact in different locations in memory. Signed-off-by: Ophestra <cat@gensokyo.uk>
-rw-r--r--internal/pkg/pkg.go35
-rw-r--r--internal/pkg/pkg_test.go31
2 files changed, 44 insertions, 22 deletions
diff --git a/internal/pkg/pkg.go b/internal/pkg/pkg.go
index 220f268d..268d0248 100644
--- a/internal/pkg/pkg.go
+++ b/internal/pkg/pkg.go
@@ -15,6 +15,7 @@ import (
"hash"
"io"
"io/fs"
+ "iter"
"maps"
"math"
"os"
@@ -1723,8 +1724,9 @@ retry:
// An InputError describes inputs of a [FloodArtifact] which had failed to cure.
type InputError map[Artifact]error
-// Error returns a user-facing, deterministic text representation of e.
-func (e InputError) Error() string {
+// unwrap returns an iterator over sorted, deduplicated [Artifact] and their
+// corresponding identifier.
+func (e InputError) unwrap() iter.Seq2[Artifact, unique.Handle[ID]] {
ir := NewIR()
type input struct {
@@ -1741,20 +1743,37 @@ func (e InputError) Error() string {
identBuf[0], identBuf[1] = a.id.Value(), b.id.Value()
return slices.Compare(identBuf[0][:], identBuf[1][:])
})
+ p = slices.CompactFunc(p, func(a, b input) bool { return a.id == b.id })
+ return func(yield func(Artifact, unique.Handle[ID]) bool) {
+ for _, i := range p {
+ if !yield(i.a, i.id) {
+ return
+ }
+ }
+ }
+}
+
+// Error returns a user-facing, deterministic text representation of e.
+func (e InputError) Error() string {
var buf strings.Builder
buf.WriteString("errors curing inputs:")
- for _, i := range p {
- buf.WriteString("\n\t" +
- reportName(i.a, i.id) + ": " +
- e[i.a].Error())
+ for a, id := range e.unwrap() {
+ buf.WriteString("\n\t")
+ buf.WriteString(reportName(a, id))
+ buf.WriteString(": ")
+ buf.WriteString(e[a].Error())
}
return buf.String()
}
-// Unwrap returns a slice of underlying errors in unspecified order.
+// Unwrap returns a slice of underlying errors sorted by identifier.
func (e InputError) Unwrap() []error {
- return slices.AppendSeq(make([]error, 0, len(e)), maps.Values(e))
+ errs := make([]error, 0, len(e))
+ for a := range e.unwrap() {
+ errs = append(errs, e[a])
+ }
+ return errs
}
// enterCure must be called before entering an [Artifact] implementation.
diff --git a/internal/pkg/pkg_test.go b/internal/pkg/pkg_test.go
index a6964798..39218d96 100644
--- a/internal/pkg/pkg_test.go
+++ b/internal/pkg/pkg_test.go
@@ -11,7 +11,6 @@ import (
"io"
"io/fs"
"log"
- "maps"
"net/http"
"os"
"path/filepath"
@@ -1979,6 +1978,22 @@ func TestInputError(t *testing.T) {
stub.UniqueError(0xbad09),
stub.UniqueError(0xbad0f),
}},
+
+ {"dedup", pkg.InputError{
+ makeIdent(0xff, 9): stub.UniqueError(0xbad09),
+ makeIdent(0xff, 9): stub.UniqueError(0xbad09),
+ makeIdent(0xff, 9): stub.UniqueError(0xbad09),
+ makeIdent(0xff, 0): stub.UniqueError(0xbad00),
+ makeIdent(0xff, 0): stub.UniqueError(0xbad00),
+ makeIdent(0xff, 1): stub.UniqueError(0xbad01),
+ }, `errors curing inputs:
+ _wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA: unique error 765184 injected by the test suite
+ _wEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA: unique error 765185 injected by the test suite
+ _wkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA: unique error 765193 injected by the test suite`, []error{
+ stub.UniqueError(0xbad00),
+ stub.UniqueError(0xbad01),
+ stub.UniqueError(0xbad09),
+ }},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
@@ -1988,19 +2003,7 @@ func TestInputError(t *testing.T) {
t.Errorf("Error:\n%s\nwant\n%s", got, tc.want)
}
- unwrap, unwrapM := tc.err.Unwrap(), make(map[error]struct{})
- for _, a := range unwrap {
- unwrapM[a] = struct{}{}
- }
-
- wantUnwrapM := make(map[error]struct{})
- for _, a := range tc.unwrap {
- wantUnwrapM[a] = struct{}{}
- }
-
- if len(unwrap) != len(unwrapM) ||
- len(tc.unwrap) != len(wantUnwrapM) ||
- !maps.Equal(unwrapM, wantUnwrapM) {
+ if unwrap := tc.err.Unwrap(); !reflect.DeepEqual(unwrap, tc.unwrap) {
t.Errorf("Unwrap: %#v, want %#v", unwrap, tc.unwrap)
}
})