goext/reflectext/convertToMap.go

103 lines
1.7 KiB
Go
Raw Permalink Normal View History

2024-01-23 17:51:52 +01:00
package reflectext
2024-03-18 11:19:01 +01:00
import (
"encoding/json"
2024-04-08 16:32:34 +02:00
"gogs.mikescher.com/BlackForestBytes/goext/langext"
2024-03-18 11:19:01 +01:00
"reflect"
)
2024-01-23 17:51:52 +01:00
2024-03-18 11:19:01 +01:00
type ConvertStructToMapOpt struct {
KeepJsonMarshalTypes bool
MaxDepth *int
2024-01-23 17:51:52 +01:00
}
2024-04-08 16:33:44 +02:00
func ConvertStructToMap(v any, opts ...ConvertStructToMapOpt) map[string]any {
2024-03-18 11:19:01 +01:00
opt := ConvertStructToMapOpt{}
if len(opts) > 0 {
opt = opts[0]
}
2024-04-08 16:32:34 +02:00
res := reflectToMap(reflect.ValueOf(v), 1, opt)
2024-04-08 16:32:34 +02:00
if v, ok := res.(map[string]any); ok {
return v
} else if langext.IsNil(res) {
return nil
} else {
panic("not an object")
}
2024-03-18 11:19:01 +01:00
}
func reflectToMap(fv reflect.Value, depth int, opt ConvertStructToMapOpt) any {
if opt.MaxDepth != nil && depth > *opt.MaxDepth {
return fv.Interface()
}
2024-01-23 17:51:52 +01:00
if fv.Kind() == reflect.Ptr {
if fv.IsNil() {
return nil
} else {
return reflectToMap(fv.Elem(), depth, opt)
2024-01-23 17:51:52 +01:00
}
}
if fv.Kind() == reflect.Func {
// skip
return nil
}
if fv.Kind() == reflect.Array {
arrlen := fv.Len()
arr := make([]any, arrlen)
for i := 0; i < arrlen; i++ {
arr[i] = reflectToMap(fv.Index(i), depth+1, opt)
2024-01-23 17:51:52 +01:00
}
return arr
}
if fv.Kind() == reflect.Slice {
arrlen := fv.Len()
arr := make([]any, arrlen)
for i := 0; i < arrlen; i++ {
arr[i] = reflectToMap(fv.Index(i), depth+1, opt)
2024-01-23 17:51:52 +01:00
}
return arr
}
if fv.Kind() == reflect.Chan {
// skip
return nil
}
if fv.Kind() == reflect.Struct {
2024-03-18 11:19:01 +01:00
if opt.KeepJsonMarshalTypes && fv.Type().Implements(reflect.TypeFor[json.Marshaler]()) {
return fv.Interface()
}
2024-01-23 17:51:52 +01:00
res := make(map[string]any)
for i := 0; i < fv.NumField(); i++ {
if fv.Type().Field(i).IsExported() {
res[fv.Type().Field(i).Name] = reflectToMap(fv.Field(i), depth+1, opt)
2024-01-23 17:51:52 +01:00
}
}
return res
}
return fv.Interface()
}