| // 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. |
| |
| // +build fuchsia |
| |
| 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 |
| ErrEnvelopeTooLong |
| ErrUnexpectedOrdinal |
| ErrUnexpectedNullHandle |
| ErrUnexpectedNullRef |
| ErrInvalidBoolValue |
| ErrNotEnoughHandles |
| ErrTooManyHandles |
| ErrBadHandleEncoding |
| ErrNonZeroPadding |
| ErrBadRefEncoding |
| ErrMessageTooSmall |
| ErrStructIsNotPayload |
| ErrInvalidUnionTag |
| ErrInvalidXUnionTag |
| ErrPayloadTooSmall |
| ErrInvalidEmptyStruct |
| ErrUnexpectedNumBytes |
| ErrUnexpectedNumHandles |
| ErrStringNotUTF8 |
| ErrUnknownMagic |
| ) |
| |
| var errorCodeNames = []string{ |
| Invalid: "Invalid", |
| ErrUnknownOrdinal: "ErrUnknownOrdinal", |
| ErrInvalidInlineType: "ErrInvalidInlineType", |
| ErrInvalidPointerType: "ErrInvalidPointerType", |
| ErrVectorTooLong: "ErrVectorTooLong", |
| ErrStringTooLong: "ErrStringTooLong", |
| ErrEnvelopeTooLong: "ErrEnvelopeTooLong", |
| ErrUnexpectedOrdinal: "ErrUnexpectedOrdinal", |
| ErrUnexpectedNullHandle: "ErrUnexpectedNullHandle", |
| ErrUnexpectedNullRef: "ErrUnexpectedNullRef", |
| ErrInvalidBoolValue: "ErrInvalidBoolValue", |
| ErrNotEnoughHandles: "ErrNotEnoughHandles", |
| ErrTooManyHandles: "ErrTooManyHandles", |
| ErrNonZeroPadding: "ErrNonZeroPadding", |
| ErrBadHandleEncoding: "ErrBadHandleEncoding", |
| ErrBadRefEncoding: "ErrBadRefEncoding", |
| ErrMessageTooSmall: "ErrMessageTooSmall", |
| ErrStructIsNotPayload: "ErrStructIsNotPayload", |
| ErrInvalidUnionTag: "ErrInvalidUnionTag", |
| ErrInvalidXUnionTag: "ErrInvalidXUnionTag", |
| ErrPayloadTooSmall: "ErrPayloadTooSmall", |
| ErrInvalidEmptyStruct: "ErrInvalidEmptyStruct", |
| ErrUnexpectedNumBytes: "ErrUnexpectedNumBytes", |
| ErrUnexpectedNumHandles: "ErrUnexpectedNumHandles", |
| ErrStringNotUTF8: "ErrStringNotUTF8", |
| ErrUnknownMagic: "ErrUnknownMagic", |
| } |
| |
| 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 ErrEnvelopeTooLong: |
| return "envelope exceeds maximum size" |
| case ErrUnexpectedOrdinal: |
| return "unexpected ordinal" |
| case ErrUnexpectedNullHandle: |
| return "unexpected null handle" |
| 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 ErrMessageTooSmall: |
| return "message too small to have FIDL header" |
| 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 ErrPayloadTooSmall: |
| return "payload too small" |
| case ErrInvalidEmptyStruct: |
| return "invalid empty struct" |
| case ErrUnexpectedNumBytes: |
| return "unexpected num bytes" |
| case ErrUnexpectedNumHandles: |
| return "unexpected num handles" |
| case ErrStringNotUTF8: |
| return "string is not valid UTF8" |
| case ErrUnknownMagic: |
| return "header magic number 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) |
| } |
| |
| // 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) |
| } |