summaryrefslogtreecommitdiff
path: root/vendor/github.com/digitalocean/go-libvirt/internal/go-xdr/xdr2/error.go
blob: 42079ad3542b44a21346ef0cabdc8951816540e8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
/*
 * Copyright (c) 2012-2014 Dave Collins <dave@davec.name>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package xdr

import "fmt"

// ErrorCode identifies a kind of error.
type ErrorCode int

const (
	// ErrBadArguments indicates arguments passed to the function are not
	// what was expected.
	ErrBadArguments ErrorCode = iota

	// ErrUnsupportedType indicates the Go type is not a supported type for
	// marshalling and unmarshalling XDR data.
	ErrUnsupportedType

	// ErrBadEnumValue indicates an enumeration value is not in the list of
	// valid values.
	ErrBadEnumValue

	// ErrNotSettable indicates an interface value cannot be written to.
	// This usually means the interface value was not passed with the &
	// operator, but it can also happen if automatic pointer allocation
	// fails.
	ErrNotSettable

	// ErrOverflow indicates that the data in question is too large to fit
	// into the corresponding Go or XDR data type.  For example, an integer
	// decoded from XDR that is too large to fit into a target type of int8,
	// or opaque data that exceeds the max length of a Go slice.
	ErrOverflow

	// ErrNilInterface indicates an interface with no concrete type
	// information was encountered.  Type information is necessary to
	// perform mapping between XDR and Go types.
	ErrNilInterface

	// ErrIO indicates an error was encountered while reading or writing to
	// an io.Reader or io.Writer, respectively.  The actual underlying error
	// will be available via the Err field of the MarshalError or
	// UnmarshalError struct.
	ErrIO

	// ErrParseTime indicates an error was encountered while parsing an
	// RFC3339 formatted time value.  The actual underlying error will be
	// available via the Err field of the UnmarshalError struct.
	ErrParseTime
)

// Map of ErrorCode values back to their constant names for pretty printing.
var errorCodeStrings = map[ErrorCode]string{
	ErrBadArguments:    "ErrBadArguments",
	ErrUnsupportedType: "ErrUnsupportedType",
	ErrBadEnumValue:    "ErrBadEnumValue",
	ErrNotSettable:     "ErrNotSettable",
	ErrOverflow:        "ErrOverflow",
	ErrNilInterface:    "ErrNilInterface",
	ErrIO:              "ErrIO",
	ErrParseTime:       "ErrParseTime",
}

// String returns the ErrorCode as a human-readable name.
func (e ErrorCode) String() string {
	if s := errorCodeStrings[e]; s != "" {
		return s
	}
	return fmt.Sprintf("Unknown ErrorCode (%d)", e)
}

// UnmarshalError describes a problem encountered while unmarshaling data.
// Some potential issues are unsupported Go types, attempting to decode a value
// which is too large to fit into a specified Go type, and exceeding max slice
// limitations.
type UnmarshalError struct {
	ErrorCode   ErrorCode   // Describes the kind of error
	Func        string      // Function name
	Value       interface{} // Value actually parsed where appropriate
	Description string      // Human readable description of the issue
	Err         error       // The underlying error for IO errors
}

// Error satisfies the error interface and prints human-readable errors.
func (e *UnmarshalError) Error() string {
	switch e.ErrorCode {
	case ErrBadEnumValue, ErrOverflow, ErrIO, ErrParseTime:
		return fmt.Sprintf("xdr:%s: %s - read: '%v'", e.Func,
			e.Description, e.Value)
	}
	return fmt.Sprintf("xdr:%s: %s", e.Func, e.Description)
}

// unmarshalError creates an error given a set of arguments and will copy byte
// slices into the Value field since they might otherwise be changed from from
// the original value.
func unmarshalError(f string, c ErrorCode, desc string, v interface{}, err error) *UnmarshalError {
	e := &UnmarshalError{ErrorCode: c, Func: f, Description: desc, Err: err}
	switch t := v.(type) {
	case []byte:
		slice := make([]byte, len(t))
		copy(slice, t)
		e.Value = slice
	default:
		e.Value = v
	}

	return e
}

// IsIO returns a boolean indicating whether the error is known to report that
// the underlying reader or writer encountered an ErrIO.
func IsIO(err error) bool {
	switch e := err.(type) {
	case *UnmarshalError:
		return e.ErrorCode == ErrIO
	case *MarshalError:
		return e.ErrorCode == ErrIO
	}
	return false
}

// MarshalError describes a problem encountered while marshaling data.
// Some potential issues are unsupported Go types, attempting to encode more
// opaque data than can be represented by a single opaque XDR entry, and
// exceeding max slice limitations.
type MarshalError struct {
	ErrorCode   ErrorCode   // Describes the kind of error
	Func        string      // Function name
	Value       interface{} // Value actually parsed where appropriate
	Description string      // Human readable description of the issue
	Err         error       // The underlying error for IO errors
}

// Error satisfies the error interface and prints human-readable errors.
func (e *MarshalError) Error() string {
	switch e.ErrorCode {
	case ErrIO:
		return fmt.Sprintf("xdr:%s: %s - wrote: '%v'", e.Func,
			e.Description, e.Value)
	case ErrBadEnumValue:
		return fmt.Sprintf("xdr:%s: %s - value: '%v'", e.Func,
			e.Description, e.Value)
	}
	return fmt.Sprintf("xdr:%s: %s", e.Func, e.Description)
}

// marshalError creates an error given a set of arguments and will copy byte
// slices into the Value field since they might otherwise be changed from from
// the original value.
func marshalError(f string, c ErrorCode, desc string, v interface{}, err error) *MarshalError {
	e := &MarshalError{ErrorCode: c, Func: f, Description: desc, Err: err}
	switch t := v.(type) {
	case []byte:
		slice := make([]byte, len(t))
		copy(slice, t)
		e.Value = slice
	default:
		e.Value = v
	}

	return e
}