Compare commits

...

1 commit

Author SHA1 Message Date
750635bd1a update to use generics 2022-03-27 03:03:42 +02:00
10 changed files with 63 additions and 676 deletions

View file

@ -1,35 +1,7 @@
# gotry # gotry
This package is a fork of lainio's [err2](https://github.com/lainio/err2) This package is a fork of lainio's [err2](https://github.com/lainio/err2)
package with an improved code generator. package.
## Add custom try package to your project
```
go install code.thetadev.de/ThetaDev/gotry/gotry_generate
gotry_generate -init
```
### Add type definitions
```
📂 try/types.csv
<Handler method name>;<Type>;<Import#1>;<Import#2>;...
# Example:
DB;*gorm.DB;gorm.io/gorm
# Add +s to the method name to generate 2 handlers for single values and slices
String+s;string
```
### Generate
```sh
go generate ./try
```
## Handle errors ## Handle errors

View file

@ -1,11 +0,0 @@
package gotry
import "embed"
//go:generate go run ./gotry_generate -of std_types
//go:embed try/*.go
var TryFiles embed.FS
//go:embed try/types.tmpl
var TypesTemplate string

2
go.mod
View file

@ -1,3 +1,3 @@
module code.thetadev.de/ThetaDev/gotry module code.thetadev.de/ThetaDev/gotry
go 1.16 go 1.18

View file

@ -1,150 +0,0 @@
package main
import (
"bufio"
"flag"
"fmt"
"os"
"os/exec"
"path"
"regexp"
"strings"
"text/template"
"code.thetadev.de/ThetaDev/gotry"
"code.thetadev.de/ThetaDev/gotry/try"
)
var variablePattern = regexp.MustCompile(`^(\w[\w\d]*)(\+s)?$`)
type line struct {
Name string
WithSlice bool
Types []string
UseExt bool
}
func parseDefinitions(defFileName, outFileName, pkgName string) (err try.Err) {
defer try.Annotate(&err, "error parsing definitions")
defFile := try.File(os.Open(defFileName))
useExt := pkgName != "try"
fileScanner := bufio.NewScanner(defFile)
fileScanner.Split(bufio.ScanLines)
ln := 0
var lines []line
imports := map[string]bool{}
for fileScanner.Scan() {
lineStr := strings.TrimSpace(fileScanner.Text())
ln++
if lineStr == "" || strings.HasPrefix(lineStr, "#") ||
strings.HasPrefix(lineStr, "/") {
continue
}
lineData, err := parseLine(lineStr, imports)
if err != nil {
fmt.Printf("[Err] line %d, %s: \"%s\n", ln, err.Error(), lineStr)
continue
}
lineData.UseExt = useExt
lines = append(lines, *lineData)
}
fmt.Printf("Parsed %d definitions\n", len(lines))
outFile := try.File(os.Create(outFileName))
tmpl := template.Must(template.New("templ").Parse(gotry.TypesTemplate))
try.Check(tmpl.Execute(outFile, struct {
Definitions []line
Imports map[string]bool
PkgName string
UseExt bool
}{
Definitions: lines,
Imports: imports,
PkgName: pkgName,
UseExt: useExt,
}))
try.Check(defFile.Close())
try.Check(outFile.Close())
try.Check(goFmt(outFileName))
return
}
func parseLine(lineStr string, imports map[string]bool) (*line, try.Err) {
lineParts := strings.Split(lineStr, ";")
lineData := line{}
if len(lineParts) < 2 {
return nil, try.NewErr("missing type name")
}
// Parse variable name
variableRaw := strings.TrimSpace(lineParts[0])
if match := variablePattern.FindStringSubmatch(variableRaw); match != nil {
lineData.Name = match[1]
lineData.WithSlice = match[2] != ""
} else {
return nil, try.NewErr("invalid variable name")
}
// Parse type name(s)
for _, typeStr := range strings.Split(lineParts[1], ",") {
typeStr = strings.TrimSpace(typeStr)
if typeStr != "" {
lineData.Types = append(lineData.Types, typeStr)
}
}
if len(lineData.Types) == 0 {
return nil, try.NewErr("invalid type name")
}
// Parse imports
for i := 2; i < len(lineParts); i++ {
pkgName := strings.TrimSpace(lineParts[i])
imports[pkgName] = true
}
return &lineData, nil
}
func goFmt(goFile string) error {
return exec.Command("gofmt", "-s", "-w", goFile).Run()
}
func main() {
defer try.CatchTrace(1)
// Read flags
var definitionFile string
var targetDir string
var typeFile string
flag.StringVar(&definitionFile, "def", path.Join("try", "types.csv"),
"Definition file")
flag.StringVar(&targetDir, "o", "try", "Target directory")
flag.StringVar(&typeFile, "of", "types", "Name of generated type definition file")
flag.Parse()
try.Check(os.MkdirAll(targetDir, 0o777))
// Generate types
if _, e := os.Stat(definitionFile); os.IsNotExist(e) {
try.Check(try.NewErr("Definition file does not exist"))
} else {
try.Check(
parseDefinitions(definitionFile, path.Join(targetDir, typeFile+".go"),
path.Base(targetDir)))
}
}

View file

@ -1,290 +0,0 @@
package try
// gotry auto-generated type definitions. DO NOT EDIT.
import (
"io"
"net/http"
"net/url"
"os"
)
// Bool is a helper method to handle errors of
// func() (bool, error) functions.
func Bool(v bool, err error) bool {
Check(err)
return v
}
// Bools is a helper method to handle errors of
// func() ([]bool, error) functions.
func Bools(v []bool, err error) []bool {
Check(err)
return v
}
// Byte is a helper method to handle errors of
// func() (byte, error) functions.
func Byte(v byte, err error) byte {
Check(err)
return v
}
// Bytes is a helper method to handle errors of
// func() ([]byte, error) functions.
func Bytes(v []byte, err error) []byte {
Check(err)
return v
}
// Rune is a helper method to handle errors of
// func() (rune, error) functions.
func Rune(v rune, err error) rune {
Check(err)
return v
}
// Runes is a helper method to handle errors of
// func() ([]rune, error) functions.
func Runes(v []rune, err error) []rune {
Check(err)
return v
}
// String is a helper method to handle errors of
// func() (string, error) functions.
func String(v string, err error) string {
Check(err)
return v
}
// Strings is a helper method to handle errors of
// func() ([]string, error) functions.
func Strings(v []string, err error) []string {
Check(err)
return v
}
// Int is a helper method to handle errors of
// func() (int, error) functions.
func Int(v int, err error) int {
Check(err)
return v
}
// Ints is a helper method to handle errors of
// func() ([]int, error) functions.
func Ints(v []int, err error) []int {
Check(err)
return v
}
// Int8 is a helper method to handle errors of
// func() (int8, error) functions.
func Int8(v int8, err error) int8 {
Check(err)
return v
}
// Int8s is a helper method to handle errors of
// func() ([]int8, error) functions.
func Int8s(v []int8, err error) []int8 {
Check(err)
return v
}
// Int16 is a helper method to handle errors of
// func() (int16, error) functions.
func Int16(v int16, err error) int16 {
Check(err)
return v
}
// Int16s is a helper method to handle errors of
// func() ([]int16, error) functions.
func Int16s(v []int16, err error) []int16 {
Check(err)
return v
}
// Int32 is a helper method to handle errors of
// func() (int32, error) functions.
func Int32(v int32, err error) int32 {
Check(err)
return v
}
// Int32s is a helper method to handle errors of
// func() ([]int32, error) functions.
func Int32s(v []int32, err error) []int32 {
Check(err)
return v
}
// Int64 is a helper method to handle errors of
// func() (int64, error) functions.
func Int64(v int64, err error) int64 {
Check(err)
return v
}
// Int64s is a helper method to handle errors of
// func() ([]int64, error) functions.
func Int64s(v []int64, err error) []int64 {
Check(err)
return v
}
// Uint is a helper method to handle errors of
// func() (uint, error) functions.
func Uint(v uint, err error) uint {
Check(err)
return v
}
// Uints is a helper method to handle errors of
// func() ([]uint, error) functions.
func Uints(v []uint, err error) []uint {
Check(err)
return v
}
// Uint8 is a helper method to handle errors of
// func() (uint8, error) functions.
func Uint8(v uint8, err error) uint8 {
Check(err)
return v
}
// Uint8s is a helper method to handle errors of
// func() ([]uint8, error) functions.
func Uint8s(v []uint8, err error) []uint8 {
Check(err)
return v
}
// Uint16 is a helper method to handle errors of
// func() (uint16, error) functions.
func Uint16(v uint16, err error) uint16 {
Check(err)
return v
}
// Uint16s is a helper method to handle errors of
// func() ([]uint16, error) functions.
func Uint16s(v []uint16, err error) []uint16 {
Check(err)
return v
}
// Uint32 is a helper method to handle errors of
// func() (uint32, error) functions.
func Uint32(v uint32, err error) uint32 {
Check(err)
return v
}
// Uint32s is a helper method to handle errors of
// func() ([]uint32, error) functions.
func Uint32s(v []uint32, err error) []uint32 {
Check(err)
return v
}
// Uint64 is a helper method to handle errors of
// func() (uint64, error) functions.
func Uint64(v uint64, err error) uint64 {
Check(err)
return v
}
// Uint64s is a helper method to handle errors of
// func() ([]uint64, error) functions.
func Uint64s(v []uint64, err error) []uint64 {
Check(err)
return v
}
// Float32 is a helper method to handle errors of
// func() (float32, error) functions.
func Float32(v float32, err error) float32 {
Check(err)
return v
}
// Float32s is a helper method to handle errors of
// func() ([]float32, error) functions.
func Float32s(v []float32, err error) []float32 {
Check(err)
return v
}
// Float64 is a helper method to handle errors of
// func() (float64, error) functions.
func Float64(v float64, err error) float64 {
Check(err)
return v
}
// Float64s is a helper method to handle errors of
// func() ([]float64, error) functions.
func Float64s(v []float64, err error) []float64 {
Check(err)
return v
}
// StrStr is a helper method to handle errors of
// func() (string, string, error) functions.
func StrStr(v string, v1 string, err error) (string, string) {
Check(err)
return v, v1
}
// X is a helper method to handle errors of
// func() (interface{}, error) functions.
func X(v interface{}, err error) interface{} {
Check(err)
return v
}
// File is a helper method to handle errors of
// func() (*os.File, error) functions.
func File(v *os.File, err error) *os.File {
Check(err)
return v
}
// Reader is a helper method to handle errors of
// func() (io.Reader, error) functions.
func Reader(v io.Reader, err error) io.Reader {
Check(err)
return v
}
// Writer is a helper method to handle errors of
// func() (io.Writer, error) functions.
func Writer(v io.Writer, err error) io.Writer {
Check(err)
return v
}
// Request is a helper method to handle errors of
// func() (*http.Request, error) functions.
func Request(v *http.Request, err error) *http.Request {
Check(err)
return v
}
// Response is a helper method to handle errors of
// func() (*http.Response, error) functions.
func Response(v *http.Response, err error) *http.Response {
Check(err)
return v
}
// Url is a helper method to handle errors of
// func() (*url.URL, error) functions.
func Url(v *url.URL, err error) *url.URL {
Check(err)
return v
}

View file

@ -1,68 +0,0 @@
package try
import (
"fmt"
"io"
"os"
"testing"
)
func TestStrHelper_noThrow(t *testing.T) {
s := String(noThrow())
if s != "test" {
t.Fail()
}
}
func TestStrHelper_throw(t *testing.T) {
var err Err
defer Return(&err)
String(throw())
t.Fail() // If everything works we are never here
}
func TestStrStrHelper(t *testing.T) {
s1, s2 := StrStr(twoStrNoThrow())
if s1 != "test" || s2 != "test" {
t.Fail()
}
}
func Example_copyFile() {
copyFile := func(src, dst string) (err Err) {
defer Annotate(&err, fmt.Sprintf("copy %s %s", src, dst))
// These helpers are as fast as Check() calls
r := File(os.Open(src))
defer Check(r.Close())
w := File(os.Create(dst))
defer Handle(&err, func() {
os.Remove(dst)
})
defer Check(w.Close())
Empty(io.Copy(w, r))
return nil
}
err := copyFile("/notfound/path/file.go", "/notfound/path/file.bak")
if err != nil {
fmt.Println(err)
}
//nolint:lll
// Output: copy /notfound/path/file.go /notfound/path/file.bak: open /notfound/path/file.go: no such file or directory
}
func BenchmarkTry_StringHelper(b *testing.B) {
for n := 0; n < b.N; n++ {
_ = String(noThrow())
}
}
func BenchmarkTry_XHelper(b *testing.B) {
for n := 0; n < b.N; n++ {
_ = X(noThrow()).(string)
}
}

View file

@ -46,8 +46,8 @@ type call struct {
Line int `json:"l"` Line int `json:"l"`
} }
// FromErr wraps a standard error into a try-compatible one with extended stack info. // fromErr wraps a standard error into a try-compatible one with extended stack info.
func FromErr(err error) Err { func fromErr(err error) Err {
// If the error is already try-compatible, return // If the error is already try-compatible, return
//nolint:errorlint //nolint:errorlint
cterr, ok := err.(Err) cterr, ok := err.(Err)
@ -88,9 +88,9 @@ func FromErr(err error) Err {
return terr return terr
} }
// NewErr creates a new try-compatible error with extended stack info. // newErr creates a new try-compatible error with extended stack info.
func NewErr(msg string) Err { func newErr(msg string) Err {
return FromErr(errors.New(msg)) return fromErr(errors.New(msg))
} }
// Error returns the standard go error message (initial message + annotations). // Error returns the standard go error message (initial message + annotations).
@ -144,41 +144,37 @@ func (e *tryErr) Annotate(msg string) {
e.annotations = append(e.annotations, msg) e.annotations = append(e.annotations, msg)
} }
// Empty is a helper method to handle errors of func() (string, error) functions. // To is a helper function to call functions which returns (error)
func Empty(_ interface{}, err error) { // and check the error value. If error occurs it panics the error where err2
Check(err) // handlers can catch it if needed.
} func To(err error) {
// Any is as similar as proposed Go2 Try macro, but it's a function and it
// returns slice of interfaces. It has quite big performance penalty when
// compared to Check function.
func Any(args ...interface{}) []interface{} {
check(args)
return args
}
// Check performs the error check for the given argument. If the err is nil,
// it does nothing. According the measurements, it's as fast as if err != nil
// {return err} on happy path.
func Check(err error) {
if err != nil { if err != nil {
panic(FromErr(err)) panic(fromErr(err))
} }
} }
// Checks the error status of the last argument. It panics with "wrong // To1 is a helper function to call functions which returns (any, error)
// signature" if the last calling parameter is not error. In case of error it // and check the error value. If error occurs it panics the error where err2
// delivers it by panicking. // handlers can catch it if needed.
func check(args []interface{}) { func To1[T any](v T, err error) T {
argCount := len(args) To(err)
last := argCount - 1 return v
if args[last] != nil { }
err, ok := args[last].(error)
if !ok { // To2 is a helper function to call functions which returns (any, any, error)
panic("wrong signature") // and check the error value. If error occurs it panics the error where err2
} // handlers can catch it if needed.
panic(FromErr(err)) func To2[T, U any](v1 T, v2 U, err error) (T, U) {
} To(err)
return v1, v2
}
// To3 is a helper function to call functions which returns (any, any, any, error)
// and check the error value. If error occurs it panics the error where err2
// handlers can catch it if needed.
func To3[T, U, V any](v1 T, v2 U, v3 V, err error) (T, U, V) {
To(err)
return v1, v2, v3
} }
// Handle is for adding an error handler to a function by defer. It's for // Handle is for adding an error handler to a function by defer. It's for

View file

@ -21,14 +21,12 @@ func twoStrNoThrow() (string, string, error) { return "test", "test", nil }
func noThrow() (string, error) { return "test", nil } func noThrow() (string, error) { return "test", nil }
func wrongSignature() (int, int) { return 0, 0 }
func recursion(a int) int { func recursion(a int) int {
if a == 0 { if a == 0 {
return 0 return 0
} }
s, err := noThrow() s, err := noThrow()
Check(err) To(err)
_ = s _ = s
return a + recursion(a-1) return a + recursion(a-1)
} }
@ -53,14 +51,14 @@ func noErr() error {
return nil return nil
} }
func TestAny_noError(t *testing.T) { func Test_noError(t *testing.T) {
d := Any(noThrow()) x := To1(noThrow())
if d[0].(string) != "test" { if x != "test" {
t.Fail() t.Fail()
} }
d = Any(twoStrNoThrow()) x, y := To2(twoStrNoThrow())
if d[0].(string) != "test" || d[1].(string) != "test" { if x != "test" || y != "test" {
t.Fail() t.Fail()
} }
} }
@ -69,7 +67,7 @@ func TestDefault_Error(t *testing.T) {
var err Err var err Err
defer Return(&err) defer Return(&err)
Any(throw()) To1(throw())
t.Fail() // If everything works we are never here t.Fail() // If everything works we are never here
} }
@ -78,7 +76,7 @@ func TestAny_Error(t *testing.T) {
var err Err var err Err
defer Handle(&err, func() {}) defer Handle(&err, func() {})
Any(throw()) To1(throw())
t.Fail() // If everything works we are never here t.Fail() // If everything works we are never here
} }
@ -87,13 +85,13 @@ func panickingHandle() {
var err Err var err Err
defer Handle(&err, func() {}) defer Handle(&err, func() {})
Any(wrongSignature()) panic("test")
} }
func TestPanickingCarryOn_Handle(t *testing.T) { func TestPanickingCarryOn_Handle(t *testing.T) {
defer func() { defer func() {
if recover() == nil { if recover() == nil {
t.Error("panics should went thru when not our errors") t.Error("panics should go through when not our errors")
} }
}() }()
panickingHandle() panickingHandle()
@ -102,7 +100,7 @@ func TestPanickingCarryOn_Handle(t *testing.T) {
func panickingCatchAll() { func panickingCatchAll() {
defer CatchAll(func(err Err) {}, func(v interface{}) {}) defer CatchAll(func(err Err) {}, func(v interface{}) {})
Any(wrongSignature()) panickingHandle()
} }
func TestPanickingCatchAll(t *testing.T) { func TestPanickingCatchAll(t *testing.T) {
@ -118,7 +116,7 @@ func panickingReturn() {
var err Err var err Err
defer Return(&err) defer Return(&err)
Any(wrongSignature()) panickingHandle()
} }
func TestPanicking_Return(t *testing.T) { func TestPanicking_Return(t *testing.T) {
@ -133,7 +131,7 @@ func TestPanicking_Return(t *testing.T) {
func panickingCatch() { func panickingCatch() {
defer Catch(func(err Err) {}) defer Catch(func(err Err) {})
Any(wrongSignature()) panickingHandle()
} }
func TestPanicking_Catch(t *testing.T) { func TestPanicking_Catch(t *testing.T) {
@ -150,13 +148,13 @@ func TestCatch_Error(t *testing.T) {
// fmt.Printf("error and defer handling:%s\n", err) // fmt.Printf("error and defer handling:%s\n", err)
}) })
Any(throw()) To1(throw())
t.Fail() // If everything works we are never here t.Fail() // If everything works we are never here
} }
func TestNewTryErr(t *testing.T) { func TestNewTryErr(t *testing.T) {
tryErr := NewErr("I f*cked up") tryErr := newErr("I f*cked up")
callStack := tryErr.CallStackString() callStack := tryErr.CallStackString()
if !strings.HasPrefix(callStack, "ERROR: I f*cked up\n") { if !strings.HasPrefix(callStack, "ERROR: I f*cked up\n") {
@ -172,7 +170,7 @@ func TestNewTryErr(t *testing.T) {
} }
func TestGetData(t *testing.T) { func TestGetData(t *testing.T) {
tryErr := NewErr("I f*cked up") tryErr := newErr("I f*cked up")
tryErr.Annotate("test1") tryErr.Annotate("test1")
tryErr.Annotate("test2") tryErr.Annotate("test2")
data := tryErr.GetData() data := tryErr.GetData()
@ -199,7 +197,7 @@ func TestGetData(t *testing.T) {
func TestErrCompare(t *testing.T) { func TestErrCompare(t *testing.T) {
err := errors.New("TestError") err := errors.New("TestError")
tryErr := FromErr(err) tryErr := fromErr(err)
if !errors.Is(tryErr, err) { if !errors.Is(tryErr, err) {
t.Fail() t.Fail()
@ -209,7 +207,7 @@ func TestErrCompare(t *testing.T) {
func TestReturnStd(t *testing.T) { func TestReturnStd(t *testing.T) {
tf := func() (err error) { tf := func() (err error) {
defer ReturnStd(&err) defer ReturnStd(&err)
String(throw()) To1(throw())
return return
} }
@ -221,11 +219,11 @@ func TestReturnStd(t *testing.T) {
} }
func TestCheckTryErr(t *testing.T) { func TestCheckTryErr(t *testing.T) {
testErr := NewErr("TestErr") testErr := newErr("TestErr")
tf := func() (err Err) { tf := func() (err Err) {
defer Return(&err) defer Return(&err)
Check(testErr) To(testErr)
return return
} }
@ -239,14 +237,14 @@ func TestCheckTryErr(t *testing.T) {
func ExampleReturn() { func ExampleReturn() {
var err Err var err Err
defer Return(&err) defer Return(&err)
Any(noThrow()) To1(noThrow())
// Output: // Output:
} }
func ExampleAnnotate() { func ExampleAnnotate() {
annotated := func() (err Err) { annotated := func() (err Err) {
defer Annotate(&err, "annotated") defer Annotate(&err, "annotated")
Any(throw()) To1(throw())
return err return err
} }
err := annotated() err := annotated()
@ -258,7 +256,7 @@ func ExampleAnnotate_deferStack() {
annotated := func() (err Err) { annotated := func() (err Err) {
defer Annotate(&err, "annotated 2nd") defer Annotate(&err, "annotated 2nd")
defer Annotate(&err, "annotated 1st") defer Annotate(&err, "annotated 1st")
Any(throw()) To1(throw())
return err return err
} }
err := annotated() err := annotated()
@ -271,7 +269,7 @@ func ExampleHandle() {
defer Handle(&err, func() { defer Handle(&err, func() {
err.Annotate(fmt.Sprintf("error with (%d, %d)", a, b)) err.Annotate(fmt.Sprintf("error with (%d, %d)", a, b))
}) })
Any(throw()) To1(throw())
return err return err
} }
err := doSomething(1, 2) err := doSomething(1, 2)
@ -290,34 +288,34 @@ func BenchmarkOldErrorCheckingWithIfClause(b *testing.B) {
func BenchmarkAny(b *testing.B) { func BenchmarkAny(b *testing.B) {
for n := 0; n < b.N; n++ { for n := 0; n < b.N; n++ {
Any(noThrow()) To1(noThrow())
} }
} }
func BenchmarkAny_ErrVar(b *testing.B) { func BenchmarkAny_ErrVar(b *testing.B) {
for n := 0; n < b.N; n++ { for n := 0; n < b.N; n++ {
_, err := noThrow() _, err := noThrow()
Any(err) To(err)
} }
} }
func BenchmarkCheckInsideCall(b *testing.B) { func BenchmarkCheckInsideCall(b *testing.B) {
for n := 0; n < b.N; n++ { for n := 0; n < b.N; n++ {
Check(noErr()) To(noErr())
} }
} }
func BenchmarkCheckVarCall(b *testing.B) { func BenchmarkCheckVarCall(b *testing.B) {
for n := 0; n < b.N; n++ { for n := 0; n < b.N; n++ {
err := noErr() err := noErr()
Check(err) To(err)
} }
} }
func BenchmarkCheck_ErrVar(b *testing.B) { func BenchmarkCheck_ErrVar(b *testing.B) {
for n := 0; n < b.N; n++ { for n := 0; n < b.N; n++ {
_, err := noThrow() _, err := noThrow()
Check(err) To(err)
} }
} }

View file

@ -1,29 +0,0 @@
Bool+s;bool
Byte+s;byte
Rune+s;rune
String+s;string
Int+s;int
Int8+s;int8
Int16+s;int16
Int32+s;int32
Int64+s;int64
Uint+s;uint
Uint8+s;uint8
Uint16+s;uint16
Uint32+s;uint32
Uint64+s;uint64
Float32+s;float32
Float64+s;float64
StrStr;string, string
X;interface{}
File;*os.File;os
Reader;io.Reader;io
Writer;io.Writer;io
Request;*http.Request;net/http
Response;*http.Response;net/http
Url;*url.URL;net/url
Can't render this file because it has a wrong number of fields in line 24.

View file

@ -1,31 +0,0 @@
package {{.PkgName}}
// gotry auto-generated type definitions. DO NOT EDIT.
import (
{{- if .UseExt }}
"code.thetadev.de/ThetaDev/gotry/try"
{{- end}}
{{- range $pkg, $b := .Imports}}
"{{$pkg}}"
{{- end}}
)
{{range $d := .Definitions }}
// {{$d.Name}} is a helper method to handle errors of
// func() ({{range $i, $t := $d.Types}}{{$t}}, {{end}}error) functions.
func {{$d.Name}}({{range $i, $t := $d.Types}}v{{if $i}}{{$i}}{{end}} {{$t}}, {{end}}err error) (
{{- range $i, $t := $d.Types}}{{if $i}}, {{end}}{{$t}}{{end}}) {
{{if .UseExt}}try.{{end}}Check(err)
return {{range $i, $t := $d.Types}}{{if $i}}, v{{$i}}{{else}}v{{end}}{{end}}
}
{{- if $d.WithSlice}}
// {{$d.Name}}s is a helper method to handle errors of
// func() ({{range $i, $t := $d.Types}}[]{{$t}}, {{end}}error) functions.
func {{$d.Name}}s({{range $i, $t := $d.Types}}v{{if $i}}{{$i}}{{end}} []{{$t}}, {{end}}err error) (
{{- range $i, $t := $d.Types}}{{if $i}}, {{end}}[]{{$t}}{{end}}) {
{{if .UseExt}}try.{{end}}Check(err)
return {{range $i, $t := $d.Types}}{{if $i}}, v{{$i}}{{else}}v{{end}}{{end}}
}
{{- end}}
{{end}}