github.com/stellar/go-xdr@v0.0.0-20231122183749-b53fb00bcac2/xdr/error.go (about)

     1  /*
     2   * Copyright (c) 2012 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  	// ErrUnexpectedEnd indicates the end of a sequence of bytes was encountered
    36  	// before it was expected.  This typically indicates issues such as
    37  	// truncated data or improper structure.
    38  	ErrUnexpectedEnd
    39  
    40  	// ErrBadEnumValue indicates an enumeration value is not in the list of
    41  	// valid values.
    42  	ErrBadEnumValue
    43  
    44  	// ErrNotSettable indicates an interface value cannot be written to.  This
    45  	// usually means the interface value was not passed with the & operator, but
    46  	// it can also happen if automatic pointer allocation fails.
    47  	ErrNotSettable
    48  
    49  	// ErrOverflow indicates that the data in question is too large to fit into
    50  	// the corresponding Go or XDR data type.  For example, an integer decoded
    51  	// from XDR that is too large to fit into a target type of int8, or opaque
    52  	// data that exceeds the max length of a Go slice.
    53  	ErrOverflow
    54  
    55  	// ErrNilInterface indicates an interface with no concrete type information
    56  	// was encountered.  Type information is necessary to perform mapping
    57  	// between XDR and Go types.
    58  	ErrNilInterface
    59  )
    60  
    61  // Map of ErrorCode values back to their constant names for pretty printing.
    62  var errorCodeStrings = map[ErrorCode]string{
    63  	ErrBadArguments:    "ErrBadArguments",
    64  	ErrUnsupportedType: "ErrUnsupportedType",
    65  	ErrUnexpectedEnd:   "ErrUnexpectedEnd",
    66  	ErrBadEnumValue:    "ErrBadEnumValue",
    67  	ErrNotSettable:     "ErrNotSettable",
    68  	ErrOverflow:        "ErrOverflow",
    69  	ErrNilInterface:    "ErrNilInterface",
    70  }
    71  
    72  // String returns the ErrorCode as a human-readable name.
    73  func (e ErrorCode) String() string {
    74  	if s := errorCodeStrings[e]; s != "" {
    75  		return s
    76  	}
    77  	return fmt.Sprintf("Unknown ErrorCode (%d)", e)
    78  }
    79  
    80  // UnmarshalError describes a problem encountered while unmarshaling data.
    81  // Some potential issues are unsupported Go types, attempting to decode a value
    82  // which is too large to fit into a specified Go type, and exceeding max slice
    83  // limitations.
    84  type UnmarshalError struct {
    85  	ErrorCode   ErrorCode   // Describes the kind of error
    86  	Func        string      // Function name
    87  	Value       interface{} // Value actually parsed where appropriate
    88  	Description string      // Human readable description of the issue
    89  }
    90  
    91  // Error satisfies the error interface and prints human-readable errors.
    92  func (e *UnmarshalError) Error() string {
    93  	switch e.ErrorCode {
    94  	case ErrUnexpectedEnd, ErrBadEnumValue, ErrOverflow:
    95  		return fmt.Sprintf("xdr:%s: %s - read: '%v'", e.Func, e.Description, e.Value)
    96  	}
    97  	return fmt.Sprintf("xdr:%s: %s", e.Func, e.Description)
    98  }
    99  
   100  // unmarshalError creates an error given a set of arguments and will copy byte
   101  // slices into the Value field since they might otherwise be changed from from
   102  // the original value.
   103  func unmarshalError(f string, c ErrorCode, desc string, v interface{}) *UnmarshalError {
   104  	e := &UnmarshalError{ErrorCode: c, Func: f, Description: desc}
   105  	switch t := v.(type) {
   106  	case []byte:
   107  		slice := make([]byte, len(t))
   108  		copy(slice, t)
   109  		e.Value = slice
   110  	default:
   111  		e.Value = v
   112  	}
   113  
   114  	return e
   115  }
   116  
   117  // MarshalError describes a problem encountered while marshaling data.
   118  // Some potential issues are unsupported Go types, attempting to encode more
   119  // opaque data than can be represented by a single opaque XDR entry, and
   120  // exceeding max slice limitations.
   121  type MarshalError struct {
   122  	ErrorCode   ErrorCode   // Describes the kind of error
   123  	Func        string      // Function name
   124  	Value       interface{} // Value actually parsed where appropriate
   125  	Description string      // Human readable description of the issue
   126  }
   127  
   128  // Error satisfies the error interface and prints human-readable errors.
   129  func (e *MarshalError) Error() string {
   130  	switch e.ErrorCode {
   131  	case ErrUnexpectedEnd, ErrBadEnumValue, ErrOverflow:
   132  		return fmt.Sprintf("xdr:%s: %s - read: '%v'", e.Func, e.Description, e.Value)
   133  	}
   134  	return fmt.Sprintf("xdr:%s: %s", e.Func, e.Description)
   135  }
   136  
   137  // marshalError creates an error given a set of arguments and will copy byte
   138  // slices into the Value field since they might otherwise be changed from from
   139  // the original value.
   140  func marshalError(f string, c ErrorCode, desc string, v interface{}) *MarshalError {
   141  	e := &MarshalError{ErrorCode: c, Func: f, Description: desc}
   142  	switch t := v.(type) {
   143  	case []byte:
   144  		slice := make([]byte, len(t))
   145  		copy(slice, t)
   146  		e.Value = slice
   147  	default:
   148  		e.Value = v
   149  	}
   150  
   151  	return e
   152  }