diff --git a/dontpanic.go b/dontpanic.go index d0577d5..893f539 100644 --- a/dontpanic.go +++ b/dontpanic.go @@ -7,8 +7,47 @@ package dontpanic import ( "fmt" + + "golang.org/x/exp/constraints" ) +// Deref invokes *p. +// Returns an error if p is nil. +func Deref[T any](p *T) (_ T, err error) { + defer Recover(&err) + return *p, nil +} + +// Div returns x / y. +// Returns an error if y is zero. +func Div[N constraints.Integer | constraints.Float | constraints.Complex](x, y N) (_ N, err error) { + defer Recover(&err) + return x / y, nil +} + +// Mod returns x % y. +// Returns an error if y is zero. +func Mod[N constraints.Integer](x, y N) (_ N, err error) { + defer Recover(&err) + return x % y, nil +} + +// Send invokes ch <- v. +// Returns an error if ch is closed. +func Send[T any](ch chan T, v T) (err error) { + defer Recover(&err) + ch <- v + return nil +} + +// Close invokes close(ch). +// Returns an error if ch is nil or closed. +func Close[T any](ch chan T) (err error) { + defer Recover(&err) + close(ch) + return nil +} + // SetMapIndex sets m[k] = v. // Returns an error if m is nil. func SetMapIndex[K comparable, V any, M ~map[K]V](m M, k K, v V) (err error) { @@ -17,6 +56,29 @@ func SetMapIndex[K comparable, V any, M ~map[K]V](m M, k K, v V) (err error) { return nil } +// Make invokes make(S, size...). +// Returns an error if length is negative or larger than capacity. +// +// Supports empty: +// MakeSlice() +// or length n: +// MakeSlice(n) +// or length n and capacity m: +// MakeSlice(n, m) +func MakeSlice[E any, S ~[]E](size ...int) (_ S, err error) { + defer Recover(&err) + switch len(size) { + case 0: + return nil, nil + case 1: + return make([]E, size[0]), nil + case 2: + return make([]E, size[0], size[1]), nil + default: + return nil, fmt.Errorf("size: expected 0-2 arguments; found %d", len(size)) + } +} + // SetSliceIndex sets s[i] = v. // Returns an error if i is out of range. func SetSliceIndex[E any, S ~[]E](s S, i int, v E) (err error) { @@ -33,16 +95,16 @@ func SliceIndex[E any, S ~[]E](s S, i int) (_ E, err error) { } // Slice returns s[i:j:k]. +// Returns an error if indexes are out of range or too many are specified. // -// Supports [:] +// Supports s[:] // Slice(s) -// or [i:] +// or s[i:] // Slice(s, i) -// or [i:j] +// or s[i:j] // Slice(s, i, j) -// or [i:j:k] +// or s[i:j:k] // Slice(s, i, j, k) -// Returns an error if indexes are out of range or too many are specified. func Slice[E any, S ~[]E](s S, ijk ...int) (_ S, err error) { defer Recover(&err) switch len(ijk) { @@ -59,6 +121,13 @@ func Slice[E any, S ~[]E](s S, ijk ...int) (_ S, err error) { } } +// StringIndex returns s[i]. +// Returns an error if i is out of range. +func StringIndex(s string, i int) (_ byte, err error) { + defer Recover(&err) + return s[i], nil +} + // Recover calls recover() and writes the result to err. func Recover(err *error) { switch r := recover().(type) { diff --git a/go.mod b/go.mod index 8d75eed..84aeb0c 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,5 @@ module github.com/phelmkamp/dontpanic go 1.18 + +require golang.org/x/exp v0.0.0-20220428152302-39d4317da171 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..698ce9b --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +golang.org/x/exp v0.0.0-20220428152302-39d4317da171 h1:TfdoLivD44QwvssI9Sv1xwa5DcL5XQr4au4sZ2F2NV4= +golang.org/x/exp v0.0.0-20220428152302-39d4317da171/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=