mirror of
https://gitee.com/johng/gf.git
synced 2024-11-30 03:07:45 +08:00
improve package gconv for custom type converting
This commit is contained in:
parent
5a0326f666
commit
8c0a905a9f
@ -7,41 +7,91 @@
|
||||
package gjson_test
|
||||
|
||||
import (
|
||||
json2 "encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/encoding/gjson"
|
||||
)
|
||||
|
||||
var (
|
||||
jsonStr1 = `[1,2,3]`
|
||||
jsonStr1 = `{"name":"john","slice":[1,2,3]}`
|
||||
jsonStr2 = `{"CallbackCommand":"Group.CallbackAfterSendMsg","From_Account":"61934946","GroupId":"@TGS#2FLGX67FD","MsgBody":[{"MsgContent":{"Text":"是的"},"MsgType":"TIMTextElem"}],"MsgSeq":23,"MsgTime":1567032819,"Operator_Account":"61934946","Random":2804799576,"Type":"Public"}`
|
||||
jsonObj1 = gjson.New(jsonStr1)
|
||||
jsonObj2 = gjson.New(jsonStr2)
|
||||
)
|
||||
|
||||
func Benchmark_Validate1(b *testing.B) {
|
||||
func Benchmark_Validate_Simple_Json(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
gjson.Valid(jsonStr1)
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Validate2(b *testing.B) {
|
||||
func Benchmark_Validate_Complicated_Json(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
gjson.Valid(jsonStr2)
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Set1(b *testing.B) {
|
||||
func Benchmark_Get_Simple_Json(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
p := gjson.New(map[string]string{
|
||||
"k1": "v1",
|
||||
"k2": "v2",
|
||||
})
|
||||
p.Set("k1.k11", []int{1, 2, 3})
|
||||
jsonObj1.Get("name")
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Set2(b *testing.B) {
|
||||
func Benchmark_Get_Complicated_Json(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
p := gjson.New([]string{"a"})
|
||||
jsonObj2.Get("GroupId")
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Stdlib_Json_Unmarshal_Simple_Json(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
var m map[string]interface{}
|
||||
json2.Unmarshal([]byte(jsonStr1), &m)
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Stdlib_Json_Unmarshal_Complicated_Json(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
var m map[string]interface{}
|
||||
json2.Unmarshal([]byte(jsonStr2), &m)
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_New_Simple_Json(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
gjson.New(jsonStr1)
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_New_Complicated_Json(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
gjson.New(jsonStr2)
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Remove_Simple_Json(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
jsonObj1.Remove("name")
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Remove_Complicated_Json(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
jsonObj2.Remove("GroupId")
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_New_Nil_And_Set_Simple(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
p := gjson.New(nil)
|
||||
p.Set("k", "v")
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_New_Nil_And_Set_Multiple_Level(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
p := gjson.New(nil)
|
||||
p.Set("0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0", []int{1, 2, 3})
|
||||
}
|
||||
}
|
||||
|
@ -52,6 +52,12 @@ type apiUnmarshalValue interface {
|
||||
UnmarshalValue(interface{}) error
|
||||
}
|
||||
|
||||
// apiUnmarshalText is the interface for custom defined types customizing value assignment.
|
||||
// Note that only pointer can implement interface apiUnmarshalText.
|
||||
type apiUnmarshalText interface {
|
||||
UnmarshalText(text []byte) error
|
||||
}
|
||||
|
||||
// apiSet is the interface for custom value assignment.
|
||||
type apiSet interface {
|
||||
Set(value interface{}) (old interface{})
|
||||
|
@ -287,6 +287,7 @@ func bindVarToStructAttr(elem reflect.Value, name string, value interface{}, map
|
||||
}
|
||||
}
|
||||
}()
|
||||
// Directly converting.
|
||||
if empty.IsNil(value) {
|
||||
structFieldValue.Set(reflect.Zero(structFieldValue.Type()))
|
||||
} else {
|
||||
@ -295,10 +296,35 @@ func bindVarToStructAttr(elem reflect.Value, name string, value interface{}, map
|
||||
return nil
|
||||
}
|
||||
|
||||
// bindVarToReflectValueWithInterfaceCheck does binding using common interfaces checks.
|
||||
func bindVarToReflectValueWithInterfaceCheck(structFieldValue reflect.Value, value interface{}) (err error, ok bool) {
|
||||
if structFieldValue.CanAddr() {
|
||||
pointer := structFieldValue.Addr().Interface()
|
||||
if v, ok := pointer.(apiUnmarshalValue); ok {
|
||||
return v.UnmarshalValue(value), ok
|
||||
}
|
||||
if v, ok := pointer.(apiUnmarshalText); ok {
|
||||
if s, ok := value.(string); ok {
|
||||
return v.UnmarshalText([]byte(s)), ok
|
||||
}
|
||||
if b, ok := value.([]byte); ok {
|
||||
return v.UnmarshalText(b), ok
|
||||
}
|
||||
}
|
||||
if v, ok := pointer.(apiSet); ok {
|
||||
v.Set(value)
|
||||
return nil, ok
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// bindVarToReflectValue sets <value> to reflect value object <structFieldValue>.
|
||||
func bindVarToReflectValue(structFieldValue reflect.Value, value interface{}, mapping ...map[string]string) (err error) {
|
||||
if err, ok := bindVarToReflectValueWithInterfaceCheck(structFieldValue, value); ok {
|
||||
return err
|
||||
}
|
||||
kind := structFieldValue.Kind()
|
||||
|
||||
// Converting using interface, for some kinds.
|
||||
switch kind {
|
||||
case reflect.Slice, reflect.Array, reflect.Ptr, reflect.Interface:
|
||||
@ -306,10 +332,6 @@ func bindVarToReflectValue(structFieldValue reflect.Value, value interface{}, ma
|
||||
if v, ok := structFieldValue.Interface().(apiSet); ok {
|
||||
v.Set(value)
|
||||
return nil
|
||||
} else if v, ok := structFieldValue.Interface().(apiUnmarshalValue); ok {
|
||||
if err = v.UnmarshalValue(value); err == nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -317,11 +339,6 @@ func bindVarToReflectValue(structFieldValue reflect.Value, value interface{}, ma
|
||||
// Converting by kind.
|
||||
switch kind {
|
||||
case reflect.Struct:
|
||||
// UnmarshalValue.
|
||||
if v, ok := structFieldValue.Addr().Interface().(apiUnmarshalValue); ok {
|
||||
return v.UnmarshalValue(value)
|
||||
}
|
||||
|
||||
// Recursively converting for struct attribute.
|
||||
if err := doStruct(value, structFieldValue); err != nil {
|
||||
// Note there's reflect conversion mechanism here.
|
||||
@ -378,10 +395,7 @@ func bindVarToReflectValue(structFieldValue reflect.Value, value interface{}, ma
|
||||
|
||||
case reflect.Ptr:
|
||||
item := reflect.New(structFieldValue.Type().Elem())
|
||||
// Assign value with interface Set.
|
||||
// Note that only pointer can implement interface Set.
|
||||
if v, ok := item.Interface().(apiUnmarshalValue); ok {
|
||||
err = v.UnmarshalValue(value)
|
||||
if err, ok := bindVarToReflectValueWithInterfaceCheck(item, value); ok {
|
||||
structFieldValue.Set(item)
|
||||
return err
|
||||
}
|
||||
|
@ -40,3 +40,11 @@ func Test_Basic(t *testing.T) {
|
||||
t.Assert(gconv.Int(s), int64(-0xFF))
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Duration(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
d := gconv.Duration("1s")
|
||||
t.Assert(d.String(), "1s")
|
||||
t.Assert(d.Nanoseconds(), 1000000000)
|
||||
})
|
||||
}
|
||||
|
41
util/gconv/gconv_z_unit_custom_type_test.go
Normal file
41
util/gconv/gconv_z_unit_custom_type_test.go
Normal file
@ -0,0 +1,41 @@
|
||||
// Copyright 2018 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package gconv_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/test/gtest"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Duration time.Duration
|
||||
|
||||
// UnmarshalText unmarshal text to duration.
|
||||
func (d *Duration) UnmarshalText(text []byte) error {
|
||||
tmp, err := time.ParseDuration(string(text))
|
||||
if err == nil {
|
||||
*d = Duration(tmp)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func Test_Struct_CustomTimeDuration_Attribute(t *testing.T) {
|
||||
type A struct {
|
||||
Name string
|
||||
Timeout Duration
|
||||
}
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var a A
|
||||
err := gconv.Struct(g.Map{
|
||||
"name": "john",
|
||||
"timeout": "1s",
|
||||
}, &a)
|
||||
t.Assert(err, nil)
|
||||
})
|
||||
}
|
Loading…
Reference in New Issue
Block a user