github.com/stellar/go-xdr@v0.0.0-20231122183749-b53fb00bcac2/xdr3/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 (
    20  	"fmt"
    21  )
    22  
    23  // ErrorCode identifies a kind of error.
    24  type ErrorCode int
    25  
    26  const (
    27  	// ErrBadArguments indicates arguments passed to the function are not
    28  	// what was expected.
    29  	ErrBadArguments ErrorCode = iota
    30  
    31  	// ErrUnsupportedType indicates the Go type is not a supported type for
    32  	// marshalling and unmarshalling XDR data.
    33  	ErrUnsupportedType
    34  
    35  	// ErrBadEnumValue indicates an enumeration value is not in the list of
    36  	// valid values.
    37  	ErrBadEnumValue
    38  
    39  	// ErrNotSettable indicates an interface value cannot be written to.
    40  	// This usually means the interface value was not passed with the &
    41  	// operator, but it can also happen if automatic pointer allocation
    42  	// fails.
    43  	ErrNotSettable
    44  
    45  	// ErrOverflow indicates that the data in question is too large to fit
    46  	// into the corresponding Go or XDR data type or that allocating it exceeds the
    47  	// maximum allocation size limit.  For example, an integer
    48  	// decoded from XDR that is too large to fit into a target type of int8,
    49  	// or opaque data that exceeds the max length of a Go slice.
    50  	ErrOverflow
    51  
    52  	// ErrNilInterface indicates an interface with no concrete type
    53  	// information was encountered.  Type information is necessary to
    54  	// perform mapping between XDR and Go types.
    55  	ErrNilInterface
    56  
    57  	// ErrIO indicates an error was encountered while reading or writing to
    58  	// an io.Reader or io.Writer, respectively.  The actual underlying error
    59  	// will be available via the Err field of the MarshalError or
    60  	// UnmarshalError struct.
    61  	ErrIO
    62  
    63  	// ErrParseTime indicates an error was encountered while parsing an
    64  	// RFC3339 formatted time value.  The actual underlying error will be
    65  	// available via the Err field of the UnmarshalError struct.
    66  	ErrParseTime
    67  
    68  	// ErrBadUnionSwitch indicates a union's disciminant is invalid
    69  	ErrBadUnionSwitch
    70  
    71  	// ErrBadUnionValue indicates a union's value is not populated when it should
    72  	// be
    73  	ErrBadUnionValue
    74  
    75  	// ErrMaxDecodingDepth indicates that the maximum decoding depth was reached
    76  	ErrMaxDecodingDepth
    77  )
    78  
    79  // Map of ErrorCode values back to their constant names for pretty printing.
    80  var errorCodeStrings = map[ErrorCode]string{
    81  	ErrBadArguments:     "ErrBadArguments",
    82  	ErrUnsupportedType:  "ErrUnsupportedType",
    83  	ErrBadEnumValue:     "ErrBadEnumValue",
    84  	ErrNotSettable:      "ErrNotSettable",
    85  	ErrOverflow:         "ErrOverflow",
    86  	ErrNilInterface:     "ErrNilInterface",
    87  	ErrIO:               "ErrIO",
    88  	ErrParseTime:        "ErrParseTime",
    89  	ErrBadUnionSwitch:   "ErrBadUnionSwitch",
    90  	ErrBadUnionValue:    "ErrBadUnionValue",
    91  	ErrMaxDecodingDepth: "ErrMaxDecodingDepth",
    92  }
    93  
    94  // String returns the ErrorCode as a human-readable name.
    95  func (e ErrorCode) String() string {
    96  	if s := errorCodeStrings[e]; s != "" {
    97  		return s
    98  	}
    99  	return fmt.Sprintf("Unknown ErrorCode (%d)", e)
   100  }
   101  
   102  // UnmarshalError describes a problem encountered while unmarshaling data.
   103  // Some potential issues are unsupported Go types, attempting to decode a value
   104  // which is too large to fit into a specified Go type, and exceeding max slice
   105  // limitations.
   106  type UnmarshalError struct {
   107  	ErrorCode   ErrorCode   // Describes the kind of error
   108  	Func        string      // Function name
   109  	Value       interface{} // Value actually parsed where appropriate
   110  	Description string      // Human readable description of the issue
   111  	Err         error       // The underlying error for IO errors
   112  }
   113  
   114  // Unwrap returns the underlying error if there is one.
   115  func (e *UnmarshalError) Unwrap() error {
   116  	return e.Err
   117  }
   118  
   119  // Error satisfies the error interface and prints human-readable errors.
   120  func (e *UnmarshalError) Error() string {
   121  	switch e.ErrorCode {
   122  	case ErrBadEnumValue, ErrOverflow, ErrIO, ErrParseTime:
   123  		return fmt.Sprintf("xdr:%s: %s - read: '%v'", e.Func,
   124  			e.Description, e.Value)
   125  	}
   126  	return fmt.Sprintf("xdr:%s: %s", e.Func, e.Description)
   127  }
   128  
   129  // unmarshalError creates an error given a set of arguments and will copy byte
   130  // slices into the Value field since they might otherwise be changed from
   131  // the original value.
   132  func unmarshalError(f string, c ErrorCode, desc string, v interface{}, err error) *UnmarshalError {
   133  	e := &UnmarshalError{ErrorCode: c, Func: f, Description: desc, Err: err}
   134  	switch t := v.(type) {
   135  	case []byte:
   136  		slice := make([]byte, len(t))
   137  		copy(slice, t)
   138  		e.Value = slice
   139  	default:
   140  		e.Value = v
   141  	}
   142  
   143  	return e
   144  }
   145  
   146  // MarshalError describes a problem encountered while marshaling data.
   147  // Some potential issues are unsupported Go types, attempting to encode more
   148  // opaque data than can be represented by a single opaque XDR entry, and
   149  // exceeding max slice limitations.
   150  type MarshalError struct {
   151  	ErrorCode   ErrorCode   // Describes the kind of error
   152  	Func        string      // Function name
   153  	Value       interface{} // Value actually parsed where appropriate
   154  	Description string      // Human readable description of the issue
   155  	Err         error       // The underlying error for IO errors
   156  }
   157  
   158  // Unwrap returns the underlying error if there is one.
   159  func (e *MarshalError) Unwrap() error {
   160  	return e.Err
   161  }
   162  
   163  // Error satisfies the error interface and prints human-readable errors.
   164  func (e *MarshalError) Error() string {
   165  	switch e.ErrorCode {
   166  	case ErrIO:
   167  		return fmt.Sprintf("xdr:%s: %s - wrote: '%v'", e.Func,
   168  			e.Description, e.Value)
   169  	case ErrBadEnumValue:
   170  		return fmt.Sprintf("xdr:%s: %s - value: '%v'", e.Func,
   171  			e.Description, e.Value)
   172  	}
   173  	return fmt.Sprintf("xdr:%s: %s", e.Func, e.Description)
   174  }
   175  
   176  // marshalError creates an error given a set of arguments and will copy byte
   177  // slices into the Value field since they might otherwise be changed from from
   178  // the original value.
   179  func marshalError(f string, c ErrorCode, desc string, v interface{}, err error) *MarshalError {
   180  	e := &MarshalError{ErrorCode: c, Func: f, Description: desc, Err: err}
   181  	switch t := v.(type) {
   182  	case []byte:
   183  		slice := make([]byte, len(t))
   184  		copy(slice, t)
   185  		e.Value = slice
   186  	default:
   187  		e.Value = v
   188  	}
   189  
   190  	return e
   191  }