Skip to content

Commit

Permalink
Merge pull request #2 from ValentinMontmirail/main
Browse files Browse the repository at this point in the history
Put GoReport to 100% A+.
  • Loading branch information
ahuigo committed Dec 11, 2023
2 parents 4a6ade9 + ab35116 commit f17c99c
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 113 deletions.
111 changes: 58 additions & 53 deletions object/obj.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,77 +31,82 @@ func convertObjectByte2String(rv reflect.Value, ptrSeen PtrSeen) (out interface{
t := rv.Type()

switch t.Kind() {
// array slice
case reflect.Slice:
ptr := ptrSeen.Add(rv)
defer delete(ptrSeen, ptr)
fallthrough
case reflect.Array:
// 882 go/1.18.1/libexec/src/encoding/json/encode.go
if t.Elem().Kind() == reflect.Uint8 {
return string(rv.Bytes())
} else {
s := make([]interface{}, rv.Len())
n := rv.Len()
for i := 0; i < n; i++ {
s[i] = convertObjectByte2String(rv.Index(i), ptrSeen)
}
return s
}
// return rv.Interface()
// map
return convertSliceArray(rv, ptrSeen)
case reflect.Map:
ptr := ptrSeen.Add(rv)
defer delete(ptrSeen, ptr)

// 798 go/1.18.1/libexec/src/encoding/json/encode.go
m := map[string]interface{}{}
mi := rv.MapRange()
for i := 0; mi.Next(); i++ {
k := mi.Key()
v := mi.Value()
m[k.String()] = convertObjectByte2String(v, ptrSeen)
}
m := convertMap(rv, ptrSeen)
outV.Set(reflect.ValueOf(m))

// pointer
// case reflect.Pointer:
case reflect.Ptr:
ptr := ptrSeen.Add(rv)
defer delete(ptrSeen, ptr)
fallthrough
case reflect.Interface:
if rv.IsNil() {
return out
}
return convertObjectByte2String(rv.Elem(), ptrSeen)
return convertPtrInterface(rv, ptrSeen)
case reflect.Struct:
m := map[string]interface{}{}
for i := 0; i < t.NumField(); i++ {
f := t.Field(i)
key := f.Name
isOmitEmpty := false
if f.Tag != "" {
key = f.Tag.Get("json")
keys := strings.Split(key, ",")
key = keys[0]
if len(keys) > 1 && keys[1] == "omitempty" {
isOmitEmpty = true
}
}
fv := rv.Field(i)
// m[key] = fv.Interface()
v := convertObjectByte2String(fv, ptrSeen)
if v == nil && isOmitEmpty {
continue
}
m[key] = v
}
m := convertStruct(rv, ptrSeen)
outV.Set(reflect.ValueOf(m))

case reflect.Chan:
default:
return rv.Interface()
}
return
}

func convertSliceArray(rv reflect.Value, ptrSeen PtrSeen) interface{} {
if rv.Type().Elem().Kind() == reflect.Uint8 {
return string(rv.Bytes())
}
s := make([]interface{}, rv.Len())
for i := 0; i < rv.Len(); i++ {
s[i] = convertObjectByte2String(rv.Index(i), ptrSeen)
}
return s
}

func convertMap(rv reflect.Value, ptrSeen PtrSeen) interface{} {
m := make(map[string]interface{})
mi := rv.MapRange()
for mi.Next() {
k := mi.Key()
v := mi.Value()
m[k.String()] = convertObjectByte2String(v, ptrSeen)
}
return m
}

func convertPtrInterface(rv reflect.Value, ptrSeen PtrSeen) interface{} {
if rv.IsNil() {
return nil
}
return convertObjectByte2String(rv.Elem(), ptrSeen)
}

func convertStruct(rv reflect.Value, ptrSeen PtrSeen) interface{} {
m := make(map[string]interface{})
t := rv.Type()
for i := 0; i < t.NumField(); i++ {
f := t.Field(i)
key := f.Name
isOmitEmpty := false
if f.Tag != "" {
key = f.Tag.Get("json")
keys := strings.Split(key, ",")
key = keys[0]
if len(keys) > 1 && keys[1] == "omitempty" {
isOmitEmpty = true
}
}
fv := rv.Field(i)
v := convertObjectByte2String(fv, ptrSeen)
if v == nil && isOmitEmpty {
continue
}
m[key] = v
}
return m
}
8 changes: 3 additions & 5 deletions examples/object_test.go → object/obj_test.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
package examples
package object

import (
"encoding/json"
"fmt"
"testing"

"github.com/ahuigo/gofnext/object"
)

func TestConvertMapBytes(t *testing.T) {
Expand All @@ -16,7 +14,7 @@ func TestConvertMapBytes(t *testing.T) {
out, _ := json.Marshal(objBytes)
fmt.Println(string(out)) //output: {"k1":"djE=","k2":"djI="}

objString := object.ConvertObjectByte2String(objBytes)
objString := ConvertObjectByte2String(objBytes)
out, _ = json.Marshal(objString)
fmt.Println(string(out)) //output: {"k1":"v1","k2":"v2"}

Expand All @@ -35,7 +33,7 @@ func TestConvertOmitEmpty(t *testing.T) {
obj := HistoryEvent{
EventId: &i,
}
if out, err := json.Marshal(object.ConvertObjectByte2String(obj)); err != nil {
if out, err := json.Marshal(ConvertObjectByte2String(obj)); err != nil {
t.Fatal(err)
} else {
expectedOut := `{"eventId":1}`
Expand Down
146 changes: 91 additions & 55 deletions serial/dump.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,73 +37,27 @@ func Bytes(val any, hashPtrAddr bool) []byte {

func dump(refV reflect.Value, hashPtrAddr bool, ps PtrSeen) []byte {
var buf bytes.Buffer

switch refV.Kind() {
case reflect.Invalid:
buf.WriteString("<invalid>")
case reflect.String:
buf.WriteString(`"`)
buf.WriteString(refV.String())
buf.WriteString(`"`)
dumpString(refV, &buf)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
buf.WriteString(fmt.Sprintf("%d", refV.Int()))
// refV.CanInt()
dumpInt(refV, &buf)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
buf.WriteString(fmt.Sprintf("%d", refV.Uint()))
dumpUint(refV, &buf)
case reflect.Float32, reflect.Float64:
buf.WriteString(fmt.Sprintf("%f", refV.Float()))
dumpFloat(refV, &buf)
case reflect.Complex64, reflect.Complex128:
buf.WriteString(fmt.Sprintf("%f", refV.Complex()))
dumpComplex(refV, &buf)
case reflect.Ptr, reflect.Interface:
if refV.IsNil() {
buf.WriteString("null")
} else {
isPtr := refV.Kind() == reflect.Ptr
if isPtr && !ps.Add(refV) {
buf.WriteString("<cycle pointer>")
break
}
if hashPtrAddr && isPtr {
buf.WriteString(fmt.Sprintf("*0x%x", refV.Pointer()))
} else {
refV = refV.Elem()
buf.WriteString(fmt.Sprintf("&%s", dump(refV, hashPtrAddr, ps)))
}
}
dumpPtrInterface(refV, hashPtrAddr, ps, &buf)
case reflect.Slice, reflect.Array:
buf.WriteString("[")
for i := 0; i < refV.Len(); i++ {
buf.Write(dump(refV.Index(i), hashPtrAddr, ps))
if i != refV.Len()-1 {
buf.WriteString(",")
}
}
buf.WriteString("]")
dumpSliceArray(refV, hashPtrAddr, ps, &buf)
case reflect.Struct:
name := refV.Type().Name()
buf.WriteString(name + "{")
for i := 0; i < refV.NumField(); i++ {
buf.WriteString(refV.Type().Field(i).Name)
buf.WriteString(":")
buf.Write(dump(refV.Field(i), hashPtrAddr, ps))
if i != refV.NumField()-1 {
buf.WriteString(",")
}
}
buf.WriteString("}")
dumpStruct(refV, hashPtrAddr, ps, &buf)
case reflect.Map:
sli := make([][]byte, len(refV.MapKeys()))
for i, key := range refV.MapKeys() {
keyVal := append(dump(key, hashPtrAddr, ps), ':')
valbytes := dump(refV.MapIndex(key), hashPtrAddr, ps)
sli[i] = append(keyVal, valbytes...)
}
slices.SortFunc(sli, func(a, b []byte) int {
return slices.Compare(a, b)
})
buf.WriteString("{")
buf.Write(bytes.Join(sli, []byte{','}))
buf.WriteString("}")
dumpMap(refV, hashPtrAddr, ps, &buf)
case reflect.Func:
buf.WriteString("<func>")
case reflect.Chan:
Expand All @@ -117,3 +71,85 @@ func dump(refV reflect.Value, hashPtrAddr bool, ps PtrSeen) []byte {

return buf.Bytes()
}

func dumpString(refV reflect.Value, buf *bytes.Buffer) {
buf.WriteString(`"`)
buf.WriteString(refV.String())
buf.WriteString(`"`)
}

func dumpInt(refV reflect.Value, buf *bytes.Buffer) {
buf.WriteString(fmt.Sprintf("%d", refV.Int()))
}

func dumpUint(refV reflect.Value, buf *bytes.Buffer) {
buf.WriteString(fmt.Sprintf("%d", refV.Uint()))
}

func dumpFloat(refV reflect.Value, buf *bytes.Buffer) {
buf.WriteString(fmt.Sprintf("%f", refV.Float()))
}

func dumpComplex(refV reflect.Value, buf *bytes.Buffer) {
buf.WriteString(fmt.Sprintf("%f", refV.Complex()))
}

func dumpPtrInterface(refV reflect.Value, hashPtrAddr bool, ps PtrSeen, buf *bytes.Buffer) {
if refV.IsNil() {
buf.WriteString("null")
return
}

isPtr := refV.Kind() == reflect.Ptr
if isPtr && !ps.Add(refV) {
buf.WriteString("<cycle pointer>")
return
}

if hashPtrAddr && isPtr {
buf.WriteString(fmt.Sprintf("*0x%x", refV.Pointer()))
} else {
refV = refV.Elem()
buf.WriteString(fmt.Sprintf("&%s", dump(refV, hashPtrAddr, ps)))
}
}

func dumpSliceArray(refV reflect.Value, hashPtrAddr bool, ps PtrSeen, buf *bytes.Buffer) {
buf.WriteString("[")
for i := 0; i < refV.Len(); i++ {
buf.Write(dump(refV.Index(i), hashPtrAddr, ps))
if i != refV.Len()-1 {
buf.WriteString(",")
}
}
buf.WriteString("]")
}

func dumpStruct(refV reflect.Value, hashPtrAddr bool, ps PtrSeen, buf *bytes.Buffer) {
name := refV.Type().Name()
buf.WriteString(name + "{")
for i := 0; i < refV.NumField(); i++ {
buf.WriteString(refV.Type().Field(i).Name)
buf.WriteString(":")
buf.Write(dump(refV.Field(i), hashPtrAddr, ps))
if i != refV.NumField()-1 {
buf.WriteString(",")
}
}
buf.WriteString("}")
}

func dumpMap(refV reflect.Value, hashPtrAddr bool, ps PtrSeen, buf *bytes.Buffer) {
sli := make([][]byte, len(refV.MapKeys()))
for i, key := range refV.MapKeys() {
keyVal := append(dump(key, hashPtrAddr, ps), ':')
valbytes := dump(refV.MapIndex(key), hashPtrAddr, ps)
sli[i] = append(keyVal, valbytes...)
}
slices.SortFunc(sli, func(a, b []byte) int {
return slices.Compare(a, b)
})
buf.WriteString("{")
buf.Write(bytes.Join(sli, []byte{','}))
buf.WriteString("}")
}

0 comments on commit f17c99c

Please sign in to comment.