diff options
| -rw-r--r-- | util/errors.go | 107 | ||||
| -rw-r--r-- | util/util.go | 74 | ||||
| -rw-r--r-- | util/util_test.go | 2 |
3 files changed, 102 insertions, 81 deletions
diff --git a/util/errors.go b/util/errors.go index bd63ac8..e5eea4b 100644 --- a/util/errors.go +++ b/util/errors.go @@ -21,25 +21,94 @@ package util import ( "fmt" + "io" "log" "os" ) -// InvalidInputF creates an error that should indicate either bad input from a -// caller of a public library function or bad user input. -func InvalidInputF(format string, a ...interface{}) error { - return fmt.Errorf("invalid input: "+format, a...) +// ErrReader wraps an io.Reader, passing along calls to Read() until a read +// fails. Then, the error is stored, and all subsequent calls to Read() do +// nothing. This allows you to write code which has many subsequent reads and +// do all of the error checking at the end. For example: +// +// r := NewErrReader(reader) +// r.Read(foo) +// r.Read(bar) +// r.Read(baz) +// if r.Err() != nil { +// // Handle error +// } +// +// Taken from https://blog.golang.org/errors-are-values by Rob Pike. +type ErrReader struct { + r io.Reader + err error +} + +// NewErrReader creates an ErrReader which wraps the provided reader. +func NewErrReader(reader io.Reader) *ErrReader { + return &ErrReader{r: reader, err: nil} +} + +// Read runs ReadFull on the wrapped reader if no errors have occurred. +// Otherwise, the previous error is just returned and no reads are attempted. +func (e *ErrReader) Read(p []byte) (n int, err error) { + if e.err == nil { + n, e.err = io.ReadFull(e.r, p) + } + return n, e.err +} + +// Err returns the first encountered err (or nil if no errors occurred). +func (e *ErrReader) Err() error { + return e.err +} + +// ErrWriter works exactly like ErrReader, except with io.Writer. +type ErrWriter struct { + w io.Writer + err error +} + +// NewErrWriter creates an ErrWriter which wraps the provided reader. +func NewErrWriter(writer io.Writer) *ErrWriter { + return &ErrWriter{w: writer, err: nil} +} + +// Write runs the wrapped writer's Write if no errors have occurred. Otherwise, +// the previous error is just returned and no writes are attempted. +func (e *ErrWriter) Write(p []byte) (n int, err error) { + if e.err == nil { + n, e.err = e.w.Write(p) + } + return n, e.err +} + +// Err returns the first encountered err (or nil if no errors occurred). +func (e *ErrWriter) Err() error { + return e.err +} + +// InvalidInput is an error that should indicate either bad input from a caller +// of a public package function. +type InvalidInput string + +func (i InvalidInput) Error() string { + return "invalid input: " + string(i) } // InvalidLengthError indicates name should have had length expected. -func InvalidLengthError(name string, expected int, actual int) error { - return InvalidInputF("expected %s of length %d, actual length was %d", name, expected, actual) +func InvalidLengthError(name string, expected int, actual int) InvalidInput { + message := fmt.Sprintf("length of %s: expected=%d, actual=%d", name, expected, actual) + return InvalidInput(message) } -// SystemErrorF creates an error that should indicate something has gone wrong -// in the underlying system (syscall failure, bad ioctl, etc...). -func SystemErrorF(format string, a ...interface{}) error { - return fmt.Errorf("system error: "+format, a...) +// SystemError is an error that should indicate something has gone wrong in the +// underlying system (syscall failure, bad ioctl, etc...). +type SystemError string + +func (s SystemError) Error() string { + return "system error: " + string(s) } // NeverError panics if a non-nil error is passed in. It should be used to check @@ -50,16 +119,20 @@ func NeverError(err error) { } } -// UnderlyingError returns the underlying error for known os error types. -// From: src/os/error.go +// UnderlyingError returns the underlying error for known os error types and +// logs the full error. From: src/os/error.go func UnderlyingError(err error) error { - switch err := err.(type) { + var newErr error + switch typedErr := err.(type) { case *os.PathError: - return err.Err + newErr = typedErr.Err case *os.LinkError: - return err.Err + newErr = typedErr.Err case *os.SyscallError: - return err.Err + newErr = typedErr.Err + default: + return err } - return err + log.Print(err) + return newErr } diff --git a/util/util.go b/util/util.go index dc1b85d..2f20151 100644 --- a/util/util.go +++ b/util/util.go @@ -24,74 +24,14 @@ package util import ( - "io" "unsafe" ) -// ErrReader wraps an io.Reader, passing along calls to Read() until a read -// fails. Then, the error is stored, and all subsequent calls to Read() do -// nothing. This allows you to write code which has many subsequent reads and -// do all of the error checking at the end. For example: -// -// r := NewErrReader(reader) -// r.Read(foo) -// io.ReadFull(r, bar) -// if r.Err() != nil { -// // Handle error -// } -// -// Taken from https://blog.golang.org/errors-are-values by Rob Pike. -type ErrReader struct { - r io.Reader - err error -} - -// NewErrReader creates an ErrReader which wraps the provided reader. -func NewErrReader(reader io.Reader) *ErrReader { - return &ErrReader{r: reader, err: nil} -} - -// Read runs ReadFull on the wrapped reader if no errors have occurred. -// Otherwise, the previous error is just returned and no reads are attempted. -func (e *ErrReader) Read(p []byte) (n int, err error) { - if e.err == nil { - n, e.err = io.ReadFull(e.r, p) - } - return n, e.err -} - -// Err returns the first encountered err (or nil if no errors occurred). -func (e *ErrReader) Err() error { - return e.err -} - -// ErrWriter works exactly like ErrReader, except with io.Writer. -type ErrWriter struct { - w io.Writer - err error -} - -// NewErrWriter creates an ErrWriter which wraps the provided reader. -func NewErrWriter(writer io.Writer) *ErrWriter { - return &ErrWriter{w: writer, err: nil} -} - -// Write runs the wrapped writer's Write if no errors have occurred. Otherwise, -// the previous error is just returned and no writes are attempted. -func (e *ErrWriter) Write(p []byte) (n int, err error) { - if e.err == nil { - n, e.err = e.w.Write(p) - } - return n, e.err -} - -// Err returns the first encountered err (or nil if no errors occurred). -func (e *ErrWriter) Err() error { - return e.err -} - // Ptr converts an Go byte array to a pointer to the start of the array. func Ptr(slice []byte) unsafe.Pointer { + if len(slice) == 0 { + return nil + } return unsafe.Pointer(&slice[0]) } @@ -124,3 +64,11 @@ func MinInt(a, b int) int { } return b } + +// MinInt64 returns the lesser of a and b. +func MinInt64(a, b int64) int64 { + if a < b { + return a + } + return b +} diff --git a/util/util_test.go b/util/util_test.go index 65541b3..33ce2ff 100644 --- a/util/util_test.go +++ b/util/util_test.go @@ -44,7 +44,7 @@ func TestNeverErrorPanic(t *testing.T) { } }() - err := SystemErrorF("Hello") + err := SystemError("Hello") NeverError(err) } |