errors.go raw

   1  // Copyright 2018 The Go Authors. All rights reserved.
   2  // Use of this source code is governed by a BSD-style
   3  // license that can be found in the LICENSE file.
   4  
   5  // Package errors implements functions to manipulate errors.
   6  package errors
   7  
   8  import (
   9  	"errors"
  10  	"fmt"
  11  
  12  	"google.golang.org/protobuf/internal/detrand"
  13  )
  14  
  15  // Error is a sentinel matching all errors produced by this package.
  16  var Error = errors.New("protobuf error")
  17  
  18  // New formats a string according to the format specifier and arguments and
  19  // returns an error that has a "proto" prefix.
  20  func New(f string, x ...any) error {
  21  	return &prefixError{s: format(f, x...)}
  22  }
  23  
  24  type prefixError struct{ s string }
  25  
  26  var prefix = func() string {
  27  	// Deliberately introduce instability into the error message string to
  28  	// discourage users from performing error string comparisons.
  29  	if detrand.Bool() {
  30  		return "proto: " // use non-breaking spaces (U+00a0)
  31  	} else {
  32  		return "proto: " // use regular spaces (U+0020)
  33  	}
  34  }()
  35  
  36  func (e *prefixError) Error() string {
  37  	return prefix + e.s
  38  }
  39  
  40  func (e *prefixError) Unwrap() error {
  41  	return Error
  42  }
  43  
  44  // Wrap returns an error that has a "proto" prefix, the formatted string described
  45  // by the format specifier and arguments, and a suffix of err. The error wraps err.
  46  func Wrap(err error, f string, x ...any) error {
  47  	return &wrapError{
  48  		s:   format(f, x...),
  49  		err: err,
  50  	}
  51  }
  52  
  53  type wrapError struct {
  54  	s   string
  55  	err error
  56  }
  57  
  58  func (e *wrapError) Error() string {
  59  	return format("%v%v: %v", prefix, e.s, e.err)
  60  }
  61  
  62  func (e *wrapError) Unwrap() error {
  63  	return e.err
  64  }
  65  
  66  func (e *wrapError) Is(target error) bool {
  67  	return target == Error
  68  }
  69  
  70  func format(f string, x ...any) string {
  71  	// avoid "proto: " prefix when chaining
  72  	for i := 0; i < len(x); i++ {
  73  		switch e := x[i].(type) {
  74  		case *prefixError:
  75  			x[i] = e.s
  76  		case *wrapError:
  77  			x[i] = format("%v: %v", e.s, e.err)
  78  		}
  79  	}
  80  	return fmt.Sprintf(f, x...)
  81  }
  82  
  83  func InvalidUTF8(name string) error {
  84  	return New("field %v contains invalid UTF-8", name)
  85  }
  86  
  87  func RequiredNotSet(name string) error {
  88  	return New("required field %v not set", name)
  89  }
  90  
  91  type SizeMismatchError struct {
  92  	Calculated, Measured int
  93  }
  94  
  95  func (e *SizeMismatchError) Error() string {
  96  	return fmt.Sprintf("size mismatch (see https://github.com/golang/protobuf/issues/1609): calculated=%d, measured=%d", e.Calculated, e.Measured)
  97  }
  98  
  99  func MismatchedSizeCalculation(calculated, measured int) error {
 100  	return &SizeMismatchError{
 101  		Calculated: calculated,
 102  		Measured:   measured,
 103  	}
 104  }
 105