diff --git a/geom/alg_buffer.go b/geom/alg_buffer.go index 29139535..b05c6c51 100644 --- a/geom/alg_buffer.go +++ b/geom/alg_buffer.go @@ -27,19 +27,17 @@ func Buffer(g Geometry, distance float64, opts ...BufferOption) (Geometry, error opt(params) } - var result Geometry - err := catch(func() error { + return catch(func() (Geometry, error) { wkbReader := jts.Io_NewWKBReader() jtsG, err := wkbReader.ReadBytes(g.AsBinary()) if err != nil { - return wrap(err, "converting geometry to JTS") + return Geometry{}, wrap(err, "converting geometry to JTS") } jtsResult := jts.OperationBuffer_BufferOp_BufferOpWithParams(jtsG, distance, params) wkbWriter := jts.Io_NewWKBWriter() - result, err = UnmarshalWKB(wkbWriter.Write(jtsResult), NoValidate{}) - return wrap(err, "converting JTS buffer result to simplefeatures") + result, err := UnmarshalWKB(wkbWriter.Write(jtsResult), NoValidate{}) + return result, wrap(err, "converting JTS buffer result to simplefeatures") }) - return result, err } // BufferOption allows the behaviour of the [Buffer] operation to be modified. diff --git a/geom/alg_overlay.go b/geom/alg_overlay.go index e3bb9524..a9b172a9 100644 --- a/geom/alg_overlay.go +++ b/geom/alg_overlay.go @@ -221,23 +221,21 @@ func gcAwareDifference(a, b Geometry) (Geometry, error) { // jtsOverlayOp invokes the JTS port's overlay operation with the given opCode. func jtsOverlayOp(a, b Geometry, opCode int) (Geometry, error) { - var result Geometry - err := catch(func() error { + return catch(func() (Geometry, error) { wkbReader := jts.Io_NewWKBReader() jtsA, err := wkbReader.ReadBytes(a.AsBinary()) if err != nil { - return wrap(err, "converting geometry A to JTS") + return Geometry{}, wrap(err, "converting geometry A to JTS") } jtsB, err := wkbReader.ReadBytes(b.AsBinary()) if err != nil { - return wrap(err, "converting geometry B to JTS") + return Geometry{}, wrap(err, "converting geometry B to JTS") } jtsResult := jts.OperationOverlayng_OverlayNGRobust_Overlay(jtsA, jtsB, opCode) wkbWriter := jts.Io_NewWKBWriter() - result, err = UnmarshalWKB(wkbWriter.Write(jtsResult), NoValidate{}) - return wrap(err, "converting JTS overlay result to simplefeatures") + result, err := UnmarshalWKB(wkbWriter.Write(jtsResult), NoValidate{}) + return result, wrap(err, "converting JTS overlay result to simplefeatures") }) - return result, err } // SymmetricDifference returns a geometry that represents the parts of geometry @@ -288,17 +286,15 @@ func UnionMany(gs []Geometry) (Geometry, error) { // jtsUnaryUnion invokes the JTS port's unary union operation. func jtsUnaryUnion(g Geometry) (Geometry, error) { - var result Geometry - err := catch(func() error { + return catch(func() (Geometry, error) { wkbReader := jts.Io_NewWKBReader() jtsG, err := wkbReader.ReadBytes(g.AsBinary()) if err != nil { - return wrap(err, "converting geometry to JTS") + return Geometry{}, wrap(err, "converting geometry to JTS") } jtsResult := jts.OperationOverlayng_OverlayNGRobust_Union(jtsG) wkbWriter := jts.Io_NewWKBWriter() - result, err = UnmarshalWKB(wkbWriter.Write(jtsResult), NoValidate{}) - return wrap(err, "converting JTS union result to simplefeatures") + result, err := UnmarshalWKB(wkbWriter.Write(jtsResult), NoValidate{}) + return result, wrap(err, "converting JTS union result to simplefeatures") }) - return result, err } diff --git a/geom/alg_prepared.go b/geom/alg_prepared.go index 972b9ceb..de92355f 100644 --- a/geom/alg_prepared.go +++ b/geom/alg_prepared.go @@ -15,16 +15,15 @@ type PreparedGeometry struct { // Prepare preprocesses a geometry for efficient repeated predicate evaluation. func Prepare(g Geometry) (PreparedGeometry, error) { - var pg PreparedGeometry - err := catch(func() error { + return catch(func() (PreparedGeometry, error) { jtsG, err := toJTS(g) if err != nil { - return err + return PreparedGeometry{}, err } - pg.prep = jts.GeomPrep_PreparedGeometryFactory_Prepare(jtsG) - return nil + return PreparedGeometry{ + prep: jts.GeomPrep_PreparedGeometryFactory_Prepare(jtsG), + }, nil }) - return pg, err } func toJTS(g Geometry) (*jts.Geom_Geometry, error) { @@ -36,16 +35,13 @@ func toJTS(g Geometry) (*jts.Geom_Geometry, error) { } func (p PreparedGeometry) eval(g Geometry, pred func(*jts.Geom_Geometry) bool) (bool, error) { - var result bool - err := catch(func() error { + return catch(func() (bool, error) { jtsG, err := toJTS(g) if err != nil { - return err + return false, err } - result = pred(jtsG) - return nil + return pred(jtsG), nil }) - return result, err } // Intersects reports whether the prepared geometry intersects g. diff --git a/geom/alg_relate.go b/geom/alg_relate.go index 903f1191..99f1c95b 100644 --- a/geom/alg_relate.go +++ b/geom/alg_relate.go @@ -64,22 +64,20 @@ func relateWithEmptyInput(a, b Geometry) string { // jtsRelateNG invokes the JTS port's RelateNG operation. func jtsRelateNG(a, b Geometry) (string, error) { - var result string - err := catch(func() error { + return catch(func() (string, error) { wkbReader := jts.Io_NewWKBReader() jtsA, err := wkbReader.ReadBytes(a.AsBinary()) if err != nil { - return wrap(err, "converting geometry A to JTS") + return "", wrap(err, "converting geometry A to JTS") } jtsB, err := wkbReader.ReadBytes(b.AsBinary()) if err != nil { - return wrap(err, "converting geometry B to JTS") + return "", wrap(err, "converting geometry B to JTS") } im := jts.OperationRelateng_RelateNG_RelateMatrix(jtsA, jtsB) - result = im.String() - return validateIntersectionMatrix(result) + result := im.String() + return result, validateIntersectionMatrix(result) }) - return result, err } func relateMatchesAnyPattern(a, b Geometry, patterns ...string) (bool, error) { diff --git a/geom/util.go b/geom/util.go index 0ed6bca5..aea4c3fc 100644 --- a/geom/util.go +++ b/geom/util.go @@ -141,7 +141,7 @@ func arbitraryControlPoint(g Geometry) Point { } } -func catch(fn func() error) (err error) { +func catch[T any](fn func() (T, error)) (result T, err error) { //nolint:ireturn // In Go 1.21+, panic(nil) causes recover() to return a *runtime.PanicNilError // rather than nil. In earlier versions, recover() returns nil for panic(nil), // making it indistinguishable from "no panic". We emulate the Go 1.21+ behavior @@ -158,7 +158,7 @@ func catch(fn func() error) (err error) { } } }() - err = fn() + result, err = fn() panicked = false return } diff --git a/geom/util_internal_test.go b/geom/util_internal_test.go index e5617d12..c651d924 100644 --- a/geom/util_internal_test.go +++ b/geom/util_internal_test.go @@ -74,42 +74,42 @@ func BenchmarkMathMax(b *testing.B) { func TestCatch(t *testing.T) { for _, tc := range []struct { name string - fn func() error + fn func() (struct{}, error) wantErr string }{ { name: "function returns nil", - fn: func() error { return nil }, + fn: func() (struct{}, error) { return struct{}{}, nil }, wantErr: "", }, { name: "function returns error", - fn: func() error { return errors.New("test error") }, + fn: func() (struct{}, error) { return struct{}{}, errors.New("test error") }, wantErr: "test error", }, { name: "function panics with string", - fn: func() error { panic("something went wrong") }, + fn: func() (struct{}, error) { panic("something went wrong") }, wantErr: "panic: something went wrong", }, { name: "function panics with error", - fn: func() error { panic(errors.New("panic error")) }, + fn: func() (struct{}, error) { panic(errors.New("panic error")) }, wantErr: "panic: panic error", }, { name: "function panics with int", - fn: func() error { panic(42) }, + fn: func() (struct{}, error) { panic(42) }, wantErr: "panic: 42", }, { name: "function panics with nil", - fn: func() error { panic(nil) }, + fn: func() (struct{}, error) { panic(nil) }, wantErr: "panic: panic called with nil argument", }, } { t.Run(tc.name, func(t *testing.T) { - err := catch(tc.fn) + _, err := catch(tc.fn) if tc.wantErr == "" { if err != nil { t.Errorf("got %v, want nil", err)