go.sdls.io/sin@v0.0.9/pkg/sin/errors.go (about)

     1  // Copyright 2014 Manu Martinez-Almeida.  All rights reserved.
     2  // Use of this source code is governed by a MIT style
     3  // license that can be found in the LICENSE file.
     4  
     5  package sin
     6  
     7  import (
     8  	"encoding/json"
     9  	"fmt"
    10  	"reflect"
    11  	"strconv"
    12  	"strings"
    13  )
    14  
    15  // ErrorType is an unsigned 64-bit error code as defined in the gin spec.
    16  type ErrorType uint64
    17  
    18  const (
    19  	// ErrorTypeBind is used when Context.Bind() fails.
    20  	ErrorTypeBind ErrorType = 1 << 63
    21  	// ErrorTypeRender is used when Context.Render() fails.
    22  	ErrorTypeRender ErrorType = 1 << 62
    23  	// ErrorTypePrivate indicates a private error.
    24  	ErrorTypePrivate ErrorType = 1 << 0
    25  	// ErrorTypePublic indicates a public error.
    26  	ErrorTypePublic ErrorType = 1 << 1
    27  	// ErrorTypeAny indicates any other error.
    28  	ErrorTypeAny ErrorType = 1<<64 - 1
    29  	// ErrorTypeNu indicates any other error.
    30  	ErrorTypeNu = 2
    31  )
    32  
    33  // Error represents a error's specification.
    34  type Error struct {
    35  	Err  error
    36  	Meta interface{}
    37  	Type ErrorType
    38  }
    39  
    40  type errorMsgs []*Error
    41  
    42  var _ error = &Error{}
    43  
    44  // SetType sets the error's type.
    45  func (msg *Error) SetType(flags ErrorType) *Error {
    46  	msg.Type = flags
    47  	return msg
    48  }
    49  
    50  // SetMeta sets the error's meta data.
    51  func (msg *Error) SetMeta(data interface{}) *Error {
    52  	msg.Meta = data
    53  	return msg
    54  }
    55  
    56  // JSON creates a properly formatted JSON
    57  func (msg *Error) JSON() interface{} {
    58  	jsonData := H{}
    59  	if msg.Meta != nil {
    60  		value := reflect.ValueOf(msg.Meta)
    61  		switch value.Kind() {
    62  		case reflect.Struct:
    63  			return msg.Meta
    64  		case reflect.Map:
    65  			for _, key := range value.MapKeys() {
    66  				jsonData[key.String()] = value.MapIndex(key).Interface()
    67  			}
    68  		default:
    69  			jsonData["meta"] = msg.Meta
    70  		}
    71  	}
    72  	if _, ok := jsonData["error"]; !ok {
    73  		jsonData["error"] = msg.Error()
    74  	}
    75  	return jsonData
    76  }
    77  
    78  // MarshalJSON implements the json.Marshaller interface.
    79  func (msg *Error) MarshalJSON() ([]byte, error) {
    80  	return json.Marshal(msg.JSON())
    81  }
    82  
    83  // Error implements the error interface.
    84  func (msg Error) Error() string {
    85  	return msg.Err.Error()
    86  }
    87  
    88  // IsType judges one error.
    89  func (msg *Error) IsType(flags ErrorType) bool {
    90  	return (msg.Type & flags) > 0
    91  }
    92  
    93  // Unwrap returns the wrapped error, to allow interoperability with errors.Is(), errors.As() and errors.Unwrap()
    94  func (msg *Error) Unwrap() error {
    95  	return msg.Err
    96  }
    97  
    98  // ByType returns a readonly copy filtered the byte.
    99  // ie ByType(gin.ErrorTypePublic) returns a slice of errors with type=ErrorTypePublic.
   100  func (a errorMsgs) ByType(typ ErrorType) errorMsgs {
   101  	if len(a) == 0 {
   102  		return nil
   103  	}
   104  	if typ == ErrorTypeAny {
   105  		return a
   106  	}
   107  	var result errorMsgs
   108  	for _, msg := range a {
   109  		if msg.IsType(typ) {
   110  			result = append(result, msg)
   111  		}
   112  	}
   113  	return result
   114  }
   115  
   116  // Last returns the last error in the slice. It returns nil if the array is empty.
   117  // Shortcut for errors[len(errors)-1].
   118  func (a errorMsgs) Last() *Error {
   119  	if length := len(a); length > 0 {
   120  		return a[length-1]
   121  	}
   122  	return nil
   123  }
   124  
   125  // Errors returns an array will all the error messages.
   126  // Example:
   127  // 		c.Error(errors.New("first"))
   128  // 		c.Error(errors.New("second"))
   129  // 		c.Error(errors.New("third"))
   130  // 		c.Errors.Errors() // == []string{"first", "second", "third"}
   131  func (a errorMsgs) Errors() []string {
   132  	if len(a) == 0 {
   133  		return nil
   134  	}
   135  	errorStrings := make([]string, len(a))
   136  	for i, err := range a {
   137  		errorStrings[i] = err.Error()
   138  	}
   139  	return errorStrings
   140  }
   141  
   142  func (a errorMsgs) JSON() interface{} {
   143  	switch length := len(a); length {
   144  	case 0:
   145  		return nil
   146  	case 1:
   147  		return a.Last().JSON()
   148  	default:
   149  		jsonData := make([]interface{}, length)
   150  		for i, err := range a {
   151  			jsonData[i] = err.JSON()
   152  		}
   153  		return jsonData
   154  	}
   155  }
   156  
   157  // MarshalJSON implements the json.Marshaller interface.
   158  func (a errorMsgs) MarshalJSON() ([]byte, error) {
   159  	return json.Marshal(a.JSON())
   160  }
   161  
   162  func (a errorMsgs) String() string {
   163  	if len(a) == 0 {
   164  		return ""
   165  	}
   166  
   167  	var buffer strings.Builder
   168  	for i, msg := range a {
   169  		buffer.WriteString("Error #")
   170  		if i < 9 {
   171  			buffer.WriteRune('0')
   172  		}
   173  		buffer.WriteString(strconv.FormatInt(int64(i+1), 10))
   174  		buffer.WriteString(": ")
   175  		buffer.WriteString(msg.Err.Error())
   176  		buffer.WriteRune('\n')
   177  
   178  		if msg.Meta != nil {
   179  			_, _ = fmt.Fprintf(&buffer, "     Meta: %v\n", msg.Meta)
   180  		}
   181  	}
   182  
   183  	return buffer.String()
   184  }