github.com/davecgh/go-xdr@v0.0.0-20161123171359-e6a2ba005892/xdr2/error.go (about)

     1  /*
     2   * Copyright (c) 2012-2014 Dave Collins <dave@davec.name>
     3   *
     4   * Permission to use, copy, modify, and distribute this software for any
     5   * purpose with or without fee is hereby granted, provided that the above
     6   * copyright notice and this permission notice appear in all copies.
     7   *
     8   * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     9   * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    10   * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    11   * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    12   * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    13   * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    14   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    15   */
    16  
    17  package xdr
    18  
    19  import "fmt"
    20  
    21  // ErrorCode identifies a kind of error.
    22  type ErrorCode int
    23  
    24  const (
    25  	// ErrBadArguments indicates arguments passed to the function are not
    26  	// what was expected.
    27  	ErrBadArguments ErrorCode = iota
    28  
    29  	// ErrUnsupportedType indicates the Go type is not a supported type for
    30  	// marshalling and unmarshalling XDR data.
    31  	ErrUnsupportedType
    32  
    33  	// ErrBadEnumValue indicates an enumeration value is not in the list of
    34  	// valid values.
    35  	ErrBadEnumValue
    36  
    37  	// ErrNotSettable indicates an interface value cannot be written to.
    38  	// This usually means the interface value was not passed with the &
    39  	// operator, but it can also happen if automatic pointer allocation
    40  	// fails.
    41  	ErrNotSettable
    42  
    43  	// ErrOverflow indicates that the data in question is too large to fit
    44  	// into the corresponding Go or XDR data type.  For example, an integer
    45  	// decoded from XDR that is too large to fit into a target type of int8,
    46  	// or opaque data that exceeds the max length of a Go slice.
    47  	ErrOverflow
    48  
    49  	// ErrNilInterface indicates an interface with no concrete type
    50  	// information was encountered.  Type information is necessary to
    51  	// perform mapping between XDR and Go types.
    52  	ErrNilInterface
    53  
    54  	// ErrIO indicates an error was encountered while reading or writing to
    55  	// an io.Reader or io.Writer, respectively.  The actual underlying error
    56  	// will be available via the Err field of the MarshalError or
    57  	// UnmarshalError struct.
    58  	ErrIO
    59  
    60  	// ErrParseTime indicates an error was encountered while parsing an
    61  	// RFC3339 formatted time value.  The actual underlying error will be
    62  	// available via the Err field of the UnmarshalError struct.
    63  	ErrParseTime
    64  )
    65  
    66  // Map of ErrorCode values back to their constant names for pretty printing.
    67  var errorCodeStrings = map[ErrorCode]string{
    68  	ErrBadArguments:    "ErrBadArguments",
    69  	ErrUnsupportedType: "ErrUnsupportedType",
    70  	ErrBadEnumValue:    "ErrBadEnumValue",
    71  	ErrNotSettable:     "ErrNotSettable",
    72  	ErrOverflow:        "ErrOverflow",
    73  	ErrNilInterface:    "ErrNilInterface",
    74  	ErrIO:              "ErrIO",
    75  	ErrParseTime:       "ErrParseTime",
    76  }
    77  
    78  // String returns the ErrorCode as a human-readable name.
    79  func (e ErrorCode) String() string {
    80  	if s := errorCodeStrings[e]; s != "" {
    81  		return s
    82  	}
    83  	return fmt.Sprintf("Unknown ErrorCode (%d)", e)
    84  }
    85  
    86  // UnmarshalError describes a problem encountered while unmarshaling data.
    87  // Some potential issues are unsupported Go types, attempting to decode a value
    88  // which is too large to fit into a specified Go type, and exceeding max slice
    89  // limitations.
    90  type UnmarshalError struct {
    91  	ErrorCode   ErrorCode   // Describes the kind of error
    92  	Func        string      // Function name
    93  	Value       interface{} // Value actually parsed where appropriate
    94  	Description string      // Human readable description of the issue
    95  	Err         error       // The underlying error for IO errors
    96  }
    97  
    98  // Error satisfies the error interface and prints human-readable errors.
    99  func (e *UnmarshalError) Error() string {
   100  	switch e.ErrorCode {
   101  	case ErrBadEnumValue, ErrOverflow, ErrIO, ErrParseTime:
   102  		return fmt.Sprintf("xdr:%s: %s - read: '%v'", e.Func,
   103  			e.Description, e.Value)
   104  	}
   105  	return fmt.Sprintf("xdr:%s: %s", e.Func, e.Description)
   106  }
   107  
   108  // unmarshalError creates an error given a set of arguments and will copy byte
   109  // slices into the Value field since they might otherwise be changed from from
   110  // the original value.
   111  func unmarshalError(f string, c ErrorCode, desc string, v interface{}, err error) *UnmarshalError {
   112  	e := &UnmarshalError{ErrorCode: c, Func: f, Description: desc, Err: err}
   113  	switch t := v.(type) {
   114  	case []byte:
   115  		slice := make([]byte, len(t))
   116  		copy(slice, t)
   117  		e.Value = slice
   118  	default:
   119  		e.Value = v
   120  	}
   121  
   122  	return e
   123  }
   124  
   125  // IsIO returns a boolean indicating whether the error is known to report that
   126  // the underlying reader or writer encountered an ErrIO.
   127  func IsIO(err error) bool {
   128  	switch e := err.(type) {
   129  	case *UnmarshalError:
   130  		return e.ErrorCode == ErrIO
   131  	case *MarshalError:
   132  		return e.ErrorCode == ErrIO
   133  	}
   134  	return false
   135  }
   136  
   137  // MarshalError describes a problem encountered while marshaling data.
   138  // Some potential issues are unsupported Go types, attempting to encode more
   139  // opaque data than can be represented by a single opaque XDR entry, and
   140  // exceeding max slice limitations.
   141  type MarshalError struct {
   142  	ErrorCode   ErrorCode   // Describes the kind of error
   143  	Func        string      // Function name
   144  	Value       interface{} // Value actually parsed where appropriate
   145  	Description string      // Human readable description of the issue
   146  	Err         error       // The underlying error for IO errors
   147  }
   148  
   149  // Error satisfies the error interface and prints human-readable errors.
   150  func (e *MarshalError) Error() string {
   151  	switch e.ErrorCode {
   152  	case ErrIO:
   153  		return fmt.Sprintf("xdr:%s: %s - wrote: '%v'", e.Func,
   154  			e.Description, e.Value)
   155  	case ErrBadEnumValue:
   156  		return fmt.Sprintf("xdr:%s: %s - value: '%v'", e.Func,
   157  			e.Description, e.Value)
   158  	}
   159  	return fmt.Sprintf("xdr:%s: %s", e.Func, e.Description)
   160  }
   161  
   162  // marshalError creates an error given a set of arguments and will copy byte
   163  // slices into the Value field since they might otherwise be changed from from
   164  // the original value.
   165  func marshalError(f string, c ErrorCode, desc string, v interface{}, err error) *MarshalError {
   166  	e := &MarshalError{ErrorCode: c, Func: f, Description: desc, Err: err}
   167  	switch t := v.(type) {
   168  	case []byte:
   169  		slice := make([]byte, len(t))
   170  		copy(slice, t)
   171  		e.Value = slice
   172  	default:
   173  		e.Value = v
   174  	}
   175  
   176  	return e
   177  }