| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128 |
- // Copyright 2018 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- // Package errors implements functions to manipulate errors.
- package errors
- import (
- "fmt"
- "sort"
- "strings"
- )
- // TODO: This package currently only provides functionality for constructing
- // non-fatal errors. However, it does not currently provide functionality
- // to test for a specific kind of non-fatal error, which is necessary
- // for the end user.
- //
- // When that functionality is added, we need to think carefully about whether
- // a user only cares that some kind of non-fatal error was present or whether
- // all of the errors are of the same kind of non-fatal error.
- // NonFatalErrors is a list of non-fatal errors where each error
- // must either be a RequiredNotSet error or InvalidUTF8 error.
- // The list must not be empty.
- type NonFatalErrors []error
- func (es NonFatalErrors) Error() string {
- ms := map[string]struct{}{}
- for _, e := range es {
- ms[e.Error()] = struct{}{}
- }
- var ss []string
- for s := range ms {
- ss = append(ss, s)
- }
- sort.Strings(ss)
- return "proto: " + strings.Join(ss, "; ")
- }
- // NonFatal contains non-fatal errors, which are errors that permit execution
- // to continue, but should return with a non-nil error. As such, NonFatal is
- // a data structure useful for swallowing non-fatal errors, but being able to
- // reproduce them at the end of the function.
- // An error is non-fatal if it is collection of non-fatal errors, or is
- // an individual error where IsRequiredNotSet or IsInvalidUTF8 reports true.
- //
- // Typical usage pattern:
- // var nerr errors.NonFatal
- // ...
- // if err := MyFunction(); !nerr.Merge(err) {
- // return nil, err // immediately return if err is fatal
- // }
- // ...
- // return out, nerr.E
- type NonFatal struct{ E error }
- // Merge merges err into nf and reports whether it was successful.
- // Otherwise it returns false for any fatal non-nil errors.
- func (nf *NonFatal) Merge(err error) (ok bool) {
- if err == nil {
- return true // not an error
- }
- if es, ok := err.(NonFatalErrors); ok {
- nf.append(es...)
- return true // merged a list of non-fatal errors
- }
- if e, ok := err.(interface{ RequiredNotSet() bool }); ok && e.RequiredNotSet() {
- nf.append(err)
- return true // non-fatal RequiredNotSet error
- }
- if e, ok := err.(interface{ InvalidUTF8() bool }); ok && e.InvalidUTF8() {
- nf.append(err)
- return true // non-fatal InvalidUTF8 error
- }
- return false // fatal error
- }
- // AppendRequiredNotSet appends a RequiredNotSet error.
- func (nf *NonFatal) AppendRequiredNotSet(field string) {
- nf.append(requiredNotSetError(field))
- }
- // AppendInvalidUTF8 appends an InvalidUTF8 error.
- func (nf *NonFatal) AppendInvalidUTF8(field string) {
- nf.append(invalidUTF8Error(field))
- }
- func (nf *NonFatal) append(errs ...error) {
- es, _ := nf.E.(NonFatalErrors)
- es = append(es, errs...)
- nf.E = es
- }
- type requiredNotSetError string
- func (e requiredNotSetError) Error() string {
- if e == "" {
- return "required field not set"
- }
- return string("required field " + e + " not set")
- }
- func (requiredNotSetError) RequiredNotSet() bool { return true }
- type invalidUTF8Error string
- func (e invalidUTF8Error) Error() string {
- if e == "" {
- return "invalid UTF-8 detected"
- }
- return string("field " + e + " contains invalid UTF-8")
- }
- func (invalidUTF8Error) InvalidUTF8() bool { return true }
- // New formats a string according to the format specifier and arguments and
- // returns an error that has a "proto" prefix.
- func New(f string, x ...interface{}) error {
- for i := 0; i < len(x); i++ {
- if e, ok := x[i].(prefixError); ok {
- x[i] = e.s // avoid "proto: " prefix when chaining
- }
- }
- return &prefixError{s: fmt.Sprintf(f, x...)}
- }
- type prefixError struct{ s string }
- func (e *prefixError) Error() string { return "proto: " + e.s }
|