1// Copyright (c) 2012, 2013 Ugorji Nwoke. All rights reserved. 2// Use of this source code is governed by a BSD-style license found in the LICENSE file. 3 4package codec 5 6// All non-std package dependencies live in this file, 7// so porting to different environment is easy (just update functions). 8 9import ( 10 "errors" 11 "fmt" 12 "math" 13 "reflect" 14) 15 16var ( 17 raisePanicAfterRecover = false 18 debugging = true 19) 20 21func panicValToErr(panicVal interface{}, err *error) { 22 switch xerr := panicVal.(type) { 23 case error: 24 *err = xerr 25 case string: 26 *err = errors.New(xerr) 27 default: 28 *err = fmt.Errorf("%v", panicVal) 29 } 30 if raisePanicAfterRecover { 31 panic(panicVal) 32 } 33 return 34} 35 36func hIsEmptyValue(v reflect.Value, deref, checkStruct bool) bool { 37 switch v.Kind() { 38 case reflect.Invalid: 39 return true 40 case reflect.Array, reflect.Map, reflect.Slice, reflect.String: 41 return v.Len() == 0 42 case reflect.Bool: 43 return !v.Bool() 44 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 45 return v.Int() == 0 46 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 47 return v.Uint() == 0 48 case reflect.Float32, reflect.Float64: 49 return v.Float() == 0 50 case reflect.Interface, reflect.Ptr: 51 if deref { 52 if v.IsNil() { 53 return true 54 } 55 return hIsEmptyValue(v.Elem(), deref, checkStruct) 56 } else { 57 return v.IsNil() 58 } 59 case reflect.Struct: 60 if !checkStruct { 61 return false 62 } 63 // return true if all fields are empty. else return false. 64 65 // we cannot use equality check, because some fields may be maps/slices/etc 66 // and consequently the structs are not comparable. 67 // return v.Interface() == reflect.Zero(v.Type()).Interface() 68 for i, n := 0, v.NumField(); i < n; i++ { 69 if !hIsEmptyValue(v.Field(i), deref, checkStruct) { 70 return false 71 } 72 } 73 return true 74 } 75 return false 76} 77 78func isEmptyValue(v reflect.Value) bool { 79 return hIsEmptyValue(v, derefForIsEmptyValue, checkStructForEmptyValue) 80} 81 82func debugf(format string, args ...interface{}) { 83 if debugging { 84 if len(format) == 0 || format[len(format)-1] != '\n' { 85 format = format + "\n" 86 } 87 fmt.Printf(format, args...) 88 } 89} 90 91func pruneSignExt(v []byte, pos bool) (n int) { 92 if len(v) < 2 { 93 } else if pos && v[0] == 0 { 94 for ; v[n] == 0 && n+1 < len(v) && (v[n+1]&(1<<7) == 0); n++ { 95 } 96 } else if !pos && v[0] == 0xff { 97 for ; v[n] == 0xff && n+1 < len(v) && (v[n+1]&(1<<7) != 0); n++ { 98 } 99 } 100 return 101} 102 103func implementsIntf(typ, iTyp reflect.Type) (success bool, indir int8) { 104 if typ == nil { 105 return 106 } 107 rt := typ 108 // The type might be a pointer and we need to keep 109 // dereferencing to the base type until we find an implementation. 110 for { 111 if rt.Implements(iTyp) { 112 return true, indir 113 } 114 if p := rt; p.Kind() == reflect.Ptr { 115 indir++ 116 if indir >= math.MaxInt8 { // insane number of indirections 117 return false, 0 118 } 119 rt = p.Elem() 120 continue 121 } 122 break 123 } 124 // No luck yet, but if this is a base type (non-pointer), the pointer might satisfy. 125 if typ.Kind() != reflect.Ptr { 126 // Not a pointer, but does the pointer work? 127 if reflect.PtrTo(typ).Implements(iTyp) { 128 return true, -1 129 } 130 } 131 return false, 0 132} 133