| // 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 |
| } |