| // Copyright 2016-2019 Alex Stocks |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| // pack/unpack fixed length variable |
| package hessian |
| |
| import ( |
| "encoding/binary" |
| "fmt" |
| "math" |
| "reflect" |
| "strings" |
| ) |
| |
| import ( |
| perrors "github.com/pkg/errors" |
| ) |
| |
| var ( |
| _zeroBoolPinter *bool |
| _zeroValue = reflect.ValueOf(_zeroBoolPinter).Elem() |
| ) |
| |
| func encByte(b []byte, t ...byte) []byte { |
| return append(b, t...) |
| } |
| |
| // validateIntKind check whether k is int kind |
| func validateIntKind(k reflect.Kind) bool { |
| switch k { |
| case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: |
| return true |
| default: |
| return false |
| } |
| } |
| |
| // validateUintKind check whether k is uint kind |
| func validateUintKind(k reflect.Kind) bool { |
| switch k { |
| case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: |
| return true |
| default: |
| return false |
| } |
| } |
| |
| // validateFloatKind check whether k is float kind |
| func validateFloatKind(k reflect.Kind) bool { |
| switch k { |
| case reflect.Float32, reflect.Float64: |
| return true |
| default: |
| return false |
| } |
| } |
| |
| // PackInt8 packs int to byte array |
| func PackInt8(v int8, b []byte) []byte { |
| return append(b, byte(v)) |
| } |
| |
| // PackInt16 packs int16 to byte array |
| //[10].pack('N').bytes => [0, 0, 0, 10] |
| func PackInt16(v int16) []byte { |
| var array [2]byte |
| binary.BigEndian.PutUint16(array[:2], uint16(v)) |
| return array[:] |
| } |
| |
| // PackUint16 packs uint16 to byte array |
| //[10].pack('N').bytes => [0, 0, 0, 10] |
| func PackUint16(v uint16) []byte { |
| var array [2]byte |
| binary.BigEndian.PutUint16(array[:2], v) |
| return array[:] |
| } |
| |
| // PackInt32 packs int32 to byte array |
| //[10].pack('N').bytes => [0, 0, 0, 10] |
| func PackInt32(v int32) []byte { |
| var array [4]byte |
| binary.BigEndian.PutUint32(array[:4], uint32(v)) |
| return array[:] |
| } |
| |
| // PackInt64 packs int64 to byte array |
| //[10].pack('q>').bytes => [0, 0, 0, 0, 0, 0, 0, 10] |
| func PackInt64(v int64) []byte { |
| var array [8]byte |
| binary.BigEndian.PutUint64(array[:8], uint64(v)) |
| return array[:] |
| } |
| |
| // PackFloat64 packs float64 to byte array |
| //[10].pack('G').bytes => [64, 36, 0, 0, 0, 0, 0, 0] |
| // PackFloat64 invokes go's official math library function Float64bits. |
| func PackFloat64(v float64) []byte { |
| var array [8]byte |
| binary.BigEndian.PutUint64(array[:8], math.Float64bits(v)) |
| return array[:] |
| } |
| |
| // UnpackInt16 unpacks int16 from byte array |
| //(0,2).unpack('n') |
| func UnpackInt16(b []byte) int16 { |
| var arr = b[:2] |
| return int16(binary.BigEndian.Uint16(arr)) |
| } |
| |
| // UnpackUint16 unpacks int16 from byte array |
| //(0,2).unpack('n') |
| func UnpackUint16(b []byte) uint16 { |
| var arr = b[:2] |
| return binary.BigEndian.Uint16(arr) |
| } |
| |
| // UnpackInt32 unpacks int32 from byte array |
| //(0,4).unpack('N') |
| func UnpackInt32(b []byte) int32 { |
| var arr = b[:4] |
| return int32(binary.BigEndian.Uint32(arr)) |
| } |
| |
| // UnpackInt64 unpacks int64 from byte array |
| //long (0,8).unpack('q>') |
| func UnpackInt64(b []byte) int64 { |
| var arr = b[:8] |
| return int64(binary.BigEndian.Uint64(arr)) |
| } |
| |
| // UnpackFloat64 unpacks float64 from byte array |
| //Double (0,8).unpack('G) |
| func UnpackFloat64(b []byte) float64 { |
| var arr = b[:8] |
| return math.Float64frombits(binary.BigEndian.Uint64(arr)) |
| } |
| |
| // UnpackPtr unpack pointer value to original value |
| func UnpackPtr(v reflect.Value) reflect.Value { |
| for v.Kind() == reflect.Ptr { |
| v = v.Elem() |
| } |
| |
| return v |
| } |
| |
| //PackPtr pack a Ptr value |
| func PackPtr(v reflect.Value) reflect.Value { |
| vv := reflect.New(v.Type()) |
| vv.Elem().Set(v) |
| return vv |
| } |
| |
| //UnpackPtrType unpack pointer type to original type |
| func UnpackPtrType(typ reflect.Type) reflect.Type { |
| for typ.Kind() == reflect.Ptr { |
| typ = typ.Elem() |
| } |
| return typ |
| } |
| |
| // UnpackPtrValue unpack pointer value to original value |
| // return the pointer if its elem is zero value, because lots of operations on zero value is invalid |
| func UnpackPtrValue(v reflect.Value) reflect.Value { |
| for v.Kind() == reflect.Ptr && v.Elem().IsValid() { |
| v = v.Elem() |
| } |
| return v |
| } |
| |
| // SprintHex converts the []byte to a Hex string. |
| func SprintHex(b []byte) (rs string) { |
| rs = fmt.Sprintf("[]byte{") |
| for _, v := range b { |
| rs += fmt.Sprintf("0x%02x,", v) |
| } |
| rs = strings.TrimSpace(rs) |
| rs += fmt.Sprintf("}\n") |
| return |
| } |
| |
| // EnsureFloat64 convert i to float64 |
| func EnsureFloat64(i interface{}) float64 { |
| if i64, ok := i.(float64); ok { |
| return i64 |
| } |
| if i32, ok := i.(float32); ok { |
| return float64(i32) |
| } |
| panic(fmt.Errorf("can't convert to float64: %v, type:%v", i, reflect.TypeOf(i))) |
| } |
| |
| // EnsureInt64 convert i to int64 |
| func EnsureInt64(i interface{}) int64 { |
| if i64, ok := i.(int64); ok { |
| return i64 |
| } |
| if i32, ok := i.(int32); ok { |
| return int64(i32) |
| } |
| if i, ok := i.(int); ok { |
| return int64(i) |
| } |
| if i16, ok := i.(int16); ok { |
| return int64(i16) |
| } |
| if i8, ok := i.(int8); ok { |
| return int64(i8) |
| } |
| panic(fmt.Errorf("can't convert to int64: %v, type:%v", i, reflect.TypeOf(i))) |
| } |
| |
| // EnsureUint64 convert i to uint64 |
| func EnsureUint64(i interface{}) uint64 { |
| if i64, ok := i.(uint64); ok { |
| return i64 |
| } |
| if i64, ok := i.(int64); ok { |
| return uint64(i64) |
| } |
| if i32, ok := i.(int32); ok { |
| return uint64(i32) |
| } |
| if i32, ok := i.(uint32); ok { |
| return uint64(i32) |
| } |
| panic(fmt.Errorf("can't convert to uint64: %v, type:%v", i, reflect.TypeOf(i))) |
| } |
| |
| // EnsurePackValue pack the interface with value |
| func EnsurePackValue(in interface{}) reflect.Value { |
| if v, ok := in.(reflect.Value); ok { |
| return v |
| } |
| return reflect.ValueOf(in) |
| } |
| |
| // EnsureInterface get value of reflect.Value |
| // return original value if not reflect.Value |
| func EnsureInterface(in interface{}, err error) (interface{}, error) { |
| if err != nil { |
| return in, err |
| } |
| |
| if v, ok := in.(reflect.Value); ok { |
| in = v.Interface() |
| } |
| |
| if v, ok := in.(*_refHolder); ok { |
| in = v.value.Interface() |
| } |
| |
| return in, nil |
| } |
| |
| //EnsureRawValue pack the interface with value, and make sure it's not a ref holder |
| func EnsureRawValue(in interface{}) reflect.Value { |
| if v, ok := in.(reflect.Value); ok { |
| if v.IsValid() { |
| if r, ok := v.Interface().(*_refHolder); ok { |
| return r.value |
| } |
| } |
| return v |
| } |
| if v, ok := in.(*_refHolder); ok { |
| return v.value |
| } |
| return reflect.ValueOf(in) |
| } |
| |
| // SetValue set the value to dest. |
| // It will auto check the Ptr pack level and unpack/pack to the right level. |
| // It make sure success to set value |
| func SetValue(dest, v reflect.Value) { |
| // check whether the v is a ref holder |
| if v.IsValid() { |
| if h, ok := v.Interface().(*_refHolder); ok { |
| h.add(dest) |
| return |
| } |
| } |
| //temporary process, only handle the same type of situation |
| if v.IsValid() && UnpackPtrType(dest.Type()) == UnpackPtrType(v.Type()) && dest.Kind() == reflect.Ptr && dest.CanSet() { |
| for dest.Type() != v.Type() { |
| v = PackPtr(v) |
| } |
| dest.Set(v) |
| return |
| } |
| |
| // if the kind of dest is Ptr, the original value will be zero value |
| // set value on zero value is not allowed |
| // unpack to one-level pointer |
| for dest.Kind() == reflect.Ptr && dest.Elem().Kind() == reflect.Ptr { |
| dest = dest.Elem() |
| } |
| |
| // if the kind of dest is Ptr, change the v to a Ptr value too. |
| if dest.Kind() == reflect.Ptr { |
| |
| // unpack to one-level pointer |
| for v.IsValid() && v.Kind() == reflect.Ptr && v.Elem().Kind() == reflect.Ptr { |
| v = v.Elem() |
| } |
| // zero value not need to set |
| if !v.IsValid() { |
| return |
| } |
| |
| if v.Kind() != reflect.Ptr { |
| // change the v to a Ptr value |
| v = PackPtr(v) |
| } |
| } else { |
| v = UnpackPtrValue(v) |
| } |
| // zero value not need to set |
| if !v.IsValid() { |
| return |
| } |
| |
| // set value as required type |
| if dest.Type() == v.Type() && dest.CanSet() { |
| dest.Set(v) |
| return |
| } |
| |
| // unpack ptr so that to special check for float,int,uint kind |
| if dest.Kind() == reflect.Ptr { |
| dest = UnpackPtrValue(dest) |
| v = UnpackPtrValue(v) |
| } |
| |
| kind := dest.Kind() |
| switch kind { |
| case reflect.Float32, reflect.Float64: |
| dest.SetFloat(EnsureFloat64(v.Interface())) |
| return |
| case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: |
| dest.SetInt(EnsureInt64(v.Interface())) |
| return |
| case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: |
| dest.SetUint(EnsureUint64(v.Interface())) |
| return |
| } |
| |
| dest.Set(v) |
| } |
| |
| // AddrEqual compares addrs |
| func AddrEqual(x, y interface{}) bool { |
| if x == nil || y == nil { |
| return x == y |
| } |
| v1 := reflect.ValueOf(x) |
| v2 := reflect.ValueOf(y) |
| if v1.Type() != v2.Type() { |
| return false |
| } |
| |
| if v1.Kind() != reflect.Ptr { |
| v1 = PackPtr(v1) |
| v2 = PackPtr(v2) |
| } |
| return v1.Pointer() == v2.Pointer() |
| } |
| |
| //SetSlice set value into slice object |
| func SetSlice(dest reflect.Value, objects interface{}) error { |
| if objects == nil { |
| return nil |
| } |
| |
| dest = UnpackPtrValue(dest) |
| destTyp := UnpackPtrType(dest.Type()) |
| elemKind := destTyp.Elem().Kind() |
| if elemKind == reflect.Uint8 { |
| // for binary |
| dest.Set(EnsureRawValue(objects)) |
| return nil |
| } |
| |
| if ref, ok := objects.(*_refHolder); ok { |
| v, err := ConvertSliceValueType(destTyp, ref.value) |
| if err != nil { |
| return err |
| } |
| SetValue(dest, v) |
| ref.change(v) // change finally |
| ref.notify() // delay set value to all destinations |
| return nil |
| } |
| |
| v := EnsurePackValue(objects) |
| if h, ok := v.Interface().(*_refHolder); ok { |
| // if the object is a ref one, just add the destination list to wait delay initialization |
| h.add(dest) |
| return nil |
| } |
| |
| v, err := ConvertSliceValueType(destTyp, v) |
| if err != nil { |
| return err |
| } |
| SetValue(dest, v) |
| return nil |
| } |
| |
| //ConvertSliceValueType convert to slice of destination type |
| func ConvertSliceValueType(destTyp reflect.Type, v reflect.Value) (reflect.Value, error) { |
| if destTyp == v.Type() { |
| return v, nil |
| } |
| |
| k := v.Type().Kind() |
| if k != reflect.Slice && k != reflect.Array { |
| return _zeroValue, perrors.Errorf("expect slice type, but get %v, objects: %v", k, v) |
| } |
| |
| if v.Len() <= 0 { |
| return _zeroValue, nil |
| } |
| |
| elemKind := destTyp.Elem().Kind() |
| elemPtrType := elemKind == reflect.Ptr |
| elemFloatType := validateFloatKind(elemKind) |
| elemIntType := validateIntKind(elemKind) |
| elemUintType := validateUintKind(elemKind) |
| |
| sl := reflect.MakeSlice(destTyp, v.Len(), v.Len()) |
| var itemValue reflect.Value |
| for i := 0; i < v.Len(); i++ { |
| item := v.Index(i).Interface() |
| if cv, ok := item.(reflect.Value); ok { |
| itemValue = cv |
| } else { |
| itemValue = reflect.ValueOf(item) |
| } |
| |
| if !elemPtrType && itemValue.Kind() == reflect.Ptr { |
| itemValue = UnpackPtrValue(itemValue) |
| } |
| |
| switch { |
| case elemFloatType: |
| sl.Index(i).SetFloat(EnsureFloat64(itemValue.Interface())) |
| case elemIntType: |
| sl.Index(i).SetInt(EnsureInt64(itemValue.Interface())) |
| case elemUintType: |
| sl.Index(i).SetUint(EnsureUint64(itemValue.Interface())) |
| default: |
| SetValue(sl.Index(i), itemValue) |
| } |
| } |
| |
| return sl, nil |
| } |