-
Notifications
You must be signed in to change notification settings - Fork 191
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
👔 up: reflects - update some util func and test
- Loading branch information
Showing
7 changed files
with
248 additions
and
139 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
package reflects | ||
|
||
import ( | ||
"reflect" | ||
"strconv" | ||
) | ||
|
||
// EachMap process any map data | ||
func EachMap(mp reflect.Value, fn func(key, val reflect.Value)) { | ||
if fn == nil { | ||
return | ||
} | ||
if mp.Kind() != reflect.Map { | ||
panic("only allow map value data") | ||
} | ||
|
||
for _, key := range mp.MapKeys() { | ||
fn(key, mp.MapIndex(key)) | ||
} | ||
} | ||
|
||
// EachStrAnyMap process any map data as string key and any value | ||
func EachStrAnyMap(mp reflect.Value, fn func(key string, val any)) { | ||
EachMap(mp, func(key, val reflect.Value) { | ||
fn(String(key), val.Interface()) | ||
}) | ||
} | ||
|
||
// FlatFunc custom collect handle func | ||
type FlatFunc func(path string, val reflect.Value) | ||
|
||
// FlatMap process tree map to flat key-value map. | ||
// | ||
// Examples: | ||
// | ||
// {"top": {"sub": "value", "sub2": "value2"} } | ||
// -> | ||
// {"top.sub": "value", "top.sub2": "value2" } | ||
func FlatMap(rv reflect.Value, fn FlatFunc) { | ||
if fn == nil { | ||
return | ||
} | ||
|
||
if rv.Kind() != reflect.Map { | ||
panic("only allow flat map data") | ||
} | ||
flatMap(rv, fn, "") | ||
} | ||
|
||
func flatMap(rv reflect.Value, fn FlatFunc, parent string) { | ||
for _, key := range rv.MapKeys() { | ||
path := String(key) | ||
if parent != "" { | ||
path = parent + "." + path | ||
} | ||
|
||
fv := Indirect(rv.MapIndex(key)) | ||
switch fv.Kind() { | ||
case reflect.Map: | ||
flatMap(fv, fn, path) | ||
case reflect.Array, reflect.Slice: | ||
flatSlice(fv, fn, path) | ||
default: | ||
fn(path, fv) | ||
} | ||
} | ||
} | ||
|
||
func flatSlice(rv reflect.Value, fn FlatFunc, parent string) { | ||
for i := 0; i < rv.Len(); i++ { | ||
path := parent + "[" + strconv.Itoa(i) + "]" | ||
fv := Indirect(rv.Index(i)) | ||
|
||
switch fv.Kind() { | ||
case reflect.Map: | ||
flatMap(fv, fn, path) | ||
case reflect.Array, reflect.Slice: | ||
flatSlice(fv, fn, path) | ||
default: | ||
fn(path, fv) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
package reflects_test | ||
|
||
import ( | ||
"reflect" | ||
"testing" | ||
|
||
"github.com/gookit/goutil/dump" | ||
"github.com/gookit/goutil/reflects" | ||
"github.com/gookit/goutil/testutil/assert" | ||
) | ||
|
||
func TestFlatMap(t *testing.T) { | ||
assert.Panics(t, func() { | ||
reflects.FlatMap(reflect.ValueOf("abc"), func(_ string, _ reflect.Value) { | ||
// nothing | ||
}) | ||
}) | ||
|
||
assert.NotPanics(t, func() { | ||
reflects.FlatMap(reflect.ValueOf(nil), nil) | ||
}) | ||
|
||
mp := map[string]any{ | ||
"name": "inhere", | ||
"age": 234, | ||
"top": map[string]any{ | ||
"sub0": "val0", | ||
"sub1": []string{"val1-0", "val1-1"}, | ||
}, | ||
} | ||
|
||
flatMp := make(map[string]any, len(mp)*2) | ||
reflects.FlatMap(reflect.ValueOf(mp), func(path string, val reflect.Value) { | ||
flatMp[path] = val.Interface() | ||
}) | ||
dump.P(flatMp) | ||
assert.Eq(t, "inhere", flatMp["name"]) | ||
assert.Eq(t, "val0", flatMp["top.sub0"]) | ||
assert.Eq(t, "val1-0", flatMp["top.sub1[0]"]) | ||
} | ||
|
||
func TestEachStrAnyMap(t *testing.T) { | ||
smp := map[int]string{ | ||
1: "val1", | ||
2: "val2", | ||
} | ||
|
||
mp := make(map[string]any) | ||
reflects.EachStrAnyMap(reflect.ValueOf(smp), func(key string, val any) { | ||
mp[key] = val | ||
}) | ||
|
||
assert.Eq(t, "val1", mp["1"]) | ||
assert.Eq(t, "val2", mp["2"]) | ||
|
||
assert.NotPanics(t, func() { | ||
reflects.EachMap(reflect.ValueOf("abc"), nil) | ||
}) | ||
assert.Panics(t, func() { | ||
reflects.EachMap(reflect.ValueOf("abc"), func(key, val reflect.Value) { | ||
// do nothing | ||
}) | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
package reflects | ||
|
||
import ( | ||
"fmt" | ||
"reflect" | ||
) | ||
|
||
// MakeSliceByElem create a new slice by the element type. | ||
// | ||
// - elType: the type of the element. | ||
// - returns: the new slice. | ||
// | ||
// Usage: | ||
// | ||
// sl := MakeSliceByElem(reflect.TypeOf(1), 10, 20) | ||
// sl.Index(0).SetInt(10) | ||
// | ||
// // Or use reflect.AppendSlice() merge two slice | ||
// // Or use `for` with `reflect.Append()` add elements | ||
func MakeSliceByElem(elTyp reflect.Type, len, cap int) reflect.Value { | ||
return reflect.MakeSlice(reflect.SliceOf(elTyp), len, cap) | ||
} | ||
|
||
// FlatSlice flatten multi-level slice to given depth-level slice. | ||
// | ||
// Example: | ||
// | ||
// FlatSlice([]any{ []any{3, 4}, []any{5, 6} }, 1) // Output: []any{3, 4, 5, 6} | ||
// | ||
// always return reflect.Value of []any. note: maybe flatSl.Cap != flatSl.Len | ||
func FlatSlice(sl reflect.Value, depth int) reflect.Value { | ||
items := make([]reflect.Value, 0, sl.Cap()) | ||
slCap := addSliceItem(sl, depth, func(item reflect.Value) { | ||
items = append(items, item) | ||
}) | ||
|
||
flatSl := reflect.MakeSlice(reflect.SliceOf(anyType), 0, slCap) | ||
flatSl = reflect.Append(flatSl, items...) | ||
|
||
return flatSl | ||
} | ||
|
||
func addSliceItem(sl reflect.Value, depth int, collector func(item reflect.Value)) (c int) { | ||
for i := 0; i < sl.Len(); i++ { | ||
v := Elem(sl.Index(i)) | ||
|
||
if depth > 0 { | ||
if v.Kind() != reflect.Slice { | ||
panic(fmt.Sprintf("depth: %d, the value of index %d is not slice", depth, i)) | ||
} | ||
c += addSliceItem(v, depth-1, collector) | ||
} else { | ||
collector(v) | ||
} | ||
} | ||
|
||
if depth == 0 { | ||
c = sl.Cap() | ||
} | ||
return c | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package reflects_test | ||
|
||
import ( | ||
"reflect" | ||
"testing" | ||
|
||
"github.com/gookit/goutil/dump" | ||
"github.com/gookit/goutil/reflects" | ||
"github.com/gookit/goutil/testutil/assert" | ||
) | ||
|
||
func TestMakeSliceByElem(t *testing.T) { | ||
slv := reflects.MakeSliceByElem(reflect.TypeOf("str"), 0, 2) | ||
slv = reflect.Append(slv, reflect.ValueOf("a")) | ||
slv = reflect.Append(slv, reflect.ValueOf("b")) | ||
|
||
sl := slv.Interface().([]string) | ||
dump.P(sl) | ||
assert.Len(t, sl, 2) | ||
assert.Eq(t, "a", sl[0]) | ||
} | ||
|
||
func TestFlatSlice(t *testing.T) { | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.