blob: cbd924842e24b8eee03b90441a9bf711c4ee31c9 [file] [log] [blame]
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package fidl
import (
"reflect"
"strconv"
)
// ValidationError represents an error produced in validating a FIDL structure.
type ValidationError interface {
error
// Code returns the underlying ErrorCode value, which all ValidationErrors
// must have.
Code() ErrorCode
}
// Assert that valueError and expectError both implement the ValidationError
// interface.
var _ = []ValidationError{
valueError{},
expectError{},
}
// ErrorCode represents a set of machine-readable error codes each ValidationError
// has.
type ErrorCode uint32
const (
Invalid ErrorCode = iota
ErrUnknownOrdinal
ErrInvalidInlineType
ErrInvalidPointerType
ErrVectorTooLong
ErrStringTooLong
ErrUnexpectedOrdinal
ErrUnexpectedNullRef
ErrInvalidBoolValue
ErrNotEnoughHandles
ErrTooManyBytesInMessage
ErrTooManyHandles
ErrBadHandleEncoding
ErrNonZeroPadding
ErrBadRefEncoding
ErrBadInlineIndicatorEncoding
ErrStructIsNotPayload
ErrInvalidUnionTag
ErrInvalidXUnionTag
ErrInvalidBitsValue
ErrInvalidEnumValue
ErrPayloadTooSmall
ErrInvalidEmptyStruct
ErrInvalidNumBytesInEnvelope
ErrInvalidNumHandlesInEnvelope
ErrStringNotUTF8
ErrUnknownMagic
ErrMissingRequiredHandleRights
ErrUnableToReduceHandleRights
ErrUnspecifiedHandleRights
ErrMissingMarshalerContext
ErrResponseWithoutRequest
ErrDuplicateTxidReceived
ErrDuplicateTxidWaiting
ErrIncorrectHandleType
ErrUnspecifiedHandleType
ErrValueTypeHandles
ErrExceededMaxOutOfLineDepth
ErrInvalidInlineBitValueInEnvelope
ErrUnsupportedWireFormatVersion
)
var errorCodeNames = []string{
Invalid: "Invalid",
ErrUnknownOrdinal: "ErrUnknownOrdinal",
ErrInvalidInlineType: "ErrInvalidInlineType",
ErrInvalidPointerType: "ErrInvalidPointerType",
ErrVectorTooLong: "ErrVectorTooLong",
ErrStringTooLong: "ErrStringTooLong",
ErrUnexpectedOrdinal: "ErrUnexpectedOrdinal",
ErrUnexpectedNullRef: "ErrUnexpectedNullRef",
ErrInvalidBoolValue: "ErrInvalidBoolValue",
ErrNotEnoughHandles: "ErrNotEnoughHandles",
ErrTooManyBytesInMessage: "ErrTooManyBytesInMessage",
ErrTooManyHandles: "ErrTooManyHandles",
ErrNonZeroPadding: "ErrNonZeroPadding",
ErrBadHandleEncoding: "ErrBadHandleEncoding",
ErrBadRefEncoding: "ErrBadRefEncoding",
ErrBadInlineIndicatorEncoding: "ErrBadInlineIndicatorEncoding",
ErrStructIsNotPayload: "ErrStructIsNotPayload",
ErrInvalidUnionTag: "ErrInvalidUnionTag",
ErrInvalidXUnionTag: "ErrInvalidXUnionTag",
ErrInvalidBitsValue: "ErrInvalidBitsValue",
ErrInvalidEnumValue: "ErrInvalidEnumValue",
ErrPayloadTooSmall: "ErrPayloadTooSmall",
ErrInvalidEmptyStruct: "ErrInvalidEmptyStruct",
ErrInvalidNumBytesInEnvelope: "ErrInvalidNumBytesInEnvelope",
ErrInvalidNumHandlesInEnvelope: "ErrInvalidNumHandlesInEnvelope",
ErrStringNotUTF8: "ErrStringNotUTF8",
ErrUnknownMagic: "ErrUnknownMagic",
ErrMissingRequiredHandleRights: "ErrMissingRequiredHandleRights",
ErrUnableToReduceHandleRights: "ErrUnableToReduceHandleRights",
ErrUnspecifiedHandleRights: "ErrUnspecifiedHandleRights",
ErrMissingMarshalerContext: "ErrMissingMarshalerContext",
ErrResponseWithoutRequest: "ErrResponseWithoutRequest",
ErrDuplicateTxidReceived: "ErrDuplicateTxidReceived",
ErrDuplicateTxidWaiting: "ErrDuplicateTxidWaiting",
ErrIncorrectHandleType: "ErrIncorrectHandleType",
ErrUnspecifiedHandleType: "ErrUnspecifiedHandleType",
ErrValueTypeHandles: "ErrValueTypeHandles",
ErrExceededMaxOutOfLineDepth: "ErrExceededMaxOutOfLineDepth",
ErrInvalidInlineBitValueInEnvelope: "ErrInvalidInlineBitValueInEnvelope",
ErrUnsupportedWireFormatVersion: "ErrUnsupportedWireFormatVersion",
}
func (c ErrorCode) String() string {
if len(errorCodeNames) < int(c) {
return strconv.Itoa(int(c))
}
return errorCodeNames[int(c)]
}
// Error implements error for ErrorCode
func (e ErrorCode) Error() string {
switch e {
case ErrUnknownOrdinal:
return "unknown ordinal"
case ErrInvalidInlineType:
return "invalid inline type"
case ErrInvalidPointerType:
return "invalid pointer type"
case ErrVectorTooLong:
return "vector exceeds maximum size"
case ErrStringTooLong:
return "string exceeds maximum size"
case ErrUnexpectedOrdinal:
return "unexpected ordinal"
case ErrUnexpectedNullRef:
return "unexpected null reference"
case ErrInvalidBoolValue:
return "unexpected boolean value"
case ErrNotEnoughHandles:
return "not enough handles"
case ErrTooManyHandles:
return "too many handles"
case ErrBadHandleEncoding:
return "bad encoding for handle"
case ErrNonZeroPadding:
return "invalid non-zero padding"
case ErrBadRefEncoding:
return "bad encoding for ref"
case ErrBadInlineIndicatorEncoding:
return "bad encoding for inline indicator"
case ErrStructIsNotPayload:
return "golang struct type must implement Payload"
case ErrInvalidUnionTag:
return "union tag out of bounds"
case ErrInvalidXUnionTag:
return "strict xunion has unknown tag"
case ErrInvalidBitsValue:
return "invalid bits value"
case ErrInvalidEnumValue:
return "invalid enum value"
case ErrPayloadTooSmall:
return "payload too small"
case ErrInvalidEmptyStruct:
return "invalid empty struct"
case ErrInvalidNumBytesInEnvelope:
return "unexpected num bytes in envelope"
case ErrInvalidNumHandlesInEnvelope:
return "unexpected num handles in envelope"
case ErrStringNotUTF8:
return "string is not valid UTF8"
case ErrUnknownMagic:
return "header magic number is not supported"
case ErrMissingRequiredHandleRights:
return "missing required handle rights"
case ErrUnableToReduceHandleRights:
return "unable to reduce handle rights"
case ErrUnspecifiedHandleRights:
return "handle rights are unspecified"
case ErrMissingMarshalerContext:
return "missing marshaler context"
case ErrResponseWithoutRequest:
return "received response without request (unexpected transaction id in mesage)"
case ErrDuplicateTxidReceived:
return "received multiple messages with the same transaction id"
case ErrDuplicateTxidWaiting:
return "multiple channel calls waiting on same transaction id"
case ErrIncorrectHandleType:
return "handle type is incorrect"
case ErrUnspecifiedHandleType:
return "handle type is unspecified"
case ErrValueTypeHandles:
return "cannot encode or decode value type with handles in unknown data"
case ErrExceededMaxOutOfLineDepth:
return "exceeded maxOutOfLineDepth"
case ErrInvalidInlineBitValueInEnvelope:
return "invalid inline bit value in envelope"
case ErrUnsupportedWireFormatVersion:
return "wire format version is not supported"
default:
return e.String()
}
}
// Code implements the ValidationError interface.
func (e ErrorCode) Code() ErrorCode {
return e
}
// stringer is an interface for types for which a string representation
// may be derived.
type stringer interface {
String() string
}
// toString generates the string representation for a limited set of types.
func toString(value interface{}) string {
if e, ok := value.(error); ok {
return e.Error()
}
if s, ok := value.(stringer); ok {
return s.String()
}
if numbers, ok := value.([]uint64); ok {
s := "["
for _, num := range numbers {
s += strconv.FormatUint(num, 10)
s += " "
}
s += "]"
return s
}
t := reflect.TypeOf(value)
switch t.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return strconv.FormatInt(reflect.ValueOf(value).Int(), 10)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return strconv.FormatUint(reflect.ValueOf(value).Uint(), 10)
case reflect.String:
return value.(string)
default:
return "##BADVALUE##"
}
}
// valueError represents an error that refers to a single value.
type valueError struct {
ErrorCode
value interface{}
}
func newValueError(code ErrorCode, value interface{}) valueError {
return valueError{
ErrorCode: code,
value: value,
}
}
func (e valueError) Error() string {
return e.ErrorCode.Error() + ": " + toString(e.value)
}
func (e valueError) Unwrap() error {
return e.ErrorCode
}
// expectError represents an error that refers to the expectation of a
// certain value, and displays a comparison between the actual value and
// the expected value.
type expectError struct {
ErrorCode
expect interface{}
actual interface{}
}
func newExpectError(code ErrorCode, expect, actual interface{}) expectError {
return expectError{
ErrorCode: code,
expect: expect,
actual: actual,
}
}
func (e expectError) Error() string {
return e.ErrorCode.Error() + ": expected " + toString(e.expect) + ", got " + toString(e.actual)
}
func (e expectError) Unwrap() error {
return e.ErrorCode
}